Refactor type-define macro rules (#243)

This commit is contained in:
qwreey 2024-10-16 03:12:36 +00:00
parent 46dd185c6f
commit 7d4e4a24b2
No known key found for this signature in database
GPG key ID: D28DB79297A214BD
22 changed files with 104 additions and 262 deletions

View file

@ -14,17 +14,17 @@ use crate::ffi::{
};
use crate::libffi_helper::get_ensured_size;
// FIXME: unsized array
// This is a series of some type.
// It provides the final size and the offset of the index,
// but does not allow multidimensional arrays because of API complexity.
// However, multidimensional arrays are not impossible to implement
// because they are a series of transcribed one-dimensional arrays.
// because they are a series of transcribed one-dimensional arrays. (flatten)
// We can simply provide array type with struct.
// See: https://stackoverflow.com/a/43525176
// Padding after each field inside the struct is set to next field can follow the alignment.
// There is no problem even if you create a struct with n fields of a single type within the struct. Array adheres to the condition that there is no additional padding between each element. Padding to a struct is padding inside the struct. Simply think of the padding byte as a trailing unnamed field.
pub struct CArr {
// element_type: Type,
struct_type: Type,

View file

@ -30,7 +30,7 @@ pub unsafe fn get_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn Native
if userdata.is::<CStruct>() {
Ok(userdata.to_pointer().cast::<CStruct>() as *const dyn NativeConvert)
} else {
unsafe { get_ctype_conv(userdata) }
get_ctype_conv(userdata)
}
}

View file

@ -5,12 +5,11 @@ use std::{cell::Ref, marker::PhantomData};
use libffi::middle::Type;
use lune_utils::fmt::{pretty_format_value, ValueFormatConfig};
use mlua::prelude::*;
use num::cast::AsPrimitive;
use super::{association_names::CTYPE_STATIC, CArr, CPtr};
use crate::ffi::{
ffi_association::set_association, native_num_cast, FfiBox, GetNativeData, NativeConvert,
NativeData, NativeSignedness, NativeSize,
ffi_association::set_association, FfiBox, GetNativeData, NativeConvert, NativeData,
NativeSignedness, NativeSize,
};
use crate::libffi_helper::get_ensured_size;
@ -39,25 +38,6 @@ impl LuaUserData for CTypeStatic {}
// Cast native data
pub trait CTypeCast {
#[inline(always)]
fn try_cast_num<T, U>(
&self,
ctype: &LuaAnyUserData,
from: &Ref<dyn NativeData>,
into: &Ref<dyn NativeData>,
) -> LuaResult<Option<()>>
where
T: AsPrimitive<U>,
U: 'static + Copy,
{
if ctype.is::<CType<U>>() {
native_num_cast::<T, U>(from, into)?;
Ok(Some(()))
} else {
Ok(None)
}
}
#[inline(always)]
fn cast(
&self,
@ -66,6 +46,7 @@ pub trait CTypeCast {
_from: &Ref<dyn NativeData>,
_into: &Ref<dyn NativeData>,
) -> LuaResult<()> {
// Show error if have no cast implement
Err(Self::cast_failed_with(self, from_ctype, into_ctype))
}

View file

@ -15,8 +15,7 @@ pub use self::{
c_type::{CType, CTypeCast, CTypeStatic},
};
pub use types::create_all_c_types;
pub use types::create_all_types;
pub use types::export_ctypes;
// Named registry table names
mod association_names {

View file

@ -1,6 +1,5 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
@ -52,10 +51,3 @@ impl NativeConvert for CType<f32> {
Ok(value)
}
}
pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
Ok((
"f32",
CType::<f32>::new_with_libffi_type(lua, Type::f32(), Some("f32"))?,
))
}

View file

@ -1,6 +1,5 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
@ -52,10 +51,3 @@ impl NativeConvert for CType<f64> {
Ok(value)
}
}
pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
Ok((
"f64",
CType::<f64>::new_with_libffi_type(lua, Type::f64(), Some("f64"))?,
))
}

View file

@ -1,6 +1,5 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
@ -52,14 +51,3 @@ impl NativeConvert for CType<i128> {
Ok(value)
}
}
pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
Ok((
"i128",
CType::<i128>::new_with_libffi_type(
lua,
Type::structure(vec![Type::u64(), Type::u64()]),
Some("i128"),
)?,
))
}

View file

@ -1,6 +1,5 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
@ -52,10 +51,3 @@ impl NativeConvert for CType<i16> {
Ok(value)
}
}
pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
Ok((
"i16",
CType::<i16>::new_with_libffi_type(lua, Type::i16(), Some("i16"))?,
))
}

