mirror of
https://gitee.com/openharmony/third_party_rust_bindgen
synced 2025-03-04 20:57:21 +00:00
dyngen: Handle variadic functions.
Right now trying to generate a dynamic library with variadic functions panics because we don't account for the extra `...` in the arguments. Keeping the current interface for variadic functions is tricky, as we cannot "wrap" a variadic function (VaList[1] is nightly-only). However, we don't need to. We're already exposing the libloading error, so exposing the function pointer field as public is just fine and allows consumers to call the variadic function. At that point the can_call() / CheckFoo libraries become pointless (you can just do library.function.is_ok() or such), so we can simplify the code as well removing those. [1]: https://doc.rust-lang.org/std/ffi/struct.VaList.html
This commit is contained in:
parent
7792d633c7
commit
01cbe44683
@ -8,7 +8,7 @@ pub struct DynamicItems {
|
||||
/// ```ignore
|
||||
/// struct Lib {
|
||||
/// __library: ::libloading::Library,
|
||||
/// x: Result<unsafe extern ..., ::libloading::Error>, // <- tracks these
|
||||
/// pub x: Result<unsafe extern ..., ::libloading::Error>, // <- tracks these
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
@ -26,15 +26,6 @@ pub struct DynamicItems {
|
||||
/// ```
|
||||
struct_implementation: Vec<proc_macro2::TokenStream>,
|
||||
|
||||
/// Tracks the tokens that will appear inside the struct used for checking if a symbol is
|
||||
/// usable, e.g.:
|
||||
/// ```ignore
|
||||
/// pub fn f(&self) -> Result<(), &'a ::libloading::Error> { // <- tracks these
|
||||
/// self.__library.f.as_ref().map(|_| ())
|
||||
/// }
|
||||
/// ```
|
||||
runtime_checks: Vec<proc_macro2::TokenStream>,
|
||||
|
||||
/// Tracks the initialization of the fields inside the `::new` constructor of the library
|
||||
/// struct, e.g.:
|
||||
/// ```ignore
|
||||
@ -80,16 +71,11 @@ impl DynamicItems {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn get_tokens(
|
||||
&self,
|
||||
lib_ident: Ident,
|
||||
check_struct_ident: Ident,
|
||||
) -> proc_macro2::TokenStream {
|
||||
pub fn get_tokens(&self, lib_ident: Ident) -> proc_macro2::TokenStream {
|
||||
let struct_members = &self.struct_members;
|
||||
let constructor_inits = &self.constructor_inits;
|
||||
let init_fields = &self.init_fields;
|
||||
let struct_implementation = &self.struct_implementation;
|
||||
let runtime_checks = &self.runtime_checks;
|
||||
quote! {
|
||||
extern crate libloading;
|
||||
|
||||
@ -107,26 +93,14 @@ impl DynamicItems {
|
||||
#( #constructor_inits )*
|
||||
Ok(
|
||||
#lib_ident {
|
||||
__library: __library,
|
||||
__library,
|
||||
#( #init_fields ),*
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
pub fn can_call(&self) -> #check_struct_ident {
|
||||
#check_struct_ident { __library: self }
|
||||
}
|
||||
|
||||
#( #struct_implementation )*
|
||||
}
|
||||
|
||||
pub struct #check_struct_ident<'a> {
|
||||
__library: &'a #lib_ident,
|
||||
}
|
||||
|
||||
impl<'a> #check_struct_ident<'a> {
|
||||
#( #runtime_checks )*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,29 +108,30 @@ impl DynamicItems {
|
||||
&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,
|
||||
) {
|
||||
assert_eq!(args.len(), args_identifiers.len());
|
||||
if !is_variadic {
|
||||
assert_eq!(args.len(), args_identifiers.len());
|
||||
}
|
||||
|
||||
self.struct_members.push(quote!{
|
||||
#ident: Result<unsafe extern #abi fn ( #( #args ),* ) #ret, ::libloading::Error>,
|
||||
self.struct_members.push(quote! {
|
||||
pub #ident: Result<unsafe extern #abi fn ( #( #args ),* ) #ret, ::libloading::Error>,
|
||||
});
|
||||
|
||||
self.struct_implementation.push(quote! {
|
||||
pub unsafe fn #ident ( &self, #( #args ),* ) -> #ret_ty {
|
||||
let sym = self.#ident.as_ref().expect("Expected function, got error.");
|
||||
(sym)(#( #args_identifiers ),*)
|
||||
}
|
||||
});
|
||||
|
||||
self.runtime_checks.push(quote! {
|
||||
pub fn #ident (&self) -> Result<(), &'a::libloading::Error> {
|
||||
self.__library.#ident.as_ref().map(|_| ())
|
||||
}
|
||||
});
|
||||
// We can't implement variadic functions from C easily, so we allow to
|
||||
// access the function pointer so that the user can call it just fine.
|
||||
if !is_variadic {
|
||||
self.struct_implementation.push(quote! {
|
||||
pub unsafe fn #ident ( &self, #( #args ),* ) -> #ret_ty {
|
||||
let sym = self.#ident.as_ref().expect("Expected function, got error.");
|
||||
(sym)(#( #args_identifiers ),*)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let ident_str = ident.to_string();
|
||||
self.constructor_inits.push(quote! {
|
||||
|
@ -3808,6 +3808,7 @@ impl CodeGenerator for Function {
|
||||
result.dynamic_items().push(
|
||||
ident,
|
||||
abi,
|
||||
signature.is_variadic(),
|
||||
args,
|
||||
args_identifiers,
|
||||
ret,
|
||||
@ -4107,11 +4108,8 @@ pub(crate) fn codegen(
|
||||
|
||||
if let Some(ref lib_name) = context.options().dynamic_library_name {
|
||||
let lib_ident = context.rust_ident(lib_name);
|
||||
let check_struct_ident =
|
||||
context.rust_ident(format!("Check{}", lib_name));
|
||||
let dynamic_items_tokens = result
|
||||
.dynamic_items()
|
||||
.get_tokens(lib_ident, check_struct_ident);
|
||||
let dynamic_items_tokens =
|
||||
result.dynamic_items().get_tokens(lib_ident);
|
||||
result.push(dynamic_items_tokens);
|
||||
}
|
||||
|
||||
|
@ -8,20 +8,20 @@
|
||||
extern crate libloading;
|
||||
pub struct TestLib {
|
||||
__library: ::libloading::Library,
|
||||
foo: Result<
|
||||
pub foo: Result<
|
||||
unsafe extern "C" fn(
|
||||
x: ::std::os::raw::c_int,
|
||||
y: ::std::os::raw::c_int,
|
||||
) -> ::std::os::raw::c_int,
|
||||
::libloading::Error,
|
||||
>,
|
||||
bar: Result<
|
||||
pub bar: Result<
|
||||
unsafe extern "C" fn(
|
||||
x: *mut ::std::os::raw::c_void,
|
||||
) -> ::std::os::raw::c_int,
|
||||
::libloading::Error,
|
||||
>,
|
||||
baz: Result<
|
||||
pub baz: Result<
|
||||
unsafe extern "C" fn() -> ::std::os::raw::c_int,
|
||||
::libloading::Error,
|
||||
>,
|
||||
@ -36,15 +36,12 @@ impl TestLib {
|
||||
let bar = __library.get("bar".as_bytes()).map(|sym| *sym);
|
||||
let baz = __library.get("baz".as_bytes()).map(|sym| *sym);
|
||||
Ok(TestLib {
|
||||
__library: __library,
|
||||
__library,
|
||||
foo,
|
||||
bar,
|
||||
baz,
|
||||
})
|
||||
}
|
||||
pub fn can_call(&self) -> CheckTestLib {
|
||||
CheckTestLib { __library: self }
|
||||
}
|
||||
pub unsafe fn foo(
|
||||
&self,
|
||||
x: ::std::os::raw::c_int,
|
||||
@ -65,17 +62,3 @@ impl TestLib {
|
||||
(sym)()
|
||||
}
|
||||
}
|
||||
pub struct CheckTestLib<'a> {
|
||||
__library: &'a TestLib,
|
||||
}
|
||||
impl<'a> CheckTestLib<'a> {
|
||||
pub fn foo(&self) -> Result<(), &'a ::libloading::Error> {
|
||||
self.__library.foo.as_ref().map(|_| ())
|
||||
}
|
||||
pub fn bar(&self) -> Result<(), &'a ::libloading::Error> {
|
||||
self.__library.bar.as_ref().map(|_| ())
|
||||
}
|
||||
pub fn baz(&self) -> Result<(), &'a ::libloading::Error> {
|
||||
self.__library.baz.as_ref().map(|_| ())
|
||||
}
|
||||
}
|
||||
|
@ -8,11 +8,11 @@
|
||||
extern crate libloading;
|
||||
pub struct TestLib {
|
||||
__library: ::libloading::Library,
|
||||
foo: Result<
|
||||
pub foo: Result<
|
||||
unsafe extern "C" fn(x: ::std::os::raw::c_int) -> ::std::os::raw::c_int,
|
||||
::libloading::Error,
|
||||
>,
|
||||
foo1: Result<unsafe extern "C" fn(x: f32) -> f32, ::libloading::Error>,
|
||||
pub foo1: Result<unsafe extern "C" fn(x: f32) -> f32, ::libloading::Error>,
|
||||
}
|
||||
impl TestLib {
|
||||
pub unsafe fn new<P>(path: P) -> Result<Self, ::libloading::Error>
|
||||
@ -23,14 +23,11 @@ impl TestLib {
|
||||
let foo = __library.get("foo".as_bytes()).map(|sym| *sym);
|
||||
let foo1 = __library.get("foo1".as_bytes()).map(|sym| *sym);
|
||||
Ok(TestLib {
|
||||
__library: __library,
|
||||
__library,
|
||||
foo,
|
||||
foo1,
|
||||
})
|
||||
}
|
||||
pub fn can_call(&self) -> CheckTestLib {
|
||||
CheckTestLib { __library: self }
|
||||
}
|
||||
pub unsafe fn foo(
|
||||
&self,
|
||||
x: ::std::os::raw::c_int,
|
||||
@ -43,14 +40,3 @@ impl TestLib {
|
||||
(sym)(x)
|
||||
}
|
||||
}
|
||||
pub struct CheckTestLib<'a> {
|
||||
__library: &'a TestLib,
|
||||
}
|
||||
impl<'a> CheckTestLib<'a> {
|
||||
pub fn foo(&self) -> Result<(), &'a ::libloading::Error> {
|
||||
self.__library.foo.as_ref().map(|_| ())
|
||||
}
|
||||
pub fn foo1(&self) -> Result<(), &'a ::libloading::Error> {
|
||||
self.__library.foo1.as_ref().map(|_| ())
|
||||
}
|
||||
}
|
||||
|
@ -59,13 +59,13 @@ impl X {
|
||||
extern crate libloading;
|
||||
pub struct TestLib {
|
||||
__library: ::libloading::Library,
|
||||
foo: Result<
|
||||
pub foo: Result<
|
||||
unsafe extern "C" fn(
|
||||
x: *mut ::std::os::raw::c_void,
|
||||
) -> ::std::os::raw::c_int,
|
||||
::libloading::Error,
|
||||
>,
|
||||
bar: Result<
|
||||
pub bar: Result<
|
||||
unsafe extern "C" fn(
|
||||
x: *mut ::std::os::raw::c_void,
|
||||
) -> ::std::os::raw::c_int,
|
||||
@ -81,14 +81,11 @@ impl TestLib {
|
||||
let foo = __library.get("foo".as_bytes()).map(|sym| *sym);
|
||||
let bar = __library.get("bar".as_bytes()).map(|sym| *sym);
|
||||
Ok(TestLib {
|
||||
__library: __library,
|
||||
__library,
|
||||
foo,
|
||||
bar,
|
||||
})
|
||||
}
|
||||
pub fn can_call(&self) -> CheckTestLib {
|
||||
CheckTestLib { __library: self }
|
||||
}
|
||||
pub unsafe fn foo(
|
||||
&self,
|
||||
x: *mut ::std::os::raw::c_void,
|
||||
@ -104,14 +101,3 @@ impl TestLib {
|
||||
(sym)(x)
|
||||
}
|
||||
}
|
||||
pub struct CheckTestLib<'a> {
|
||||
__library: &'a TestLib,
|
||||
}
|
||||
impl<'a> CheckTestLib<'a> {
|
||||
pub fn foo(&self) -> Result<(), &'a ::libloading::Error> {
|
||||
self.__library.foo.as_ref().map(|_| ())
|
||||
}
|
||||
pub fn bar(&self) -> Result<(), &'a ::libloading::Error> {
|
||||
self.__library.bar.as_ref().map(|_| ())
|
||||
}
|
||||
}
|
||||
|
@ -59,13 +59,13 @@ impl A {
|
||||
extern crate libloading;
|
||||
pub struct TestLib {
|
||||
__library: ::libloading::Library,
|
||||
foo: Result<
|
||||
pub foo: Result<
|
||||
unsafe extern "C" fn(
|
||||
x: *mut ::std::os::raw::c_void,
|
||||
) -> ::std::os::raw::c_int,
|
||||
::libloading::Error,
|
||||
>,
|
||||
bar: Result<unsafe extern "C" fn(), ::libloading::Error>,
|
||||
pub bar: Result<unsafe extern "C" fn(), ::libloading::Error>,
|
||||
}
|
||||
impl TestLib {
|
||||
pub unsafe fn new<P>(path: P) -> Result<Self, ::libloading::Error>
|
||||
@ -76,14 +76,11 @@ impl TestLib {
|
||||
let foo = __library.get("foo".as_bytes()).map(|sym| *sym);
|
||||
let bar = __library.get("bar".as_bytes()).map(|sym| *sym);
|
||||
Ok(TestLib {
|
||||
__library: __library,
|
||||
__library,
|
||||
foo,
|
||||
bar,
|
||||
})
|
||||
}
|
||||
pub fn can_call(&self) -> CheckTestLib {
|
||||
CheckTestLib { __library: self }
|
||||
}
|
||||
pub unsafe fn foo(
|
||||
&self,
|
||||
x: *mut ::std::os::raw::c_void,
|
||||
@ -96,14 +93,3 @@ impl TestLib {
|
||||
(sym)()
|
||||
}
|
||||
}
|
||||
pub struct CheckTestLib<'a> {
|
||||
__library: &'a TestLib,
|
||||
}
|
||||
impl<'a> CheckTestLib<'a> {
|
||||
pub fn foo(&self) -> Result<(), &'a ::libloading::Error> {
|
||||
self.__library.foo.as_ref().map(|_| ())
|
||||
}
|
||||
pub fn bar(&self) -> Result<(), &'a ::libloading::Error> {
|
||||
self.__library.bar.as_ref().map(|_| ())
|
||||
}
|
||||
}
|
||||
|
@ -8,18 +8,25 @@
|
||||
extern crate libloading;
|
||||
pub struct TestLib {
|
||||
__library: ::libloading::Library,
|
||||
foo: Result<
|
||||
pub foo: Result<
|
||||
unsafe extern "C" fn(
|
||||
x: *mut ::std::os::raw::c_void,
|
||||
) -> ::std::os::raw::c_int,
|
||||
::libloading::Error,
|
||||
>,
|
||||
baz: Result<
|
||||
pub baz: Result<
|
||||
unsafe extern "C" fn(
|
||||
x: *mut ::std::os::raw::c_void,
|
||||
) -> ::std::os::raw::c_int,
|
||||
::libloading::Error,
|
||||
>,
|
||||
pub bazz: Result<
|
||||
unsafe extern "C" fn(
|
||||
arg1: ::std::os::raw::c_int,
|
||||
...
|
||||
) -> ::std::os::raw::c_int,
|
||||
::libloading::Error,
|
||||
>,
|
||||
}
|
||||
impl TestLib {
|
||||
pub unsafe fn new<P>(path: P) -> Result<Self, ::libloading::Error>
|
||||
@ -29,15 +36,14 @@ impl TestLib {
|
||||
let __library = ::libloading::Library::new(path)?;
|
||||
let foo = __library.get("foo".as_bytes()).map(|sym| *sym);
|
||||
let baz = __library.get("baz".as_bytes()).map(|sym| *sym);
|
||||
let bazz = __library.get("bazz".as_bytes()).map(|sym| *sym);
|
||||
Ok(TestLib {
|
||||
__library: __library,
|
||||
__library,
|
||||
foo,
|
||||
baz,
|
||||
bazz,
|
||||
})
|
||||
}
|
||||
pub fn can_call(&self) -> CheckTestLib {
|
||||
CheckTestLib { __library: self }
|
||||
}
|
||||
pub unsafe fn foo(
|
||||
&self,
|
||||
x: *mut ::std::os::raw::c_void,
|
||||
@ -53,14 +59,3 @@ impl TestLib {
|
||||
(sym)(x)
|
||||
}
|
||||
}
|
||||
pub struct CheckTestLib<'a> {
|
||||
__library: &'a TestLib,
|
||||
}
|
||||
impl<'a> CheckTestLib<'a> {
|
||||
pub fn foo(&self) -> Result<(), &'a ::libloading::Error> {
|
||||
self.__library.foo.as_ref().map(|_| ())
|
||||
}
|
||||
pub fn baz(&self) -> Result<(), &'a ::libloading::Error> {
|
||||
self.__library.baz.as_ref().map(|_| ())
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// bindgen-flags: --dynamic-loading TestLib --whitelist-function baz --whitelist-function foo
|
||||
// bindgen-flags: --dynamic-loading TestLib --whitelist-function baz --whitelist-function foo --whitelist-function bazz
|
||||
|
||||
class X {
|
||||
int _x;
|
||||
@ -13,3 +13,4 @@ class X {
|
||||
int foo(void *x);
|
||||
int bar(void *x);
|
||||
int baz(void *x);
|
||||
int bazz(int, ...);
|
||||
|
Loading…
x
Reference in New Issue
Block a user