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