summaryrefslogtreecommitdiff
path: root/src/codegen/dyngen.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen/dyngen.rs')
-rw-r--r--src/codegen/dyngen.rs65
1 files changed, 51 insertions, 14 deletions
diff --git a/src/codegen/dyngen.rs b/src/codegen/dyngen.rs
index 768fb02e..de9e0f98 100644
--- a/src/codegen/dyngen.rs
+++ b/src/codegen/dyngen.rs
@@ -5,6 +5,11 @@ use proc_macro2::Ident;
/// Used to build the output tokens for dynamic bindings.
#[derive(Default)]
pub struct DynamicItems {
+ /// Tracks whether or not we contain any required symbols.
+ /// If so, the signature of the generated `from_library` function
+ /// will be altered to return a `Result<Self, ::libloading::Error>`
+ has_required: bool,
+
/// Tracks the tokens that will appears inside the library struct -- e.g.:
/// ```ignore
/// struct Lib {
@@ -77,6 +82,11 @@ impl DynamicItems {
let constructor_inits = &self.constructor_inits;
let init_fields = &self.init_fields;
let struct_implementation = &self.struct_implementation;
+
+ // FIXME: Is there a better way to lay this out? Conditional in the quote
+ // macro?
+ // If we have any required symbols, we must alter the signature of `from_library`
+ // so that it can return a failure code.
quote! {
extern crate libloading;
@@ -91,19 +101,19 @@ impl DynamicItems {
) -> Result<Self, ::libloading::Error>
where P: AsRef<::std::ffi::OsStr> {
let library = ::libloading::Library::new(path)?;
- Ok(Self::from_library(library))
+ Self::from_library(library)
}
pub unsafe fn from_library<L>(
library: L
- ) -> Self
+ ) -> Result<Self, ::libloading::Error>
where L: Into<::libloading::Library> {
let __library = library.into();
#( #constructor_inits )*
- #lib_ident {
+ Ok(#lib_ident {
__library,
#( #init_fields ),*
- }
+ })
}
#( #struct_implementation )*
@@ -116,6 +126,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,
@@ -125,24 +136,50 @@ impl DynamicItems {
assert_eq!(args.len(), args_identifiers.len());
}
- self.struct_members.push(quote! {
- pub #ident: Result<unsafe extern #abi fn ( #( #args ),* ) #ret, ::libloading::Error>,
- });
+ self.has_required |= is_required;
+
+ self.struct_members.push(
+ if is_required {
+ quote! {
+ pub #ident: unsafe extern #abi fn ( #( #args),* ) #ret,
+ }
+ } else {
+ quote! {
+ pub #ident: Result<unsafe extern #abi fn ( #( #args ),* ) #ret, ::libloading::Error>,
+ }
+ }
+ );
// 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 ),*)
+ self.struct_implementation.push(
+ if is_required {
+ quote! {
+ pub unsafe fn #ident ( &self, #( #args ),* ) -> #ret_ty {
+ self.#ident(#( #args_identifiers ),*)
+ }
+ }
+ } else {
+ quote! {
+ pub unsafe fn #ident ( &self, #( #args ),* ) -> #ret_ty {
+ let sym = self.#ident.as_ref().expect("Expected function, got error.");
+ (sym)(#( #args_identifiers ),*)
+ }
+ }
}
- });
+ );
}
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! {