1 use crate::ir::function::Abi; 2 use proc_macro2::Ident; 3 4 /// Used to build the output tokens for dynamic bindings. 5 #[derive(Default)] 6 pub struct DynamicItems { 7 /// Tracks the tokens that will appears inside the library struct -- e.g.: 8 /// ```ignore 9 /// struct Lib { 10 /// __library: ::libloading::Library, 11 /// pub x: Result<unsafe extern ..., ::libloading::Error>, // <- tracks these 12 /// ... 13 /// } 14 /// ``` 15 struct_members: Vec<proc_macro2::TokenStream>, 16 17 /// Tracks the tokens that will appear inside the library struct's implementation, e.g.: 18 /// 19 /// ```ignore 20 /// impl Lib { 21 /// ... 22 /// pub unsafe fn foo(&self, ...) { // <- tracks these 23 /// ... 24 /// } 25 /// } 26 /// ``` 27 struct_implementation: Vec<proc_macro2::TokenStream>, 28 29 /// Tracks the initialization of the fields inside the `::new` constructor of the library 30 /// struct, e.g.: 31 /// ```ignore 32 /// impl Lib { 33 /// 34 /// pub unsafe fn new<P>(path: P) -> Result<Self, ::libloading::Error> 35 /// where 36 /// P: AsRef<::std::ffi::OsStr>, 37 /// { 38 /// ... 39 /// let foo = __library.get(...) ...; // <- tracks these 40 /// ... 41 /// } 42 /// 43 /// ... 44 /// } 45 /// ``` 46 constructor_inits: Vec<proc_macro2::TokenStream>, 47 48 /// Tracks the information that is passed to the library struct at the end of the `::new` 49 /// constructor, e.g.: 50 /// ```ignore 51 /// impl LibFoo { 52 /// pub unsafe fn new<P>(path: P) -> Result<Self, ::libloading::Error> 53 /// where 54 /// P: AsRef<::std::ffi::OsStr>, 55 /// { 56 /// ... 57 /// Ok(LibFoo { 58 /// __library: __library, 59 /// foo, 60 /// bar, // <- tracks these 61 /// ... 62 /// }) 63 /// } 64 /// } 65 /// ``` 66 init_fields: Vec<proc_macro2::TokenStream>, 67 } 68 69 impl DynamicItems { new() -> Self70 pub fn new() -> Self { 71 Self::default() 72 } 73 get_tokens(&self, lib_ident: Ident) -> proc_macro2::TokenStream74 pub fn get_tokens(&self, lib_ident: Ident) -> proc_macro2::TokenStream { 75 let struct_members = &self.struct_members; 76 let constructor_inits = &self.constructor_inits; 77 let init_fields = &self.init_fields; 78 let struct_implementation = &self.struct_implementation; 79 quote! { 80 extern crate libloading; 81 82 pub struct #lib_ident { 83 __library: ::libloading::Library, 84 #(#struct_members)* 85 } 86 87 impl #lib_ident { 88 pub unsafe fn new<P>( 89 path: P 90 ) -> Result<Self, ::libloading::Error> 91 where P: AsRef<::std::ffi::OsStr> { 92 let __library = ::libloading::Library::new(path)?; 93 #( #constructor_inits )* 94 Ok( 95 #lib_ident { 96 __library, 97 #( #init_fields ),* 98 } 99 ) 100 } 101 102 #( #struct_implementation )* 103 } 104 } 105 } 106 push( &mut self, ident: Ident, abi: Abi, is_variadic: bool, args: Vec<proc_macro2::TokenStream>, args_identifiers: Vec<proc_macro2::TokenStream>, ret: proc_macro2::TokenStream, ret_ty: proc_macro2::TokenStream, )107 pub fn push( 108 &mut self, 109 ident: Ident, 110 abi: Abi, 111 is_variadic: bool, 112 args: Vec<proc_macro2::TokenStream>, 113 args_identifiers: Vec<proc_macro2::TokenStream>, 114 ret: proc_macro2::TokenStream, 115 ret_ty: proc_macro2::TokenStream, 116 ) { 117 if !is_variadic { 118 assert_eq!(args.len(), args_identifiers.len()); 119 } 120 121 self.struct_members.push(quote! { 122 pub #ident: Result<unsafe extern #abi fn ( #( #args ),* ) #ret, ::libloading::Error>, 123 }); 124 125 // We can't implement variadic functions from C easily, so we allow to 126 // access the function pointer so that the user can call it just fine. 127 if !is_variadic { 128 self.struct_implementation.push(quote! { 129 pub unsafe fn #ident ( &self, #( #args ),* ) -> #ret_ty { 130 let sym = self.#ident.as_ref().expect("Expected function, got error."); 131 (sym)(#( #args_identifiers ),*) 132 } 133 }); 134 } 135 136 let ident_str = ident.to_string(); 137 self.constructor_inits.push(quote! { 138 let #ident = __library.get(#ident_str.as_bytes()).map(|sym| *sym); 139 }); 140 141 self.init_fields.push(quote! { 142 #ident 143 }); 144 } 145 } 146