@@ -182,6 +182,7 @@ impl From<DerivableTraits> for Vec<&'static str> {
182182 }
183183}
184184
185+ #[ derive( Clone ) ]
185186struct CodegenResult < ' a > {
186187 items : Vec < proc_macro2:: TokenStream > ,
187188
@@ -435,6 +436,15 @@ impl CodeGenerator for Item {
435436 return ;
436437 }
437438
439+ if self . is_dynamic ( ctx) {
440+ debug ! (
441+ "Item is to be dynamically generated; ignoring it for now. \
442+ self = {:?}",
443+ self
444+ ) ;
445+ return ;
446+ }
447+
438448 if self . is_blacklisted ( ctx) || result. seen ( self . id ( ) ) {
439449 debug ! (
440450 "<Item as CodeGenerator>::codegen: Ignoring hidden or seen: \
@@ -3913,6 +3923,126 @@ impl CodeGenerator for ObjCInterface {
39133923 }
39143924}
39153925
3926+ trait DynamicBindingGenerator {
3927+ /// Extra information from the caller.
3928+ type Extra ;
3929+
3930+ fn dyngen < ' a > (
3931+ & self ,
3932+ ctx : & BindgenContext ,
3933+ def_result : & mut CodegenResult < ' a > ,
3934+ impl_result : & mut CodegenResult < ' a > ,
3935+ extra : & Self :: Extra ,
3936+ ) ;
3937+ }
3938+
3939+ impl DynamicBindingGenerator for Item {
3940+ type Extra = ( ) ;
3941+
3942+ fn dyngen < ' a > (
3943+ & self ,
3944+ ctx : & BindgenContext ,
3945+ def_result : & mut CodegenResult < ' a > ,
3946+ impl_result : & mut CodegenResult < ' a > ,
3947+ _extra : & ( ) ,
3948+ ) {
3949+ assert ! ( self . is_dynamic( ctx) ) ;
3950+ if !self . is_enabled_for_codegen ( ctx) {
3951+ return ;
3952+ }
3953+
3954+ // If this item is blacklisted, or we've already seen it, nothing to do.
3955+ if self . is_blacklisted ( ctx) ||
3956+ def_result. seen ( self . id ( ) ) ||
3957+ impl_result. seen ( self . id ( ) )
3958+ {
3959+ debug ! (
3960+ "<Item as DynamicBindingGenerator>::codegen: Ignoring hidden or seen: \
3961+ self = {:?}",
3962+ self
3963+ ) ;
3964+ return ;
3965+ }
3966+
3967+ debug ! (
3968+ "<Item as DynamicBindingGenerator>::dyngen: self = {:?}" ,
3969+ self
3970+ ) ;
3971+
3972+ if !ctx. codegen_items ( ) . contains ( & self . id ( ) ) {
3973+ warn ! ( "Found non-whitelisted item in dynamic binding generation: {:?}" , self ) ;
3974+ }
3975+
3976+ def_result. set_seen ( self . id ( ) ) ;
3977+ impl_result. set_seen ( self . id ( ) ) ;
3978+
3979+ match * self . kind ( ) {
3980+ ItemKind :: Function ( ref fun) => {
3981+ assert ! ( fun. kind( ) == FunctionKind :: Function ) ;
3982+ fun. dyngen ( ctx, def_result, impl_result, self ) ;
3983+ }
3984+ _ => panic ! (
3985+ "Unexpected item type when doing dynamic bindings generation."
3986+ ) ,
3987+ }
3988+ }
3989+ }
3990+
3991+ impl DynamicBindingGenerator for Function {
3992+ type Extra = Item ;
3993+
3994+ fn dyngen < ' a > (
3995+ & self ,
3996+ ctx : & BindgenContext ,
3997+ def_result : & mut CodegenResult < ' a > ,
3998+ impl_result : & mut CodegenResult < ' a > ,
3999+ item : & Item ,
4000+ ) {
4001+ let signature_item = ctx. resolve_item ( self . signature ( ) ) ;
4002+ let signature = signature_item. kind ( ) . expect_type ( ) . canonical_type ( ctx) ;
4003+ let signature = match * signature. kind ( ) {
4004+ TypeKind :: Function ( ref sig) => sig,
4005+ _ => panic ! ( "Signature kind is not a Function: {:?}" , signature) ,
4006+ } ;
4007+
4008+ let canonical_name = item. canonical_name ( ctx) ;
4009+ let abi = match signature. abi ( ) {
4010+ Abi :: ThisCall if !ctx. options ( ) . rust_features ( ) . thiscall_abi => {
4011+ warn ! ( "Skipping function with thiscall ABI that isn't supported by the configured Rust target" ) ;
4012+ return ;
4013+ }
4014+ Abi :: Win64 if signature. is_variadic ( ) => {
4015+ warn ! ( "Skipping variadic function with Win64 ABI that isn't supported" ) ;
4016+ return ;
4017+ }
4018+ Abi :: Unknown ( unknown_abi) => {
4019+ panic ! (
4020+ "Invalid or unknown abi {:?} for function {:?} ({:?})" ,
4021+ unknown_abi, canonical_name, self
4022+ ) ;
4023+ }
4024+ abi => abi,
4025+ } ;
4026+
4027+ let args = utils:: fnsig_arguments ( ctx, signature) ;
4028+ let args_identifiers =
4029+ utils:: fnsig_argument_identifiers ( ctx, signature) ;
4030+ let ret = utils:: fnsig_return_ty ( ctx, signature) ;
4031+
4032+ let ident = ctx. rust_ident ( & canonical_name) ;
4033+
4034+ def_result. push ( quote ! {
4035+ #ident: unsafe extern #abi fn ( #( #args ) , * ) #ret,
4036+ } ) ;
4037+
4038+ impl_result. push ( quote ! {
4039+ pub unsafe extern #abi fn #ident ( & self , #( #args ) , * ) #ret {
4040+ ( self . #ident) ( #( #args_identifiers ) , * )
4041+ }
4042+ } ) ;
4043+ }
4044+ }
4045+
39164046pub ( crate ) fn codegen (
39174047 context : BindgenContext ,
39184048) -> ( Vec < proc_macro2:: TokenStream > , BindgenOptions ) {
@@ -3948,6 +4078,116 @@ pub(crate) fn codegen(
39484078 & ( ) ,
39494079 ) ;
39504080
4081+ // If the set of items to generate dynamic bindings for is nonempty...
4082+ if !context. dyngen_items ( ) . is_empty ( ) {
4083+ let _t = context. timer ( "dyngen" ) ;
4084+ debug ! ( "dyngen: {:?}" , context. options( ) ) ;
4085+
4086+ // `def_result` tracks the tokens that will appears inside the library struct -- these
4087+ // are the definitions of the symbols inside the library struct, e.g.:
4088+ // ```
4089+ // struct Lib {
4090+ // __library: ::libloading::Library,
4091+ // x: unsafe extern ..., // <- tracks these!
4092+ // ...
4093+ // }
4094+ // ```
4095+ //
4096+ // `impl_result` tracks the tokens that will appear inside the call implementation,
4097+ // e.g.:
4098+ //
4099+ // ```
4100+ // impl Lib {
4101+ // ...
4102+ // pub unsafe extern "C" fn foo(&self, ...) { // <- tracks these!
4103+ // (self.foo)(...)
4104+ // }
4105+ // }
4106+ // ```
4107+ //
4108+ // We clone the CodeGenerator object used for normal code generation, but set its items
4109+ // to the empty vector. We do this so that we can keep track of which items we have
4110+ // seen, etc.
4111+ let mut def_result = result. clone ( ) ;
4112+ def_result. items = vec ! [ ] ;
4113+ let mut impl_result = result. clone ( ) ;
4114+ impl_result. items = vec ! [ ] ;
4115+
4116+ // Extern the libloading crate.
4117+ result. push ( quote ! {
4118+ extern crate libloading;
4119+ } ) ;
4120+
4121+ // Run dynamic binding generation for each of the required items.
4122+ for item in context. dyngen_items ( ) {
4123+ context. resolve_item ( * item) . dyngen (
4124+ context,
4125+ & mut def_result,
4126+ & mut impl_result,
4127+ & ( ) ,
4128+ ) ;
4129+ }
4130+
4131+ let lib_ident = context. rust_ident (
4132+ context. options ( ) . dynamic_library_name . as_ref ( ) . unwrap ( ) ,
4133+ ) ;
4134+
4135+ let struct_items = def_result. items ;
4136+ result. push ( quote ! {
4137+ pub struct #lib_ident {
4138+ __library: :: libloading:: Library ,
4139+ #( #struct_items) *
4140+ }
4141+ } ) ;
4142+
4143+ let build_locals = context
4144+ . dyngen_items ( )
4145+ . iter ( )
4146+ . map ( |& item| {
4147+ let canonical_name = item. canonical_name ( context) ;
4148+ let ident = context. rust_ident ( & canonical_name) ;
4149+
4150+ quote ! {
4151+ let #ident = * __library. get( #canonical_name. as_bytes( ) ) ?;
4152+ }
4153+ } )
4154+ . collect :: < Vec < _ > > ( ) ;
4155+
4156+ let init_fields = context
4157+ . dyngen_items ( )
4158+ . iter ( )
4159+ . map ( |& item| {
4160+ let canonical_name = item. canonical_name ( context) ;
4161+ let ident = context. rust_ident ( & canonical_name) ;
4162+
4163+ quote ! {
4164+ #ident
4165+ }
4166+ } )
4167+ . collect :: < Vec < _ > > ( ) ;
4168+
4169+ let impl_items = impl_result. items ;
4170+ result. push ( quote ! {
4171+ impl #lib_ident {
4172+ pub unsafe fn new<P >(
4173+ path: P
4174+ ) -> Result <Self , :: libloading:: Error >
4175+ where P : AsRef <:: std:: ffi:: OsStr > {
4176+ let __library = :: libloading:: Library :: new( path) ?;
4177+ #( #build_locals ) *
4178+ Ok (
4179+ #lib_ident {
4180+ __library: __library,
4181+ #( #init_fields ) , *
4182+ }
4183+ )
4184+ }
4185+
4186+ #( #impl_items ) *
4187+ }
4188+ } ) ;
4189+ }
4190+
39514191 result. items
39524192 } )
39534193}
@@ -4356,6 +4596,35 @@ mod utils {
43564596 args
43574597 }
43584598
4599+ pub fn fnsig_argument_identifiers (
4600+ ctx : & BindgenContext ,
4601+ sig : & FunctionSig ,
4602+ ) -> Vec < proc_macro2:: TokenStream > {
4603+ let mut unnamed_arguments = 0 ;
4604+ let args = sig
4605+ . argument_types ( )
4606+ . iter ( )
4607+ . map ( |& ( ref name, _ty) | {
4608+ let arg_name = match * name {
4609+ Some ( ref name) => ctx. rust_mangle ( name) . into_owned ( ) ,
4610+ None => {
4611+ unnamed_arguments += 1 ;
4612+ format ! ( "arg{}" , unnamed_arguments)
4613+ }
4614+ } ;
4615+
4616+ assert ! ( !arg_name. is_empty( ) ) ;
4617+ let arg_name = ctx. rust_ident ( arg_name) ;
4618+
4619+ quote ! {
4620+ #arg_name
4621+ }
4622+ } )
4623+ . collect :: < Vec < _ > > ( ) ;
4624+
4625+ args
4626+ }
4627+
43594628 pub fn fnsig_block (
43604629 ctx : & BindgenContext ,
43614630 sig : & FunctionSig ,
0 commit comments