Rename ToFfi to IntoFfi
This commit is contained in:
parent
cadf0a8551
commit
45db380466
@ -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())
|
||||
}
|
||||
|
@ -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> {
|
||||
|
4
crates/luaffi/src/result.rs
Normal file
4
crates/luaffi/src/result.rs
Normal file
@ -0,0 +1,4 @@
|
||||
// pub enum lua_result<T> {
|
||||
// Err(lua_error),
|
||||
// Ok(T),
|
||||
// }
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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 }
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user