Update luaffi
This commit is contained in:
parent
7548c68c7c
commit
cadf0a8551
@ -9,7 +9,6 @@ use std::{
|
||||
};
|
||||
|
||||
pub mod future;
|
||||
// pub mod option;
|
||||
pub mod string;
|
||||
|
||||
#[doc(hidden)]
|
||||
@ -82,7 +81,7 @@ const CACHE_LOCALS: &[(&str, &str)] = &[
|
||||
("__tunpack", "table.unpack"),
|
||||
// string
|
||||
("__slen", "string.len"),
|
||||
("__sformat", "string.format"),
|
||||
("__sprintf", "string.format"),
|
||||
("__ssub", "string.sub"),
|
||||
("__sgsub", "string.gsub"),
|
||||
("__sgmatch", "string.gmatch"),
|
||||
@ -528,6 +527,19 @@ macro_rules! impl_primitive {
|
||||
|
||||
impl_primitive!((), "void");
|
||||
impl_primitive!(c_void, "void");
|
||||
impl_primitive!(bool, "bool");
|
||||
impl_primitive!(u8, "uint8_t");
|
||||
impl_primitive!(u16, "uint16_t");
|
||||
impl_primitive!(u32, "uint32_t");
|
||||
impl_primitive!(u64, "uint64_t");
|
||||
impl_primitive!(usize, "uintptr_t");
|
||||
impl_primitive!(i8, "int8_t");
|
||||
impl_primitive!(i16, "int16_t");
|
||||
impl_primitive!(i32, "int32_t");
|
||||
impl_primitive!(i64, "int64_t");
|
||||
impl_primitive!(isize, "intptr_t");
|
||||
impl_primitive!(c_float, "float");
|
||||
impl_primitive!(c_double, "double");
|
||||
|
||||
unsafe impl ToFfi for () {
|
||||
//
|
||||
@ -536,8 +548,8 @@ unsafe impl ToFfi for () {
|
||||
// so it should return the unit type instead.
|
||||
//
|
||||
type To = ();
|
||||
fn convert(self) -> Self::To {}
|
||||
|
||||
fn convert(self) -> Self::To {}
|
||||
fn postlude(_ret: &str, conv: FfiReturnConvention) -> impl Display {
|
||||
assert!(
|
||||
conv == FfiReturnConvention::Void,
|
||||
@ -547,19 +559,53 @@ unsafe impl ToFfi for () {
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_primitive_abi {
|
||||
($rtype:ty, $ctype:expr, $ltype:expr $(, $unwrap:expr)?) => {
|
||||
impl_primitive!($rtype, $ctype);
|
||||
unsafe impl FromFfi for bool {
|
||||
type From = bool;
|
||||
type FromArg = bool;
|
||||
|
||||
//
|
||||
// SAFETY: Primitive types are always copyable so we can pass and return them by value.
|
||||
//
|
||||
fn prelude(arg: &str) -> impl Display {
|
||||
display!(
|
||||
r#"assert(type({arg}) == "boolean", "boolean expected in argument '{arg}', got " .. type({arg})); "#
|
||||
)
|
||||
}
|
||||
|
||||
fn convert(from: Self::From) -> Self {
|
||||
from
|
||||
}
|
||||
|
||||
fn convert_arg(from: Self::FromArg) -> Self {
|
||||
from
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl ToFfi for bool {
|
||||
type To = bool;
|
||||
|
||||
fn convert(self) -> Self::To {
|
||||
self
|
||||
}
|
||||
|
||||
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; ")?,
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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#"assert(type({arg}) == "{0}", "{0} expected in argument '{arg}', got " .. type({arg})); "#, $ltype)
|
||||
display!(r#"do local __{arg} = {arg}; {arg} = tonumber({arg}); assert(type({arg}) == "number", "number expected in argument '{arg}', got " .. type(__{arg})); end; "#)
|
||||
}
|
||||
|
||||
fn convert(from: Self::From) -> Self {
|
||||
@ -570,7 +616,49 @@ macro_rules! impl_primitive_abi {
|
||||
from
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_number_fromabi!(u8);
|
||||
impl_number_fromabi!(u16);
|
||||
impl_number_fromabi!(u32);
|
||||
impl_number_fromabi!(u64);
|
||||
impl_number_fromabi!(usize);
|
||||
impl_number_fromabi!(i8);
|
||||
impl_number_fromabi!(i16);
|
||||
impl_number_fromabi!(i32);
|
||||
impl_number_fromabi!(i64);
|
||||
impl_number_fromabi!(isize);
|
||||
impl_number_fromabi!(f32);
|
||||
impl_number_fromabi!(f64);
|
||||
|
||||
macro_rules! impl_number_toabi {
|
||||
($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 {
|
||||
type To = Self;
|
||||
|
||||
@ -578,35 +666,19 @@ macro_rules! impl_primitive_abi {
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
fn postlude(ret: &str, conv: FfiReturnConvention) -> impl Display {
|
||||
disp(move |f| Ok({
|
||||
match conv {
|
||||
FfiReturnConvention::Void => unreachable!(),
|
||||
FfiReturnConvention::ByValue => {},
|
||||
// if a primitive type for some reason gets returned by out-param, unwrap
|
||||
// the cdata containing the value to convert it to the equivalent lua value
|
||||
FfiReturnConvention::ByOutParam => { $(write!(f, "{ret} = {}; ", $unwrap(ret))?;)? },
|
||||
}
|
||||
}))
|
||||
fn postlude(ret: &str, _conv: FfiReturnConvention) -> impl Display {
|
||||
display!("{ret} = tonumber({ret}); ")
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_primitive_abi!(bool, "bool", "boolean", |n| display!("{n} ~= 0"));
|
||||
impl_primitive_abi!(u8, "uint8_t", "number", |n| display!("tonumber({n})"));
|
||||
impl_primitive_abi!(u16, "uint16_t", "number", |n| display!("tonumber({n})"));
|
||||
impl_primitive_abi!(u32, "uint32_t", "number", |n| display!("tonumber({n})"));
|
||||
impl_primitive_abi!(u64, "uint64_t", "number");
|
||||
impl_primitive_abi!(usize, "uintptr_t", "number");
|
||||
impl_primitive_abi!(i8, "int8_t", "number", |n| display!("tonumber({n})"));
|
||||
impl_primitive_abi!(i16, "int16_t", "number", |n| display!("tonumber({n})"));
|
||||
impl_primitive_abi!(i32, "int32_t", "number", |n| display!("tonumber({n})"));
|
||||
impl_primitive_abi!(i64, "int64_t", "number");
|
||||
impl_primitive_abi!(isize, "intptr_t", "number");
|
||||
impl_primitive_abi!(c_float, "float", "number", |n| display!("tonumber({n})"));
|
||||
impl_primitive_abi!(c_double, "double", "number", |n| display!("tonumber({n})"));
|
||||
impl_bigint_toabi!(u64);
|
||||
impl_bigint_toabi!(i64);
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
impl_bigint_toabi!(usize);
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
impl_bigint_toabi!(isize);
|
||||
|
||||
macro_rules! impl_const_ptr {
|
||||
($ty:ty) => {
|
||||
@ -827,7 +899,7 @@ macro_rules! impl_function {
|
||||
fn name() -> impl Display {
|
||||
disp(|f| Ok({
|
||||
write!(f, "fn_{}", $ret::name())?;
|
||||
$(write!(f, "_{}", $arg::name())?;)*
|
||||
$(write!(f, "__{}", $arg::name())?;)*
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -1,78 +0,0 @@
|
||||
use crate::{Cdef, CdefBuilder, FfiReturnConvention, FromFfi, ToFfi, Type, TypeBuilder, display};
|
||||
use std::{ffi::c_int, fmt::Display, ptr};
|
||||
|
||||
#[repr(C)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum lua_option<T> {
|
||||
None, // __tag = 0
|
||||
Some(T), // __tag = 1
|
||||
}
|
||||
|
||||
unsafe impl<T: Type> Type for lua_option<T> {
|
||||
fn name() -> impl Display {
|
||||
display!("option__{}", T::name())
|
||||
}
|
||||
|
||||
fn cdecl(name: impl Display) -> impl Display {
|
||||
display!("struct option__{} {name}", T::name())
|
||||
}
|
||||
|
||||
fn build(b: &mut TypeBuilder) {
|
||||
b.include::<T>().cdef::<Self>();
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Type> Cdef for lua_option<T> {
|
||||
fn build(b: &mut CdefBuilder) {
|
||||
b.field::<c_int>("__tag").field::<T>("__value");
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: FromFfi> FromFfi for Option<T> {
|
||||
type From = lua_option<T::From>;
|
||||
type FromArg = *mut Self::From; // pass by-ref
|
||||
|
||||
fn require_keepalive() -> bool {
|
||||
T::require_keepalive()
|
||||
}
|
||||
|
||||
fn prelude(arg: &str) -> impl Display {
|
||||
let ct = Self::From::name();
|
||||
display!(
|
||||
"if {arg} == nil then {arg} = __new(__ct.{ct}); else {}{arg} = __new(__ct.{ct}, 1, {arg}); end; ",
|
||||
T::prelude(arg)
|
||||
)
|
||||
}
|
||||
|
||||
fn convert(from: Self::From) -> Self {
|
||||
match from {
|
||||
lua_option::Some(value) => Some(T::convert(value)),
|
||||
lua_option::None => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_arg(from: Self::FromArg) -> Self {
|
||||
debug_assert!(!from.is_null());
|
||||
Self::convert(unsafe { ptr::replace(from, lua_option::None) })
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: ToFfi> ToFfi for Option<T> {
|
||||
type To = lua_option<T::To>;
|
||||
|
||||
fn convert(self) -> Self::To {
|
||||
match self {
|
||||
Some(value) => lua_option::Some(value.convert()),
|
||||
None => lua_option::None,
|
||||
}
|
||||
}
|
||||
|
||||
fn postlude(ret: &str, _conv: FfiReturnConvention) -> impl Display {
|
||||
// if we don't have a value, return nil. otherwise copy out the inner value immediately,
|
||||
// forget the option cdata, then call postlude on the inner value.
|
||||
display!(
|
||||
"if {ret}.__tag == 0 then {ret} = nil; else {ret} = {ret}.__value; {}end; ",
|
||||
T::postlude(ret, FfiReturnConvention::ByValue)
|
||||
)
|
||||
}
|
||||
}
|
@ -1,6 +1,10 @@
|
||||
use crate::{__internal::disp, FromFfi, IS_UTF8_FN, Type};
|
||||
use crate::{
|
||||
__internal::{disp, display},
|
||||
FfiReturnConvention, FromFfi, IS_UTF8_FN, ToFfi, Type,
|
||||
};
|
||||
use bstr::BStr;
|
||||
use luaffi_impl::{cdef, metatype};
|
||||
use std::{fmt, ptr, slice};
|
||||
use std::{fmt::Display, slice};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[cdef]
|
||||
@ -12,48 +16,81 @@ pub struct lua_buf {
|
||||
#[metatype]
|
||||
impl lua_buf {}
|
||||
|
||||
unsafe impl FromFfi for *const [u8] {
|
||||
// not implemented yet
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[cdef]
|
||||
pub struct lua_buffer {
|
||||
__ptr: *const u8,
|
||||
__len: usize,
|
||||
__cap: usize,
|
||||
}
|
||||
|
||||
#[metatype]
|
||||
impl lua_buffer {}
|
||||
|
||||
unsafe impl<'s> FromFfi for &'s [u8] {
|
||||
type From = lua_buf;
|
||||
type FromArg = *const Self::From;
|
||||
type FromArg = Option<&'s Self::From>;
|
||||
|
||||
fn require_keepalive() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn prelude(arg: &str) -> impl fmt::Display {
|
||||
fn prelude(arg: &str) -> impl Display {
|
||||
// this converts string arguments to a `lua_buf` with a pointer to the string and its length
|
||||
disp(move |f| {
|
||||
let ct = Self::From::name();
|
||||
write!(
|
||||
f,
|
||||
r#"if {arg} ~= nil then assert(type({arg}) == "string", "string expected in argument '{arg}', got " .. type({arg})); "#
|
||||
r#"assert(type({arg}) == "string", "string expected in argument '{arg}', got " .. type({arg})); "#
|
||||
)?;
|
||||
write!(f, "{arg} = __new(__ct.{ct}, {arg}, #{arg}); end; ")
|
||||
})
|
||||
}
|
||||
|
||||
fn convert(from: Self::From) -> Self {
|
||||
ptr::slice_from_raw_parts(from.__ptr, from.__len)
|
||||
// SAFETY: we already checked that the string is nonnull from the lua side
|
||||
debug_assert!(!from.__ptr.is_null());
|
||||
unsafe { slice::from_raw_parts(from.__ptr, from.__len) }
|
||||
}
|
||||
|
||||
fn convert_arg(from: Self::FromArg) -> Self {
|
||||
if from.is_null() {
|
||||
ptr::slice_from_raw_parts(ptr::null(), 0)
|
||||
} else {
|
||||
Self::convert(unsafe { *from })
|
||||
}
|
||||
// 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 FromFfi for &str {
|
||||
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()
|
||||
}
|
||||
|
||||
fn prelude(arg: &str) -> impl Display {
|
||||
<&'s [u8] as FromFfi>::prelude(arg)
|
||||
}
|
||||
|
||||
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 = *const Self::From;
|
||||
type FromArg = Option<&'s Self::From>;
|
||||
|
||||
fn require_keepalive() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn prelude(arg: &str) -> impl fmt::Display {
|
||||
fn prelude(arg: &str) -> impl Display {
|
||||
disp(move |f| {
|
||||
let ct = Self::From::name();
|
||||
write!(
|
||||
@ -82,7 +119,47 @@ unsafe impl FromFfi for &str {
|
||||
}
|
||||
|
||||
fn convert_arg(from: Self::FromArg) -> Self {
|
||||
debug_assert!(!from.is_null());
|
||||
unsafe { Self::convert(*from) }
|
||||
// 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 impl ToFfi for &'static [u8] {
|
||||
type To = lua_buf;
|
||||
|
||||
fn convert(self) -> Self::To {
|
||||
lua_buf {
|
||||
__ptr: self.as_ptr(),
|
||||
__len: self.len(),
|
||||
}
|
||||
}
|
||||
|
||||
fn postlude(ret: &str, _conv: FfiReturnConvention) -> impl Display {
|
||||
display!("{ret} = __intern({ret}.__ptr, {ret}.__len)")
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl ToFfi for &'static BStr {
|
||||
type To = <&'static [u8] as ToFfi>::To;
|
||||
|
||||
fn convert(self) -> Self::To {
|
||||
<&'static [u8] as ToFfi>::convert(self.as_ref())
|
||||
}
|
||||
|
||||
fn postlude(ret: &str, conv: FfiReturnConvention) -> impl Display {
|
||||
<&'static [u8] as ToFfi>::postlude(ret, conv)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl ToFfi for &'static str {
|
||||
type To = <&'static [u8] as ToFfi>::To;
|
||||
|
||||
fn convert(self) -> Self::To {
|
||||
<&'static [u8] as ToFfi>::convert(self.as_bytes())
|
||||
}
|
||||
|
||||
fn postlude(ret: &str, conv: FfiReturnConvention) -> impl Display {
|
||||
<&'static [u8] as ToFfi>::postlude(ret, conv)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user