diff --git a/crates/lune-std-ffi/README.md b/crates/lune-std-ffi/README.md index c5fa3c8a..e7b3fbcd 100644 --- a/crates/lune-std-ffi/README.md +++ b/crates/lune-std-ffi/README.md @@ -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. diff --git a/crates/lune-std-ffi/src/c/arr_info.rs b/crates/lune-std-ffi/src/c/arr_info.rs index 4a109ff3..0362f264 100644 --- a/crates/lune-std-ffi/src/c/arr_info.rs +++ b/crates/lune-std-ffi/src/c/arr_info.rs @@ -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: - // + // Stringify for pretty-print + // ex: pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { let this = userdata.borrow::()?; 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 { diff --git a/crates/lune-std-ffi/src/c/fn_info.rs b/crates/lune-std-ffi/src/c/fn_info.rs index 29944991..21ce3f0d 100644 --- a/crates/lune-std-ffi/src/c/fn_info.rs +++ b/crates/lune-std-ffi/src/c/fn_info.rs @@ -67,7 +67,7 @@ fn create_arg_info(userdata: &LuaAnyUserData) -> LuaResult { } else if userdata.is::() { 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: - // u8 )> + // Stringify for pretty-print + // ex: u8 )> pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { 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> { if !target_ref.is::() { - return Err(LuaError::external("argument 0 must be ffiref")); + return Err(LuaError::external("Argument 'functionRef' must be RefData")); } let ffi_ref = target_ref.borrow::()?; 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 diff --git a/crates/lune-std-ffi/src/c/helper.rs b/crates/lune-std-ffi/src/c/helper.rs index 760e5824..68f7183e 100644 --- a/crates/lune-std-ffi/src/c/helper.rs +++ b/crates/lune-std-ffi/src/c/helper.rs @@ -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 { } } -// 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::() { - Ok(userdata.to_pointer().cast::() as *const dyn FfiConvert) - } else if userdata.is::() { - Ok(userdata.to_pointer().cast::() as *const dyn FfiConvert) - } else if userdata.is::() { - Ok(userdata.to_pointer().cast::() as *const dyn FfiConvert) - } else { - ctype_helper::get_conv(userdata) - } -} - // Create vec from table with (userdata)->T pub fn create_list( table: &LuaTable, @@ -228,27 +212,23 @@ pub fn create_list( Ok(list) } -//Get -pub unsafe fn get_conv_list(table: &LuaTable) -> LuaResult> { - create_list(table, |userdata| get_conv(userdata)) -} - -// Get type size from ctype userdata -pub fn get_size(userdata: &LuaAnyUserData) -> LuaResult { +// 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::() { - Ok(userdata.borrow::()?.get_size()) + Ok(userdata.to_pointer().cast::() as *const dyn FfiConvert) } else if userdata.is::() { - Ok(userdata.borrow::()?.get_size()) + Ok(userdata.to_pointer().cast::() as *const dyn FfiConvert) } else if userdata.is::() { - Ok(userdata.borrow::()?.get_size()) - } else if userdata.is::() { - Ok(userdata.borrow::()?.get_size()) - } else if userdata.is::() { - Ok(userdata.borrow::()?.get_size()) + Ok(userdata.to_pointer().cast::() as *const dyn FfiConvert) } else { - ctype_helper::get_size(userdata) + ctype_helper::get_conv(userdata) } } +pub unsafe fn get_conv_list(table: &LuaTable) -> LuaResult> { + create_list(table, |userdata| get_conv(userdata)) +} // Get libffi_type from ctype userdata pub fn get_middle_type(userdata: &LuaAnyUserData) -> LuaResult { @@ -276,12 +256,28 @@ pub fn get_middle_type(userdata: &LuaAnyUserData) -> LuaResult { ))) } } - -// get Vec from table(array) of c-type userdata pub fn get_middle_type_list(table: &LuaTable) -> LuaResult> { create_list(table, get_middle_type) } +// Get type size from ctype userdata +pub fn get_size(userdata: &LuaAnyUserData) -> LuaResult { + if userdata.is::() { + Ok(userdata.borrow::()?.get_size()) + } else if userdata.is::() { + Ok(userdata.borrow::()?.get_size()) + } else if userdata.is::() { + Ok(userdata.borrow::()?.get_size()) + } else if userdata.is::() { + Ok(userdata.borrow::()?.get_size()) + } else if userdata.is::() { + Ok(userdata.borrow::()?.get_size()) + } else { + ctype_helper::get_size(userdata) + } +} + +// Check lua table has void ctype userdata pub fn has_void(table: &LuaTable) -> LuaResult { 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 { Ok(false) } -// stringify any c-type userdata (for recursive) +// Stringify any c-type userdata recursively pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { if userdata.is::() { CStructInfo::stringify(lua, userdata) @@ -311,7 +307,7 @@ pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { } } -// get name tag for any c-type userdata +// Get name tag from ctype userdata pub fn get_tag_name(userdata: &LuaAnyUserData) -> LuaResult { Ok(if userdata.is::() { String::from("CStructInfo") @@ -330,7 +326,8 @@ pub fn get_tag_name(userdata: &LuaAnyUserData) -> LuaResult { }) } -// 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 { if ctype_helper::is_ctype(userdata) { stringify(lua, userdata) diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index 911cdb6f..5f9293a2 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -36,6 +36,7 @@ mod association_names { pub const CLOSURE_CFN: &str = "__closure_cfn"; } +// Export c namespace pub fn export_c(lua: &Lua) -> LuaResult { TableBuilder::new(lua)? .with_value("void", CVoidInfo::new())? diff --git a/crates/lune-std-ffi/src/c/ptr_info.rs b/crates/lune-std-ffi/src/c/ptr_info.rs index 0758ba82..12ad7b37 100644 --- a/crates/lune-std-ffi/src/c/ptr_info.rs +++ b/crates/lune-std-ffi/src/c/ptr_info.rs @@ -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, 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")) }); } diff --git a/crates/lune-std-ffi/src/c/string_info.rs b/crates/lune-std-ffi/src/c/string_info.rs index 2a4da645..7fe35684 100644 --- a/crates/lune-std-ffi/src/c/string_info.rs +++ b/crates/lune-std-ffi/src/c/string_info.rs @@ -1,3 +1,5 @@ +// TODO: + use mlua::prelude::*; pub struct CStringInfo(); diff --git a/crates/lune-std-ffi/src/c/struct_info.rs b/crates/lune-std-ffi/src/c/struct_info.rs index 9f5b1c98..55b8a429 100644 --- a/crates/lune-std-ffi/src/c/struct_info.rs +++ b/crates/lune-std-ffi/src/c/struct_info.rs @@ -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: - // + // Stringify cstruct for pretty printing + // ex: pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { 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::()?.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 { - 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)| { diff --git a/crates/lune-std-ffi/src/c/type_info.rs b/crates/lune-std-ffi/src/c/type_info.rs index 96c989c6..fa606fd5 100644 --- a/crates/lune-std-ffi/src/c/type_info.rs +++ b/crates/lune-std-ffi/src/c/type_info.rs @@ -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, diff --git a/crates/lune-std-ffi/src/c/types/f32.rs b/crates/lune-std-ffi/src/c/types/f32.rs index 6352e5b2..b13fb4af 100644 --- a/crates/lune-std-ffi/src/c/types/f32.rs +++ b/crates/lune-std-ffi/src/c/types/f32.rs @@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo { .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 { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/f64.rs b/crates/lune-std-ffi/src/c/types/f64.rs index 8657052a..1747e39e 100644 --- a/crates/lune-std-ffi/src/c/types/f64.rs +++ b/crates/lune-std-ffi/src/c/types/f64.rs @@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo { .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 { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/i128.rs b/crates/lune-std-ffi/src/c/types/i128.rs index 17eb8884..e60b1305 100644 --- a/crates/lune-std-ffi/src/c/types/i128.rs +++ b/crates/lune-std-ffi/src/c/types/i128.rs @@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo { .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 { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/i16.rs b/crates/lune-std-ffi/src/c/types/i16.rs index 39035b52..e82920fa 100644 --- a/crates/lune-std-ffi/src/c/types/i16.rs +++ b/crates/lune-std-ffi/src/c/types/i16.rs @@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo { .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 { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/i32.rs b/crates/lune-std-ffi/src/c/types/i32.rs index 4dae14ac..b25515a9 100644 --- a/crates/lune-std-ffi/src/c/types/i32.rs +++ b/crates/lune-std-ffi/src/c/types/i32.rs @@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo { .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 { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/i64.rs b/crates/lune-std-ffi/src/c/types/i64.rs index 3e353101..db4e5673 100644 --- a/crates/lune-std-ffi/src/c/types/i64.rs +++ b/crates/lune-std-ffi/src/c/types/i64.rs @@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo { .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 { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/i8.rs b/crates/lune-std-ffi/src/c/types/i8.rs index ea778e2c..4384f747 100644 --- a/crates/lune-std-ffi/src/c/types/i8.rs +++ b/crates/lune-std-ffi/src/c/types/i8.rs @@ -27,7 +27,7 @@ impl FfiConvert for CTypeInfo { 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 { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/isize.rs b/crates/lune-std-ffi/src/c/types/isize.rs index 9c363eaa..bee4db62 100644 --- a/crates/lune-std-ffi/src/c/types/isize.rs +++ b/crates/lune-std-ffi/src/c/types/isize.rs @@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo { .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 { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/mod.rs b/crates/lune-std-ffi/src/c/types/mod.rs index 2de89bb9..cfbd6175 100644 --- a/crates/lune-std-ffi/src/c/types/mod.rs +++ b/crates/lune-std-ffi/src/c/types/mod.rs @@ -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::>() { @@ -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::>() { @@ -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::>() { diff --git a/crates/lune-std-ffi/src/c/types/u128.rs b/crates/lune-std-ffi/src/c/types/u128.rs index 78851f0a..3bb8443b 100644 --- a/crates/lune-std-ffi/src/c/types/u128.rs +++ b/crates/lune-std-ffi/src/c/types/u128.rs @@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo { .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 { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/u16.rs b/crates/lune-std-ffi/src/c/types/u16.rs index 2a9dc044..ec1d0721 100644 --- a/crates/lune-std-ffi/src/c/types/u16.rs +++ b/crates/lune-std-ffi/src/c/types/u16.rs @@ -32,7 +32,7 @@ impl FfiConvert for CTypeInfo { .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 { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/u32.rs b/crates/lune-std-ffi/src/c/types/u32.rs index 04e95483..25942e0b 100644 --- a/crates/lune-std-ffi/src/c/types/u32.rs +++ b/crates/lune-std-ffi/src/c/types/u32.rs @@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo { .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 { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/u64.rs b/crates/lune-std-ffi/src/c/types/u64.rs index 07911b5f..33d9785d 100644 --- a/crates/lune-std-ffi/src/c/types/u64.rs +++ b/crates/lune-std-ffi/src/c/types/u64.rs @@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo { .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 { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/u8.rs b/crates/lune-std-ffi/src/c/types/u8.rs index a9d575b3..8764bfc3 100644 --- a/crates/lune-std-ffi/src/c/types/u8.rs +++ b/crates/lune-std-ffi/src/c/types/u8.rs @@ -28,7 +28,7 @@ impl FfiConvert for CTypeInfo { 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 { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/usize.rs b/crates/lune-std-ffi/src/c/types/usize.rs index ab97d232..a7902ed1 100644 --- a/crates/lune-std-ffi/src/c/types/usize.rs +++ b/crates/lune-std-ffi/src/c/types/usize.rs @@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo { .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 { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/void_info.rs b/crates/lune-std-ffi/src/c/void_info.rs index 97a2fa28..3c0ed880 100644 --- a/crates/lune-std-ffi/src/c/void_info.rs +++ b/crates/lune-std-ffi/src/c/void_info.rs @@ -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); diff --git a/crates/lune-std-ffi/src/data/box_data/mod.rs b/crates/lune-std-ffi/src/data/box_data/mod.rs index 9585a57d..dd6cc958 100644 --- a/crates/lune-std-ffi/src/data/box_data/mod.rs +++ b/crates/lune-std-ffi/src/data/box_data/mod.rs @@ -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>, } -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::()?.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()) + }); } } diff --git a/crates/lune-std-ffi/src/data/callable_data.rs b/crates/lune-std-ffi/src/data/callable_data.rs index fab6c7e8..2e95a27b 100644 --- a/crates/lune-std-ffi/src/data/callable_data.rs +++ b/crates/lune-std-ffi/src/data/callable_data.rs @@ -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::() { arg.write(arg_ref.get_inner_pointer().cast::()); } 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::() { arg_list.push(arg_ref.get_inner_pointer().cast::()); } else { - return Err(LuaError::external("Argument should be a RefData")); + return Err(LuaError::external("Argument must be a RefData")); } } diff --git a/crates/lune-std-ffi/src/data/closure_data.rs b/crates/lune-std-ffi/src/data/closure_data.rs index bd4256f2..bc6c0784 100644 --- a/crates/lune-std-ffi/src/data/closure_data.rs +++ b/crates/lune-std-ffi/src/data/closure_data.rs @@ -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, diff --git a/crates/lune-std-ffi/src/data/helper.rs b/crates/lune-std-ffi/src/data/helper.rs index a1aebd44..812e7f5a 100644 --- a/crates/lune-std-ffi/src/data/helper.rs +++ b/crates/lune-std-ffi/src/data/helper.rs @@ -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, diff --git a/crates/lune-std-ffi/src/data/lib_data.rs b/crates/lune-std-ffi/src/data/lib_data.rs index a7d38a45..9c92ce59 100644 --- a/crates/lune-std-ffi/src/data/lib_data.rs +++ b/crates/lune-std-ffi/src/data/lib_data.rs @@ -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 { 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) }); } } diff --git a/crates/lune-std-ffi/src/data/mod.rs b/crates/lune-std-ffi/src/data/mod.rs index 2c4a68f4..558873fd 100644 --- a/crates/lune-std-ffi/src/data/mod.rs +++ b/crates/lune-std-ffi/src/data/mod.rs @@ -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>; fn is_ffi_data(&self) -> bool; } - impl GetFfiData for LuaAnyUserData<'_> { fn get_ffi_data(&self) -> LuaResult> { if self.is::() { @@ -51,7 +51,6 @@ impl GetFfiData for LuaAnyUserData<'_> { self.is::() | self.is::() | self.is::() } } - impl GetFfiData for LuaValue<'_> { fn get_ffi_data(&self) -> LuaResult> { self.as_userdata() diff --git a/crates/lune-std-ffi/src/data/ref_data/bounds.rs b/crates/lune-std-ffi/src/data/ref_data/bounds.rs index 0a702e1f..be3e288e 100644 --- a/crates/lune-std-ffi/src/data/ref_data/bounds.rs +++ b/crates/lune-std-ffi/src/data/ref_data/bounds.rs @@ -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 { diff --git a/crates/lune-std-ffi/src/data/ref_data/mod.rs b/crates/lune-std-ffi/src/data/ref_data/mod.rs index d54ab4ba..86ad176c 100644 --- a/crates/lune-std-ffi/src/data/ref_data/mod.rs +++ b/crates/lune-std-ffi/src/data/ref_data/mod.rs @@ -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>, - 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 { + // 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::()) { - 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 { - u8_test(self.flags, RefFlag::Offsetable.value()) - .then_some(()) - .ok_or_else(|| 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 offsetable + if u8_test_not(self.flags, RefFlag::Offsetable.value()) { + return Err(LuaError::external("Reference is not offsetable")); + } - let boundary = self.boundary.offset(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 + ))); + } - // TODO + let boundary = self.boundary.offset(offset); 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::()?; - 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::()?.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()) + }); } } diff --git a/crates/lune-std-ffi/src/ffi/association.rs b/crates/lune-std-ffi/src/ffi/association.rs index 19382306..f9a68c83 100644 --- a/crates/lune-std-ffi/src/ffi/association.rs +++ b/crates/lune-std-ffi/src/ffi/association.rs @@ -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] diff --git a/crates/lune-std-ffi/src/ffi/cast.rs b/crates/lune-std-ffi/src/ffi/cast.rs index 1cd6c3f2..bbbe5804 100644 --- a/crates/lune-std-ffi/src/ffi/cast.rs +++ b/crates/lune-std-ffi/src/ffi/cast.rs @@ -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: &Ref, diff --git a/crates/lune-std-ffi/src/ffi/libffi_helper.rs b/crates/lune-std-ffi/src/ffi/libffi_helper.rs index c91d2d5f..df0e28fd 100644 --- a/crates/lune-std-ffi/src/ffi/libffi_helper.rs +++ b/crates/lune-std-ffi/src/ffi/libffi_helper.rs @@ -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 { 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 { 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(()) diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index 7e65f5e2..5131b968 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -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 } diff --git a/types/ffi.luau b/types/ffi.luau index c6e32ded..b6ec423e 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -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