112a9d9c8Sopenharmony_ciuse crate::codegen; 212a9d9c8Sopenharmony_ciuse crate::ir::context::BindgenContext; 312a9d9c8Sopenharmony_ciuse crate::ir::function::ClangAbi; 412a9d9c8Sopenharmony_ciuse proc_macro2::Ident; 512a9d9c8Sopenharmony_ci 612a9d9c8Sopenharmony_ci/// Used to build the output tokens for dynamic bindings. 712a9d9c8Sopenharmony_ci#[derive(Default)] 812a9d9c8Sopenharmony_cipub struct DynamicItems { 912a9d9c8Sopenharmony_ci /// Tracks the tokens that will appears inside the library struct -- e.g.: 1012a9d9c8Sopenharmony_ci /// ```ignore 1112a9d9c8Sopenharmony_ci /// struct Lib { 1212a9d9c8Sopenharmony_ci /// __library: ::libloading::Library, 1312a9d9c8Sopenharmony_ci /// pub x: Result<unsafe extern ..., ::libloading::Error>, // <- tracks these 1412a9d9c8Sopenharmony_ci /// ... 1512a9d9c8Sopenharmony_ci /// } 1612a9d9c8Sopenharmony_ci /// ``` 1712a9d9c8Sopenharmony_ci struct_members: Vec<proc_macro2::TokenStream>, 1812a9d9c8Sopenharmony_ci 1912a9d9c8Sopenharmony_ci /// Tracks the tokens that will appear inside the library struct's implementation, e.g.: 2012a9d9c8Sopenharmony_ci /// 2112a9d9c8Sopenharmony_ci /// ```ignore 2212a9d9c8Sopenharmony_ci /// impl Lib { 2312a9d9c8Sopenharmony_ci /// ... 2412a9d9c8Sopenharmony_ci /// pub unsafe fn foo(&self, ...) { // <- tracks these 2512a9d9c8Sopenharmony_ci /// ... 2612a9d9c8Sopenharmony_ci /// } 2712a9d9c8Sopenharmony_ci /// } 2812a9d9c8Sopenharmony_ci /// ``` 2912a9d9c8Sopenharmony_ci struct_implementation: Vec<proc_macro2::TokenStream>, 3012a9d9c8Sopenharmony_ci 3112a9d9c8Sopenharmony_ci /// Tracks the initialization of the fields inside the `::new` constructor of the library 3212a9d9c8Sopenharmony_ci /// struct, e.g.: 3312a9d9c8Sopenharmony_ci /// ```ignore 3412a9d9c8Sopenharmony_ci /// impl Lib { 3512a9d9c8Sopenharmony_ci /// 3612a9d9c8Sopenharmony_ci /// pub unsafe fn new<P>(path: P) -> Result<Self, ::libloading::Error> 3712a9d9c8Sopenharmony_ci /// where 3812a9d9c8Sopenharmony_ci /// P: AsRef<::std::ffi::OsStr>, 3912a9d9c8Sopenharmony_ci /// { 4012a9d9c8Sopenharmony_ci /// ... 4112a9d9c8Sopenharmony_ci /// let foo = __library.get(...) ...; // <- tracks these 4212a9d9c8Sopenharmony_ci /// ... 4312a9d9c8Sopenharmony_ci /// } 4412a9d9c8Sopenharmony_ci /// 4512a9d9c8Sopenharmony_ci /// ... 4612a9d9c8Sopenharmony_ci /// } 4712a9d9c8Sopenharmony_ci /// ``` 4812a9d9c8Sopenharmony_ci constructor_inits: Vec<proc_macro2::TokenStream>, 4912a9d9c8Sopenharmony_ci 5012a9d9c8Sopenharmony_ci /// Tracks the information that is passed to the library struct at the end of the `::new` 5112a9d9c8Sopenharmony_ci /// constructor, e.g.: 5212a9d9c8Sopenharmony_ci /// ```ignore 5312a9d9c8Sopenharmony_ci /// impl LibFoo { 5412a9d9c8Sopenharmony_ci /// pub unsafe fn new<P>(path: P) -> Result<Self, ::libloading::Error> 5512a9d9c8Sopenharmony_ci /// where 5612a9d9c8Sopenharmony_ci /// P: AsRef<::std::ffi::OsStr>, 5712a9d9c8Sopenharmony_ci /// { 5812a9d9c8Sopenharmony_ci /// ... 5912a9d9c8Sopenharmony_ci /// Ok(LibFoo { 6012a9d9c8Sopenharmony_ci /// __library: __library, 6112a9d9c8Sopenharmony_ci /// foo, 6212a9d9c8Sopenharmony_ci /// bar, // <- tracks these 6312a9d9c8Sopenharmony_ci /// ... 6412a9d9c8Sopenharmony_ci /// }) 6512a9d9c8Sopenharmony_ci /// } 6612a9d9c8Sopenharmony_ci /// } 6712a9d9c8Sopenharmony_ci /// ``` 6812a9d9c8Sopenharmony_ci init_fields: Vec<proc_macro2::TokenStream>, 6912a9d9c8Sopenharmony_ci} 7012a9d9c8Sopenharmony_ci 7112a9d9c8Sopenharmony_ciimpl DynamicItems { 7212a9d9c8Sopenharmony_ci pub fn new() -> Self { 7312a9d9c8Sopenharmony_ci Self::default() 7412a9d9c8Sopenharmony_ci } 7512a9d9c8Sopenharmony_ci 7612a9d9c8Sopenharmony_ci pub fn get_tokens( 7712a9d9c8Sopenharmony_ci &self, 7812a9d9c8Sopenharmony_ci lib_ident: Ident, 7912a9d9c8Sopenharmony_ci ctx: &BindgenContext, 8012a9d9c8Sopenharmony_ci ) -> proc_macro2::TokenStream { 8112a9d9c8Sopenharmony_ci let struct_members = &self.struct_members; 8212a9d9c8Sopenharmony_ci let constructor_inits = &self.constructor_inits; 8312a9d9c8Sopenharmony_ci let init_fields = &self.init_fields; 8412a9d9c8Sopenharmony_ci let struct_implementation = &self.struct_implementation; 8512a9d9c8Sopenharmony_ci 8612a9d9c8Sopenharmony_ci let from_library = if ctx.options().wrap_unsafe_ops { 8712a9d9c8Sopenharmony_ci quote!(unsafe { Self::from_library(library) }) 8812a9d9c8Sopenharmony_ci } else { 8912a9d9c8Sopenharmony_ci quote!(Self::from_library(library)) 9012a9d9c8Sopenharmony_ci }; 9112a9d9c8Sopenharmony_ci 9212a9d9c8Sopenharmony_ci quote! { 9312a9d9c8Sopenharmony_ci extern crate libloading; 9412a9d9c8Sopenharmony_ci 9512a9d9c8Sopenharmony_ci pub struct #lib_ident { 9612a9d9c8Sopenharmony_ci __library: ::libloading::Library, 9712a9d9c8Sopenharmony_ci #(#struct_members)* 9812a9d9c8Sopenharmony_ci } 9912a9d9c8Sopenharmony_ci 10012a9d9c8Sopenharmony_ci impl #lib_ident { 10112a9d9c8Sopenharmony_ci pub unsafe fn new<P>( 10212a9d9c8Sopenharmony_ci path: P 10312a9d9c8Sopenharmony_ci ) -> Result<Self, ::libloading::Error> 10412a9d9c8Sopenharmony_ci where P: AsRef<::std::ffi::OsStr> { 10512a9d9c8Sopenharmony_ci let library = ::libloading::Library::new(path)?; 10612a9d9c8Sopenharmony_ci #from_library 10712a9d9c8Sopenharmony_ci } 10812a9d9c8Sopenharmony_ci 10912a9d9c8Sopenharmony_ci pub unsafe fn from_library<L>( 11012a9d9c8Sopenharmony_ci library: L 11112a9d9c8Sopenharmony_ci ) -> Result<Self, ::libloading::Error> 11212a9d9c8Sopenharmony_ci where L: Into<::libloading::Library> { 11312a9d9c8Sopenharmony_ci let __library = library.into(); 11412a9d9c8Sopenharmony_ci #( #constructor_inits )* 11512a9d9c8Sopenharmony_ci Ok(#lib_ident { 11612a9d9c8Sopenharmony_ci __library, 11712a9d9c8Sopenharmony_ci #( #init_fields ),* 11812a9d9c8Sopenharmony_ci }) 11912a9d9c8Sopenharmony_ci } 12012a9d9c8Sopenharmony_ci 12112a9d9c8Sopenharmony_ci #( #struct_implementation )* 12212a9d9c8Sopenharmony_ci } 12312a9d9c8Sopenharmony_ci } 12412a9d9c8Sopenharmony_ci } 12512a9d9c8Sopenharmony_ci 12612a9d9c8Sopenharmony_ci #[allow(clippy::too_many_arguments)] 12712a9d9c8Sopenharmony_ci pub(crate) fn push( 12812a9d9c8Sopenharmony_ci &mut self, 12912a9d9c8Sopenharmony_ci ident: Ident, 13012a9d9c8Sopenharmony_ci abi: ClangAbi, 13112a9d9c8Sopenharmony_ci is_variadic: bool, 13212a9d9c8Sopenharmony_ci is_required: bool, 13312a9d9c8Sopenharmony_ci args: Vec<proc_macro2::TokenStream>, 13412a9d9c8Sopenharmony_ci args_identifiers: Vec<proc_macro2::TokenStream>, 13512a9d9c8Sopenharmony_ci ret: proc_macro2::TokenStream, 13612a9d9c8Sopenharmony_ci ret_ty: proc_macro2::TokenStream, 13712a9d9c8Sopenharmony_ci attributes: Vec<proc_macro2::TokenStream>, 13812a9d9c8Sopenharmony_ci ctx: &BindgenContext, 13912a9d9c8Sopenharmony_ci ) { 14012a9d9c8Sopenharmony_ci if !is_variadic { 14112a9d9c8Sopenharmony_ci assert_eq!(args.len(), args_identifiers.len()); 14212a9d9c8Sopenharmony_ci } 14312a9d9c8Sopenharmony_ci 14412a9d9c8Sopenharmony_ci let signature = quote! { unsafe extern #abi fn ( #( #args),* ) #ret }; 14512a9d9c8Sopenharmony_ci let member = if is_required { 14612a9d9c8Sopenharmony_ci signature 14712a9d9c8Sopenharmony_ci } else { 14812a9d9c8Sopenharmony_ci quote! { Result<#signature, ::libloading::Error> } 14912a9d9c8Sopenharmony_ci }; 15012a9d9c8Sopenharmony_ci 15112a9d9c8Sopenharmony_ci self.struct_members.push(quote! { 15212a9d9c8Sopenharmony_ci pub #ident: #member, 15312a9d9c8Sopenharmony_ci }); 15412a9d9c8Sopenharmony_ci 15512a9d9c8Sopenharmony_ci // N.B: If the signature was required, it won't be wrapped in a Result<...> 15612a9d9c8Sopenharmony_ci // and we can simply call it directly. 15712a9d9c8Sopenharmony_ci let fn_ = if is_required { 15812a9d9c8Sopenharmony_ci quote! { self.#ident } 15912a9d9c8Sopenharmony_ci } else { 16012a9d9c8Sopenharmony_ci quote! { self.#ident.as_ref().expect("Expected function, got error.") } 16112a9d9c8Sopenharmony_ci }; 16212a9d9c8Sopenharmony_ci let call_body = if ctx.options().wrap_unsafe_ops { 16312a9d9c8Sopenharmony_ci quote!(unsafe { (#fn_)(#( #args_identifiers ),*) }) 16412a9d9c8Sopenharmony_ci } else { 16512a9d9c8Sopenharmony_ci quote!((#fn_)(#( #args_identifiers ),*) ) 16612a9d9c8Sopenharmony_ci }; 16712a9d9c8Sopenharmony_ci 16812a9d9c8Sopenharmony_ci // We can't implement variadic functions from C easily, so we allow to 16912a9d9c8Sopenharmony_ci // access the function pointer so that the user can call it just fine. 17012a9d9c8Sopenharmony_ci if !is_variadic { 17112a9d9c8Sopenharmony_ci self.struct_implementation.push(quote! { 17212a9d9c8Sopenharmony_ci #(#attributes)* 17312a9d9c8Sopenharmony_ci pub unsafe fn #ident ( &self, #( #args ),* ) #ret_ty { 17412a9d9c8Sopenharmony_ci #call_body 17512a9d9c8Sopenharmony_ci } 17612a9d9c8Sopenharmony_ci }); 17712a9d9c8Sopenharmony_ci } 17812a9d9c8Sopenharmony_ci 17912a9d9c8Sopenharmony_ci // N.B: Unwrap the signature upon construction if it is required to be resolved. 18012a9d9c8Sopenharmony_ci let ident_str = codegen::helpers::ast_ty::cstr_expr(ident.to_string()); 18112a9d9c8Sopenharmony_ci let library_get = if ctx.options().wrap_unsafe_ops { 18212a9d9c8Sopenharmony_ci quote!(unsafe { __library.get(#ident_str) }) 18312a9d9c8Sopenharmony_ci } else { 18412a9d9c8Sopenharmony_ci quote!(__library.get(#ident_str)) 18512a9d9c8Sopenharmony_ci }; 18612a9d9c8Sopenharmony_ci 18712a9d9c8Sopenharmony_ci self.constructor_inits.push(if is_required { 18812a9d9c8Sopenharmony_ci quote! { 18912a9d9c8Sopenharmony_ci let #ident = #library_get.map(|sym| *sym)?; 19012a9d9c8Sopenharmony_ci } 19112a9d9c8Sopenharmony_ci } else { 19212a9d9c8Sopenharmony_ci quote! { 19312a9d9c8Sopenharmony_ci let #ident = #library_get.map(|sym| *sym); 19412a9d9c8Sopenharmony_ci } 19512a9d9c8Sopenharmony_ci }); 19612a9d9c8Sopenharmony_ci 19712a9d9c8Sopenharmony_ci self.init_fields.push(quote! { 19812a9d9c8Sopenharmony_ci #ident 19912a9d9c8Sopenharmony_ci }); 20012a9d9c8Sopenharmony_ci } 20112a9d9c8Sopenharmony_ci} 202