1 use crate::codegen; 2 use crate::ir::context::BindgenContext; 3 use crate::ir::function::ClangAbi; 4 use proc_macro2::Ident; 5 6 /// Used to build the output tokens for dynamic bindings. 7 #[derive(Default)] 8 pub(crate) struct DynamicItems { 9 /// Tracks the tokens that will appears inside the library struct -- e.g.: 10 /// ```ignore 11 /// struct Lib { 12 /// __library: ::libloading::Library, 13 /// pub x: Result<unsafe extern ..., ::libloading::Error>, // <- tracks these 14 /// ... 15 /// } 16 /// ``` 17 struct_members: Vec<proc_macro2::TokenStream>, 18 19 /// Tracks the tokens that will appear inside the library struct's implementation, e.g.: 20 /// 21 /// ```ignore 22 /// impl Lib { 23 /// ... 24 /// pub unsafe fn foo(&self, ...) { // <- tracks these 25 /// ... 26 /// } 27 /// } 28 /// ``` 29 struct_implementation: Vec<proc_macro2::TokenStream>, 30 31 /// Tracks the initialization of the fields inside the `::new` constructor of the library 32 /// struct, e.g.: 33 /// ```ignore 34 /// impl Lib { 35 /// 36 /// pub unsafe fn new<P>(path: P) -> Result<Self, ::libloading::Error> 37 /// where 38 /// P: AsRef<::std::ffi::OsStr>, 39 /// { 40 /// ... 41 /// let foo = __library.get(...) ...; // <- tracks these 42 /// ... 43 /// } 44 /// 45 /// ... 46 /// } 47 /// ``` 48 constructor_inits: Vec<proc_macro2::TokenStream>, 49 50 /// Tracks the information that is passed to the library struct at the end of the `::new` 51 /// constructor, e.g.: 52 /// ```ignore 53 /// impl LibFoo { 54 /// pub unsafe fn new<P>(path: P) -> Result<Self, ::libloading::Error> 55 /// where 56 /// P: AsRef<::std::ffi::OsStr>, 57 /// { 58 /// ... 59 /// Ok(LibFoo { 60 /// __library: __library, 61 /// foo, 62 /// bar, // <- tracks these 63 /// ... 64 /// }) 65 /// } 66 /// } 67 /// ``` 68 init_fields: Vec<proc_macro2::TokenStream>, 69 } 70 71 impl DynamicItems { new() -> Self72 pub(crate) fn new() -> Self { 73 Self::default() 74 } 75 get_tokens( &self, lib_ident: Ident, ctx: &BindgenContext, ) -> proc_macro2::TokenStream76 pub(crate) fn get_tokens( 77 &self, 78 lib_ident: Ident, 79 ctx: &BindgenContext, 80 ) -> proc_macro2::TokenStream { 81 let struct_members = &self.struct_members; 82 let constructor_inits = &self.constructor_inits; 83 let init_fields = &self.init_fields; 84 let struct_implementation = &self.struct_implementation; 85 86 let from_library = if ctx.options().wrap_unsafe_ops { 87 quote!(unsafe { Self::from_library(library) }) 88 } else { 89 quote!(Self::from_library(library)) 90 }; 91 92 quote! { 93 extern crate libloading; 94 95 pub struct #lib_ident { 96 __library: ::libloading::Library, 97 #(#struct_members)* 98 } 99 100 impl #lib_ident { 101 pub unsafe fn new<P>( 102 path: P 103 ) -> Result<Self, ::libloading::Error> 104 where P: AsRef<::std::ffi::OsStr> { 105 let library = ::libloading::Library::new(path)?; 106 #from_library 107 } 108 109 pub unsafe fn from_library<L>( 110 library: L 111 ) -> Result<Self, ::libloading::Error> 112 where L: Into<::libloading::Library> { 113 let __library = library.into(); 114 #( #constructor_inits )* 115 Ok(#lib_ident { 116 __library, 117 #( #init_fields ),* 118 }) 119 } 120 121 #( #struct_implementation )* 122 } 123 } 124 } 125 126 #[allow(clippy::too_many_arguments)] push( &mut self, ident: Ident, abi: ClangAbi, is_variadic: bool, is_required: bool, args: Vec<proc_macro2::TokenStream>, args_identifiers: Vec<proc_macro2::TokenStream>, ret: proc_macro2::TokenStream, ret_ty: proc_macro2::TokenStream, attributes: Vec<proc_macro2::TokenStream>, ctx: &BindgenContext, )127 pub(crate) fn push( 128 &mut self, 129 ident: Ident, 130 abi: ClangAbi, 131 is_variadic: bool, 132 is_required: bool, 133 args: Vec<proc_macro2::TokenStream>, 134 args_identifiers: Vec<proc_macro2::TokenStream>, 135 ret: proc_macro2::TokenStream, 136 ret_ty: proc_macro2::TokenStream, 137 attributes: Vec<proc_macro2::TokenStream>, 138 ctx: &BindgenContext, 139 ) { 140 if !is_variadic { 141 assert_eq!(args.len(), args_identifiers.len()); 142 } 143 144 let signature = quote! { unsafe extern #abi fn ( #( #args),* ) #ret }; 145 let member = if is_required { 146 signature 147 } else { 148 quote! { Result<#signature, ::libloading::Error> } 149 }; 150 151 self.struct_members.push(quote! { 152 pub #ident: #member, 153 }); 154 155 // N.B: If the signature was required, it won't be wrapped in a Result<...> 156 // and we can simply call it directly. 157 let fn_ = if is_required { 158 quote! { self.#ident } 159 } else { 160 quote! { self.#ident.as_ref().expect("Expected function, got error.") } 161 }; 162 let call_body = if ctx.options().wrap_unsafe_ops { 163 quote!(unsafe { (#fn_)(#( #args_identifiers ),*) }) 164 } else { 165 quote!((#fn_)(#( #args_identifiers ),*) ) 166 }; 167 168 // We can't implement variadic functions from C easily, so we allow to 169 // access the function pointer so that the user can call it just fine. 170 if !is_variadic { 171 self.struct_implementation.push(quote! { 172 #(#attributes)* 173 pub unsafe fn #ident ( &self, #( #args ),* ) #ret_ty { 174 #call_body 175 } 176 }); 177 } 178 179 // N.B: Unwrap the signature upon construction if it is required to be resolved. 180 let ident_str = codegen::helpers::ast_ty::cstr_expr(ident.to_string()); 181 let library_get = if ctx.options().wrap_unsafe_ops { 182 quote!(unsafe { __library.get(#ident_str) }) 183 } else { 184 quote!(__library.get(#ident_str)) 185 }; 186 187 self.constructor_inits.push(if is_required { 188 quote! { 189 let #ident = #library_get.map(|sym| *sym)?; 190 } 191 } else { 192 quote! { 193 let #ident = #library_get.map(|sym| *sym); 194 } 195 }); 196 197 self.init_fields.push(quote! { 198 #ident 199 }); 200 } 201 } 202