mirror of
https://github.com/lune-org/lune.git
synced 2025-04-03 18:10:54 +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
|
## TODO
|
||||||
|
|
||||||
- Rewrite error messages
|
- Rewrite error messages
|
||||||
- Deref
|
|
||||||
- CString
|
- CString
|
||||||
- Add buffer for owned data support
|
- Add buffer for owned data support
|
||||||
- Add math operation.
|
- 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.
|
// This is a series of some type.
|
||||||
// It provides the final size and the offset of the index,
|
// It provides the final size and the offset of the index,
|
||||||
// but does not allow multidimensional arrays because of API complexity.
|
// 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)
|
// because they are a series of transcribed one-dimensional arrays. (flatten)
|
||||||
|
|
||||||
// We can simply provide array type with struct.
|
// We can simply provide array type with struct.
|
||||||
// See: https://stackoverflow.com/a/43525176
|
// See: https://stackoverflow.com/a/43525176
|
||||||
|
|
||||||
pub struct CArrInfo {
|
pub struct CArrInfo {
|
||||||
struct_type: Type,
|
struct_type: Type,
|
||||||
length: usize,
|
length: usize,
|
||||||
|
@ -33,7 +31,6 @@ impl CArrInfo {
|
||||||
let struct_type = Type::structure(vec![element_type.clone(); length]);
|
let struct_type = Type::structure(vec![element_type.clone(); length]);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
// element_type,
|
|
||||||
struct_type,
|
struct_type,
|
||||||
length,
|
length,
|
||||||
size: inner_size * length,
|
size: inner_size * length,
|
||||||
|
@ -63,8 +60,8 @@ impl CArrInfo {
|
||||||
self.struct_type.clone()
|
self.struct_type.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stringify for pretty printing like:
|
// Stringify for pretty-print
|
||||||
// <CArr( u8, length = 8 )>
|
// ex: <CArr( u8, length = 8 )>
|
||||||
pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult<String> {
|
pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult<String> {
|
||||||
let this = userdata.borrow::<CArrInfo>()?;
|
let this = userdata.borrow::<CArrInfo>()?;
|
||||||
if let Some(LuaValue::UserData(inner_userdata)) =
|
if let Some(LuaValue::UserData(inner_userdata)) =
|
||||||
|
@ -76,7 +73,7 @@ impl CArrInfo {
|
||||||
this.length,
|
this.length,
|
||||||
))
|
))
|
||||||
} else {
|
} 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 {
|
impl LuaUserData for CArrInfo {
|
||||||
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
|
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
|
||||||
fields.add_field_method_get("size", |_, this| Ok(this.get_size()));
|
fields.add_field_method_get("size", |_lua, this| Ok(this.get_size()));
|
||||||
fields.add_field_method_get("length", |_, this| Ok(this.get_length()));
|
fields.add_field_method_get("length", |_lua, this| Ok(this.get_length()));
|
||||||
fields.add_field_function_get("inner", |lua, this: LuaAnyUserData| {
|
fields.add_field_function_get("inner", |lua, this: LuaAnyUserData| {
|
||||||
let inner: LuaValue = association::get(lua, CARR_INNER, this)?
|
association::get(lua, CARR_INNER, this)?
|
||||||
// It shouldn't happen.
|
.ok_or_else(|| LuaError::external("Failed to retrieve inner field"))
|
||||||
.ok_or_else(|| LuaError::external("inner field not found"))?;
|
|
||||||
Ok(inner)
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,7 +168,7 @@ impl LuaUserData for CArrInfo {
|
||||||
method_provider::provide_write_data(methods);
|
method_provider::provide_write_data(methods);
|
||||||
method_provider::provide_copy_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 {
|
if this.length > (offset as usize) && offset >= 0 {
|
||||||
Ok(this.inner_size * (offset as usize))
|
Ok(this.inner_size * (offset as usize))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -67,7 +67,7 @@ fn create_arg_info(userdata: &LuaAnyUserData) -> LuaResult<FfiArg> {
|
||||||
} else if userdata.is::<CFnInfo>() {
|
} else if userdata.is::<CFnInfo>() {
|
||||||
CALLBACK_ARG_REF_FLAG_CFN
|
CALLBACK_ARG_REF_FLAG_CFN
|
||||||
} else {
|
} else {
|
||||||
return Err(LuaError::external("unexpected type userdata"));
|
return Err(LuaError::external("Unexpected argument type"));
|
||||||
};
|
};
|
||||||
Ok(FfiArg {
|
Ok(FfiArg {
|
||||||
size: helper::get_size(userdata)?,
|
size: helper::get_size(userdata)?,
|
||||||
|
@ -116,8 +116,8 @@ impl CFnInfo {
|
||||||
Ok(cfn)
|
Ok(cfn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stringify for pretty printing like:
|
// Stringify for pretty-print
|
||||||
// <CFn( (u8, i32) -> u8 )>
|
// ex: <CFn( (u8, i32) -> u8 )>
|
||||||
pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult<String> {
|
pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult<String> {
|
||||||
let mut result = String::from(" (");
|
let mut result = String::from(" (");
|
||||||
if let (Some(LuaValue::Table(arg_table)), Some(LuaValue::UserData(result_userdata))) = (
|
if let (Some(LuaValue::Table(arg_table)), Some(LuaValue::UserData(result_userdata))) = (
|
||||||
|
@ -142,7 +142,7 @@ impl CFnInfo {
|
||||||
);
|
);
|
||||||
Ok(result)
|
Ok(result)
|
||||||
} else {
|
} 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,
|
target_ref: &LuaAnyUserData,
|
||||||
) -> LuaResult<LuaAnyUserData<'lua>> {
|
) -> LuaResult<LuaAnyUserData<'lua>> {
|
||||||
if !target_ref.is::<RefData>() {
|
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>()?;
|
let ffi_ref = target_ref.borrow::<RefData>()?;
|
||||||
if u8_test_not(ffi_ref.flags, RefFlag::Function.value()) {
|
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 {
|
let callable = lua.create_userdata(unsafe {
|
||||||
|
@ -203,7 +205,7 @@ impl CFnInfo {
|
||||||
|
|
||||||
impl LuaUserData for CFnInfo {
|
impl LuaUserData for CFnInfo {
|
||||||
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
|
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
|
||||||
fields.add_field_method_get("size", |_, _| 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) {
|
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
// Subtype
|
// Subtype
|
||||||
|
|
|
@ -53,7 +53,7 @@ pub mod method_provider {
|
||||||
return Err(LuaError::external("Out of bounds"));
|
return Err(LuaError::external("Out of bounds"));
|
||||||
}
|
}
|
||||||
if !data_handle.is_readable() {
|
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) }
|
unsafe { this.value_from_data(lua, offset, data_handle) }
|
||||||
|
@ -77,7 +77,7 @@ pub mod method_provider {
|
||||||
return Err(LuaError::external("Out of bounds"));
|
return Err(LuaError::external("Out of bounds"));
|
||||||
}
|
}
|
||||||
if !data_handle.is_writable() {
|
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) }
|
unsafe { this.value_into_data(lua, offset, data_handle, value) }
|
||||||
|
@ -106,18 +106,18 @@ pub mod method_provider {
|
||||||
let dst = &dst.get_ffi_data()?;
|
let dst = &dst.get_ffi_data()?;
|
||||||
// use or functions
|
// use or functions
|
||||||
if !dst.check_inner_boundary(dst_offset, this.get_size()) {
|
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() {
|
if !dst.is_writable() {
|
||||||
return Err(LuaError::external("Unwritable data handle"));
|
return Err(LuaError::external("Destination is unwritable"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let src = &src.get_ffi_data()?;
|
let src = &src.get_ffi_data()?;
|
||||||
if !src.check_inner_boundary(dst_offset, this.get_size()) {
|
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() {
|
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) }
|
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
|
// Create vec<T> from table with (userdata)->T
|
||||||
pub fn create_list<T>(
|
pub fn create_list<T>(
|
||||||
table: &LuaTable,
|
table: &LuaTable,
|
||||||
|
@ -228,28 +212,24 @@ pub fn create_list<T>(
|
||||||
Ok(list)
|
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>> {
|
pub unsafe fn get_conv_list(table: &LuaTable) -> LuaResult<Vec<*const dyn FfiConvert>> {
|
||||||
create_list(table, |userdata| get_conv(userdata))
|
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
|
// Get libffi_type from ctype userdata
|
||||||
pub fn get_middle_type(userdata: &LuaAnyUserData) -> LuaResult<Type> {
|
pub fn get_middle_type(userdata: &LuaAnyUserData) -> LuaResult<Type> {
|
||||||
if userdata.is::<CStructInfo>() {
|
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>> {
|
pub fn get_middle_type_list(table: &LuaTable) -> LuaResult<Vec<Type>> {
|
||||||
create_list(table, get_middle_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> {
|
pub fn has_void(table: &LuaTable) -> LuaResult<bool> {
|
||||||
for i in 0..table.raw_len() {
|
for i in 0..table.raw_len() {
|
||||||
let value: LuaValue = table.raw_get(i + 1)?;
|
let value: LuaValue = table.raw_get(i + 1)?;
|
||||||
|
@ -292,7 +288,7 @@ pub fn has_void(table: &LuaTable) -> LuaResult<bool> {
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// stringify any c-type userdata (for recursive)
|
// Stringify any c-type userdata recursively
|
||||||
pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult<String> {
|
pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult<String> {
|
||||||
if userdata.is::<CStructInfo>() {
|
if userdata.is::<CStructInfo>() {
|
||||||
CStructInfo::stringify(lua, userdata)
|
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> {
|
pub fn get_tag_name(userdata: &LuaAnyUserData) -> LuaResult<String> {
|
||||||
Ok(if userdata.is::<CStructInfo>() {
|
Ok(if userdata.is::<CStructInfo>() {
|
||||||
String::from("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> {
|
pub fn pretty_format(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult<String> {
|
||||||
if ctype_helper::is_ctype(userdata) {
|
if ctype_helper::is_ctype(userdata) {
|
||||||
stringify(lua, userdata)
|
stringify(lua, userdata)
|
||||||
|
|
|
@ -36,6 +36,7 @@ mod association_names {
|
||||||
pub const CLOSURE_CFN: &str = "__closure_cfn";
|
pub const CLOSURE_CFN: &str = "__closure_cfn";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Export c namespace
|
||||||
pub fn export_c(lua: &Lua) -> LuaResult<LuaTable> {
|
pub fn export_c(lua: &Lua) -> LuaResult<LuaTable> {
|
||||||
TableBuilder::new(lua)?
|
TableBuilder::new(lua)?
|
||||||
.with_value("void", CVoidInfo::new())?
|
.with_value("void", CVoidInfo::new())?
|
||||||
|
|
|
@ -11,12 +11,9 @@ use crate::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const READ_CPTR_REF_FLAGS: u8 =
|
const READ_CPTR_REF_FLAGS: u8 = RefFlag::Dereferenceable.value() | RefFlag::Offsetable.value();
|
||||||
RefFlag::Dereferenceable.value() | RefFlag::Offsetable.value() | RefFlag::Leaked.value();
|
const READ_REF_FLAGS: u8 =
|
||||||
const READ_REF_FLAGS: u8 = RefFlag::Offsetable.value()
|
RefFlag::Offsetable.value() | RefFlag::Readable.value() | RefFlag::Writable.value();
|
||||||
| RefFlag::Leaked.value()
|
|
||||||
| RefFlag::Readable.value()
|
|
||||||
| RefFlag::Writable.value();
|
|
||||||
|
|
||||||
pub struct CPtrInfo {
|
pub struct CPtrInfo {
|
||||||
inner_size: usize,
|
inner_size: usize,
|
||||||
|
@ -42,9 +39,12 @@ impl FfiConvert for CPtrInfo {
|
||||||
data_handle: &Ref<dyn FfiData>,
|
data_handle: &Ref<dyn FfiData>,
|
||||||
value: LuaValue<'lua>,
|
value: LuaValue<'lua>,
|
||||||
) -> LuaResult<()> {
|
) -> LuaResult<()> {
|
||||||
let value_userdata = value
|
let value_userdata = value.as_userdata().ok_or_else(|| {
|
||||||
.as_userdata()
|
LuaError::external(format!(
|
||||||
.ok_or_else(|| LuaError::external("CPtrInfo:writeRef only allows data"))?;
|
"Value must be a RefData, BoxData or ClosureData, got {}",
|
||||||
|
value.type_name()
|
||||||
|
))
|
||||||
|
})?;
|
||||||
*data_handle
|
*data_handle
|
||||||
.get_inner_pointer()
|
.get_inner_pointer()
|
||||||
.byte_offset(offset)
|
.byte_offset(offset)
|
||||||
|
@ -112,7 +112,7 @@ impl CPtrInfo {
|
||||||
format!(" {pretty_formatted} ")
|
format!(" {pretty_formatted} ")
|
||||||
})
|
})
|
||||||
} else {
|
} 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 {
|
impl LuaUserData for CPtrInfo {
|
||||||
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
|
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
|
||||||
fields.add_field_method_get("size", |_, _| Ok(SIZE_OF_POINTER));
|
fields.add_field_method_get("size", |_lua, _this| Ok(SIZE_OF_POINTER));
|
||||||
fields.add_field_function_get("inner", |lua, this| {
|
fields.add_field_function_get("inner", |lua, this| {
|
||||||
let inner = association::get(lua, CPTR_INNER, this)?
|
association::get(lua, CPTR_INNER, this)?
|
||||||
.ok_or_else(|| LuaError::external("inner type not found"))?;
|
.ok_or_else(|| LuaError::external("Failed to retrieve inner type"))
|
||||||
Ok(inner)
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// TODO:
|
||||||
|
|
||||||
use mlua::prelude::*;
|
use mlua::prelude::*;
|
||||||
|
|
||||||
pub struct CStringInfo();
|
pub struct CStringInfo();
|
||||||
|
|
|
@ -46,9 +46,7 @@ impl CStructInfo {
|
||||||
inner_offset_list.set_len(len);
|
inner_offset_list.set_len(len);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get tailing padded size of struct
|
// Get tailing padded size of struct (get_ensured_size not required)
|
||||||
// See http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html
|
|
||||||
// In here, using get_ensured_size is not required
|
|
||||||
let size = unsafe { (*middle_type.as_raw_ptr()).size };
|
let size = unsafe { (*middle_type.as_raw_ptr()).size };
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
@ -59,8 +57,8 @@ impl CStructInfo {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new CStruct UserData from LuaTable.
|
// Create new CStruct from LuaTable.
|
||||||
// Lock and hold table for .inner ref
|
// Freeze and hold table
|
||||||
pub fn from_table<'lua>(
|
pub fn from_table<'lua>(
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
table: LuaTable<'lua>,
|
table: LuaTable<'lua>,
|
||||||
|
@ -73,25 +71,27 @@ impl CStructInfo {
|
||||||
.create_userdata(Self::new(helper::get_middle_type_list(&table)?, unsafe {
|
.create_userdata(Self::new(helper::get_middle_type_list(&table)?, unsafe {
|
||||||
helper::get_conv_list(&table)?
|
helper::get_conv_list(&table)?
|
||||||
})?)?;
|
})?)?;
|
||||||
|
|
||||||
|
// Save field table
|
||||||
table.set_readonly(true);
|
table.set_readonly(true);
|
||||||
association::set(lua, CSTRUCT_INNER, &cstruct, table)?;
|
association::set(lua, CSTRUCT_INNER, &cstruct, table)?;
|
||||||
Ok(cstruct)
|
Ok(cstruct)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stringify cstruct for pretty printing like:
|
// Stringify cstruct for pretty printing
|
||||||
// <CStruct( u8, i32, size = 8 )>
|
// ex: <CStruct( u8, i32, size = 8 )>
|
||||||
pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult<String> {
|
pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult<String> {
|
||||||
let fields = get_field_table(lua, userdata)?;
|
let fields = get_field_table(lua, userdata)?;
|
||||||
let mut stringified = String::from(" ");
|
let mut stringified = String::from(" ");
|
||||||
|
|
||||||
// children
|
// Children
|
||||||
for i in 0..fields.raw_len() {
|
for i in 0..fields.raw_len() {
|
||||||
let child: LuaAnyUserData = fields.raw_get(i + 1)?;
|
let child: LuaAnyUserData = fields.raw_get(i + 1)?;
|
||||||
let pretty_formatted = helper::pretty_format(lua, &child)?;
|
let pretty_formatted = helper::pretty_format(lua, &child)?;
|
||||||
stringified.push_str(format!("{pretty_formatted}, ").as_str());
|
stringified.push_str(format!("{pretty_formatted}, ").as_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// size of
|
// Size
|
||||||
stringified
|
stringified
|
||||||
.push_str(format!("size = {} ", userdata.borrow::<CStructInfo>()?.get_size()).as_str());
|
.push_str(format!("size = {} ", userdata.borrow::<CStructInfo>()?.get_size()).as_str());
|
||||||
Ok(stringified)
|
Ok(stringified)
|
||||||
|
@ -99,12 +99,11 @@ impl CStructInfo {
|
||||||
|
|
||||||
// Get byte offset of nth field
|
// Get byte offset of nth field
|
||||||
pub fn offset(&self, index: usize) -> LuaResult<usize> {
|
pub fn offset(&self, index: usize) -> LuaResult<usize> {
|
||||||
let offset = self
|
Ok(self
|
||||||
.inner_offset_list
|
.inner_offset_list
|
||||||
.get(index)
|
.get(index)
|
||||||
.ok_or_else(|| LuaError::external("Out of index"))?
|
.ok_or_else(|| LuaError::external("Out of index"))?
|
||||||
.to_owned();
|
.to_owned())
|
||||||
Ok(offset)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_middle_type(&self) -> Type {
|
pub fn get_middle_type(&self) -> Type {
|
||||||
|
@ -182,7 +181,7 @@ impl FfiConvert for CStructInfo {
|
||||||
|
|
||||||
impl LuaUserData for CStructInfo {
|
impl LuaUserData for CStructInfo {
|
||||||
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
|
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
|
||||||
fields.add_field_method_get("size", |_, this| Ok(this.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) {
|
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
// Subtype
|
// Subtype
|
||||||
|
@ -198,8 +197,9 @@ impl LuaUserData for CStructInfo {
|
||||||
method_provider::provide_write_data(methods);
|
method_provider::provide_write_data(methods);
|
||||||
method_provider::provide_copy_data(methods);
|
method_provider::provide_copy_data(methods);
|
||||||
|
|
||||||
methods.add_method("offset", |_, this, index: usize| this.offset(index));
|
// Get nth field offset
|
||||||
// Get nth field type userdata
|
methods.add_method("offset", |_lua, this, index: usize| this.offset(index));
|
||||||
|
// Get nth field type
|
||||||
methods.add_function(
|
methods.add_function(
|
||||||
"field",
|
"field",
|
||||||
|lua, (this, field_index): (LuaAnyUserData, usize)| {
|
|lua, (this, field_index): (LuaAnyUserData, usize)| {
|
||||||
|
|
|
@ -24,7 +24,7 @@ pub trait CTypeCast {
|
||||||
_from_offset: isize,
|
_from_offset: isize,
|
||||||
_into_offset: isize,
|
_into_offset: isize,
|
||||||
) -> LuaResult<()> {
|
) -> LuaResult<()> {
|
||||||
// Show error if have no cast implement
|
// Error if have no cast implement
|
||||||
Err(Self::cast_failed_with(self, from_ctype, into_ctype))
|
Err(Self::cast_failed_with(self, from_ctype, into_ctype))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ pub trait CTypeCast {
|
||||||
) -> LuaError {
|
) -> LuaError {
|
||||||
let config = ValueFormatConfig::new();
|
let config = ValueFormatConfig::new();
|
||||||
LuaError::external(format!(
|
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(from_ctype.to_owned()), &config),
|
||||||
pretty_format_value(&LuaValue::UserData(into_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) {
|
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
|
||||||
fields.add_meta_field(LuaMetaMethod::Type, "CTypeInfo");
|
fields.add_meta_field(LuaMetaMethod::Type, "CTypeInfo");
|
||||||
fields.add_field_method_get("size", |_, this| Ok(this.get_size()));
|
fields.add_field_method_get("size", |_lua, this| Ok(this.get_size()));
|
||||||
fields.add_field_method_get("signedness", |_, this| Ok(this.get_signedness()));
|
fields.add_field_method_get("signedness", |_lua, this| Ok(this.get_signedness()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
|
@ -115,7 +115,7 @@ where
|
||||||
|
|
||||||
methods.add_function(
|
methods.add_function(
|
||||||
"cast",
|
"cast",
|
||||||
|_,
|
|_lua,
|
||||||
(from_type, into_type, from, into, from_offset, into_offset): (
|
(from_type, into_type, from, into, from_offset, into_offset): (
|
||||||
LuaAnyUserData,
|
LuaAnyUserData,
|
||||||
LuaAnyUserData,
|
LuaAnyUserData,
|
||||||
|
|
|
@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo<f32> {
|
||||||
.map_err(LuaError::external)?,
|
.map_err(LuaError::external)?,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(LuaError::external(format!(
|
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()
|
value.type_name()
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo<f32> {
|
||||||
unsafe fn value_from_data<'lua>(
|
unsafe fn value_from_data<'lua>(
|
||||||
&self,
|
&self,
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
|
||||||
offset: isize,
|
offset: isize,
|
||||||
data_handle: &Ref<dyn FfiData>,
|
data_handle: &Ref<dyn FfiData>,
|
||||||
) -> LuaResult<LuaValue<'lua>> {
|
) -> LuaResult<LuaValue<'lua>> {
|
||||||
|
|
|
@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo<f64> {
|
||||||
.map_err(LuaError::external)?,
|
.map_err(LuaError::external)?,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(LuaError::external(format!(
|
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()
|
value.type_name()
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo<f64> {
|
||||||
unsafe fn value_from_data<'lua>(
|
unsafe fn value_from_data<'lua>(
|
||||||
&self,
|
&self,
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
|
||||||
offset: isize,
|
offset: isize,
|
||||||
data_handle: &Ref<dyn FfiData>,
|
data_handle: &Ref<dyn FfiData>,
|
||||||
) -> LuaResult<LuaValue<'lua>> {
|
) -> LuaResult<LuaValue<'lua>> {
|
||||||
|
|
|
@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo<i128> {
|
||||||
.map_err(LuaError::external)?,
|
.map_err(LuaError::external)?,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(LuaError::external(format!(
|
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()
|
value.type_name()
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo<i128> {
|
||||||
unsafe fn value_from_data<'lua>(
|
unsafe fn value_from_data<'lua>(
|
||||||
&self,
|
&self,
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
|
||||||
offset: isize,
|
offset: isize,
|
||||||
data_handle: &Ref<dyn FfiData>,
|
data_handle: &Ref<dyn FfiData>,
|
||||||
) -> LuaResult<LuaValue<'lua>> {
|
) -> LuaResult<LuaValue<'lua>> {
|
||||||
|
|
|
@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo<i16> {
|
||||||
.map_err(LuaError::external)?,
|
.map_err(LuaError::external)?,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(LuaError::external(format!(
|
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()
|
value.type_name()
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo<i16> {
|
||||||
unsafe fn value_from_data<'lua>(
|
unsafe fn value_from_data<'lua>(
|
||||||
&self,
|
&self,
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
|
||||||
offset: isize,
|
offset: isize,
|
||||||
data_handle: &Ref<dyn FfiData>,
|
data_handle: &Ref<dyn FfiData>,
|
||||||
) -> LuaResult<LuaValue<'lua>> {
|
) -> LuaResult<LuaValue<'lua>> {
|
||||||
|
|
|
@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo<i32> {
|
||||||
.map_err(LuaError::external)?,
|
.map_err(LuaError::external)?,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(LuaError::external(format!(
|
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()
|
value.type_name()
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo<i32> {
|
||||||
unsafe fn value_from_data<'lua>(
|
unsafe fn value_from_data<'lua>(
|
||||||
&self,
|
&self,
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
|
||||||
offset: isize,
|
offset: isize,
|
||||||
data_handle: &Ref<dyn FfiData>,
|
data_handle: &Ref<dyn FfiData>,
|
||||||
) -> LuaResult<LuaValue<'lua>> {
|
) -> LuaResult<LuaValue<'lua>> {
|
||||||
|
|
|
@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo<i64> {
|
||||||
.map_err(LuaError::external)?,
|
.map_err(LuaError::external)?,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(LuaError::external(format!(
|
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()
|
value.type_name()
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo<i64> {
|
||||||
unsafe fn value_from_data<'lua>(
|
unsafe fn value_from_data<'lua>(
|
||||||
&self,
|
&self,
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
|
||||||
offset: isize,
|
offset: isize,
|
||||||
data_handle: &Ref<dyn FfiData>,
|
data_handle: &Ref<dyn FfiData>,
|
||||||
) -> LuaResult<LuaValue<'lua>> {
|
) -> 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_(),
|
LuaValue::String(t) => t.as_bytes().first().map_or(0, u8::to_owned).as_(),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(LuaError::external(format!(
|
return Err(LuaError::external(format!(
|
||||||
"Argument LuaValue expected a Integer or String, got {}",
|
"Value must be a Integer or String, got {}",
|
||||||
value.type_name()
|
value.type_name()
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,6 @@ impl FfiConvert for CTypeInfo<i8> {
|
||||||
unsafe fn value_from_data<'lua>(
|
unsafe fn value_from_data<'lua>(
|
||||||
&self,
|
&self,
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
|
||||||
offset: isize,
|
offset: isize,
|
||||||
data_handle: &Ref<dyn FfiData>,
|
data_handle: &Ref<dyn FfiData>,
|
||||||
) -> LuaResult<LuaValue<'lua>> {
|
) -> LuaResult<LuaValue<'lua>> {
|
||||||
|
|
|
@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo<isize> {
|
||||||
.map_err(LuaError::external)?,
|
.map_err(LuaError::external)?,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(LuaError::external(format!(
|
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()
|
value.type_name()
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo<isize> {
|
||||||
unsafe fn value_from_data<'lua>(
|
unsafe fn value_from_data<'lua>(
|
||||||
&self,
|
&self,
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
|
||||||
offset: isize,
|
offset: isize,
|
||||||
data_handle: &Ref<dyn FfiData>,
|
data_handle: &Ref<dyn FfiData>,
|
||||||
) -> LuaResult<LuaValue<'lua>> {
|
) -> LuaResult<LuaValue<'lua>> {
|
||||||
|
|
|
@ -126,7 +126,7 @@ where
|
||||||
pub mod ctype_helper {
|
pub mod ctype_helper {
|
||||||
use super::*;
|
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 {
|
macro_rules! define_get_conv {
|
||||||
($userdata:ident, $( $rust_type:ty )*) => {
|
($userdata:ident, $( $rust_type:ty )*) => {
|
||||||
$( if $userdata.is::<CTypeInfo<$rust_type>>() {
|
$( 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)
|
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 {
|
macro_rules! define_get_size {
|
||||||
($userdata:ident, $( $rust_type:ty )*) => {
|
($userdata:ident, $( $rust_type:ty )*) => {
|
||||||
$( if $userdata.is::<CTypeInfo<$rust_type>>() {
|
$( 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)
|
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 {
|
macro_rules! define_is_ctype {
|
||||||
($userdata:ident, $( $rust_type:ty )*) => {
|
($userdata:ident, $( $rust_type:ty )*) => {
|
||||||
$( if $userdata.is::<CTypeInfo<$rust_type>>() {
|
$( if $userdata.is::<CTypeInfo<$rust_type>>() {
|
||||||
|
|
|
@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo<u128> {
|
||||||
.map_err(LuaError::external)?,
|
.map_err(LuaError::external)?,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(LuaError::external(format!(
|
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()
|
value.type_name()
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo<u128> {
|
||||||
unsafe fn value_from_data<'lua>(
|
unsafe fn value_from_data<'lua>(
|
||||||
&self,
|
&self,
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
|
||||||
offset: isize,
|
offset: isize,
|
||||||
data_handle: &Ref<dyn FfiData>,
|
data_handle: &Ref<dyn FfiData>,
|
||||||
) -> LuaResult<LuaValue<'lua>> {
|
) -> LuaResult<LuaValue<'lua>> {
|
||||||
|
|
|
@ -32,7 +32,7 @@ impl FfiConvert for CTypeInfo<u16> {
|
||||||
.map_err(LuaError::external)?,
|
.map_err(LuaError::external)?,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(LuaError::external(format!(
|
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()
|
value.type_name()
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,6 @@ impl FfiConvert for CTypeInfo<u16> {
|
||||||
unsafe fn value_from_data<'lua>(
|
unsafe fn value_from_data<'lua>(
|
||||||
&self,
|
&self,
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
|
||||||
offset: isize,
|
offset: isize,
|
||||||
data_handle: &Ref<dyn FfiData>,
|
data_handle: &Ref<dyn FfiData>,
|
||||||
) -> LuaResult<LuaValue<'lua>> {
|
) -> LuaResult<LuaValue<'lua>> {
|
||||||
|
|
|
@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo<u32> {
|
||||||
.map_err(LuaError::external)?,
|
.map_err(LuaError::external)?,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(LuaError::external(format!(
|
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()
|
value.type_name()
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo<u32> {
|
||||||
unsafe fn value_from_data<'lua>(
|
unsafe fn value_from_data<'lua>(
|
||||||
&self,
|
&self,
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
|
||||||
offset: isize,
|
offset: isize,
|
||||||
data_handle: &Ref<dyn FfiData>,
|
data_handle: &Ref<dyn FfiData>,
|
||||||
) -> LuaResult<LuaValue<'lua>> {
|
) -> LuaResult<LuaValue<'lua>> {
|
||||||
|
|
|
@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo<u64> {
|
||||||
.map_err(LuaError::external)?,
|
.map_err(LuaError::external)?,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(LuaError::external(format!(
|
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()
|
value.type_name()
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo<u64> {
|
||||||
unsafe fn value_from_data<'lua>(
|
unsafe fn value_from_data<'lua>(
|
||||||
&self,
|
&self,
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
|
||||||
offset: isize,
|
offset: isize,
|
||||||
data_handle: &Ref<dyn FfiData>,
|
data_handle: &Ref<dyn FfiData>,
|
||||||
) -> LuaResult<LuaValue<'lua>> {
|
) -> 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_(),
|
LuaValue::String(t) => t.as_bytes().first().map_or(0, u8::to_owned).as_(),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(LuaError::external(format!(
|
return Err(LuaError::external(format!(
|
||||||
"Argument LuaValue expected a Integer or String, got {}",
|
"Value must be a Integer or String, got {}",
|
||||||
value.type_name()
|
value.type_name()
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,6 @@ impl FfiConvert for CTypeInfo<u8> {
|
||||||
unsafe fn value_from_data<'lua>(
|
unsafe fn value_from_data<'lua>(
|
||||||
&self,
|
&self,
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
|
||||||
offset: isize,
|
offset: isize,
|
||||||
data_handle: &Ref<dyn FfiData>,
|
data_handle: &Ref<dyn FfiData>,
|
||||||
) -> LuaResult<LuaValue<'lua>> {
|
) -> LuaResult<LuaValue<'lua>> {
|
||||||
|
|
|
@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo<usize> {
|
||||||
.map_err(LuaError::external)?,
|
.map_err(LuaError::external)?,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(LuaError::external(format!(
|
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()
|
value.type_name()
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo<usize> {
|
||||||
unsafe fn value_from_data<'lua>(
|
unsafe fn value_from_data<'lua>(
|
||||||
&self,
|
&self,
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
// _type_userdata: &LuaAnyUserData<'lua>,
|
|
||||||
offset: isize,
|
offset: isize,
|
||||||
data_handle: &Ref<dyn FfiData>,
|
data_handle: &Ref<dyn FfiData>,
|
||||||
) -> LuaResult<LuaValue<'lua>> {
|
) -> LuaResult<LuaValue<'lua>> {
|
||||||
|
|
|
@ -32,7 +32,7 @@ impl CVoidInfo {
|
||||||
|
|
||||||
impl LuaUserData for CVoidInfo {
|
impl LuaUserData for CVoidInfo {
|
||||||
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
|
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
|
||||||
fields.add_field_method_get("size", |_, _| Ok(0));
|
fields.add_field_method_get("size", |_lua, _this| Ok(0));
|
||||||
}
|
}
|
||||||
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
method_provider::provide_to_string(methods);
|
method_provider::provide_to_string(methods);
|
||||||
|
|
|
@ -17,28 +17,20 @@ mod flag;
|
||||||
|
|
||||||
pub use self::flag::BoxFlag;
|
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 =
|
const BOX_REF_FLAGS: u8 =
|
||||||
RefFlag::Readable.value() | RefFlag::Writable.value() | RefFlag::Offsetable.value();
|
RefFlag::Readable.value() | RefFlag::Writable.value() | RefFlag::Offsetable.value();
|
||||||
|
|
||||||
// It is an untyped, sized memory area that Lua can manage.
|
// Untyped runtime sized memory for luau.
|
||||||
// This area is safe within Lua. Operations have their boundaries checked.
|
// This operations are safe, have boundaries check.
|
||||||
// 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.
|
|
||||||
|
|
||||||
pub struct BoxData {
|
pub struct BoxData {
|
||||||
flags: u8,
|
flags: u8,
|
||||||
data: ManuallyDrop<Box<[u8]>>,
|
data: ManuallyDrop<Box<[u8]>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const FFI_BOX_PRINT_MAX_LENGTH: usize = 1024;
|
|
||||||
|
|
||||||
impl BoxData {
|
impl BoxData {
|
||||||
// For efficiency, it is initialized non-zeroed.
|
|
||||||
pub fn new(size: usize) -> Self {
|
pub fn new(size: usize) -> Self {
|
||||||
let slice = unsafe {
|
let slice = unsafe {
|
||||||
Box::from_raw(ptr::slice_from_raw_parts_mut(
|
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 {
|
pub fn stringify(&self) -> String {
|
||||||
if self.size() > FFI_BOX_PRINT_MAX_LENGTH * 2 {
|
if self.size() > FFI_BOX_PRINT_MAX_LENGTH * 2 {
|
||||||
// FIXME
|
return String::from("length limit exceed");
|
||||||
// Todo: if too big, print as another format
|
|
||||||
return String::from("exceed");
|
|
||||||
}
|
}
|
||||||
let mut buff: String = String::with_capacity(self.size() * 2);
|
let mut buff: String = String::with_capacity(self.size() * 2);
|
||||||
for value in self.data.iter() {
|
for value in self.data.iter() {
|
||||||
|
@ -72,7 +61,7 @@ impl BoxData {
|
||||||
self.flags = u8_set(self.flags, BoxFlag::Leaked.value(), true);
|
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>(
|
pub fn luaref<'lua>(
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
this: LuaAnyUserData<'lua>,
|
this: LuaAnyUserData<'lua>,
|
||||||
|
@ -97,17 +86,13 @@ impl BoxData {
|
||||||
|
|
||||||
let luaref = lua.create_userdata(RefData::new(ptr.cast(), BOX_REF_FLAGS, bounds))?;
|
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)?;
|
association::set(lua, REF_INNER, &luaref, &this)?;
|
||||||
|
|
||||||
Ok(luaref)
|
Ok(luaref)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn drop(&mut self) {
|
// Fill with zero
|
||||||
ManuallyDrop::drop(&mut self.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill every field with 0
|
|
||||||
pub fn zero(&mut self) {
|
pub fn zero(&mut self) {
|
||||||
self.data.fill(0);
|
self.data.fill(0);
|
||||||
}
|
}
|
||||||
|
@ -122,7 +107,7 @@ impl BoxData {
|
||||||
impl Drop for BoxData {
|
impl Drop for BoxData {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if u8_test_not(self.flags, BoxFlag::Leaked.value()) {
|
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 {
|
impl LuaUserData for BoxData {
|
||||||
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
|
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
|
||||||
fields.add_field_method_get("size", |_, this| Ok(this.size()));
|
fields.add_field_method_get("size", |_lua, this| Ok(this.size()));
|
||||||
}
|
}
|
||||||
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
method_provider::provide_copy_from(methods);
|
method_provider::provide_copy_from(methods);
|
||||||
// For convenience, :zero returns self.
|
// For convenience, :zero returns box itself.
|
||||||
methods.add_function_mut("zero", |_, this: LuaAnyUserData| {
|
methods.add_function_mut("zero", |_lua, this: LuaAnyUserData| {
|
||||||
this.borrow_mut::<BoxData>()?.zero();
|
this.borrow_mut::<BoxData>()?.zero();
|
||||||
Ok(this)
|
Ok(this)
|
||||||
});
|
});
|
||||||
|
@ -173,6 +158,8 @@ impl LuaUserData for BoxData {
|
||||||
BoxData::luaref(lua, this, offset)
|
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 VOID_RESULT_PTR: *mut () = ptr::null_mut();
|
||||||
const ZERO_SIZE_ARG_PTR: *mut *mut c_void = 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 {
|
macro_rules! create_caller {
|
||||||
($len:expr) => {
|
($len:expr) => {
|
||||||
|callable: &CallableData, result: LuaValue, args: LuaMultiValue| unsafe {
|
|callable: &CallableData, result: LuaValue, args: LuaMultiValue| unsafe {
|
||||||
|
@ -42,12 +43,12 @@ macro_rules! create_caller {
|
||||||
.get(index)
|
.get(index)
|
||||||
.ok_or_else(|| LuaError::external(format!("Argument {index} required")))?
|
.ok_or_else(|| LuaError::external(format!("Argument {index} required")))?
|
||||||
.as_userdata()
|
.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>() {
|
if let Ok(arg_ref) = arg_value.borrow::<RefData>() {
|
||||||
arg.write(arg_ref.get_inner_pointer().cast::<c_void>());
|
arg.write(arg_ref.get_inner_pointer().cast::<c_void>());
|
||||||
} else {
|
} 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
|
// Call without arguments
|
||||||
unsafe fn zero_size_caller(
|
unsafe fn zero_size_caller(
|
||||||
callable: &CallableData,
|
callable: &CallableData,
|
||||||
|
@ -88,6 +90,7 @@ unsafe fn zero_size_caller(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Optimization: sized callers
|
||||||
type Caller =
|
type Caller =
|
||||||
unsafe fn(callable: &CallableData, result: LuaValue, args: LuaMultiValue) -> LuaResult<()>;
|
unsafe fn(callable: &CallableData, result: LuaValue, args: LuaMultiValue) -> LuaResult<()>;
|
||||||
const SIZED_CALLERS: [Caller; 13] = [
|
const SIZED_CALLERS: [Caller; 13] = [
|
||||||
|
@ -123,6 +126,7 @@ impl CallableData {
|
||||||
|
|
||||||
pub unsafe fn call(&self, result: LuaValue, args: LuaMultiValue) -> LuaResult<()> {
|
pub unsafe fn call(&self, result: LuaValue, args: LuaMultiValue) -> LuaResult<()> {
|
||||||
let arg_len = self.arg_info_list.len();
|
let arg_len = self.arg_info_list.len();
|
||||||
|
// Optimization: use sized caller when possible
|
||||||
if arg_len < SIZED_CALLERS.len() {
|
if arg_len < SIZED_CALLERS.len() {
|
||||||
return SIZED_CALLERS[arg_len](self, result, args);
|
return SIZED_CALLERS[arg_len](self, result, args);
|
||||||
}
|
}
|
||||||
|
@ -142,12 +146,12 @@ impl CallableData {
|
||||||
.get(index)
|
.get(index)
|
||||||
.ok_or_else(|| LuaError::external(format!("Argument {index} required")))?
|
.ok_or_else(|| LuaError::external(format!("Argument {index} required")))?
|
||||||
.as_userdata()
|
.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>() {
|
if let Ok(arg_ref) = arg_value.borrow::<RefData>() {
|
||||||
arg_list.push(arg_ref.get_inner_pointer().cast::<c_void>());
|
arg_list.push(arg_ref.get_inner_pointer().cast::<c_void>());
|
||||||
} else {
|
} 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 =
|
const RESULT_REF_FLAGS: u8 = RefFlag::Writable.value() | RefFlag::Offsetable.value();
|
||||||
RefFlag::Leaked.value() | RefFlag::Writable.value() | RefFlag::Offsetable.value();
|
|
||||||
const CLOSURE_REF_FLAGS: u8 = RefFlag::Function.value();
|
const CLOSURE_REF_FLAGS: u8 = RefFlag::Function.value();
|
||||||
|
|
||||||
|
// Process C -> Lua function call
|
||||||
unsafe extern "C" fn callback(
|
unsafe extern "C" fn callback(
|
||||||
cif: *mut ffi_cif,
|
cif: *mut ffi_cif,
|
||||||
result_pointer: *mut c_void,
|
result_pointer: *mut c_void,
|
||||||
|
@ -84,6 +84,7 @@ unsafe extern "C" fn callback(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClosureData {
|
impl ClosureData {
|
||||||
|
// Allocate new ffi closure with lua function
|
||||||
pub fn alloc(
|
pub fn alloc(
|
||||||
lua: &Lua,
|
lua: &Lua,
|
||||||
cif: *mut ffi_cif,
|
cif: *mut ffi_cif,
|
||||||
|
|
|
@ -3,9 +3,9 @@ use mlua::prelude::*;
|
||||||
use super::{FfiData, GetFfiData};
|
use super::{FfiData, GetFfiData};
|
||||||
|
|
||||||
pub mod method_provider {
|
pub mod method_provider {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
// Implement copyFrom method
|
||||||
pub fn provide_copy_from<'lua, Target, M>(methods: &mut M)
|
pub fn provide_copy_from<'lua, Target, M>(methods: &mut M)
|
||||||
where
|
where
|
||||||
Target: FfiData,
|
Target: FfiData,
|
||||||
|
|
|
@ -12,17 +12,20 @@ const LIB_REF_FLAGS: u8 = RefFlag::Offsetable.value()
|
||||||
| RefFlag::Dereferenceable.value()
|
| RefFlag::Dereferenceable.value()
|
||||||
| RefFlag::Function.value();
|
| RefFlag::Function.value();
|
||||||
|
|
||||||
|
// Runtime dynamic loaded libraries
|
||||||
pub struct LibData(Library);
|
pub struct LibData(Library);
|
||||||
|
|
||||||
impl LibData {
|
impl LibData {
|
||||||
|
// Open library then return library handle
|
||||||
pub fn new(libname: String) -> LuaResult<Self> {
|
pub fn new(libname: String) -> LuaResult<Self> {
|
||||||
match Library::open(libname) {
|
match Library::open(libname) {
|
||||||
Ok(t) => Ok(Self(t)),
|
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,
|
lua: &'lua Lua,
|
||||||
this: LuaAnyUserData<'lua>,
|
this: LuaAnyUserData<'lua>,
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -31,12 +34,12 @@ impl LibData {
|
||||||
let sym = unsafe {
|
let sym = unsafe {
|
||||||
lib.0
|
lib.0
|
||||||
.symbol::<*const ()>(name.as_str())
|
.symbol::<*const ()>(name.as_str())
|
||||||
.map_err(|err| LuaError::external(format!("{err}")))?
|
.map_err(LuaError::external)?
|
||||||
};
|
};
|
||||||
|
|
||||||
let ffi_ref =
|
let ffi_ref =
|
||||||
lua.create_userdata(RefData::new(sym.cast_mut(), LIB_REF_FLAGS, UNSIZED_BOUNDS))?;
|
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)?;
|
association::set(lua, SYM_INNER, &ffi_ref, &this)?;
|
||||||
|
|
||||||
Ok(ffi_ref)
|
Ok(ffi_ref)
|
||||||
|
@ -46,7 +49,7 @@ impl LibData {
|
||||||
impl LuaUserData for LibData {
|
impl LuaUserData for LibData {
|
||||||
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
methods.add_function("find", |lua, (this, name): (LuaAnyUserData, String)| {
|
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";
|
pub const CLSOURE_REF_INNER: &str = "__closure_ref_inner";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get dynamic FfiData handle from LuaValue and LuaAnyUserData
|
||||||
pub trait GetFfiData {
|
pub trait GetFfiData {
|
||||||
fn get_ffi_data(&self) -> LuaResult<Ref<dyn FfiData>>;
|
fn get_ffi_data(&self) -> LuaResult<Ref<dyn FfiData>>;
|
||||||
fn is_ffi_data(&self) -> bool;
|
fn is_ffi_data(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GetFfiData for LuaAnyUserData<'_> {
|
impl GetFfiData for LuaAnyUserData<'_> {
|
||||||
fn get_ffi_data(&self) -> LuaResult<Ref<dyn FfiData>> {
|
fn get_ffi_data(&self) -> LuaResult<Ref<dyn FfiData>> {
|
||||||
if self.is::<BoxData>() {
|
if self.is::<BoxData>() {
|
||||||
|
@ -51,7 +51,6 @@ impl GetFfiData for LuaAnyUserData<'_> {
|
||||||
self.is::<BoxData>() | self.is::<RefData>() | self.is::<ClosureData>()
|
self.is::<BoxData>() | self.is::<RefData>() | self.is::<ClosureData>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GetFfiData for LuaValue<'_> {
|
impl GetFfiData for LuaValue<'_> {
|
||||||
fn get_ffi_data(&self) -> LuaResult<Ref<dyn FfiData>> {
|
fn get_ffi_data(&self) -> LuaResult<Ref<dyn FfiData>> {
|
||||||
self.as_userdata()
|
self.as_userdata()
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
// Memory range for ref or box data. For boundary checking
|
// Memory boundaries
|
||||||
pub struct RefBounds {
|
pub struct RefBounds {
|
||||||
// Indicates how much data is above the pointer
|
// How much data available above
|
||||||
pub(crate) above: usize,
|
pub(crate) above: usize,
|
||||||
// Indicates how much data is below the pointer
|
// How much data available below
|
||||||
pub(crate) below: usize,
|
pub(crate) below: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,8 +39,7 @@ impl RefBounds {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check boundary
|
// Check boundary with specific size
|
||||||
// Check required here
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn check_sized(&self, offset: isize, size: usize) -> bool {
|
pub fn check_sized(&self, offset: isize, size: usize) -> bool {
|
||||||
if self.is_unsized() {
|
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
|
// No boundary checking in here
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn offset(&self, offset: isize) -> Self {
|
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
|
// Box:ref():ref() should not be able to modify, Only for external
|
||||||
const BOX_REF_REF_FLAGS: u8 = 0;
|
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 {
|
pub struct RefData {
|
||||||
ptr: ManuallyDrop<Box<*mut ()>>,
|
ptr: ManuallyDrop<Box<*mut ()>>,
|
||||||
pub flags: u8,
|
pub(crate) flags: u8,
|
||||||
pub boundary: RefBounds,
|
boundary: RefBounds,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RefData {
|
impl RefData {
|
||||||
|
@ -45,7 +35,7 @@ impl RefData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make FfiRef from ref
|
// Create reference of this reference box
|
||||||
pub fn luaref<'lua>(
|
pub fn luaref<'lua>(
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
this: LuaAnyUserData<'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)?;
|
association::set(lua, REF_INNER, &luaref, &this)?;
|
||||||
|
|
||||||
Ok(luaref)
|
Ok(luaref)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dereference this reference
|
||||||
pub unsafe fn deref(&self) -> LuaResult<Self> {
|
pub unsafe fn deref(&self) -> LuaResult<Self> {
|
||||||
|
// Check dereferenceable
|
||||||
if !u8_test(self.flags, RefFlag::Dereferenceable.value()) {
|
if !u8_test(self.flags, RefFlag::Dereferenceable.value()) {
|
||||||
return Err(LuaError::external("Reference is not dereferenceable"));
|
return Err(LuaError::external("Reference is not dereferenceable"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check boundary
|
||||||
if !self.boundary.check_sized(0, size_of::<usize>()) {
|
if !self.boundary.check_sized(0, size_of::<usize>()) {
|
||||||
return Err(LuaError::external(
|
return Err(LuaError::external("Out of bounds"));
|
||||||
"Offset out of bounds",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME flags
|
|
||||||
Ok(Self::new(
|
Ok(Self::new(
|
||||||
*self.ptr.cast::<*mut ()>(),
|
*self.ptr.cast::<*mut ()>(),
|
||||||
self.flags,
|
u8_set(self.flags, RefFlag::Leaked.value(), false),
|
||||||
UNSIZED_BOUNDS,
|
UNSIZED_BOUNDS,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_nullptr(&self) -> bool {
|
pub fn is_null(&self) -> bool {
|
||||||
// * ManuallyDrop wrapper
|
// * ManuallyDrop wrapper
|
||||||
// * Box wrapper
|
// * Box wrapper
|
||||||
(**self.ptr) as usize == 0
|
(**self.ptr) as usize == 0
|
||||||
|
@ -96,31 +86,33 @@ impl RefData {
|
||||||
self.flags = u8_set(self.flags, RefFlag::Leaked.value(), true);
|
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> {
|
pub unsafe fn offset(&self, offset: isize) -> LuaResult<Self> {
|
||||||
u8_test(self.flags, RefFlag::Offsetable.value())
|
// Check offsetable
|
||||||
.then_some(())
|
if u8_test_not(self.flags, RefFlag::Offsetable.value()) {
|
||||||
.ok_or_else(|| LuaError::external("Reference is not offsetable"))?;
|
return Err(LuaError::external("Reference is not offsetable"));
|
||||||
|
}
|
||||||
|
|
||||||
// Check boundary, if exceed, return error
|
// Check boundary
|
||||||
self.boundary
|
if !self.boundary.check_boundary(offset) {
|
||||||
.check_boundary(offset)
|
return Err(LuaError::external(format!(
|
||||||
.then_some(())
|
"Offset out of bounds (high: {}, low: {}, got {})",
|
||||||
.ok_or_else(|| {
|
self.boundary.above, self.boundary.below, offset
|
||||||
LuaError::external(format!(
|
)));
|
||||||
"Offset out of bounds (high: {}, low: {}, got {})",
|
}
|
||||||
self.boundary.above, self.boundary.below, offset
|
|
||||||
))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let boundary = self.boundary.offset(offset);
|
let boundary = self.boundary.offset(offset);
|
||||||
|
|
||||||
// TODO
|
|
||||||
Ok(Self::new(
|
Ok(Self::new(
|
||||||
self.ptr.byte_offset(offset),
|
self.ptr.byte_offset(offset),
|
||||||
self.flags,
|
u8_set(self.flags, RefFlag::Leaked.value(), false),
|
||||||
boundary,
|
boundary,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stringify for pretty-print, with hex format address
|
||||||
|
pub fn stringify(&self) -> String {
|
||||||
|
format!("{:x}", **self.ptr as usize)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for RefData {
|
impl Drop for RefData {
|
||||||
|
@ -154,24 +146,12 @@ impl LuaUserData for RefData {
|
||||||
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
method_provider::provide_copy_from(methods);
|
method_provider::provide_copy_from(methods);
|
||||||
|
|
||||||
// FIXME:
|
methods.add_method("deref", |_lua, this, ()| unsafe { this.deref() });
|
||||||
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_function("offset", |lua, (this, offset): (LuaAnyUserData, isize)| {
|
methods.add_function("offset", |lua, (this, offset): (LuaAnyUserData, isize)| {
|
||||||
let ffiref = unsafe { this.borrow::<RefData>()?.offset(offset)? };
|
let ffiref = unsafe { this.borrow::<RefData>()?.offset(offset)? };
|
||||||
let userdata = lua.create_userdata(ffiref)?;
|
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)? {
|
if let Some(t) = association::get(lua, REF_INNER, &this)? {
|
||||||
association::set(lua, REF_INNER, &userdata, t)?;
|
association::set(lua, REF_INNER, &userdata, t)?;
|
||||||
}
|
}
|
||||||
|
@ -185,7 +165,10 @@ impl LuaUserData for RefData {
|
||||||
methods.add_function("ref", |lua, this: LuaAnyUserData| {
|
methods.add_function("ref", |lua, this: LuaAnyUserData| {
|
||||||
RefData::luaref(lua, this)
|
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.
|
// In FFI, there is often data that is dependent on other data.
|
||||||
// However, if you use user_value to inform Lua of the dependency,
|
// However, if you use user_value to inform Lua of the dependency,
|
||||||
// a table will be created for each userdata.
|
// 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.
|
// 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
|
// 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.
|
// 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
|
// You can delete the relationship by changing 'associated' to nil
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set<'lua, T, U>(lua: &'lua Lua, regname: &str, value: T, associated: U) -> LuaResult<()>
|
pub fn set<'lua, T, U>(lua: &'lua Lua, regname: &str, value: T, associated: U) -> LuaResult<()>
|
||||||
where
|
where
|
||||||
|
@ -52,7 +36,7 @@ where
|
||||||
Ok(())
|
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 table in registry, it returns None.
|
||||||
// If there is no value in table, it returns LuaNil.
|
// If there is no value in table, it returns LuaNil.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -5,6 +5,7 @@ use num::cast::AsPrimitive;
|
||||||
|
|
||||||
use super::FfiData;
|
use super::FfiData;
|
||||||
|
|
||||||
|
// Cast number type to another number type, with num::cast library
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn num_cast<From, Into>(
|
pub fn num_cast<From, Into>(
|
||||||
from: &Ref<dyn FfiData>,
|
from: &Ref<dyn FfiData>,
|
||||||
|
|
|
@ -3,8 +3,9 @@ use std::ptr::{self, null_mut};
|
||||||
use libffi::{low, raw};
|
use libffi::{low, raw};
|
||||||
use mlua::prelude::*;
|
use mlua::prelude::*;
|
||||||
|
|
||||||
// Get ensured size of c-type (raw::libffi_type)
|
pub const SIZE_OF_POINTER: usize = size_of::<*mut ()>();
|
||||||
// See: http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html
|
|
||||||
|
// Get ensured size of ctype (raw::libffi_type)
|
||||||
pub fn get_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult<usize> {
|
pub fn get_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult<usize> {
|
||||||
let mut cif = low::ffi_cif::default();
|
let mut cif = low::ffi_cif::default();
|
||||||
let result = unsafe {
|
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) }
|
unsafe { Ok((*ffi_type).size) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const SIZE_OF_POINTER: usize = size_of::<*mut ()>();
|
// Converts ffi status into &str for formatting
|
||||||
|
|
||||||
// Converts ffi status into &str
|
|
||||||
pub const FFI_STATUS_NAMES: [&str; 4] = [
|
pub const FFI_STATUS_NAMES: [&str; 4] = [
|
||||||
"ffi_status_FFI_OK",
|
"ffi_status_FFI_OK",
|
||||||
"ffi_status_FFI_BAD_TYPEDEF",
|
"ffi_status_FFI_BAD_TYPEDEF",
|
||||||
|
@ -31,6 +30,7 @@ pub const FFI_STATUS_NAMES: [&str; 4] = [
|
||||||
"ffi_status_FFI_BAD_ARGTYPE",
|
"ffi_status_FFI_BAD_ARGTYPE",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Check ffi_result is OK
|
||||||
pub fn ffi_status_assert(result: raw::ffi_status) -> LuaResult<()> {
|
pub fn ffi_status_assert(result: raw::ffi_status) -> LuaResult<()> {
|
||||||
if result == raw::ffi_status_FFI_OK {
|
if result == raw::ffi_status_FFI_OK {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -9,17 +9,17 @@ pub mod libffi_helper;
|
||||||
|
|
||||||
pub use self::cast::num_cast;
|
pub use self::cast::num_cast;
|
||||||
|
|
||||||
|
// Common type information
|
||||||
pub trait FfiSize {
|
pub trait FfiSize {
|
||||||
fn get_size(&self) -> usize;
|
fn get_size(&self) -> usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FfiSignedness {
|
pub trait FfiSignedness {
|
||||||
fn get_signedness(&self) -> bool {
|
fn get_signedness(&self) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provide type conversion between luavalue and ffidata types
|
// Provide conversion between luau value and ffi types
|
||||||
pub trait FfiConvert {
|
pub trait FfiConvert {
|
||||||
// Write LuaValue into FfiData
|
// Write LuaValue into FfiData
|
||||||
unsafe fn value_into_data<'lua>(
|
unsafe fn value_into_data<'lua>(
|
||||||
|
@ -57,6 +57,7 @@ pub trait FfiConvert {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Provide read, write, boundary check methods for datas
|
||||||
pub trait FfiData {
|
pub trait FfiData {
|
||||||
fn check_inner_boundary(&self, offset: isize, size: usize) -> bool;
|
fn check_inner_boundary(&self, offset: isize, size: usize) -> bool;
|
||||||
unsafe fn get_inner_pointer(&self) -> *mut ();
|
unsafe fn get_inner_pointer(&self) -> *mut ();
|
||||||
|
@ -75,11 +76,11 @@ pub trait FfiData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function argument informations
|
||||||
pub struct FfiArg {
|
pub struct FfiArg {
|
||||||
pub size: usize,
|
pub size: usize,
|
||||||
pub callback_ref_flag: u8,
|
pub callback_ref_flag: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for FfiArg {
|
impl Clone for FfiArg {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -89,10 +90,10 @@ impl Clone for FfiArg {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function result information
|
||||||
pub struct FfiResult {
|
pub struct FfiResult {
|
||||||
pub size: usize,
|
pub size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for FfiResult {
|
impl Clone for FfiResult {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self { size: self.size }
|
Self { size: self.size }
|
||||||
|
|
|
@ -52,7 +52,9 @@ ffi.c = c
|
||||||
--[=[
|
--[=[
|
||||||
@class RefData
|
@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 = {
|
export type RefData = {
|
||||||
--[=[
|
--[=[
|
||||||
|
@ -60,7 +62,10 @@ export type RefData = {
|
||||||
@tag Method
|
@tag Method
|
||||||
@method deref
|
@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`
|
@return A dereferenced `RefData`
|
||||||
]=]
|
]=]
|
||||||
|
@ -71,7 +76,9 @@ export type RefData = {
|
||||||
@method offset
|
@method offset
|
||||||
|
|
||||||
Create a reference with specific offset from this reference.
|
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
|
@param offset Create a reference at the given offset
|
||||||
@return A offseted reference
|
@return A offseted reference
|
||||||
]=]
|
]=]
|
||||||
|
@ -83,7 +90,7 @@ export type RefData = {
|
||||||
|
|
||||||
Create a reference of this reference.
|
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
|
@return A reference of this reference
|
||||||
]=]
|
]=]
|
||||||
|
@ -1089,6 +1096,7 @@ end
|
||||||
@within FFI
|
@within FFI
|
||||||
|
|
||||||
Create a `Box` with specific size.
|
Create a `Box` with specific size.
|
||||||
|
The created box is not filed with zero.
|
||||||
|
|
||||||
@param size The size of the new box
|
@param size The size of the new box
|
||||||
@return A allocated box
|
@return A allocated box
|
||||||
|
|
Loading…
Add table
Reference in a new issue