Rename ToFfi to IntoFfi

This commit is contained in:
lumi 2025-06-24 11:42:11 +10:00
parent cadf0a8551
commit 45db380466
Signed by: luaneko
GPG Key ID: 406809B8763FF07A
6 changed files with 176 additions and 193 deletions

View File

@ -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<F: Future<Output: ToFfi>> {
pub struct lua_future<F: Future<Output: IntoFfi>> {
//
// 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<F: Future<Output: ToFfi>> {
sig: Signature,
poll: fn(Pin<&mut Self>, cx: &mut Context) -> Poll<()>,
state: State<F>,
take: unsafe extern "C" fn(&mut Self) -> <F::Output as ToFfi>::To,
take: unsafe extern "C" fn(&mut Self) -> <F::Output as IntoFfi>::To,
drop: unsafe extern "C" fn(&mut Self),
}
@ -70,7 +70,7 @@ enum State<F: Future> {
Complete,
}
impl<F: Future<Output: ToFfi>> lua_future<F> {
impl<F: Future<Output: IntoFfi>> lua_future<F> {
pub fn new(fut: F) -> Self {
Self {
sig: SIGNATURE,
@ -94,7 +94,7 @@ impl<F: Future<Output: ToFfi>> lua_future<F> {
}
}
unsafe extern "C" fn take(&mut self) -> <F::Output as ToFfi>::To {
unsafe extern "C" fn take(&mut self) -> <F::Output as IntoFfi>::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<F: Future<Output: ToFfi> + 'static> Type for lua_future<F> {
unsafe impl<F: Future<Output: IntoFfi> + 'static> Type for lua_future<F> {
fn name() -> impl Display {
display!("future__{:x}", type_id::<F>())
}
@ -145,15 +145,15 @@ unsafe impl<F: Future<Output: ToFfi> + 'static> Type for lua_future<F> {
}
}
unsafe impl<F: Future<Output: ToFfi> + 'static> Cdef for lua_future<F> {
unsafe impl<F: Future<Output: IntoFfi> + 'static> Cdef for lua_future<F> {
fn build(s: &mut CdefBuilder) {
s.field_opaque(mem::offset_of!(Self, take)) // opaque .sig, .poll and .state
.field::<UnsafeExternCFn<(&mut Self,), <F::Output as ToFfi>::To>>("__take")
.field::<UnsafeExternCFn<(&mut Self,), <F::Output as IntoFfi>::To>>("__take")
.field::<UnsafeExternCFn<(&mut Self,), ()>>("__drop");
}
}
unsafe impl<F: Future<Output: ToFfi> + 'static> Metatype for lua_future<F> {
unsafe impl<F: Future<Output: IntoFfi> + 'static> Metatype for lua_future<F> {
type Target = Self;
fn build(s: &mut MetatypeBuilder) {
@ -161,7 +161,7 @@ unsafe impl<F: Future<Output: ToFfi> + 'static> Metatype for lua_future<F> {
}
}
unsafe impl<F: Future<Output: ToFfi> + 'static> ToFfi for lua_future<F> {
unsafe impl<F: Future<Output: IntoFfi> + 'static> IntoFfi for lua_future<F> {
type To = lua_future<F>;
fn convert(self) -> Self::To {
@ -179,12 +179,12 @@ unsafe impl<F: Future<Output: ToFfi> + 'static> ToFfi for lua_future<F> {
// `coroutine.yield` is cached as `yield` and `ffi.gc` as `gc` in locals (see lib.rs)
display!(
"yield({ret}); {ret} = gc({ret}, nil):__take(); {}",
<F::Output as ToFfi>::postlude(ret, FfiReturnConvention::ByValue)
<F::Output as IntoFfi>::postlude(ret, FfiReturnConvention::ByValue)
)
}
}
impl<F: IntoFuture<Output: ToFfi>> From<F> for lua_future<F::IntoFuture> {
impl<F: IntoFuture<Output: IntoFfi>> From<F> for lua_future<F::IntoFuture> {
fn from(value: F) -> Self {
Self::new(value.into_future())
}

View File

@ -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<T: ToFfi>(&mut self, func: impl Display, ret: FfiReturnConvention) {
pub fn call<T: IntoFfi>(&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<T: Type> 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<T: Type> ToFfi for $ty {
unsafe impl<T: Type> 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<T: Type> 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> {

View File

@ -0,0 +1,4 @@
// pub enum lua_result<T> {
// Err(lua_error),
// Ok(T),
// }

View File

@ -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)
}
}

View File

@ -60,7 +60,8 @@ fn generate_type(ty: &Ident) -> Result<TokenStream> {
}
}
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 }
}

View File

@ -231,8 +231,8 @@ fn generate_ffi_wrapper(func: &FfiFunction) -> Result<TokenStream> {
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<TokenStream> {
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<TokenStream> {
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<TokenStream> {
};
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 {