View file

@ -1,6 +1,5 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
@ -52,10 +51,3 @@ impl NativeConvert for CType<i32> {
Ok(value)
}
}
pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
Ok((
"i32",
CType::<i32>::new_with_libffi_type(lua, Type::i32(), Some("i32"))?,
))
}

View file

@ -1,6 +1,5 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
@ -52,10 +51,3 @@ impl NativeConvert for CType<i64> {
Ok(value)
}
}
pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
Ok((
"i64",
CType::<i64>::new_with_libffi_type(lua, Type::i64(), Some("i64"))?,
))
}

View file

@ -1,6 +1,5 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
@ -48,10 +47,3 @@ impl NativeConvert for CType<i8> {
Ok(value)
}
}
pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
Ok((
"i8",
CType::<i8>::new_with_libffi_type(lua, Type::i8(), Some("i8"))?,
))
}

View file

@ -1,6 +1,5 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
@ -52,10 +51,3 @@ impl NativeConvert for CType<isize> {
Ok(value)
}
}
pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
Ok((
"isize",
CType::<isize>::new_with_libffi_type(lua, Type::isize(), Some("isize"))?,
))
}

View file

@ -8,7 +8,7 @@ use mlua::prelude::*;
use num::cast::AsPrimitive;
use super::{CType, CTypeCast};
use crate::ffi::{NativeConvert, NativeData, NativeSize};
use crate::ffi::{native_num_cast, NativeConvert, NativeData, NativeSize};
pub mod f32;
pub mod f64;
@ -25,14 +25,83 @@ pub mod u64;
pub mod u8;
pub mod usize;
macro_rules! cast_nums {
($T:ident, $self:ident, $from_ctype:ident, $into_ctype:ident, $from:ident, $into:ident, $t:ty, $($c:ty),*) => {
$self
.try_cast_num::<$T, $t>($into_ctype, $from, $into)?
$(.or($self.try_cast_num::<$T, $c>($into_ctype, $from, $into)?))*
.ok_or_else(|| $self.cast_failed_with($from_ctype, $into_ctype))
macro_rules! create_ctypes {
($lua:ident, $(( $name:expr, $rust_type:ty, $libffi_type:expr ),)* ) => {
Ok(vec![$((
$name,
CType::<$rust_type>::new_with_libffi_type($lua, $libffi_type, Some($name))?,
),)*])
};
}
// create CType userdata and export
pub fn export_ctypes(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaAnyUserData)>> {
create_ctypes!(
lua,
// Export Compile-time known c-types
("char", c_char, {
if TypeId::of::<c_char>() == TypeId::of::<u8>() {
Type::c_uchar()
} else {
Type::c_schar()
}
}),
("uchar", c_uchar, Type::c_uchar()),
("schar", c_schar, Type::c_schar()),
("short", c_short, Type::c_short()),
("ushort", c_ushort, Type::c_ushort()),
("int", c_int, Type::c_int()),
("uint", c_uint, Type::c_uint()),
("long", c_long, Type::c_long()),
("ulong", c_ulong, Type::c_ulong()),
("longlong", c_longlong, Type::c_longlong()),
("ulonglong", c_ulonglong, Type::c_ulonglong()),
// TODO: c_float and c_double sometime can be half and single,
// TODO: but libffi-rs doesn't support it. need work-around or drop support
("float", f32, Type::f32()),
("double", f64, Type::f64()),
// Export Source-time known c-types (fixed)
("u8", u8, Type::u8()),
("u16", u16, Type::u16()),
("u32", u32, Type::u32()),
("u64", u64, Type::u64()),
("u128", u128, Type::c_longlong()),
("i8", i8, Type::i8()),
("i16", i16, Type::i16()),
("i32", i32, Type::i32()),
("i64", i64, Type::i64()),
("i128", i128, Type::c_ulonglong()),
("f64", f64, Type::f64()),
("f32", f32, Type::f32()),
("usize", usize, Type::usize()),
("isize", isize, Type::isize()),
)
}
macro_rules! define {
(@get_conv $userdata:ident, $( $rust_type:ty )*) => {
$( if $userdata.is::<CType<$rust_type>>() {
Ok($userdata.to_pointer().cast::<CType<$rust_type>>() as *const dyn NativeConvert)
} else )* {
Err(LuaError::external("Unexpected type"))
}
};
(@get_size $userdata:ident, $( $rust_type:ty )*) => {
$( if $userdata.is::<CType<$rust_type>>() {
Ok($userdata.borrow::<CType<$rust_type>>()?.get_size())
} else )* {
Err(LuaError::external("Unexpected type"))
}
};
(@cast_num $from_rust_type:ident, $self:ident, $from_ctype:ident, $into_ctype:ident, $from:ident, $into:ident, $($into_rust_type:ty)*) => {
$( if $into_ctype.is::<CType<$into_rust_type>>() {
native_num_cast::<$from_rust_type, $into_rust_type>($from, $into)
} else )* {
Err($self.cast_failed_with($from_ctype, $into_ctype))
}
};
}
impl<T> CTypeCast for CType<T>
where
T: AsPrimitive<u8>
@ -57,106 +126,17 @@ where
from: &Ref<dyn NativeData>,
into: &Ref<dyn NativeData>,
) -> LuaResult<()> {
cast_nums!(
T, self, into_ctype, from_ctype, from, into, u8, u16, u32, u64, u128, i8, i16, i128,
f32, f64, usize, isize
define!(
@cast_num T, self, into_ctype, from_ctype, from, into,
u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize
)
}
}
// export all default c-types
macro_rules! define_c_types {
( $lua:ident, $n:expr, $t:ident ) => {
(
$n,
CType::<$t>::new_with_libffi_type($lua, Type::$t(), Some($n))?,
)
};
}
pub fn create_all_c_types(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaAnyUserData)>> {
Ok(vec![
(
"char",
CType::<c_char>::new_with_libffi_type(
lua,
if TypeId::of::<c_char>() == TypeId::of::<u8>() {
Type::c_uchar()
} else {
Type::c_schar()
},
Some("char"),
)?,
),
(
"float",
CType::<c_float>::new_with_libffi_type(lua, Type::f32(), Some("float"))?,
),
(
"double",
CType::<c_double>::new_with_libffi_type(lua, Type::f64(), Some("double"))?,
),
define_c_types!(lua, "uchar", c_uchar),
define_c_types!(lua, "schar", c_schar),
define_c_types!(lua, "short", c_short),
define_c_types!(lua, "ushort", c_ushort),
define_c_types!(lua, "int", c_int),
define_c_types!(lua, "uint", c_uint),
define_c_types!(lua, "long", c_long),
define_c_types!(lua, "ulong", c_ulong),
define_c_types!(lua, "longlong", c_longlong),
define_c_types!(lua, "ulonglong", c_ulonglong),
])
}
// export all default c-types
pub fn create_all_types(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaAnyUserData)>> {
Ok(vec![
self::u8::create_type(lua)?,
self::u16::create_type(lua)?,
self::u32::create_type(lua)?,
self::u64::create_type(lua)?,
self::u128::create_type(lua)?,
self::i8::create_type(lua)?,
self::i16::create_type(lua)?,
self::i32::create_type(lua)?,
self::i64::create_type(lua)?,
self::i128::create_type(lua)?,
self::f64::create_type(lua)?,
self::f32::create_type(lua)?,
self::usize::create_type(lua)?,
self::isize::create_type(lua)?,
])
}
// Use UB method, but safe. because we use ffi_association to ensure children keep alive
// Much faster then get NativeConvert handle every time from lua table
// it's spam of table.get(), if ud.is::<T>() { ud.borrow::<T>()? ... }
macro_rules! define_get_ctype_conv {
($userdata:ident, $f:ty, $( $c:ty ),*) => {
if $userdata.is::<CType<$f>>() {
Ok($userdata.to_pointer().cast::<CType<$f>>() as *const dyn NativeConvert)
}$( else if $userdata.is::<CType<$c>>() {
Ok($userdata.to_pointer().cast::<CType<$c>>() as *const dyn NativeConvert)
})* else {
Err(LuaError::external("Unexpected type"))
}
};
}
pub unsafe fn get_ctype_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn NativeConvert> {
define_get_ctype_conv!(userdata, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64)
}
macro_rules! define_get_ctype_size {
($userdata:ident, $f:ty, $( $c:ty ),*) => {
if $userdata.is::<CType<$f>>() {
Ok($userdata.borrow::<CType<$f>>()?.get_size())
}$( else if $userdata.is::<CType<$c>>() {
Ok($userdata.borrow::<CType<$c>>()?.get_size())
})* else {
Err(LuaError::external("Unexpected type"))
}
};
// To prevent drop NativeConvert, we must use ffi_association to ensure children keep alive
pub fn get_ctype_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn NativeConvert> {
define!(@get_conv userdata, u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize)
}
pub fn get_ctype_size(userdata: &LuaAnyUserData) -> LuaResult<usize> {
define_get_ctype_size!(userdata, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64)
define!(@get_size userdata, u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize)
}

View file

@ -1,6 +1,5 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
@ -52,14 +51,3 @@ impl NativeConvert for CType<u128> {
Ok(value)
}
}
pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
Ok((
"u128",
CType::<u128>::new_with_libffi_type(
lua,
Type::structure(vec![Type::u64(), Type::u64()]),
Some("u128"),
)?,
))
}

