Use CType<T> instead of CType (#243)

This commit is contained in:
qwreey 2024-08-25 19:22:46 +00:00
parent 26706d9355
commit d60a1b99f6
No known key found for this signature in database
GPG key ID: D28DB79297A214BD
9 changed files with 128 additions and 202 deletions

View file

@ -1,3 +1,5 @@
use std::any::Any;
use libffi::middle::Type; use libffi::middle::Type;
use mlua::prelude::*; use mlua::prelude::*;
@ -54,13 +56,13 @@ impl CArr {
Ok(carr) Ok(carr)
} }
pub fn get_type(&self) -> Type { pub fn get_type(&self) -> &Type {
self.struct_type.clone() &self.struct_type
} }
// pub fn get_element_type(&self) -> Type { pub fn get_element_type(&self) -> &Type {
// self.element_type.clone() &self.element_type
// } }
// Stringify cstruct for pretty printing something like: // Stringify cstruct for pretty printing something like:
// <CStruct( u8, i32, size = 8 )> // <CStruct( u8, i32, size = 8 )>
@ -73,7 +75,7 @@ impl CArr {
.as_userdata() .as_userdata()
.ok_or(LuaError::external("failed to get inner type userdata."))?; .ok_or(LuaError::external("failed to get inner type userdata."))?;
if inner.is::<CType>() { if inner.is::<CType<dyn Any>>() {
Ok(format!( Ok(format!(
" {} ; {} ", " {} ; {} ",
stringify_userdata(inner)?, stringify_userdata(inner)?,

View file

@ -1,3 +1,4 @@
use std::any::Any;
use std::ptr::{self, null_mut}; use std::ptr::{self, null_mut};
use libffi::{low, middle::Type, raw}; use libffi::{low, middle::Type, raw};
@ -37,11 +38,11 @@ pub fn type_list_from_table(table: &LuaTable) -> LuaResult<Vec<Type>> {
// get libffi_type from any c-type userdata // get libffi_type from any c-type userdata
pub fn type_from_userdata(userdata: &LuaAnyUserData) -> LuaResult<Type> { pub fn type_from_userdata(userdata: &LuaAnyUserData) -> LuaResult<Type> {
if userdata.is::<CStruct>() { if userdata.is::<CStruct>() {
Ok(userdata.borrow::<CStruct>()?.get_type()) Ok(userdata.borrow::<CStruct>()?.get_type().to_owned())
} else if userdata.is::<CType>() { } else if userdata.is::<CType<dyn Any>>() {
Ok(userdata.borrow::<CType>()?.get_type()) Ok(userdata.borrow::<CType<dyn Any>>()?.get_type().to_owned())
} else if userdata.is::<CArr>() { } else if userdata.is::<CArr>() {
Ok(userdata.borrow::<CArr>()?.get_type()) Ok(userdata.borrow::<CArr>()?.get_type().to_owned())
} else if userdata.is::<CPtr>() { } else if userdata.is::<CPtr>() {
Ok(CPtr::get_type()) Ok(CPtr::get_type())
} else { } else {
@ -59,9 +60,10 @@ pub fn type_from_userdata(userdata: &LuaAnyUserData) -> LuaResult<Type> {
// stringify any c-type userdata (for recursive) // stringify any c-type userdata (for recursive)
pub fn stringify_userdata(userdata: &LuaAnyUserData) -> LuaResult<String> { pub fn stringify_userdata(userdata: &LuaAnyUserData) -> LuaResult<String> {
if userdata.is::<CType>() { if userdata.is::<CType<dyn Any>>() {
let name = userdata.borrow::<CType>()?.stringify(); Ok(String::from(
Ok(name) userdata.borrow::<CType<dyn Any>>()?.stringify(),
))
} else if userdata.is::<CStruct>() { } else if userdata.is::<CStruct>() {
let name = CStruct::stringify(userdata)?; let name = CStruct::stringify(userdata)?;
Ok(name) Ok(name)
@ -80,7 +82,7 @@ pub fn stringify_userdata(userdata: &LuaAnyUserData) -> LuaResult<String> {
pub fn name_from_userdata(userdata: &LuaAnyUserData) -> String { pub fn name_from_userdata(userdata: &LuaAnyUserData) -> String {
if userdata.is::<CStruct>() { if userdata.is::<CStruct>() {
String::from("CStruct") String::from("CStruct")
} else if userdata.is::<CType>() { } else if userdata.is::<CType<dyn Any>>() {
String::from("CType") String::from("CType")
} else if userdata.is::<CArr>() { } else if userdata.is::<CArr>() {
String::from("CArr") String::from("CArr")

View file

@ -1,12 +1,9 @@
#![allow(clippy::cargo_common_metadata)] #![allow(clippy::cargo_common_metadata)]
use std::{borrow::Borrow, vec::Vec}; use std::any::Any;
use std::vec::Vec;
use libffi::{ use libffi::{low, middle::Type, raw};
low,
middle::{Cif, Type},
raw,
};
use mlua::prelude::*; use mlua::prelude::*;
use super::association_names::CSTRUCT_INNER; use super::association_names::CSTRUCT_INNER;
@ -20,14 +17,14 @@ use crate::ffi::ffi_helper::FFI_STATUS_NAMES;
pub struct CStruct { pub struct CStruct {
// libffi_cif: Cif, // libffi_cif: Cif,
fields: Vec<Type>, fields: Vec<Type>,
libffi_type: Type, struct_type: Type,
offsets: Vec<usize>, offsets: Vec<usize>,
size: usize, size: usize,
} }
impl CStruct { impl CStruct {
pub fn new(fields: Vec<Type>) -> LuaResult<Self> { pub fn new(fields: Vec<Type>) -> LuaResult<Self> {
let libffi_type = Type::structure(fields.iter().cloned()); let struct_type = Type::structure(fields.iter().cloned());
// let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void()); // let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void());
// Get field offsets with ffi_get_struct_offsets // Get field offsets with ffi_get_struct_offsets
@ -35,7 +32,7 @@ impl CStruct {
unsafe { unsafe {
let offset_result: raw::ffi_status = raw::ffi_get_struct_offsets( let offset_result: raw::ffi_status = raw::ffi_get_struct_offsets(
low::ffi_abi_FFI_DEFAULT_ABI, low::ffi_abi_FFI_DEFAULT_ABI,
libffi_type.as_raw_ptr(), struct_type.as_raw_ptr(),
offsets.as_mut_ptr(), offsets.as_mut_ptr(),
); );
if offset_result != raw::ffi_status_FFI_OK { if offset_result != raw::ffi_status_FFI_OK {
@ -49,12 +46,12 @@ impl CStruct {
// Get tailing padded size of struct // Get tailing padded size of struct
// See http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html // See http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html
let size = unsafe { (*libffi_type.as_raw_ptr()).size }; let size = unsafe { (*struct_type.as_raw_ptr()).size };
Ok(Self { Ok(Self {
// libffi_cif: libffi_cfi, // libffi_cif: libffi_cfi,
fields, fields,
libffi_type, struct_type,
offsets, offsets,
size, size,
}) })
@ -85,7 +82,7 @@ impl CStruct {
let mut result = String::from(" "); let mut result = String::from(" ");
for i in 0..table.raw_len() { for i in 0..table.raw_len() {
let child: LuaAnyUserData = table.raw_get(i + 1)?; let child: LuaAnyUserData = table.raw_get(i + 1)?;
if child.is::<CType>() { if child.is::<CType<dyn Any>>() {
result.push_str(format!("{}, ", stringify_userdata(&child)?).as_str()); result.push_str(format!("{}, ", stringify_userdata(&child)?).as_str());
} else { } else {
result.push_str( result.push_str(
@ -117,8 +114,12 @@ impl CStruct {
Ok(offset) Ok(offset)
} }
pub fn get_type(&self) -> Type { pub fn get_fields(&self) -> &Vec<Type> {
self.libffi_type.clone() &self.fields
}
pub fn get_type(&self) -> &Type {
&self.struct_type
} }
} }

View file

@ -1,5 +1,7 @@
#![allow(clippy::cargo_common_metadata)] #![allow(clippy::cargo_common_metadata)]
use std::marker::PhantomData;
use libffi::middle::Type; use libffi::middle::Type;
use mlua::prelude::*; use mlua::prelude::*;
@ -8,27 +10,20 @@ use super::c_helper::get_ensured_size;
use super::c_ptr::CPtr; use super::c_ptr::CPtr;
use crate::ffi::ffi_helper::get_ptr_from_userdata; use crate::ffi::ffi_helper::get_ptr_from_userdata;
pub struct CType { pub struct CType<T: ?Sized> {
// for ffi_ptrarray_to_raw? // for ffi_ptrarray_to_raw?
// libffi_cif: Cif, // libffi_cif: Cif,
libffi_type: Type, libffi_type: Type,
size: usize, size: usize,
name: Option<String>, name: Option<&'static str>,
_phantom: PhantomData<T>,
// Write converted data from luavalue into some ptr
pub luavalue_into_ptr: fn(value: LuaValue, ptr: *mut ()) -> LuaResult<()>,
// Read luavalue from some ptr
pub ptr_into_luavalue: fn(lua: &Lua, ptr: *mut ()) -> LuaResult<LuaValue>,
} }
impl CType { impl<T> CType<T>
pub fn new( where
libffi_type: Type, T: ?Sized,
name: Option<String>, {
luavalue_into_ptr: fn(value: LuaValue, ptr: *mut ()) -> LuaResult<()>, pub fn new_with_libffi_type(libffi_type: Type, name: Option<&'static str>) -> LuaResult<Self> {
ptr_into_luavalue: fn(lua: &Lua, ptr: *mut ()) -> LuaResult<LuaValue>,
) -> LuaResult<Self> {
// let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void()); // let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void());
let size = get_ensured_size(libffi_type.as_raw_ptr())?; let size = get_ensured_size(libffi_type.as_raw_ptr())?;
Ok(Self { Ok(Self {
@ -36,78 +31,83 @@ impl CType {
libffi_type, libffi_type,
size, size,
name, name,
luavalue_into_ptr, _phantom: PhantomData {},
ptr_into_luavalue,
}) })
} }
pub fn get_type(&self) -> Type { pub fn get_type(&self) -> &Type {
self.libffi_type.clone() &self.libffi_type
} }
pub fn stringify(&self) -> String { pub fn stringify(&self) -> &str {
match &self.name { match self.name {
Some(t) => t.to_owned(), Some(t) => t,
None => String::from("unnamed"), None => "unnamed",
} }
} }
}
// Read data from ptr and convert it into luavalue pub trait PtrHandle {
pub unsafe fn read_ptr<'lua>( // Convert luavalue into data, then write into ptr
fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()>;
// Read data from ptr, then convert into luavalue
fn ptr_into_luavalue(lua: &Lua, ptr: *mut ()) -> LuaResult<LuaValue>;
// Read data from userdata (such as box or ref) and convert it into luavalue
unsafe fn read_userdata<'lua>(
&self, &self,
lua: &'lua Lua, lua: &'lua Lua,
userdata: LuaAnyUserData<'lua>, userdata: LuaAnyUserData<'lua>,
offset: Option<isize>, offset: Option<isize>,
) -> LuaResult<LuaValue<'lua>> { ) -> LuaResult<LuaValue<'lua>> {
let ptr = unsafe { get_ptr_from_userdata(&userdata, offset)? }; let ptr = unsafe { get_ptr_from_userdata(&userdata, offset)? };
let value = (self.ptr_into_luavalue)(lua, ptr)?; let value = Self::ptr_into_luavalue(lua, ptr)?;
Ok(value) Ok(value)
} }
// Write converted data from luavalue into ptr // Write data into userdata (such as box or ref) from luavalue
pub unsafe fn write_ptr<'lua>( unsafe fn write_userdata<'lua>(
&self, &self,
luavalue: LuaValue<'lua>, luavalue: LuaValue<'lua>,
userdata: LuaAnyUserData<'lua>, userdata: LuaAnyUserData<'lua>,
offset: Option<isize>, offset: Option<isize>,
) -> LuaResult<()> { ) -> LuaResult<()> {
let ptr = unsafe { get_ptr_from_userdata(&userdata, offset)? }; let ptr = unsafe { get_ptr_from_userdata(&userdata, offset)? };
(self.luavalue_into_ptr)(luavalue, ptr)?; Self::luavalue_into_ptr(luavalue, ptr)?;
Ok(()) Ok(())
} }
} }
impl LuaUserData for CType { impl<T> LuaUserData for CType<T>
where
Self: Sized + PtrHandle,
{
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("size", |_, this| Ok(this.size)); fields.add_field_method_get("size", |_, this| Ok(this.size));
} }
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_function("ptr", |lua, this: LuaAnyUserData| { methods.add_function("ptr", |lua, this: LuaAnyUserData| {
let pointer = CPtr::from_lua_userdata(lua, &this)?; CPtr::from_lua_userdata(lua, &this)
Ok(pointer)
}); });
methods.add_method( methods.add_method(
"from", "from",
|lua, ctype, (userdata, offset): (LuaAnyUserData, Option<isize>)| { |lua, ctype, (userdata, offset): (LuaAnyUserData, Option<isize>)| unsafe {
let value = unsafe { ctype.read_ptr(lua, userdata, offset)? }; ctype.read_userdata(lua, userdata, offset)
Ok(value)
}, },
); );
methods.add_method( methods.add_method(
"into", "into",
|_, ctype, (value, userdata, offset): (LuaValue, LuaAnyUserData, Option<isize>)| { |_, ctype, (value, userdata, offset): (LuaValue, LuaAnyUserData, Option<isize>)| unsafe {
unsafe { ctype.write_ptr(value, userdata, offset)? }; ctype.write_userdata(value, userdata, offset)
Ok(())
}, },
); );
methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| { methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| {
let carr = CArr::from_lua_userdata(lua, &this, length)?; CArr::from_lua_userdata(lua, &this, length)
Ok(carr)
}); });
methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| { methods.add_meta_method(LuaMetaMethod::ToString, |lua, this, ()| {
let name = this.stringify(); lua.create_string(this.stringify())
Ok(name)
}); });
} }
} }

View file

@ -5,6 +5,9 @@ pub(super) mod c_ptr;
pub(super) mod c_string; pub(super) mod c_string;
pub(super) mod c_struct; pub(super) mod c_struct;
pub(super) mod c_type; pub(super) mod c_type;
pub(super) mod types;
pub use types::create_all_types;
// Named registry table names // Named registry table names
mod association_names { mod association_names {
@ -12,133 +15,3 @@ mod association_names {
pub const CARR_INNER: &str = "__carr_inner"; pub const CARR_INNER: &str = "__carr_inner";
pub const CSTRUCT_INNER: &str = "__cstruct_inner"; pub const CSTRUCT_INNER: &str = "__cstruct_inner";
} }
use core::ffi::{
c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint,
c_ulong, c_ulonglong, c_ushort, c_void,
};
use libffi::middle::Type;
use mlua::prelude::*;
use self::c_type::CType;
use crate::ffi::ffi_platform::CHAR_IS_SIGNED;
// export all default c-types
#[allow(clippy::too_many_lines)]
pub fn create_all_types(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaValue)>> {
Ok(vec![
(
"int",
CType::new(
Type::c_int(),
Some(String::from("int")),
|data, ptr| {
let value = match data {
LuaValue::Integer(t) => t,
_ => {
return Err(LuaError::external(format!(
"Integer expected, got {}",
data.type_name()
)))
}
} as c_int;
unsafe {
*(ptr.cast::<c_int>()) = value;
}
Ok(())
},
|lua: &Lua, ptr: *mut ()| {
let value = unsafe { (*ptr.cast::<c_int>()).into_lua(lua)? };
Ok(value)
},
)?
.into_lua(lua)?,
),
(
"long",
CType::new(
Type::c_long(),
Some(String::from("long")),
|data, ptr| {
let value = match data {
LuaValue::Integer(t) => t,
_ => {
return Err(LuaError::external(format!(
"Integer expected, got {}",
data.type_name()
)))
}
} as c_long;
unsafe {
*(ptr.cast::<c_long>()) = value;
}
Ok(())
},
|lua: &Lua, ptr: *mut ()| {
let value = unsafe { (*ptr.cast::<c_long>()).into_lua(lua)? };
Ok(value)
},
)?
.into_lua(lua)?,
),
(
"longlong",
CType::new(
Type::c_longlong(),
Some(String::from("longlong")),
|data, ptr| {
let value = match data {
LuaValue::Integer(t) => t,
_ => {
return Err(LuaError::external(format!(
"Integer expected, got {}",
data.type_name()
)))
}
} as c_longlong;
unsafe {
*(ptr.cast::<c_longlong>()) = value;
}
Ok(())
},
|lua: &Lua, ptr: *mut ()| {
let value = unsafe { (*ptr.cast::<c_longlong>()).into_lua(lua)? };
Ok(value)
},
)?
.into_lua(lua)?,
),
(
"char",
CType::new(
if CHAR_IS_SIGNED {
Type::c_schar()
} else {
Type::c_uchar()
},
Some(String::from("char")),
|data, ptr| {
let value = match data {
LuaValue::Integer(t) => t,
_ => {
return Err(LuaError::external(format!(
"Integer expected, got {}",
data.type_name()
)))
}
} as c_char;
unsafe {
*(ptr.cast::<c_char>()) = value;
}
Ok(())
},
|lua: &Lua, ptr: *mut ()| {
let value = unsafe { (*ptr.cast::<c_char>()).into_lua(lua)? };
Ok(value)
},
)?
.into_lua(lua)?,
),
])
}

View file

@ -0,0 +1,38 @@
use core::ffi::c_int;
use libffi::middle::Type;
use mlua::prelude::*;
use super::super::c_type::{CType, PtrHandle};
impl PtrHandle for CType<c_int> {
fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()> {
let value = match value {
LuaValue::Integer(t) => t,
_ => {
return Err(LuaError::external(format!(
"Integer expected, got {}",
value.type_name()
)))
}
} as c_int;
unsafe {
*(ptr.cast::<c_int>()) = value;
}
Ok(())
}
fn ptr_into_luavalue(lua: &Lua, ptr: *mut ()) -> LuaResult<LuaValue> {
let value = unsafe { (*ptr.cast::<c_int>()).into_lua(lua)? };
Ok(value)
}
}
impl CType<c_int> {
fn new() -> LuaResult<Self> {
Self::new_with_libffi_type(Type::c_int(), Some("int"))
}
}
pub fn get_export(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
Ok(("int", lua.create_userdata(CType::<c_int>::new()?)?))
}

View file

@ -0,0 +1,8 @@
mod c_int;
use mlua::prelude::*;
// export all default c-types
pub fn create_all_types(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaAnyUserData)>> {
Ok(vec![c_int::get_export(lua)?])
}

View file

@ -22,7 +22,7 @@ pub unsafe fn get_ptr_from_userdata(
} else if userdata.is::<FfiRef>() { } else if userdata.is::<FfiRef>() {
userdata.borrow::<FfiRef>()?.get_ptr() userdata.borrow::<FfiRef>()?.get_ptr()
} else { } else {
return Err(LuaError::external("asdf")); return Err(LuaError::external("Unexpected userdata"));
}; };
let ptr = if let Some(t) = offset { let ptr = if let Some(t) = offset {

View file

@ -12,6 +12,8 @@ use super::ffi_bounds::FfiRefBounds;
// If it references an area managed by Lua, // If it references an area managed by Lua,
// the box will remain as long as this reference is alive. // the box will remain as long as this reference is alive.
// Todo : how to impl ref == nullptr
pub struct FfiRef { pub struct FfiRef {
ptr: *mut (), ptr: *mut (),
range: Option<FfiRefBounds>, range: Option<FfiRefBounds>,