mirror of
https://github.com/lune-org/lune.git
synced 2025-04-03 01:50:55 +01:00
Improve code quality (#243)
This commit is contained in:
parent
4b2277fec3
commit
a655a4dad0
38 changed files with 220 additions and 268 deletions
|
@ -7,7 +7,6 @@ See [tests/ffi](../../tests/ffi/README.md)
|
|||
## TODO
|
||||
|
||||
- Rewrite error messages
|
||||
- Deref
|
||||
- CString
|
||||
- Add buffer for owned data support
|
||||
- Add math operation.
|
||||
|
|
|
@ -9,12 +9,10 @@ use crate::ffi::{association, libffi_helper::get_ensured_size, FfiConvert, FfiDa
|
|||
// 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
|
||||
// Multidimensional arrays can be implemented
|
||||
// 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
|
||||
|
||||
pub struct CArrInfo {
|
||||
struct_type: Type,
|
||||
length: usize,
|
||||
|
@ -33,7 +31,6 @@ impl CArrInfo {
|
|||
let struct_type = Type::structure(vec![element_type.clone(); length]);
|
||||
|
||||
Ok(Self {
|
||||
// element_type,
|
||||
struct_type,
|
||||
length,
|
||||
size: inner_size * length,
|
||||
|
@ -63,8 +60,8 @@ impl CArrInfo {
|
|||
self.struct_type.clone()
|
||||
}
|
||||
|
||||
// Stringify for pretty printing like:
|
||||
// <CArr( u8, length = 8 )>
|
||||
// Stringify for pretty-print
|
||||
// ex: <CArr( u8, length = 8 )>
|
||||
pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult<String> {
|
||||
let this = userdata.borrow::<CArrInfo>()?;
|
||||
if let Some(LuaValue::UserData(inner_userdata)) =
|
||||
|
@ -76,7 +73,7 @@ impl CArrInfo {
|
|||
this.length,
|
||||
))
|
||||
} else {
|
||||
Err(LuaError::external("failed to get inner type userdata."))
|
||||
Err(LuaError::external("Failed to retrieve inner type"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -150,13 +147,11 @@ impl FfiConvert for CArrInfo {
|
|||
|
||||
impl LuaUserData for CArrInfo {
|
||||
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("size", |_, this| Ok(this.get_size()));
|
||||
fields.add_field_method_get("length", |_, this| Ok(this.get_length()));
|
||||
fields.add_field_method_get("size", |_lua, this| Ok(this.get_size()));
|
||||
fields.add_field_method_get("length", |_lua, this| Ok(this.get_length()));
|
||||
fields.add_field_function_get("inner", |lua, this: LuaAnyUserData| {
|
||||
let inner: LuaValue = association::get(lua, CARR_INNER, this)?
|
||||
// It shouldn't happen.
|
||||
.ok_or_else(|| LuaError::external("inner field not found"))?;
|
||||
Ok(inner)
|
||||
association::get(lua, CARR_INNER, this)?
|
||||
.ok_or_else(|| LuaError::external("Failed to retrieve inner field"))
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -173,7 +168,7 @@ impl LuaUserData for CArrInfo {
|
|||
method_provider::provide_write_data(methods);
|
||||
method_provider::provide_copy_data(methods);
|
||||
|
||||
methods.add_method("offset", |_, this, offset: isize| {
|
||||
methods.add_method("offset", |_lua, this, offset: isize| {
|
||||
if this.length > (offset as usize) && offset >= 0 {
|
||||
Ok(this.inner_size * (offset as usize))
|
||||
} else {
|
||||
|
|
|
@ -67,7 +67,7 @@ fn create_arg_info(userdata: &LuaAnyUserData) -> LuaResult<FfiArg> {
|
|||
} else if userdata.is::<CFnInfo>() {
|
||||
CALLBACK_ARG_REF_FLAG_CFN
|
||||
} else {
|
||||
return Err(LuaError::external("unexpected type userdata"));
|
||||
return Err(LuaError::external("Unexpected argument type"));
|
||||
};
|
||||
Ok(FfiArg {
|
||||
size: helper::get_size(userdata)?,
|
||||
|
@ -116,8 +116,8 @@ impl CFnInfo {
|
|||
Ok(cfn)
|
||||
}
|
||||
|
||||
// Stringify for pretty printing like:
|
||||
// <CFn( (u8, i32) -> u8 )>
|
||||
// Stringify for pretty-print
|
||||
// ex: <CFn( (u8, i32) -> u8 )>
|
||||
pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult<String> {
|
||||
let mut result = String::from(" (");
|
||||
if let (Some(LuaValue::Table(arg_table)), Some(LuaValue::UserData(result_userdata))) = (
|
||||
|
@ -142,7 +142,7 @@ impl CFnInfo {
|
|||
);
|
||||
Ok(result)
|
||||
} else {
|
||||
Err(LuaError::external("failed to get inner type userdata."))
|
||||
Err(LuaError::external("Failed to retrieve inner type"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,12 +173,14 @@ impl CFnInfo {
|
|||
target_ref: &LuaAnyUserData,
|
||||
) -> LuaResult<LuaAnyUserData<'lua>> {
|
||||
if !target_ref.is::<RefData>() {
|
||||
return Err(LuaError::external("argument 0 must be ffiref"));
|
||||
return Err(LuaError::external("Argument 'functionRef' must be RefData"));
|
||||
}
|
||||
|
||||
let ffi_ref = target_ref.borrow::<RefData>()?;
|
||||
if u8_test_not(ffi_ref.flags, RefFlag::Function.value()) {
|
||||
return Err(LuaError::external("not a function ref"));
|
||||
return Err(LuaError::external(
|
||||
"Argument 'functionRef' is not a valid function reference",
|
||||
));
|
||||
}
|
||||
|
||||
let callable = lua.create_userdata(unsafe {
|
||||
|
@ -203,7 +205,7 @@ impl CFnInfo {
|
|||
|
||||
impl LuaUserData for CFnInfo {
|
||||
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("size", |_, _| Ok(SIZE_OF_POINTER));
|
||||
fields.add_field_method_get("size", |_lua, _this| Ok(SIZE_OF_POINTER));
|
||||
}
|
||||
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
// Subtype
|
||||
|
|
|
@ -53,7 +53,7 @@ pub mod method_provider {
|
|||
return Err(LuaError::external("Out of bounds"));
|
||||
}
|
||||
if !data_handle.is_readable() {
|
||||
return Err(LuaError::external("Unreadable data handle"));
|
||||
return Err(LuaError::external("Unreadable data"));
|
||||
}
|
||||
|
||||
unsafe { this.value_from_data(lua, offset, data_handle) }
|
||||
|
@ -77,7 +77,7 @@ pub mod method_provider {
|
|||
return Err(LuaError::external("Out of bounds"));
|
||||
}
|
||||
if !data_handle.is_writable() {
|
||||
return Err(LuaError::external("Unwritable data handle"));
|
||||
return Err(LuaError::external("Unwritable data"));
|
||||
}
|
||||
|
||||
unsafe { this.value_into_data(lua, offset, data_handle, value) }
|
||||
|
@ -106,18 +106,18 @@ pub mod method_provider {
|
|||
let dst = &dst.get_ffi_data()?;
|
||||
// use or functions
|
||||
if !dst.check_inner_boundary(dst_offset, this.get_size()) {
|
||||
return Err(LuaError::external("Out of bounds"));
|
||||
return Err(LuaError::external("Destination out of bounds"));
|
||||
}
|
||||
if !dst.is_writable() {
|
||||
return Err(LuaError::external("Unwritable data handle"));
|
||||
return Err(LuaError::external("Destination is unwritable"));
|
||||
}
|
||||
|
||||
let src = &src.get_ffi_data()?;
|
||||
if !src.check_inner_boundary(dst_offset, this.get_size()) {
|
||||
return Err(LuaError::external("Out of bounds"));
|
||||
return Err(LuaError::external("Source out of bounds"));
|
||||
}
|
||||
if !src.is_readable() {
|
||||
return Err(LuaError::external("Unreadable value data handle"));
|
||||
return Err(LuaError::external("Source is unreadable"));
|
||||
}
|
||||
|
||||
unsafe { this.copy_data(lua, dst_offset, src_offset, dst, src) }
|
||||
|
@ -196,22 +196,6 @@ pub fn get_userdata(value: LuaValue) -> LuaResult<LuaAnyUserData> {
|
|||
}
|
||||
}
|
||||
|
||||
// Get the NativeConvert handle from the type UserData
|
||||
// this is intended to avoid lookup userdata and lua table every time. (eg: struct)
|
||||
// userdata must live longer than the NativeConvert handle.
|
||||
// However, c_struct is a strong reference to each field, so this is not a problem.
|
||||
pub unsafe fn get_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn FfiConvert> {
|
||||
if userdata.is::<CStructInfo>() {
|
||||
Ok(userdata.to_pointer().cast::<CStructInfo>() as *const dyn FfiConvert)
|
||||
} else if userdata.is::<CArrInfo>() {
|
||||
Ok(userdata.to_pointer().cast::<CArrInfo>() as *const dyn FfiConvert)
|
||||
} else if userdata.is::<CPtrInfo>() {
|
||||
Ok(userdata.to_pointer().cast::<CPtrInfo>() as *const dyn FfiConvert)
|
||||
} else {
|
||||
ctype_helper::get_conv(userdata)
|
||||
}
|
||||
}
|
||||
|
||||
// Create vec<T> from table with (userdata)->T
|
||||
pub fn create_list<T>(
|
||||
table: &LuaTable,
|
||||
|
@ -228,28 +212,24 @@ pub fn create_list<T>(
|
|||
Ok(list)
|
||||
}
|
||||
|
||||
//Get
|
||||
// Get the NativeConvert handle from the ctype userData
|
||||
// This is intended to avoid lookup userdata and lua table every time. (eg: struct)
|
||||
// The userdata must live longer than the NativeConvert handle
|
||||
pub unsafe fn get_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn FfiConvert> {
|
||||
if userdata.is::<CStructInfo>() {
|
||||
Ok(userdata.to_pointer().cast::<CStructInfo>() as *const dyn FfiConvert)
|
||||
} else if userdata.is::<CArrInfo>() {
|
||||
Ok(userdata.to_pointer().cast::<CArrInfo>() as *const dyn FfiConvert)
|
||||
} else if userdata.is::<CPtrInfo>() {
|
||||
Ok(userdata.to_pointer().cast::<CPtrInfo>() as *const dyn FfiConvert)
|
||||
} else {
|
||||
ctype_helper::get_conv(userdata)
|
||||
}
|
||||
}
|
||||
pub unsafe fn get_conv_list(table: &LuaTable) -> LuaResult<Vec<*const dyn FfiConvert>> {
|
||||
create_list(table, |userdata| get_conv(userdata))
|
||||
}
|
||||
|
||||
// Get type size from ctype userdata
|
||||
pub fn get_size(userdata: &LuaAnyUserData) -> LuaResult<usize> {
|
||||
if userdata.is::<CStructInfo>() {
|
||||
Ok(userdata.borrow::<CStructInfo>()?.get_size())
|
||||
} else if userdata.is::<CArrInfo>() {
|
||||
Ok(userdata.borrow::<CArrInfo>()?.get_size())
|
||||
} else if userdata.is::<CPtrInfo>() {
|
||||
Ok(userdata.borrow::<CPtrInfo>()?.get_size())
|
||||
} else if userdata.is::<CVoidInfo>() {
|
||||
Ok(userdata.borrow::<CVoidInfo>()?.get_size())
|
||||
} else if userdata.is::<CFnInfo>() {
|
||||
Ok(userdata.borrow::<CFnInfo>()?.get_size())
|
||||
} else {
|
||||
ctype_helper::get_size(userdata)
|
||||
}
|
||||
}
|
||||
|
||||
// Get libffi_type from ctype userdata
|
||||
pub fn get_middle_type(userdata: &LuaAnyUserData) -> LuaResult<Type> {
|
||||
if userdata.is::<CStructInfo>() {
|
||||
|
@ -276,12 +256,28 @@ pub fn get_middle_type(userdata: &LuaAnyUserData) -> LuaResult<Type> {
|
|||
)))
|
||||
}
|
||||
}
|
||||
|
||||
// get Vec<libffi_type> from table(array) of c-type userdata
|
||||
pub fn get_middle_type_list(table: &LuaTable) -> LuaResult<Vec<Type>> {
|
||||
create_list(table, get_middle_type)
|
||||
}
|
||||
|
||||
// Get type size from ctype userdata
|
||||
pub fn get_size(userdata: &LuaAnyUserData) -> LuaResult<usize> {
|
||||
if userdata.is::<CStructInfo>() {
|
||||
Ok(userdata.borrow::<CStructInfo>()?.get_size())
|
||||
} else if userdata.is::<CArrInfo>() {
|
||||
Ok(userdata.borrow::<CArrInfo>()?.get_size())
|
||||
} else if userdata.is::<CPtrInfo>() {
|
||||
Ok(userdata.borrow::<CPtrInfo>()?.get_size())
|
||||
} else if userdata.is::<CVoidInfo>() {
|
||||
Ok(userdata.borrow::<CVoidInfo>()?.get_size())
|
||||
} else if userdata.is::<CFnInfo>() {
|
||||
Ok(userdata.borrow::<CFnInfo>()?.get_size())
|
||||
} else {
|
||||
ctype_helper::get_size(userdata)
|
||||
}
|
||||
}
|
||||
|
||||
// Check lua table has void ctype userdata
|
||||
pub fn has_void(table: &LuaTable) -> LuaResult<bool> {
|
||||
for i in 0..table.raw_len() {
|
||||
let value: LuaValue = table.raw_get(i + 1)?;
|
||||
|
@ -292,7 +288,7 @@ pub fn has_void(table: &LuaTable) -> LuaResult<bool> {
|
|||
Ok(false)
|
||||
}
|
||||
|
||||
// stringify any c-type userdata (for recursive)
|
||||
// Stringify any c-type userdata recursively
|
||||
pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult<String> {
|
||||
if userdata.is::<CStructInfo>() {
|
||||
CStructInfo::stringify(lua, userdata)
|
||||
|
@ -311,7 +307,7 @@ pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult<String> {
|
|||
}
|
||||
}
|
||||
|
||||
// get name tag for any c-type userdata
|
||||
// Get name tag from ctype userdata
|
||||
pub fn get_tag_name(userdata: &LuaAnyUserData) -> LuaResult<String> {
|
||||
Ok(if userdata.is::<CStructInfo>() {
|
||||
String::from("CStructInfo")
|
||||
|
@ -330,7 +326,8 @@ pub fn get_tag_name(userdata: &LuaAnyUserData) -> LuaResult<String> {
|
|||
})
|
||||
}
|
||||
|
||||
// emulate 'print' for ctype userdata, but ctype is simplified
|
||||
// Emulate 'print' for ctype userdata, but simplified
|
||||
// Used for print struct field, cfn arguments, etc...
|
||||
pub fn pretty_format(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult<String> {
|
||||
if ctype_helper::is_ctype(userdata) {
|
||||
stringify(lua, userdata)
|
||||
|
|
|
@ -36,6 +36,7 @@ mod association_names {
|
|||
pub const CLOSURE_CFN: &str = "__closure_cfn";
|
||||
}
|
||||
|
||||
// Export c namespace
|
||||
pub fn export_c(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
TableBuilder::new(lua)?
|
||||
.with_value("void", CVoidInfo::new())?
|
||||
|
|
|
@ -11,12 +11,9 @@ use crate::{
|
|||
},
|
||||
};
|
||||
|
||||
const READ_CPTR_REF_FLAGS: u8 =
|
||||
RefFlag::Dereferenceable.value() | RefFlag::Offsetable.value() | RefFlag::Leaked.value();
|
||||
const READ_REF_FLAGS: u8 = RefFlag::Offsetable.value()
|
||||
| RefFlag::Leaked.value()
|
||||
| RefFlag::Readable.value()
|
||||
| RefFlag::Writable.value();
|
||||
const READ_CPTR_REF_FLAGS: u8 = RefFlag::Dereferenceable.value() | RefFlag::Offsetable.value();
|
||||
const READ_REF_FLAGS: u8 =
|
||||
RefFlag::Offsetable.value() | RefFlag::Readable.value() | RefFlag::Writable.value();
|
||||
|
||||
pub struct CPtrInfo {
|
||||
inner_size: usize,
|
||||
|
@ -42,9 +39,12 @@ impl FfiConvert for CPtrInfo {
|
|||
data_handle: &Ref<dyn FfiData>,
|
||||
value: LuaValue<'lua>,
|
||||
) -> LuaResult<()> {
|
||||
let value_userdata = value
|
||||
.as_userdata()
|
||||
.ok_or_else(|| LuaError::external("CPtrInfo:writeRef only allows data"))?;
|
||||
let value_userdata = value.as_userdata().ok_or_else(|| {
|
||||
LuaError::external(format!(
|
||||
"Value must be a RefData, BoxData or ClosureData, got {}",
|
||||
value.type_name()
|
||||
))
|
||||
})?;
|
||||
*data_handle
|
||||
.get_inner_pointer()
|
||||
.byte_offset(offset)
|
||||
|
@ -112,7 +112,7 @@ impl CPtrInfo {
|
|||
format!(" {pretty_formatted} ")
|
||||
})
|
||||
} else {
|
||||
Err(LuaError::external("failed to get inner type userdata."))
|
||||
Err(LuaError::external("Failed to retrieve inner type"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,11 +124,10 @@ impl CPtrInfo {
|
|||
|
||||
impl LuaUserData for CPtrInfo {
|
||||
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("size", |_, _| Ok(SIZE_OF_POINTER));
|
||||
fields.add_field_method_get("size", |_lua, _this| Ok(SIZE_OF_POINTER));
|
||||
fields.add_field_function_get("inner", |lua, this| {
|
||||
let inner = association::get(lua, CPTR_INNER, this)?
|
||||
.ok_or_else(|| LuaError::external("inner type not found"))?;
|
||||
Ok(inner)
|
||||
association::get(lua, CPTR_INNER, this)?
|
||||
.ok_or_else(|| LuaError::external("Failed to retrieve inner type"))
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// TODO:
|
||||
|
||||
use mlua::prelude::*;
|
||||
|
||||
pub struct CStringInfo();
|
||||
|
|
|
@ -46,9 +46,7 @@ impl CStructInfo {
|
|||
inner_offset_list.set_len(len);
|
||||
}
|
||||
|
||||
// Get tailing padded size of struct
|
||||
// See http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html
|
||||
// In here, using get_ensured_size is not required
|
||||
// Get tailing padded size of struct (get_ensured_size not required)
|
||||
let size = unsafe { (*middle_type.as_raw_ptr()).size };
|
||||
|
||||
Ok(Self {
|
||||
|
@ -59,8 +57,8 @@ impl CStructInfo {
|
|||
})
|
||||
}
|
||||
|
||||
// Create new CStruct UserData from LuaTable.
|
||||
// Lock and hold table for .inner ref
|
||||
// Create new CStruct from LuaTable.
|
||||
// Freeze and hold table
|
||||
pub fn from_table<'lua>(
|
||||
lua: &'lua Lua,
|
||||
table: LuaTable<'lua>,
|
||||
|
@ -73,25 +71,27 @@ impl CStructInfo {
|
|||
.create_userdata(Self::new(helper::get_middle_type_list(&table)?, unsafe {
|
||||
helper::get_conv_list(&table)?
|
||||
})?)?;
|
||||
|
||||
// Save field table
|
||||
table.set_readonly(true);
|
||||
association::set(lua, CSTRUCT_INNER, &cstruct, table)?;
|
||||
Ok(cstruct)
|
||||
}
|
||||
|
||||
// Stringify cstruct for pretty printing like:
|
||||
// <CStruct( u8, i32, size = 8 )>
|
||||
// Stringify cstruct for pretty printing
|
||||
// ex: <CStruct( u8, i32, size = 8 )>
|
||||
pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult<String> {
|
||||
let fields = get_field_table(lua, userdata)?;
|
||||
let mut stringified = String::from(" ");
|
||||
|
||||
// children
|
||||
// Children
|
||||
for i in 0..fields.raw_len() {
|
||||
let child: LuaAnyUserData = fields.raw_get(i + 1)?;
|
||||
let pretty_formatted = helper::pretty_format(lua, &child)?;
|
||||
stringified.push_str(format!("{pretty_formatted}, ").as_str());
|
||||
}
|
||||
|
||||
// size of
|
||||
// Size
|
||||
stringified
|
||||
.push_str(format!("size = {} ", userdata.borrow::<CStructInfo>()?.get_size()).as_str());
|
||||
Ok(stringified)
|
||||
|
@ -99,12 +99,11 @@ impl CStructInfo {
|
|||
|
||||
// Get byte offset of nth field
|
||||
pub fn offset(&self, index: usize) -> LuaResult<usize> {
|
||||
let offset = self
|
||||
Ok(self
|
||||
.inner_offset_list
|
||||
.get(index)
|
||||
.ok_or_else(|| LuaError::external("Out of index"))?
|
||||
.to_owned();
|
||||
Ok(offset)
|
||||
.to_owned())
|
||||
}
|
||||
|
||||
pub fn get_middle_type(&self) -> Type {
|
||||
|
@ -182,7 +181,7 @@ impl FfiConvert for CStructInfo {
|
|||
|
||||
impl LuaUserData for CStructInfo {
|
||||
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("size", |_, this| Ok(this.get_size()));
|
||||
fields.add_field_method_get("size", |_lua, this| Ok(this.get_size()));
|
||||
}
|
||||
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
// Subtype
|
||||
|
@ -198,8 +197,9 @@ impl LuaUserData for CStructInfo {
|
|||
method_provider::provide_write_data(methods);
|
||||
method_provider::provide_copy_data(methods);
|
||||
|
||||
methods.add_method("offset", |_, this, index: usize| this.offset(index));
|
||||
// Get nth field type userdata
|
||||
// Get nth field offset
|
||||
methods.add_method("offset", |_lua, this, index: usize| this.offset(index));
|
||||
// Get nth field type
|
||||
methods.add_function(
|
||||
"field",
|
||||
|lua, (this, field_index): (LuaAnyUserData, usize)| {
|
||||
|
|
|
@ -24,7 +24,7 @@ pub trait CTypeCast {
|
|||
_from_offset: isize,
|
||||
_into_offset: isize,
|
||||
) -> LuaResult<()> {
|
||||
// Show error if have no cast implement
|
||||
// Error if have no cast implement
|
||||
Err(Self::cast_failed_with(self, from_ctype, into_ctype))
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ pub trait CTypeCast {
|
|||
) -> LuaError {
|
||||
let config = ValueFormatConfig::new();
|
||||
LuaError::external(format!(
|
||||
"Cannot cast {} to {}",
|
||||
"Failed to cast {} into {}",
|
||||
pretty_format_value(&LuaValue::UserData(from_ctype.to_owned()), &config),
|
||||
pretty_format_value(&LuaValue::UserData(into_ctype.to_owned()), &config),
|
||||
))
|
||||
|
@ -94,8 +94,8 @@ where
|
|||
{
|
||||
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
|
||||
fields.add_meta_field(LuaMetaMethod::Type, "CTypeInfo");
|
||||
fields.add_field_method_get("size", |_, this| Ok(this.get_size()));
|
||||
fields.add_field_method_get("signedness", |_, this| Ok(this.get_signedness()));
|
||||
fields.add_field_method_get("size", |_lua, this| Ok(this.get_size()));
|
||||
fields.add_field_method_get("signedness", |_lua, this| Ok(this.get_signedness()));
|
||||
}
|
||||
|
||||
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
|
@ -115,7 +115,7 @@ where
|
|||
|
||||
methods.add_function(
|
||||
"cast",
|
||||
|_,
|
||||
|_lua,
|
||||
(from_type, into_type, from, into, from_offset, into_offset): (
|
||||
LuaAnyUserData,
|
||||
LuaAnyUserData,
|
||||
|
|
|
@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo<f32> {
|
|||
.map_err(LuaError::external)?,
|
||||
_ => {
|
||||
return Err(LuaError::external(format!(
|
||||
"Argument LuaValue expected a Integer, Number or String, got {}",
|
||||
"Value must be a Integer, Number or String, got {}",
|
||||
value.type_name()
|
||||
)))
|
||||
}
|
||||
|
@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo<f32> {
|
|||
unsafe fn value_from_data<'lua>(
|
||||
&self,
|
||||
lua: &'lua Lua,
|
||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
||||
offset: isize,
|
||||
data_handle: &Ref<dyn FfiData>,
|
||||
) -> LuaResult<LuaValue<'lua>> {
|
||||
|
|
|
@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo<f64> {
|
|||
.map_err(LuaError::external)?,
|
||||
_ => {
|
||||
return Err(LuaError::external(format!(
|
||||
"Argument LuaValue expected a Integer, Number or String, got {}",
|
||||
"Value must be a Integer, Number or String, got {}",
|
||||
value.type_name()
|
||||
)))
|
||||
}
|
||||
|
@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo<f64> {
|
|||
unsafe fn value_from_data<'lua>(
|
||||
&self,
|
||||
lua: &'lua Lua,
|
||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
||||
offset: isize,
|
||||
data_handle: &Ref<dyn FfiData>,
|
||||
) -> LuaResult<LuaValue<'lua>> {
|
||||
|
|
|
@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo<i128> {
|
|||
.map_err(LuaError::external)?,
|
||||
_ => {
|
||||
return Err(LuaError::external(format!(
|
||||
"Argument LuaValue expected a Integer, Number or String, got {}",
|
||||
"Value must be a Integer, Number or String, got {}",
|
||||
value.type_name()
|
||||
)))
|
||||
}
|
||||
|
@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo<i128> {
|
|||
unsafe fn value_from_data<'lua>(
|
||||
&self,
|
||||
lua: &'lua Lua,
|
||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
||||
offset: isize,
|
||||
data_handle: &Ref<dyn FfiData>,
|
||||
) -> LuaResult<LuaValue<'lua>> {
|
||||
|
|
|
@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo<i16> {
|
|||
.map_err(LuaError::external)?,
|
||||
_ => {
|
||||
return Err(LuaError::external(format!(
|
||||
"Argument LuaValue expected a Integer, Number or String, got {}",
|
||||
"Value must be a Integer, Number or String, got {}",
|
||||
value.type_name()
|
||||
)))
|
||||
}
|
||||
|
@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo<i16> {
|
|||
unsafe fn value_from_data<'lua>(
|
||||
&self,
|
||||
lua: &'lua Lua,
|
||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
||||
offset: isize,
|
||||
data_handle: &Ref<dyn FfiData>,
|
||||
) -> LuaResult<LuaValue<'lua>> {
|
||||
|
|
|
@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo<i32> {
|
|||
.map_err(LuaError::external)?,
|
||||
_ => {
|
||||
return Err(LuaError::external(format!(
|
||||
"Argument LuaValue expected a Integer, Number or String, got {}",
|
||||
"Value must be a Integer, Number or String, got {}",
|
||||
value.type_name()
|
||||
)))
|
||||
}
|
||||
|
@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo<i32> {
|
|||
unsafe fn value_from_data<'lua>(
|
||||
&self,
|
||||
lua: &'lua Lua,
|
||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
||||
offset: isize,
|
||||
data_handle: &Ref<dyn FfiData>,
|
||||
) -> LuaResult<LuaValue<'lua>> {
|
||||
|
|
|
@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo<i64> {
|
|||
.map_err(LuaError::external)?,
|
||||
_ => {
|
||||
return Err(LuaError::external(format!(
|
||||
"Argument LuaValue expected a Integer, Number or String, got {}",
|
||||
"Value must be a Integer, Number or String, got {}",
|
||||
value.type_name()
|
||||
)))
|
||||
}
|
||||
|
@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo<i64> {
|
|||
unsafe fn value_from_data<'lua>(
|
||||
&self,
|
||||
lua: &'lua Lua,
|
||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
||||
offset: isize,
|
||||
data_handle: &Ref<dyn FfiData>,
|
||||
) -> LuaResult<LuaValue<'lua>> {
|
||||
|
|
|
@ -27,7 +27,7 @@ impl FfiConvert for CTypeInfo<i8> {
|
|||
LuaValue::String(t) => t.as_bytes().first().map_or(0, u8::to_owned).as_(),
|
||||
_ => {
|
||||
return Err(LuaError::external(format!(
|
||||
"Argument LuaValue expected a Integer or String, got {}",
|
||||
"Value must be a Integer or String, got {}",
|
||||
value.type_name()
|
||||
)))
|
||||
}
|
||||
|
@ -43,7 +43,6 @@ impl FfiConvert for CTypeInfo<i8> {
|
|||
unsafe fn value_from_data<'lua>(
|
||||
&self,
|
||||
lua: &'lua Lua,
|
||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
||||
offset: isize,
|
||||
data_handle: &Ref<dyn FfiData>,
|
||||
) -> LuaResult<LuaValue<'lua>> {
|
||||
|
|
|
@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo<isize> {
|
|||
.map_err(LuaError::external)?,
|
||||
_ => {
|
||||
return Err(LuaError::external(format!(
|
||||
"Argument LuaValue expected a Integer, Number or String, got {}",
|
||||
"Value must be a Integer, Number or String, got {}",
|
||||
value.type_name()
|
||||
)))
|
||||
}
|
||||
|
@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo<isize> {
|
|||
unsafe fn value_from_data<'lua>(
|
||||
&self,
|
||||
lua: &'lua Lua,
|
||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
||||
offset: isize,
|
||||
data_handle: &Ref<dyn FfiData>,
|
||||
) -> LuaResult<LuaValue<'lua>> {
|
||||
|
|
|
@ -126,7 +126,7 @@ where
|
|||
pub mod ctype_helper {
|
||||
use super::*;
|
||||
|
||||
// To prevent drop NativeConvert, we must use ffi_association to ensure children keep alive
|
||||
// To prevent droping NativeConvert, need to ensure userdata keep alive
|
||||
macro_rules! define_get_conv {
|
||||
($userdata:ident, $( $rust_type:ty )*) => {
|
||||
$( if $userdata.is::<CTypeInfo<$rust_type>>() {
|
||||
|
@ -141,7 +141,7 @@ pub mod ctype_helper {
|
|||
define_get_conv!(userdata, u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize)
|
||||
}
|
||||
|
||||
// Get size of ctype (not includes struct, arr, ... only CType<*>)
|
||||
// Get size of ctype (not including struct, arr, ... only CType<*>)
|
||||
macro_rules! define_get_size {
|
||||
($userdata:ident, $( $rust_type:ty )*) => {
|
||||
$( if $userdata.is::<CTypeInfo<$rust_type>>() {
|
||||
|
@ -186,6 +186,7 @@ pub mod ctype_helper {
|
|||
define_get_middle_type!(userdata, u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize)
|
||||
}
|
||||
|
||||
// Check whether userdata is ctype or not
|
||||
macro_rules! define_is_ctype {
|
||||
($userdata:ident, $( $rust_type:ty )*) => {
|
||||
$( if $userdata.is::<CTypeInfo<$rust_type>>() {
|
||||
|
|
|
@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo<u128> {
|
|||
.map_err(LuaError::external)?,
|
||||
_ => {
|
||||
return Err(LuaError::external(format!(
|
||||
"Argument LuaValue expected a Integer, Number or String, got {}",
|
||||
"Value must be a Integer, Number or String, got {}",
|
||||
value.type_name()
|
||||
)))
|
||||
}
|
||||
|
@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo<u128> {
|
|||
unsafe fn value_from_data<'lua>(
|
||||
&self,
|
||||
lua: &'lua Lua,
|
||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
||||
offset: isize,
|
||||
data_handle: &Ref<dyn FfiData>,
|
||||
) -> LuaResult<LuaValue<'lua>> {
|
||||
|
|
|
@ -32,7 +32,7 @@ impl FfiConvert for CTypeInfo<u16> {
|
|||
.map_err(LuaError::external)?,
|
||||
_ => {
|
||||
return Err(LuaError::external(format!(
|
||||
"Argument LuaValue expected a Integer, Number or String, got {}",
|
||||
"Value must be a Integer, Number or String, got {}",
|
||||
value.type_name()
|
||||
)))
|
||||
}
|
||||
|
@ -48,7 +48,6 @@ impl FfiConvert for CTypeInfo<u16> {
|
|||
unsafe fn value_from_data<'lua>(
|
||||
&self,
|
||||
lua: &'lua Lua,
|
||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
||||
offset: isize,
|
||||
data_handle: &Ref<dyn FfiData>,
|
||||
) -> LuaResult<LuaValue<'lua>> {
|
||||
|
|
|
@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo<u32> {
|
|||
.map_err(LuaError::external)?,
|
||||
_ => {
|
||||
return Err(LuaError::external(format!(
|
||||
"Argument LuaValue expected a Integer, Number or String, got {}",
|
||||
"Value must be a Integer, Number or String, got {}",
|
||||
value.type_name()
|
||||
)))
|
||||
}
|
||||
|
@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo<u32> {
|
|||
unsafe fn value_from_data<'lua>(
|
||||
&self,
|
||||
lua: &'lua Lua,
|
||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
||||
offset: isize,
|
||||
data_handle: &Ref<dyn FfiData>,
|
||||
) -> LuaResult<LuaValue<'lua>> {
|
||||
|
|
|
@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo<u64> {
|
|||
.map_err(LuaError::external)?,
|
||||
_ => {
|
||||
return Err(LuaError::external(format!(
|
||||
"Argument LuaValue expected a Integer, Number or String, got {}",
|
||||
"Value must be a Integer, Number or String, got {}",
|
||||
value.type_name()
|
||||
)))
|
||||
}
|
||||
|
@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo<u64> {
|
|||
unsafe fn value_from_data<'lua>(
|
||||
&self,
|
||||
lua: &'lua Lua,
|
||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
||||
offset: isize,
|
||||
data_handle: &Ref<dyn FfiData>,
|
||||
) -> LuaResult<LuaValue<'lua>> {
|
||||
|
|
|
@ -28,7 +28,7 @@ impl FfiConvert for CTypeInfo<u8> {
|
|||
LuaValue::String(t) => t.as_bytes().first().map_or(0, u8::to_owned).as_(),
|
||||
_ => {
|
||||
return Err(LuaError::external(format!(
|
||||
"Argument LuaValue expected a Integer or String, got {}",
|
||||
"Value must be a Integer or String, got {}",
|
||||
value.type_name()
|
||||
)))
|
||||
}
|
||||
|
@ -46,7 +46,6 @@ impl FfiConvert for CTypeInfo<u8> {
|
|||
unsafe fn value_from_data<'lua>(
|
||||
&self,
|
||||
lua: &'lua Lua,
|
||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
||||
offset: isize,
|
||||
data_handle: &Ref<dyn FfiData>,
|
||||
) -> LuaResult<LuaValue<'lua>> {
|
||||
|
|
|
@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo<usize> {
|
|||
.map_err(LuaError::external)?,
|
||||
_ => {
|
||||
return Err(LuaError::external(format!(
|
||||
"Argument LuaValue expected a Integer, Number or String, got {}",
|
||||
"Value must be a Integer, Number or String, got {}",
|
||||
value.type_name()
|
||||
)))
|
||||
}
|
||||
|
@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo<usize> {
|
|||
unsafe fn value_from_data<'lua>(
|
||||
&self,
|
||||
lua: &'lua Lua,
|
||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
||||
offset: isize,
|
||||
data_handle: &Ref<dyn FfiData>,
|
||||
) -> LuaResult<LuaValue<'lua>> {
|
||||
|
|
|
@ -32,7 +32,7 @@ impl CVoidInfo {
|
|||
|
||||
impl LuaUserData for CVoidInfo {
|
||||
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("size", |_, _| Ok(0));
|
||||
fields.add_field_method_get("size", |_lua, _this| Ok(0));
|
||||
}
|
||||
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
method_provider::provide_to_string(methods);
|
||||
|
|
|
@ -17,28 +17,20 @@ mod flag;
|
|||
|
||||
pub use self::flag::BoxFlag;
|
||||
|
||||
// Ref which created by lua should not be dereferenceable,
|
||||
const FFI_BOX_PRINT_MAX_LENGTH: usize = 1024;
|
||||
|
||||
// Reference which created by lua should not be dereferenceable
|
||||
const BOX_REF_FLAGS: u8 =
|
||||
RefFlag::Readable.value() | RefFlag::Writable.value() | RefFlag::Offsetable.value();
|
||||
|
||||
// It is an untyped, sized memory area that Lua can manage.
|
||||
// This area is safe within Lua. Operations have their boundaries checked.
|
||||
// It is basically intended to implement passing a pointed space to the outside.
|
||||
// It also helps you handle data that Lua cannot handle.
|
||||
// Depending on the type, operations such as sum, mul, and mod may be implemented.
|
||||
// There is no need to enclose all data in a box;
|
||||
// rather, it creates more heap space, so it should be used appropriately
|
||||
// where necessary.
|
||||
|
||||
// Untyped runtime sized memory for luau.
|
||||
// This operations are safe, have boundaries check.
|
||||
pub struct BoxData {
|
||||
flags: u8,
|
||||
data: ManuallyDrop<Box<[u8]>>,
|
||||
}
|
||||
|
||||
const FFI_BOX_PRINT_MAX_LENGTH: usize = 1024;
|
||||
|
||||
impl BoxData {
|
||||
// For efficiency, it is initialized non-zeroed.
|
||||
pub fn new(size: usize) -> Self {
|
||||
let slice = unsafe {
|
||||
Box::from_raw(ptr::slice_from_raw_parts_mut(
|
||||
|
@ -53,13 +45,10 @@ impl BoxData {
|
|||
}
|
||||
}
|
||||
|
||||
// pub fn copy(&self, target: &mut FfiBox) {}
|
||||
|
||||
// Stringify for pretty-print, with hex format content
|
||||
pub fn stringify(&self) -> String {
|
||||
if self.size() > FFI_BOX_PRINT_MAX_LENGTH * 2 {
|
||||
// FIXME
|
||||
// Todo: if too big, print as another format
|
||||
return String::from("exceed");
|
||||
return String::from("length limit exceed");
|
||||
}
|
||||
let mut buff: String = String::with_capacity(self.size() * 2);
|
||||
for value in self.data.iter() {
|
||||
|
@ -72,7 +61,7 @@ impl BoxData {
|
|||
self.flags = u8_set(self.flags, BoxFlag::Leaked.value(), true);
|
||||
}
|
||||
|
||||
// Make FfiRef from box, with boundary checking
|
||||
// Make FfiRef from box, with boundary check
|
||||
pub fn luaref<'lua>(
|
||||
lua: &'lua Lua,
|
||||
this: LuaAnyUserData<'lua>,
|
||||
|
@ -97,17 +86,13 @@ impl BoxData {
|
|||
|
||||
let luaref = lua.create_userdata(RefData::new(ptr.cast(), BOX_REF_FLAGS, bounds))?;
|
||||
|
||||
// Makes box alive longer then ref
|
||||
// Make box live longer then ref
|
||||
association::set(lua, REF_INNER, &luaref, &this)?;
|
||||
|
||||
Ok(luaref)
|
||||
}
|
||||
|
||||
pub unsafe fn drop(&mut self) {
|
||||
ManuallyDrop::drop(&mut self.data);
|
||||
}
|
||||
|
||||
// Fill every field with 0
|
||||
// Fill with zero
|
||||
pub fn zero(&mut self) {
|
||||
self.data.fill(0);
|
||||
}
|
||||
|
@ -122,7 +107,7 @@ impl BoxData {
|
|||
impl Drop for BoxData {
|
||||
fn drop(&mut self) {
|
||||
if u8_test_not(self.flags, BoxFlag::Leaked.value()) {
|
||||
unsafe { self.drop() };
|
||||
unsafe { ManuallyDrop::drop(&mut self.data) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -151,12 +136,12 @@ impl FfiData for BoxData {
|
|||
|
||||
impl LuaUserData for BoxData {
|
||||
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", |_lua, this| Ok(this.size()));
|
||||
}
|
||||
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
method_provider::provide_copy_from(methods);
|
||||
// For convenience, :zero returns self.
|
||||
methods.add_function_mut("zero", |_, this: LuaAnyUserData| {
|
||||
// For convenience, :zero returns box itself.
|
||||
methods.add_function_mut("zero", |_lua, this: LuaAnyUserData| {
|
||||
this.borrow_mut::<BoxData>()?.zero();
|
||||
Ok(this)
|
||||
});
|
||||
|
@ -173,6 +158,8 @@ impl LuaUserData for BoxData {
|
|||
BoxData::luaref(lua, this, offset)
|
||||
},
|
||||
);
|
||||
methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| Ok(this.stringify()));
|
||||
methods.add_meta_method(LuaMetaMethod::ToString, |_lua, this, ()| {
|
||||
Ok(this.stringify())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,8 @@ pub struct CallableData {
|
|||
const VOID_RESULT_PTR: *mut () = ptr::null_mut();
|
||||
const ZERO_SIZE_ARG_PTR: *mut *mut c_void = ptr::null_mut();
|
||||
|
||||
// Use known size array in stack instead of creating new Vec on heap
|
||||
// Optimization:
|
||||
// Use known size array in stack instead of creating new Vec to eliminate heap allocation
|
||||
macro_rules! create_caller {
|
||||
($len:expr) => {
|
||||
|callable: &CallableData, result: LuaValue, args: LuaMultiValue| unsafe {
|
||||
|
@ -42,12 +43,12 @@ macro_rules! create_caller {
|
|||
.get(index)
|
||||
.ok_or_else(|| LuaError::external(format!("Argument {index} required")))?
|
||||
.as_userdata()
|
||||
.ok_or_else(|| LuaError::external("Argument should be a RefData"))?;
|
||||
.ok_or_else(|| LuaError::external("Argument must be a RefData"))?;
|
||||
|
||||
if let Ok(arg_ref) = arg_value.borrow::<RefData>() {
|
||||
arg.write(arg_ref.get_inner_pointer().cast::<c_void>());
|
||||
} else {
|
||||
return Err(LuaError::external("Argument should be a RefData"));
|
||||
return Err(LuaError::external("Argument must be a RefData"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,6 +66,7 @@ macro_rules! create_caller {
|
|||
};
|
||||
}
|
||||
|
||||
// Optimization:
|
||||
// Call without arguments
|
||||
unsafe fn zero_size_caller(
|
||||
callable: &CallableData,
|
||||
|
@ -88,6 +90,7 @@ unsafe fn zero_size_caller(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
// Optimization: sized callers
|
||||
type Caller =
|
||||
unsafe fn(callable: &CallableData, result: LuaValue, args: LuaMultiValue) -> LuaResult<()>;
|
||||
const SIZED_CALLERS: [Caller; 13] = [
|
||||
|
@ -123,6 +126,7 @@ impl CallableData {
|
|||
|
||||
pub unsafe fn call(&self, result: LuaValue, args: LuaMultiValue) -> LuaResult<()> {
|
||||
let arg_len = self.arg_info_list.len();
|
||||
// Optimization: use sized caller when possible
|
||||
if arg_len < SIZED_CALLERS.len() {
|
||||
return SIZED_CALLERS[arg_len](self, result, args);
|
||||
}
|
||||
|
@ -142,12 +146,12 @@ impl CallableData {
|
|||
.get(index)
|
||||
.ok_or_else(|| LuaError::external(format!("Argument {index} required")))?
|
||||
.as_userdata()
|
||||
.ok_or_else(|| LuaError::external("Argument should be a RefData"))?;
|
||||
.ok_or_else(|| LuaError::external("Argument must be a RefData"))?;
|
||||
|
||||
if let Ok(arg_ref) = arg_value.borrow::<RefData>() {
|
||||
arg_list.push(arg_ref.get_inner_pointer().cast::<c_void>());
|
||||
} else {
|
||||
return Err(LuaError::external("Argument should be a RefData"));
|
||||
return Err(LuaError::external("Argument must be a RefData"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,10 +34,10 @@ impl Drop for ClosureData {
|
|||
}
|
||||
}
|
||||
|
||||
const RESULT_REF_FLAGS: u8 =
|
||||
RefFlag::Leaked.value() | RefFlag::Writable.value() | RefFlag::Offsetable.value();
|
||||
const RESULT_REF_FLAGS: u8 = RefFlag::Writable.value() | RefFlag::Offsetable.value();
|
||||
const CLOSURE_REF_FLAGS: u8 = RefFlag::Function.value();
|
||||
|
||||
// Process C -> Lua function call
|
||||
unsafe extern "C" fn callback(
|
||||
cif: *mut ffi_cif,
|
||||
result_pointer: *mut c_void,
|
||||
|
@ -84,6 +84,7 @@ unsafe extern "C" fn callback(
|
|||
}
|
||||
|
||||
impl ClosureData {
|
||||
// Allocate new ffi closure with lua function
|
||||
pub fn alloc(
|
||||
lua: &Lua,
|
||||
cif: *mut ffi_cif,
|
||||
|
|
|
@ -3,9 +3,9 @@ use mlua::prelude::*;
|
|||
use super::{FfiData, GetFfiData};
|
||||
|
||||
pub mod method_provider {
|
||||
|
||||
use super::*;
|
||||
|
||||
// Implement copyFrom method
|
||||
pub fn provide_copy_from<'lua, Target, M>(methods: &mut M)
|
||||
where
|
||||
Target: FfiData,
|
||||
|
|
|
@ -12,17 +12,20 @@ const LIB_REF_FLAGS: u8 = RefFlag::Offsetable.value()
|
|||
| RefFlag::Dereferenceable.value()
|
||||
| RefFlag::Function.value();
|
||||
|
||||
// Runtime dynamic loaded libraries
|
||||
pub struct LibData(Library);
|
||||
|
||||
impl LibData {
|
||||
// Open library then return library handle
|
||||
pub fn new(libname: String) -> LuaResult<Self> {
|
||||
match Library::open(libname) {
|
||||
Ok(t) => Ok(Self(t)),
|
||||
Err(err) => Err(LuaError::external(format!("{err}"))),
|
||||
Err(err) => Err(err.into_lua_err()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_sym<'lua>(
|
||||
// Get named symbol from library
|
||||
pub fn find_symbol<'lua>(
|
||||
lua: &'lua Lua,
|
||||
this: LuaAnyUserData<'lua>,
|
||||
name: String,
|
||||
|
@ -31,12 +34,12 @@ impl LibData {
|
|||
let sym = unsafe {
|
||||
lib.0
|
||||
.symbol::<*const ()>(name.as_str())
|
||||
.map_err(|err| LuaError::external(format!("{err}")))?
|
||||
.map_err(LuaError::external)?
|
||||
};
|
||||
|
||||
let ffi_ref =
|
||||
lua.create_userdata(RefData::new(sym.cast_mut(), LIB_REF_FLAGS, UNSIZED_BOUNDS))?;
|
||||
|
||||
// Library handle should live longer than retrieved symbol
|
||||
association::set(lua, SYM_INNER, &ffi_ref, &this)?;
|
||||
|
||||
Ok(ffi_ref)
|
||||
|
@ -46,7 +49,7 @@ impl LibData {
|
|||
impl LuaUserData for LibData {
|
||||
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_function("find", |lua, (this, name): (LuaAnyUserData, String)| {
|
||||
LibData::get_sym(lua, this, name)
|
||||
LibData::find_symbol(lua, this, name)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,11 +26,11 @@ mod association_names {
|
|||
pub const CLSOURE_REF_INNER: &str = "__closure_ref_inner";
|
||||
}
|
||||
|
||||
// Get dynamic FfiData handle from LuaValue and LuaAnyUserData
|
||||
pub trait GetFfiData {
|
||||
fn get_ffi_data(&self) -> LuaResult<Ref<dyn FfiData>>;
|
||||
fn is_ffi_data(&self) -> bool;
|
||||
}
|
||||
|
||||
impl GetFfiData for LuaAnyUserData<'_> {
|
||||
fn get_ffi_data(&self) -> LuaResult<Ref<dyn FfiData>> {
|
||||
if self.is::<BoxData>() {
|
||||
|
@ -51,7 +51,6 @@ impl GetFfiData for LuaAnyUserData<'_> {
|
|||
self.is::<BoxData>() | self.is::<RefData>() | self.is::<ClosureData>()
|
||||
}
|
||||
}
|
||||
|
||||
impl GetFfiData for LuaValue<'_> {
|
||||
fn get_ffi_data(&self) -> LuaResult<Ref<dyn FfiData>> {
|
||||
self.as_userdata()
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// Memory range for ref or box data. For boundary checking
|
||||
// Memory boundaries
|
||||
pub struct RefBounds {
|
||||
// Indicates how much data is above the pointer
|
||||
// How much data available above
|
||||
pub(crate) above: usize,
|
||||
// Indicates how much data is below the pointer
|
||||
// How much data available below
|
||||
pub(crate) below: usize,
|
||||
}
|
||||
|
||||
|
@ -39,8 +39,7 @@ impl RefBounds {
|
|||
}
|
||||
}
|
||||
|
||||
// Check boundary
|
||||
// Check required here
|
||||
// Check boundary with specific size
|
||||
#[inline]
|
||||
pub fn check_sized(&self, offset: isize, size: usize) -> bool {
|
||||
if self.is_unsized() {
|
||||
|
@ -62,7 +61,7 @@ impl RefBounds {
|
|||
}
|
||||
}
|
||||
|
||||
// Calculate new bounds from bounds and offset
|
||||
// Calculate new boundaries from bounds and offset
|
||||
// No boundary checking in here
|
||||
#[inline]
|
||||
pub fn offset(&self, offset: isize) -> Self {
|
||||
|
|
|
@ -18,22 +18,12 @@ pub use self::{
|
|||
|
||||
// Box:ref():ref() should not be able to modify, Only for external
|
||||
const BOX_REF_REF_FLAGS: u8 = 0;
|
||||
// | FfiRefFlag::Writable.value()
|
||||
// | FfiRefFlag::Readable.value()
|
||||
// | FfiRefFlag::Dereferenceable.value()
|
||||
// | FfiRefFlag::Offsetable.value()
|
||||
// | FfiRefFlag::Function.value();
|
||||
|
||||
// A referenced space. It is possible to read and write through types.
|
||||
// This operation is not safe. This may cause a memory error in Lua
|
||||
// if use it incorrectly.
|
||||
// If it references an area managed by Lua,
|
||||
// the box will remain as long as this reference is alive.
|
||||
|
||||
// A referenced memory address box. Possible to read and write through types.
|
||||
pub struct RefData {
|
||||
ptr: ManuallyDrop<Box<*mut ()>>,
|
||||
pub flags: u8,
|
||||
pub boundary: RefBounds,
|
||||
pub(crate) flags: u8,
|
||||
boundary: RefBounds,
|
||||
}
|
||||
|
||||
impl RefData {
|
||||
|
@ -45,7 +35,7 @@ impl RefData {
|
|||
}
|
||||
}
|
||||
|
||||
// Make FfiRef from ref
|
||||
// Create reference of this reference box
|
||||
pub fn luaref<'lua>(
|
||||
lua: &'lua Lua,
|
||||
this: LuaAnyUserData<'lua>,
|
||||
|
@ -61,32 +51,32 @@ impl RefData {
|
|||
},
|
||||
))?;
|
||||
|
||||
// If the ref holds a box, make sure the new ref also holds the box by holding ref
|
||||
// Make new reference live longer then this reference
|
||||
association::set(lua, REF_INNER, &luaref, &this)?;
|
||||
|
||||
Ok(luaref)
|
||||
}
|
||||
|
||||
// Dereference this reference
|
||||
pub unsafe fn deref(&self) -> LuaResult<Self> {
|
||||
// Check dereferenceable
|
||||
if !u8_test(self.flags, RefFlag::Dereferenceable.value()) {
|
||||
return Err(LuaError::external("Reference is not dereferenceable"));
|
||||
}
|
||||
|
||||
// Check boundary
|
||||
if !self.boundary.check_sized(0, size_of::<usize>()) {
|
||||
return Err(LuaError::external(
|
||||
"Offset out of bounds",
|
||||
));
|
||||
return Err(LuaError::external("Out of bounds"));
|
||||
}
|
||||
|
||||
// FIXME flags
|
||||
Ok(Self::new(
|
||||
*self.ptr.cast::<*mut ()>(),
|
||||
self.flags,
|
||||
u8_set(self.flags, RefFlag::Leaked.value(), false),
|
||||
UNSIZED_BOUNDS,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn is_nullptr(&self) -> bool {
|
||||
pub fn is_null(&self) -> bool {
|
||||
// * ManuallyDrop wrapper
|
||||
// * Box wrapper
|
||||
(**self.ptr) as usize == 0
|
||||
|
@ -96,31 +86,33 @@ impl RefData {
|
|||
self.flags = u8_set(self.flags, RefFlag::Leaked.value(), true);
|
||||
}
|
||||
|
||||
// Create new reference with specific offset from this reference
|
||||
pub unsafe fn offset(&self, offset: isize) -> LuaResult<Self> {
|
||||
u8_test(self.flags, RefFlag::Offsetable.value())
|
||||
.then_some(())
|
||||
.ok_or_else(|| LuaError::external("Reference is not offsetable"))?;
|
||||
// Check offsetable
|
||||
if u8_test_not(self.flags, RefFlag::Offsetable.value()) {
|
||||
return Err(LuaError::external("Reference is not offsetable"));
|
||||
}
|
||||
|
||||
// Check boundary, if exceed, return error
|
||||
self.boundary
|
||||
.check_boundary(offset)
|
||||
.then_some(())
|
||||
.ok_or_else(|| {
|
||||
LuaError::external(format!(
|
||||
"Offset out of bounds (high: {}, low: {}, got {})",
|
||||
self.boundary.above, self.boundary.below, offset
|
||||
))
|
||||
})?;
|
||||
// Check boundary
|
||||
if !self.boundary.check_boundary(offset) {
|
||||
return Err(LuaError::external(format!(
|
||||
"Offset out of bounds (high: {}, low: {}, got {})",
|
||||
self.boundary.above, self.boundary.below, offset
|
||||
)));
|
||||
}
|
||||
|
||||
let boundary = self.boundary.offset(offset);
|
||||
|
||||
// TODO
|
||||
Ok(Self::new(
|
||||
self.ptr.byte_offset(offset),
|
||||
self.flags,
|
||||
u8_set(self.flags, RefFlag::Leaked.value(), false),
|
||||
boundary,
|
||||
))
|
||||
}
|
||||
|
||||
// Stringify for pretty-print, with hex format address
|
||||
pub fn stringify(&self) -> String {
|
||||
format!("{:x}", **self.ptr as usize)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RefData {
|
||||
|
@ -154,24 +146,12 @@ impl LuaUserData for RefData {
|
|||
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
method_provider::provide_copy_from(methods);
|
||||
|
||||
// FIXME:
|
||||
methods.add_function("deref", |lua, this: LuaAnyUserData| {
|
||||
let inner = association::get(lua, REF_INNER, &this)?;
|
||||
let ffiref = this.borrow::<RefData>()?;
|
||||
let result = lua.create_userdata(unsafe { ffiref.deref()? })?;
|
||||
|
||||
if let Some(t) = inner {
|
||||
// if let Some(u) = association::get(lua, regname, value) {}
|
||||
association::set(lua, REF_INNER, &result, &t)?;
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
});
|
||||
methods.add_method("deref", |_lua, this, ()| unsafe { this.deref() });
|
||||
methods.add_function("offset", |lua, (this, offset): (LuaAnyUserData, isize)| {
|
||||
let ffiref = unsafe { this.borrow::<RefData>()?.offset(offset)? };
|
||||
let userdata = lua.create_userdata(ffiref)?;
|
||||
|
||||
// If the ref holds a box, make sure the new ref also holds the box
|
||||
// If the ref holds a box or reference, make sure the new ref also holds it
|
||||
if let Some(t) = association::get(lua, REF_INNER, &this)? {
|
||||
association::set(lua, REF_INNER, &userdata, t)?;
|
||||
}
|
||||
|
@ -185,7 +165,10 @@ impl LuaUserData for RefData {
|
|||
methods.add_function("ref", |lua, this: LuaAnyUserData| {
|
||||
RefData::luaref(lua, this)
|
||||
});
|
||||
methods.add_method("isNull", |_, this, ()| Ok(this.is_nullptr()));
|
||||
methods.add_method("isNull", |_lua, this, ()| Ok(this.is_null()));
|
||||
methods.add_meta_method(LuaMetaMethod::ToString, |_lua, this, ()| {
|
||||
Ok(this.stringify())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,30 +4,14 @@ use mlua::prelude::*;
|
|||
// In FFI, there is often data that is dependent on other data.
|
||||
// However, if you use user_value to inform Lua of the dependency,
|
||||
// a table will be created for each userdata.
|
||||
// To prevent this, we place a weak reference table in the registry
|
||||
// To prevent this, we place a weak reference table in the named registry
|
||||
// and simulate what mlua does.
|
||||
// Since mlua does not provide Lua state (private),
|
||||
// uservalue operations cannot be performed directly,
|
||||
// so this is the best solution for now.
|
||||
|
||||
// If the dependency is deep, the value may be completely destroyed when
|
||||
// gc is performed multiple times. To prevent this situation, FFI 'copies'
|
||||
// gc is performed multiple times. To prevent this situation, FFI should copy
|
||||
// dependency if possible.
|
||||
//
|
||||
// ffi.i32:ptr():ptr()
|
||||
// Something like this, every pointer type will have various inner field.
|
||||
//
|
||||
// box:ref():ref()
|
||||
// But, in this case,
|
||||
//
|
||||
// Since the outermost pointer holds the definition for the pointer
|
||||
// type inside it, only the outermost type will be removed on the first gc.
|
||||
// It doesn't matter much. But if there is a cleaner way, we should choose it
|
||||
|
||||
// Forces 'associated' to persist as long as 'value' is alive.
|
||||
// 'value' can only hold one value. If you want to keep something else,
|
||||
// use a table with a different name.
|
||||
// You can delete the relationship by changing 'associated' to nil
|
||||
|
||||
#[inline]
|
||||
pub fn set<'lua, T, U>(lua: &'lua Lua, regname: &str, value: T, associated: U) -> LuaResult<()>
|
||||
where
|
||||
|
@ -52,7 +36,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
// returns the Lua value that 'value' keeps.
|
||||
// Returns the Lua value that 'value' keeps.
|
||||
// If there is no table in registry, it returns None.
|
||||
// If there is no value in table, it returns LuaNil.
|
||||
#[inline]
|
||||
|
|
|
@ -5,6 +5,7 @@ use num::cast::AsPrimitive;
|
|||
|
||||
use super::FfiData;
|
||||
|
||||
// Cast number type to another number type, with num::cast library
|
||||
#[inline]
|
||||
pub fn num_cast<From, Into>(
|
||||
from: &Ref<dyn FfiData>,
|
||||
|
|
|
@ -3,8 +3,9 @@ use std::ptr::{self, null_mut};
|
|||
use libffi::{low, raw};
|
||||
use mlua::prelude::*;
|
||||
|
||||
// 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 const SIZE_OF_POINTER: usize = size_of::<*mut ()>();
|
||||
|
||||
// Get ensured size of ctype (raw::libffi_type)
|
||||
pub fn get_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult<usize> {
|
||||
let mut cif = low::ffi_cif::default();
|
||||
let result = unsafe {
|
||||
|
@ -21,9 +22,7 @@ pub fn get_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult<usize> {
|
|||
unsafe { Ok((*ffi_type).size) }
|
||||
}
|
||||
|
||||
pub const SIZE_OF_POINTER: usize = size_of::<*mut ()>();
|
||||
|
||||
// Converts ffi status into &str
|
||||
// Converts ffi status into &str for formatting
|
||||
pub const FFI_STATUS_NAMES: [&str; 4] = [
|
||||
"ffi_status_FFI_OK",
|
||||
"ffi_status_FFI_BAD_TYPEDEF",
|
||||
|
@ -31,6 +30,7 @@ pub const FFI_STATUS_NAMES: [&str; 4] = [
|
|||
"ffi_status_FFI_BAD_ARGTYPE",
|
||||
];
|
||||
|
||||
// Check ffi_result is OK
|
||||
pub fn ffi_status_assert(result: raw::ffi_status) -> LuaResult<()> {
|
||||
if result == raw::ffi_status_FFI_OK {
|
||||
Ok(())
|
||||
|
|
|
@ -9,17 +9,17 @@ pub mod libffi_helper;
|
|||
|
||||
pub use self::cast::num_cast;
|
||||
|
||||
// Common type information
|
||||
pub trait FfiSize {
|
||||
fn get_size(&self) -> usize;
|
||||
}
|
||||
|
||||
pub trait FfiSignedness {
|
||||
fn get_signedness(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// Provide type conversion between luavalue and ffidata types
|
||||
// Provide conversion between luau value and ffi types
|
||||
pub trait FfiConvert {
|
||||
// Write LuaValue into FfiData
|
||||
unsafe fn value_into_data<'lua>(
|
||||
|
@ -57,6 +57,7 @@ pub trait FfiConvert {
|
|||
}
|
||||
}
|
||||
|
||||
// Provide read, write, boundary check methods for datas
|
||||
pub trait FfiData {
|
||||
fn check_inner_boundary(&self, offset: isize, size: usize) -> bool;
|
||||
unsafe fn get_inner_pointer(&self) -> *mut ();
|
||||
|
@ -75,11 +76,11 @@ pub trait FfiData {
|
|||
}
|
||||
}
|
||||
|
||||
// Function argument informations
|
||||
pub struct FfiArg {
|
||||
pub size: usize,
|
||||
pub callback_ref_flag: u8,
|
||||
}
|
||||
|
||||
impl Clone for FfiArg {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
|
@ -89,10 +90,10 @@ impl Clone for FfiArg {
|
|||
}
|
||||
}
|
||||
|
||||
// Function result information
|
||||
pub struct FfiResult {
|
||||
pub size: usize,
|
||||
}
|
||||
|
||||
impl Clone for FfiResult {
|
||||
fn clone(&self) -> Self {
|
||||
Self { size: self.size }
|
||||
|
|
|
@ -52,7 +52,9 @@ ffi.c = c
|
|||
--[=[
|
||||
@class RefData
|
||||
|
||||
A user manageable memory reference.
|
||||
A user manageable memory reference box.
|
||||
|
||||
It can be GCed, But it doesn't free the referenced memory.
|
||||
]=]
|
||||
export type RefData = {
|
||||
--[=[
|
||||
|
@ -60,7 +62,10 @@ export type RefData = {
|
|||
@tag Method
|
||||
@method deref
|
||||
|
||||
Get a RefData by dereference this reference.
|
||||
Create a RefData by dereference this reference.
|
||||
The created reference has no boundaries and has no restrictions.
|
||||
|
||||
This method is unsafe.
|
||||
|
||||
@return A dereferenced `RefData`
|
||||
]=]
|
||||
|
@ -71,7 +76,9 @@ export type RefData = {
|
|||
@method offset
|
||||
|
||||
Create a reference with specific offset from this reference.
|
||||
|
||||
|
||||
The created reference can be GCed and holds same data.
|
||||
|
||||
@param offset Create a reference at the given offset
|
||||
@return A offseted reference
|
||||
]=]
|
||||
|
@ -83,7 +90,7 @@ export type RefData = {
|
|||
|
||||
Create a reference of this reference.
|
||||
|
||||
The created reference keeps the box from being garbage collected until the reference itself is collected.
|
||||
The created reference keeps the target reference from being garbage collected until created reference itself is collected.
|
||||
|
||||
@return A reference of this reference
|
||||
]=]
|
||||
|
@ -1089,6 +1096,7 @@ end
|
|||
@within FFI
|
||||
|
||||
Create a `Box` with specific size.
|
||||
The created box is not filed with zero.
|
||||
|
||||
@param size The size of the new box
|
||||
@return A allocated box
|
||||
|
|
Loading…
Add table
Reference in a new issue