@@ -5,6 +5,11 @@ use proc_macro2::Ident;
5
5
/// Used to build the output tokens for dynamic bindings.
6
6
#[ derive( Default ) ]
7
7
pub struct DynamicItems {
8
+ /// Tracks whether or not we contain any required symbols.
9
+ /// If so, the signature of the generated `from_library` function
10
+ /// will be altered to return a `Result<Self, ::libloading::Error>`
11
+ has_required : bool ,
12
+
8
13
/// Tracks the tokens that will appears inside the library struct -- e.g.:
9
14
/// ```ignore
10
15
/// struct Lib {
@@ -77,6 +82,11 @@ impl DynamicItems {
77
82
let constructor_inits = & self . constructor_inits ;
78
83
let init_fields = & self . init_fields ;
79
84
let struct_implementation = & self . struct_implementation ;
85
+
86
+ // FIXME: Is there a better way to lay this out? Conditional in the quote
87
+ // macro?
88
+ // If we have any required symbols, we must alter the signature of `from_library`
89
+ // so that it can return a failure code.
80
90
quote ! {
81
91
extern crate libloading;
82
92
@@ -91,19 +101,19 @@ impl DynamicItems {
91
101
) -> Result <Self , :: libloading:: Error >
92
102
where P : AsRef <:: std:: ffi:: OsStr > {
93
103
let library = :: libloading:: Library :: new( path) ?;
94
- Ok ( Self :: from_library( library) )
104
+ Self :: from_library( library)
95
105
}
96
106
97
107
pub unsafe fn from_library<L >(
98
108
library: L
99
- ) -> Self
109
+ ) -> Result < Self , :: libloading :: Error >
100
110
where L : Into <:: libloading:: Library > {
101
111
let __library = library. into( ) ;
102
112
#( #constructor_inits ) *
103
- #lib_ident {
113
+ Ok ( #lib_ident {
104
114
__library,
105
115
#( #init_fields ) , *
106
- }
116
+ } )
107
117
}
108
118
109
119
#( #struct_implementation ) *
@@ -116,6 +126,7 @@ impl DynamicItems {
116
126
ident : Ident ,
117
127
abi : Abi ,
118
128
is_variadic : bool ,
129
+ is_required : bool ,
119
130
args : Vec < proc_macro2:: TokenStream > ,
120
131
args_identifiers : Vec < proc_macro2:: TokenStream > ,
121
132
ret : proc_macro2:: TokenStream ,
@@ -125,24 +136,50 @@ impl DynamicItems {
125
136
assert_eq ! ( args. len( ) , args_identifiers. len( ) ) ;
126
137
}
127
138
128
- self . struct_members . push ( quote ! {
129
- pub #ident: Result <unsafe extern #abi fn ( #( #args ) , * ) #ret, :: libloading:: Error >,
130
- } ) ;
139
+ self . has_required |= is_required;
140
+
141
+ self . struct_members . push (
142
+ if is_required {
143
+ quote ! {
144
+ pub #ident: unsafe extern #abi fn ( #( #args) , * ) #ret,
145
+ }
146
+ } else {
147
+ quote ! {
148
+ pub #ident: Result <unsafe extern #abi fn ( #( #args ) , * ) #ret, :: libloading:: Error >,
149
+ }
150
+ }
151
+ ) ;
131
152
132
153
// We can't implement variadic functions from C easily, so we allow to
133
154
// access the function pointer so that the user can call it just fine.
134
155
if !is_variadic {
135
- self . struct_implementation . push ( quote ! {
136
- pub unsafe fn #ident ( & self , #( #args ) , * ) -> #ret_ty {
137
- let sym = self . #ident. as_ref( ) . expect( "Expected function, got error." ) ;
138
- ( sym) ( #( #args_identifiers ) , * )
156
+ self . struct_implementation . push (
157
+ if is_required {
158
+ quote ! {
159
+ pub unsafe fn #ident ( & self , #( #args ) , * ) -> #ret_ty {
160
+ self . #ident( #( #args_identifiers ) , * )
161
+ }
162
+ }
163
+ } else {
164
+ quote ! {
165
+ pub unsafe fn #ident ( & self , #( #args ) , * ) -> #ret_ty {
166
+ let sym = self . #ident. as_ref( ) . expect( "Expected function, got error." ) ;
167
+ ( sym) ( #( #args_identifiers ) , * )
168
+ }
169
+ }
139
170
}
140
- } ) ;
171
+ ) ;
141
172
}
142
173
143
174
let ident_str = codegen:: helpers:: ast_ty:: cstr_expr ( ident. to_string ( ) ) ;
144
- self . constructor_inits . push ( quote ! {
145
- let #ident = __library. get( #ident_str) . map( |sym| * sym) ;
175
+ self . constructor_inits . push ( if is_required {
176
+ quote ! {
177
+ let #ident = __library. get( #ident_str) . map( |sym| * sym) ?;
178
+ }
179
+ } else {
180
+ quote ! {
181
+ let #ident = __library. get( #ident_str) . map( |sym| * sym) ;
182
+ }
146
183
} ) ;
147
184
148
185
self . init_fields . push ( quote ! {
0 commit comments