From 45db38046649eaa73da247661944c3b8ef32774b Mon Sep 17 00:00:00 2001 From: luaneko Date: Tue, 24 Jun 2025 11:42:11 +1000 Subject: [PATCH] Rename ToFfi to IntoFfi --- crates/luaffi/src/future.rs | 24 +-- crates/luaffi/src/lib.rs | 260 ++++++++++++++--------------- crates/luaffi/src/result.rs | 4 + crates/luaffi/src/string.rs | 57 +++---- crates/luaffi_impl/src/cdef.rs | 3 +- crates/luaffi_impl/src/metatype.rs | 21 ++- 6 files changed, 176 insertions(+), 193 deletions(-) create mode 100644 crates/luaffi/src/result.rs diff --git a/crates/luaffi/src/future.rs b/crates/luaffi/src/future.rs index 147b656..2bdbf01 100644 --- a/crates/luaffi/src/future.rs +++ b/crates/luaffi/src/future.rs @@ -1,6 +1,6 @@ use crate::{ __internal::{display, type_id}, - Cdef, CdefBuilder, FfiReturnConvention, Metatype, MetatypeBuilder, ToFfi, Type, TypeBuilder, + Cdef, CdefBuilder, FfiReturnConvention, IntoFfi, Metatype, MetatypeBuilder, Type, TypeBuilder, UnsafeExternCFn, }; use luaify::luaify; @@ -21,7 +21,7 @@ const SIGNATURE: Signature = Signature::from_ne_bytes(*b"\x00lb_poll"); #[repr(C)] #[allow(non_camel_case_types)] -pub struct lua_future> { +pub struct lua_future> { // // SAFETY: LuaJIT guarantees that cdata payloads, which are GC-managed, are never relocated // (i.e. pinned). We can safely assume that we are pinned and poll the future inside this @@ -43,7 +43,7 @@ pub struct lua_future> { sig: Signature, poll: fn(Pin<&mut Self>, cx: &mut Context) -> Poll<()>, state: State, - take: unsafe extern "C" fn(&mut Self) -> ::To, + take: unsafe extern "C" fn(&mut Self) -> ::To, drop: unsafe extern "C" fn(&mut Self), } @@ -70,7 +70,7 @@ enum State { Complete, } -impl> lua_future { +impl> lua_future { pub fn new(fut: F) -> Self { Self { sig: SIGNATURE, @@ -94,7 +94,7 @@ impl> lua_future { } } - unsafe extern "C" fn take(&mut self) -> ::To { + unsafe extern "C" fn take(&mut self) -> ::To { // `fut:__take()` returns the fulfilled value by-value (not by out-param) because if we // preallocate a cdata for the out-param and the thread for some reason gets dropped and // never resumed, the GC could call the destructor on an uninitialised cdata. @@ -131,7 +131,7 @@ impl Future for lua_pollable { } } -unsafe impl + 'static> Type for lua_future { +unsafe impl + 'static> Type for lua_future { fn name() -> impl Display { display!("future__{:x}", type_id::()) } @@ -145,15 +145,15 @@ unsafe impl + 'static> Type for lua_future { } } -unsafe impl + 'static> Cdef for lua_future { +unsafe impl + 'static> Cdef for lua_future { fn build(s: &mut CdefBuilder) { s.field_opaque(mem::offset_of!(Self, take)) // opaque .sig, .poll and .state - .field::::To>>("__take") + .field::::To>>("__take") .field::>("__drop"); } } -unsafe impl + 'static> Metatype for lua_future { +unsafe impl + 'static> Metatype for lua_future { type Target = Self; fn build(s: &mut MetatypeBuilder) { @@ -161,7 +161,7 @@ unsafe impl + 'static> Metatype for lua_future { } } -unsafe impl + 'static> ToFfi for lua_future { +unsafe impl + 'static> IntoFfi for lua_future { type To = lua_future; fn convert(self) -> Self::To { @@ -179,12 +179,12 @@ unsafe impl + 'static> ToFfi for lua_future { // `coroutine.yield` is cached as `yield` and `ffi.gc` as `gc` in locals (see lib.rs) display!( "yield({ret}); {ret} = gc({ret}, nil):__take(); {}", - ::postlude(ret, FfiReturnConvention::ByValue) + ::postlude(ret, FfiReturnConvention::ByValue) ) } } -impl> From for lua_future { +impl> From for lua_future { fn from(value: F) -> Self { Self::new(value.into_future()) } diff --git a/crates/luaffi/src/lib.rs b/crates/luaffi/src/lib.rs index a1c2d11..9ab7360 100644 --- a/crates/luaffi/src/lib.rs +++ b/crates/luaffi/src/lib.rs @@ -379,7 +379,6 @@ impl<'r> Drop for MetatypeBuilder<'r> { pub unsafe trait FromFfi: Sized { type From: Type + Sized; - type FromArg: Type + Sized; fn require_keepalive() -> bool { false @@ -390,10 +389,9 @@ pub unsafe trait FromFfi: Sized { } fn convert(from: Self::From) -> Self; - fn convert_arg(from: Self::FromArg) -> Self; } -pub unsafe trait ToFfi: Sized { +pub unsafe trait IntoFfi: Sized { type To: Type + Sized; fn postlude(_ret: &str, _conv: FfiReturnConvention) -> impl Display { @@ -472,7 +470,7 @@ impl<'r, 'm> MetatypeMethodBuilder<'r, 'm> { self } - pub fn call(&mut self, func: impl Display, ret: FfiReturnConvention) { + pub fn call(&mut self, func: impl Display, ret: FfiReturnConvention) { let Self { metatype, params, @@ -541,7 +539,7 @@ impl_primitive!(isize, "intptr_t"); impl_primitive!(c_float, "float"); impl_primitive!(c_double, "double"); -unsafe impl ToFfi for () { +unsafe impl IntoFfi for () { // // SAFETY: Unit type return maps to a C void return, which is a nil return in lua. There is no // equivalent to passing a unit type as an argument in C. `c_void` cannot be returned from rust @@ -561,7 +559,6 @@ unsafe impl ToFfi for () { unsafe impl FromFfi for bool { type From = bool; - type FromArg = bool; fn prelude(arg: &str) -> impl Display { display!( @@ -572,13 +569,9 @@ unsafe impl FromFfi for bool { fn convert(from: Self::From) -> Self { from } - - fn convert_arg(from: Self::FromArg) -> Self { - from - } } -unsafe impl ToFfi for bool { +unsafe impl IntoFfi for bool { type To = bool; fn convert(self) -> Self::To { @@ -586,14 +579,10 @@ unsafe impl ToFfi for bool { } fn postlude(ret: &str, conv: FfiReturnConvention) -> impl Display { - disp(move |f| { - Ok({ - match conv { - FfiReturnConvention::Void => unreachable!(), - FfiReturnConvention::ByValue => {} - FfiReturnConvention::ByOutParam => write!(f, "{ret} = {ret} ~= 0; ")?, - } - }) + disp(move |f| match conv { + FfiReturnConvention::Void => unreachable!(), + FfiReturnConvention::ByValue => Ok(()), + FfiReturnConvention::ByOutParam => write!(f, "{ret} = {ret} ~= 0; "), }) } } @@ -602,7 +591,6 @@ macro_rules! impl_number_fromabi { ($rtype:ty) => { unsafe impl FromFfi for $rtype { type From = Self; - type FromArg = Self; fn prelude(arg: &str) -> impl Display { display!(r#"do local __{arg} = {arg}; {arg} = tonumber({arg}); assert(type({arg}) == "number", "number expected in argument '{arg}', got " .. type(__{arg})); end; "#) @@ -611,10 +599,6 @@ macro_rules! impl_number_fromabi { fn convert(from: Self::From) -> Self { from } - - fn convert_arg(from: Self::FromArg) -> Self { - from - } } }; } @@ -632,53 +616,66 @@ impl_number_fromabi!(isize); impl_number_fromabi!(f32); impl_number_fromabi!(f64); -macro_rules! impl_number_toabi { +macro_rules! impl_number_intoabi { ($rtype:ty) => { - unsafe impl ToFfi for $rtype { - type To = Self; - - fn convert(self) -> Self::To { - self - } - } - }; -} - -impl_number_toabi!(u8); -impl_number_toabi!(u16); -impl_number_toabi!(u32); -impl_number_toabi!(i8); -impl_number_toabi!(i16); -impl_number_toabi!(i32); -#[cfg(target_pointer_width = "32")] -impl_number_toabi!(usize); -#[cfg(target_pointer_width = "32")] -impl_number_toabi!(isize); -impl_number_toabi!(c_float); -impl_number_toabi!(c_double); - -macro_rules! impl_bigint_toabi { - ($rtype:ty) => { - unsafe impl ToFfi for $rtype { + unsafe impl IntoFfi for $rtype { type To = Self; fn convert(self) -> Self::To { self } - fn postlude(ret: &str, _conv: FfiReturnConvention) -> impl Display { - display!("{ret} = tonumber({ret}); ") + fn postlude(ret: &str, conv: FfiReturnConvention) -> impl Display { + disp(move |f| match conv { + FfiReturnConvention::Void => unreachable!(), + FfiReturnConvention::ByValue => Ok(()), + FfiReturnConvention::ByOutParam => write!(f, "{ret} = tonumber({ret}); "), + }) } } }; } -impl_bigint_toabi!(u64); -impl_bigint_toabi!(i64); +impl_number_intoabi!(u8); +impl_number_intoabi!(u16); +impl_number_intoabi!(u32); +impl_number_intoabi!(i8); +impl_number_intoabi!(i16); +impl_number_intoabi!(i32); +#[cfg(target_pointer_width = "32")] +impl_number_intoabi!(usize); +#[cfg(target_pointer_width = "32")] +impl_number_intoabi!(isize); +impl_number_intoabi!(c_float); +impl_number_intoabi!(c_double); + +macro_rules! impl_bigint_intoabi { + ($rtype:ty) => { + unsafe impl IntoFfi for $rtype { + type To = Self; + + fn convert(self) -> Self::To { + self + } + + fn postlude(ret: &str, conv: FfiReturnConvention) -> impl Display { + disp(move |f| match conv { + FfiReturnConvention::Void => unreachable!(), + FfiReturnConvention::ByValue | FfiReturnConvention::ByOutParam => { + write!(f, "{ret} = tonumber({ret}); ") + } + }) + } + } + }; +} + +impl_bigint_intoabi!(u64); +impl_bigint_intoabi!(i64); #[cfg(target_pointer_width = "64")] -impl_bigint_toabi!(usize); +impl_bigint_intoabi!(usize); #[cfg(target_pointer_width = "64")] -impl_bigint_toabi!(isize); +impl_bigint_intoabi!(isize); macro_rules! impl_const_ptr { ($ty:ty) => { @@ -737,15 +734,10 @@ macro_rules! impl_ptr_fromabi { ($ty:ty) => { unsafe impl FromFfi for $ty { type From = Self; - type FromArg = Self; fn convert(from: Self::From) -> Self { from } - - fn convert_arg(from: Self::FromArg) -> Self { - from - } } }; } @@ -755,77 +747,14 @@ impl_ptr_fromabi!(*mut T); impl_ptr_fromabi!(Option<&T>); impl_ptr_fromabi!(Option<&mut T>); -unsafe impl<'s, T: Type> FromFfi for &'s T { - type From = Option<&'s T>; - type FromArg = Option<&'s T>; - - fn prelude(arg: &str) -> impl Display { - display!(r#"assert({arg} ~= nil, "argument '{arg}' cannot be nil"); "#) - } - - fn convert(from: Self::From) -> Self { - debug_assert!( - from.is_some(), - "<&T>::convert() called on a null reference when it was checked to be non-null" - ); - - unsafe { from.unwrap_unchecked() } - } - - fn convert_arg(from: Self::FromArg) -> Self { - FromFfi::convert(from) - } -} - -unsafe impl<'s, T: Type> FromFfi for &'s mut T { - // - // SAFETY: `FromFfi` for *mutable* references is safe because it is guaranteed that no two Rust - // code called via FFI can be running at the same time on the same OS thread (no Lua - // reentrancy). - // - // i.e. The call stack will always look something like this: - // - // * Runtime (LuaJIT/Rust) -> Lua (via C) -> Rust (via FFI): This is SAFE and the only use case - // we support. All references (mutable or not) to Rust user objects will be dropped before - // returning to Lua. - // - // * Runtime (LuaJIT/Rust) -> Lua (via C) -> Rust (via FFI) -> Lua (via callback): This is - // UNSAFE because we cannot prevent the Lua callback from calling back into Rust code via - // FFI which could violate exclusive borrow semantics. This is prevented by not implementing - // `FromFfi` for function pointers (see below). - // - // The runtime does not keep any references to Rust user objects boxed in cdata (futures are - // the only exception; their ownership is transferred to the runtime via yield). - // - type From = Option<&'s mut T>; - type FromArg = Option<&'s mut T>; - - fn prelude(arg: &str) -> impl Display { - display!(r#"assert({arg} ~= nil, "argument '{arg}' cannot be nil"); "#) - } - - fn convert(from: Self::From) -> Self { - debug_assert!( - from.is_some(), - "<&mut T>::convert() called on a null reference when it was checked to be non-null" - ); - - unsafe { from.unwrap_unchecked() } - } - - fn convert_arg(from: Self::FromArg) -> Self { - FromFfi::convert(from) - } -} - // // SAFETY: Return by value for pointers, which maps to a `cdata` return in lua containing the // pointer (`T *`). We also map null pointers to `nil` for convenience (otherwise it's still a cdata // value containing a null pointer) // -macro_rules! impl_ptr_toabi { +macro_rules! impl_ptr_intoabi { ($ty:ty) => { - unsafe impl ToFfi for $ty { + unsafe impl IntoFfi for $ty { type To = Self; fn convert(self) -> Self::To { @@ -839,15 +768,76 @@ macro_rules! impl_ptr_toabi { }; } -impl_ptr_toabi!(*const T); -impl_ptr_toabi!(*mut T); -impl_ptr_toabi!(&'static T); -impl_ptr_toabi!(&'static mut T); -impl_ptr_toabi!(Option<&'static T>); -impl_ptr_toabi!(Option<&'static mut T>); +impl_ptr_intoabi!(*const T); +impl_ptr_intoabi!(*mut T); +impl_ptr_intoabi!(Option<&'static T>); +impl_ptr_intoabi!(Option<&'static mut T>); // -// SAFETY: No `FromFfi` and `ToFfi` for arrays because passing or returning them by value is not a +// SAFETY: `FromFfi` for *mutable* references is safe because it is guaranteed that no two Rust code +// called via FFI can be running at the same time on the same OS thread (no Lua reentrancy). +// +// i.e. The call stack will always look something like this: +// +// * Runtime (LuaJIT/Rust) -> Lua (via C) -> Rust (via FFI): This is SAFE and the only use case we +// support. All references (mutable or not) to Rust user objects will be dropped before +// returning to Lua. +// +// * Runtime (LuaJIT/Rust) -> Lua (via C) -> Rust (via FFI) -> Lua (via callback): This is UNSAFE +// because we cannot prevent the Lua callback from calling back into Rust code via FFI which +// could violate exclusive borrow semantics. This is prevented by not implementing `FromFfi` for +// function pointers (see below). +// +// The runtime does not keep any references to Rust user objects boxed in cdata (futures are the +// only exception; their ownership is transferred to the runtime via yield). +// +macro_rules! impl_ref_fromabi { + ($ty:ty) => { + unsafe impl<'s, T: Type> FromFfi for $ty { + type From = Option<$ty>; + + fn prelude(arg: &str) -> impl Display { + display!(r#"assert({arg} ~= nil, "argument '{arg}' cannot be nil"); "#) + } + + fn convert(from: Self::From) -> Self { + // SAFETY: we already checked that the reference is nonnull from the lua side + debug_assert!( + from.is_some(), + "<{}>::convert() called on a null reference when it was checked to be nonnull", + stringify!($ty), + ); + + unsafe { from.unwrap_unchecked() } + } + } + }; +} + +impl_ref_fromabi!(&'s T); +impl_ref_fromabi!(&'s mut T); + +// +// SAFETY: `IntoFfi` only for 'static references because we cannot guarantee that the pointer will +// not outlive the pointee otherwise. +// +macro_rules! impl_ref_intoabi { + ($ty:ty) => { + unsafe impl IntoFfi for $ty { + type To = Self; + + fn convert(self) -> Self::To { + self + } + } + }; +} + +impl_ref_intoabi!(&'static T); +impl_ref_intoabi!(&'static mut T); + +// +// SAFETY: No `FromFfi` and `IntoFfi` for arrays because passing or returning them by value is not a // thing in C (they are just pointers). // // TODO: we could automatically convert them to tables and vice-versa @@ -892,7 +882,7 @@ macro_rules! impl_function { // SAFETY: No `FromFfi` for function pointers because of borrow safety invariants (see above // in `&mut T`). // - // We also can't implement `ToFfi` because we can't call `FromFfi` and `ToFfi` for the + // We also can't implement `IntoFfi` because we can't call `FromFfi` and `IntoFfi` for the // function's respective argument and return values. // unsafe impl<$($arg: Type,)* $ret: Type> Type for $ty<($($arg,)*), $ret> { diff --git a/crates/luaffi/src/result.rs b/crates/luaffi/src/result.rs new file mode 100644 index 0000000..24c82cb --- /dev/null +++ b/crates/luaffi/src/result.rs @@ -0,0 +1,4 @@ +// pub enum lua_result { +// Err(lua_error), +// Ok(T), +// } diff --git a/crates/luaffi/src/string.rs b/crates/luaffi/src/string.rs index cc70c1a..c07670e 100644 --- a/crates/luaffi/src/string.rs +++ b/crates/luaffi/src/string.rs @@ -1,6 +1,6 @@ use crate::{ __internal::{disp, display}, - FfiReturnConvention, FromFfi, IS_UTF8_FN, ToFfi, Type, + FfiReturnConvention, FromFfi, IS_UTF8_FN, IntoFfi, Type, }; use bstr::BStr; use luaffi_impl::{cdef, metatype}; @@ -29,8 +29,7 @@ pub struct lua_buffer { impl lua_buffer {} unsafe impl<'s> FromFfi for &'s [u8] { - type From = lua_buf; - type FromArg = Option<&'s Self::From>; + type From = Option<&'s lua_buf>; fn require_keepalive() -> bool { true @@ -50,20 +49,15 @@ unsafe impl<'s> FromFfi for &'s [u8] { fn convert(from: Self::From) -> Self { // SAFETY: we already checked that the string is nonnull from the lua side + debug_assert!(from.is_some()); + let from = unsafe { from.unwrap_unchecked() }; debug_assert!(!from.__ptr.is_null()); unsafe { slice::from_raw_parts(from.__ptr, from.__len) } } - - fn convert_arg(from: Self::FromArg) -> Self { - // SAFETY: we already checked that the string is nonnull from the lua side - debug_assert!(from.is_some()); - unsafe { FromFfi::convert(*from.unwrap_unchecked()) } - } } unsafe impl<'s> FromFfi for &'s BStr { type From = <&'s [u8] as FromFfi>::From; - type FromArg = <&'s [u8] as FromFfi>::FromArg; fn require_keepalive() -> bool { <&'s [u8] as FromFfi>::require_keepalive() @@ -76,21 +70,18 @@ unsafe impl<'s> FromFfi for &'s BStr { fn convert(from: Self::From) -> Self { <&'s [u8] as FromFfi>::convert(from).into() } - - fn convert_arg(from: Self::FromArg) -> Self { - <&'s [u8] as FromFfi>::convert_arg(from).into() - } } unsafe impl<'s> FromFfi for &'s str { - type From = lua_buf; - type FromArg = Option<&'s Self::From>; + type From = Option<&'s lua_buf>; fn require_keepalive() -> bool { true } fn prelude(arg: &str) -> impl Display { + // this converts string arguments to a `lua_buf` with a pointer to the string and its length + // and ensures that the string is valid utf8 disp(move |f| { let ct = Self::From::name(); write!( @@ -107,25 +98,19 @@ unsafe impl<'s> FromFfi for &'s str { fn convert(from: Self::From) -> Self { // SAFETY: we already checked that the string is nonnull and valid utf8 from the lua side + debug_assert!(from.is_some()); + let from = unsafe { from.unwrap_unchecked() }; debug_assert!(!from.__ptr.is_null()); - let s = unsafe { slice::from_raw_parts(from.__ptr, from.__len) }; - + let from = unsafe { slice::from_raw_parts(from.__ptr, from.__len) }; debug_assert!( - std::str::from_utf8(s).is_ok(), + std::str::from_utf8(from).is_ok(), "<&str>::convert() called on an invalid utf8 string when it was checked to be valid" ); - - unsafe { std::str::from_utf8_unchecked(s) } - } - - fn convert_arg(from: Self::FromArg) -> Self { - // SAFETY: we already checked that the string is nonnull and valid utf8 from the lua side - debug_assert!(from.is_some()); - unsafe { FromFfi::convert(*from.unwrap_unchecked()) } + unsafe { std::str::from_utf8_unchecked(from) } } } -unsafe impl ToFfi for &'static [u8] { +unsafe impl IntoFfi for &'static [u8] { type To = lua_buf; fn convert(self) -> Self::To { @@ -140,26 +125,26 @@ unsafe impl ToFfi for &'static [u8] { } } -unsafe impl ToFfi for &'static BStr { - type To = <&'static [u8] as ToFfi>::To; +unsafe impl IntoFfi for &'static BStr { + type To = <&'static [u8] as IntoFfi>::To; fn convert(self) -> Self::To { - <&'static [u8] as ToFfi>::convert(self.as_ref()) + <&'static [u8] as IntoFfi>::convert(self.as_ref()) } fn postlude(ret: &str, conv: FfiReturnConvention) -> impl Display { - <&'static [u8] as ToFfi>::postlude(ret, conv) + <&'static [u8] as IntoFfi>::postlude(ret, conv) } } -unsafe impl ToFfi for &'static str { - type To = <&'static [u8] as ToFfi>::To; +unsafe impl IntoFfi for &'static str { + type To = <&'static [u8] as IntoFfi>::To; fn convert(self) -> Self::To { - <&'static [u8] as ToFfi>::convert(self.as_bytes()) + <&'static [u8] as IntoFfi>::convert(self.as_bytes()) } fn postlude(ret: &str, conv: FfiReturnConvention) -> impl Display { - <&'static [u8] as ToFfi>::postlude(ret, conv) + <&'static [u8] as IntoFfi>::postlude(ret, conv) } } diff --git a/crates/luaffi_impl/src/cdef.rs b/crates/luaffi_impl/src/cdef.rs index cad0111..e0fb428 100644 --- a/crates/luaffi_impl/src/cdef.rs +++ b/crates/luaffi_impl/src/cdef.rs @@ -60,7 +60,8 @@ fn generate_type(ty: &Ident) -> Result { } } - unsafe impl #ffi::ToFfi for #ty { + // SAFETY: we can always implement `IntoFfi` because it transfers ownership from Rust to Lua + unsafe impl #ffi::IntoFfi for #ty { type To = Self; fn convert(self) -> Self::To { self } } diff --git a/crates/luaffi_impl/src/metatype.rs b/crates/luaffi_impl/src/metatype.rs index 675307d..32e7c09 100644 --- a/crates/luaffi_impl/src/metatype.rs +++ b/crates/luaffi_impl/src/metatype.rs @@ -231,8 +231,8 @@ fn generate_ffi_wrapper(func: &FfiFunction) -> Result { match get_ffi_arg_type(ty) { FfiArgType::Default => { - params.push(quote! { #name: <#ty as #ffi::FromFfi>::FromArg }); - args.push(quote! { <#ty as #ffi::FromFfi>::convert_arg(#name) }); + params.push(quote! { #name: <#ty as #ffi::FromFfi>::From }); + args.push(quote! { <#ty as #ffi::FromFfi>::convert(#name) }); } } } @@ -240,19 +240,22 @@ fn generate_ffi_wrapper(func: &FfiFunction) -> Result { let (ret, call) = if func.ret_by_out { // make return by out-param the first parameter let ret = &func.ret; - params.insert(0, quote! { out: *mut #ret }); + params.insert(0, quote! { out: *mut <#ret as #ffi::IntoFfi>::To }); ( quote!(()), - quote! { ::std::ptr::write(out, Self::#name(#(#args),*)) }, + quote! { ::std::ptr::write(out, <#ret as #ffi::IntoFfi>::convert(Self::#name(#(#args),*))) }, ) } else { let ret = &func.ret; - (quote! { #ret }, quote! { Self::#name(#(#args),*) }) + ( + quote! { <#ret as #ffi::IntoFfi>::To }, + quote! { <#ret as #ffi::IntoFfi>::convert(Self::#name(#(#args),*)) }, + ) }; Ok(quote! { #[unsafe(export_name = #c_name)] - unsafe extern "C" fn #rust_name(#(#params),*) -> #ret { unsafe { #call } } + unsafe extern "C" fn #rust_name(#(#params),*) -> #ret { #call } }) } @@ -275,7 +278,7 @@ fn generate_ffi_register(func: &FfiFunction) -> Result { match get_ffi_arg_type(ty) { FfiArgType::Default => { - params.push(quote! { <#ty as #ffi::FromFfi>::FromArg }); + params.push(quote! { <#ty as #ffi::FromFfi>::From }); register.push(quote! { b.param::<#ty>(#name); }) } }; @@ -291,9 +294,9 @@ fn generate_ffi_register(func: &FfiFunction) -> Result { }; let declare = if func.ret_by_out { - quote! { b.declare::<#ffi::UnsafeExternCFn<(*mut #ret, #(#params,)*), ()>>(#c_name); } + quote! { b.declare::<#ffi::UnsafeExternCFn<(*mut <#ret as #ffi::IntoFfi>::To, #(#params,)*), ()>>(#c_name); } } else { - quote! { b.declare::<#ffi::UnsafeExternCFn<(#(#params,)*), #ret>>(#c_name); } + quote! { b.declare::<#ffi::UnsafeExternCFn<(#(#params,)*), <#ret as #ffi::IntoFfi>::To>>(#c_name); } }; let register = match func.attrs.metatable {