aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/dyngen.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen/dyngen.rs')
-rw-r--r--src/codegen/dyngen.rs56
1 files changed, 44 insertions, 12 deletions
diff --git a/src/codegen/dyngen.rs b/src/codegen/dyngen.rs
index 94dd574..71c4dab 100644
--- a/src/codegen/dyngen.rs
+++ b/src/codegen/dyngen.rs
@@ -77,6 +77,7 @@ impl DynamicItems {
let constructor_inits = &self.constructor_inits;
let init_fields = &self.init_fields;
let struct_implementation = &self.struct_implementation;
+
quote! {
extern crate libloading;
@@ -90,14 +91,20 @@ impl DynamicItems {
path: P
) -> Result<Self, ::libloading::Error>
where P: AsRef<::std::ffi::OsStr> {
- let __library = ::libloading::Library::new(path)?;
+ let library = ::libloading::Library::new(path)?;
+ Self::from_library(library)
+ }
+
+ pub unsafe fn from_library<L>(
+ library: L
+ ) -> Result<Self, ::libloading::Error>
+ where L: Into<::libloading::Library> {
+ let __library = library.into();
#( #constructor_inits )*
- Ok(
- #lib_ident {
- __library,
- #( #init_fields ),*
- }
- )
+ Ok(#lib_ident {
+ __library,
+ #( #init_fields ),*
+ })
}
#( #struct_implementation )*
@@ -110,6 +117,7 @@ impl DynamicItems {
ident: Ident,
abi: Abi,
is_variadic: bool,
+ is_required: bool,
args: Vec<proc_macro2::TokenStream>,
args_identifiers: Vec<proc_macro2::TokenStream>,
ret: proc_macro2::TokenStream,
@@ -119,24 +127,48 @@ impl DynamicItems {
assert_eq!(args.len(), args_identifiers.len());
}
+ let signature = quote! { unsafe extern #abi fn ( #( #args),* ) #ret };
+ let member = if is_required {
+ signature
+ } else {
+ quote! { Result<#signature, ::libloading::Error> }
+ };
+
self.struct_members.push(quote! {
- pub #ident: Result<unsafe extern #abi fn ( #( #args ),* ) #ret, ::libloading::Error>,
+ pub #ident: #member,
});
+ // N.B: If the signature was required, it won't be wrapped in a Result<...>
+ // and we can simply call it directly.
+ let fn_ = if is_required {
+ quote! { self.#ident }
+ } else {
+ quote! { self.#ident.as_ref().expect("Expected function, got error.") }
+ };
+ let call_body = quote! {
+ (#fn_)(#( #args_identifiers ),*)
+ };
+
// We can't implement variadic functions from C easily, so we allow to
// access the function pointer so that the user can call it just fine.
if !is_variadic {
self.struct_implementation.push(quote! {
pub unsafe fn #ident ( &self, #( #args ),* ) -> #ret_ty {
- let sym = self.#ident.as_ref().expect("Expected function, got error.");
- (sym)(#( #args_identifiers ),*)
+ #call_body
}
});
}
+ // N.B: Unwrap the signature upon construction if it is required to be resolved.
let ident_str = codegen::helpers::ast_ty::cstr_expr(ident.to_string());
- self.constructor_inits.push(quote! {
- let #ident = __library.get(#ident_str).map(|sym| *sym);
+ self.constructor_inits.push(if is_required {
+ quote! {
+ let #ident = __library.get(#ident_str).map(|sym| *sym)?;
+ }
+ } else {
+ quote! {
+ let #ident = __library.get(#ident_str).map(|sym| *sym);
+ }
});
self.init_fields.push(quote! {