View file

@ -1,6 +1,5 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
@ -53,10 +52,3 @@ impl NativeConvert for CType<u16> {
Ok(value)
}
}
pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
Ok((
"u16",
CType::<u16>::new_with_libffi_type(lua, Type::u16(), Some("u16"))?,
))
}

View file

@ -1,6 +1,5 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
@ -52,10 +51,3 @@ impl NativeConvert for CType<u32> {
Ok(value)
}
}
pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
Ok((
"u32",
CType::<u32>::new_with_libffi_type(lua, Type::u32(), Some("u32"))?,
))
}

View file

@ -1,6 +1,5 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
@ -52,10 +51,3 @@ impl NativeConvert for CType<u64> {
Ok(value)
}
}
pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
Ok((
"u64",
CType::<u64>::new_with_libffi_type(lua, Type::u64(), Some("u64"))?,
))
}

View file

@ -1,6 +1,5 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
@ -51,10 +50,3 @@ impl NativeConvert for CType<u8> {
Ok(value)
}
}
pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
Ok((
"u8",
CType::<u8>::new_with_libffi_type(lua, Type::u8(), Some("u8"))?,
))
}

View file

@ -1,6 +1,5 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
@ -52,10 +51,3 @@ impl NativeConvert for CType<usize> {
Ok(value)
}
}
pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
Ok((
"usize",
CType::<usize>::new_with_libffi_type(lua, Type::usize(), Some("usize"))?,
))
}

View file

@ -155,6 +155,7 @@ impl NativeData for FfiRef {
impl LuaUserData for FfiRef {
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
// FIXME:
methods.add_function("deref", |lua, this: LuaAnyUserData| {
let inner = get_association(lua, REF_INNER, &this)?;
let ffiref = this.borrow::<FfiRef>()?;
@ -178,6 +179,7 @@ impl LuaUserData for FfiRef {
Ok(userdata)
});
// FIXME:
methods.add_function("ref", |lua, this: LuaAnyUserData| {
let ffiref = FfiRef::luaref(lua, this)?;
Ok(ffiref)

View file

@ -9,7 +9,7 @@ mod ffi;
mod libffi_helper;
use crate::{
c::{create_all_c_types, create_all_types, CFn, CStruct},
c::{export_ctypes, CFn, CStruct},
ffi::{create_nullptr, is_integer, FfiBox, FfiLib},
};
@ -22,19 +22,19 @@ use crate::{
*/
pub fn module(lua: &Lua) -> LuaResult<LuaTable> {
let result = TableBuilder::new(lua)?
.with_values(create_all_types(lua)?)?
.with_values(create_all_c_types(lua)?)?
.with_value("nullptr", create_nullptr(lua)?)?
.with_values(export_ctypes(lua)?)?
.with_value("nullRef", create_nullptr(lua)?)?
.with_function("box", |_lua, size: usize| Ok(FfiBox::new(size)))?
.with_function("open", |_lua, name: String| FfiLib::new(name))?
.with_function("struct", |lua, types: LuaTable| {
.with_function("structInfo", |lua, types: LuaTable| {
CStruct::new_from_lua_table(lua, types)
})?
.with_function("ref", |_lua, ()| Ok(FfiRef::new_uninit()))?
.with_function("uninitRef", |_lua, ()| Ok(FfiRef::new_uninit()))?
.with_function("isInteger", |_lua, num: LuaValue| Ok(is_integer(num)))?
.with_function("fn", |lua, (args, ret): (LuaTable, LuaAnyUserData)| {
CFn::new_from_lua_table(lua, args, ret)
})?;
.with_function(
"funcInfo",
|lua, (args, ret): (LuaTable, LuaAnyUserData)| CFn::new_from_lua_table(lua, args, ret),
)?;
#[cfg(debug_assertions)]
let result = result.with_function("debug_associate", |lua, str: String| {

View file

@ -5,7 +5,7 @@ use mlua::prelude::*;
use crate::ffi::FFI_STATUS_NAMES;
// Ensure sizeof c-type (raw::libffi_type)
// Get ensured size of c-type (raw::libffi_type)
// See: http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html
pub fn get_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult<usize> {
let mut cif = low::ffi_cif::default();