From 26706d935515d4b82d1c6443df32f3bcfb95396b Mon Sep 17 00:00:00 2001 From: qwreey Date: Sun, 25 Aug 2024 14:37:31 +0000 Subject: [PATCH] Improve ctype export and Refactor (#243) --- crates/lune-std-ffi/src/c/c_arr.rs | 18 +-- crates/lune-std-ffi/src/c/c_ptr.rs | 4 +- crates/lune-std-ffi/src/c/c_struct.rs | 16 +-- crates/lune-std-ffi/src/c/c_type.rs | 143 ++-------------------- crates/lune-std-ffi/src/c/mod.rs | 130 ++++++++++++++++++++ crates/lune-std-ffi/src/ffi/ffi_bounds.rs | 67 ++++++++++ crates/lune-std-ffi/src/ffi/ffi_box.rs | 72 +++++------ crates/lune-std-ffi/src/ffi/ffi_helper.rs | 10 +- crates/lune-std-ffi/src/ffi/ffi_lib.rs | 4 +- crates/lune-std-ffi/src/ffi/ffi_raw.rs | 4 +- crates/lune-std-ffi/src/ffi/ffi_ref.rs | 68 +++++----- crates/lune-std-ffi/src/ffi/mod.rs | 2 +- crates/lune-std-ffi/src/lib.rs | 11 +- crates/lune-std-ffi/todo.md | 13 +- 14 files changed, 308 insertions(+), 254 deletions(-) create mode 100644 crates/lune-std-ffi/src/ffi/ffi_bounds.rs diff --git a/crates/lune-std-ffi/src/c/c_arr.rs b/crates/lune-std-ffi/src/c/c_arr.rs index 6fbd964..2b2b94b 100644 --- a/crates/lune-std-ffi/src/c/c_arr.rs +++ b/crates/lune-std-ffi/src/c/c_arr.rs @@ -21,7 +21,7 @@ use crate::ffi::ffi_association::{get_association, set_association}; // There is no problem even if you create a struct with n fields of a single type within the struct. Array adheres to the condition that there is no additional padding between each element. Padding to a struct is padding inside the struct. Simply think of the padding byte as a trailing unnamed field. pub struct CArr { - libffi_type: Type, + element_type: Type, struct_type: Type, length: usize, field_size: usize, @@ -29,12 +29,12 @@ pub struct CArr { } impl CArr { - pub fn new(libffi_type: Type, length: usize) -> LuaResult { - let struct_type = Type::structure(vec![libffi_type.clone(); length]); - let field_size = get_ensured_size(libffi_type.as_raw_ptr())?; + pub fn new(element_type: Type, length: usize) -> LuaResult { + let struct_type = Type::structure(vec![element_type.clone(); length]); + let field_size = get_ensured_size(element_type.as_raw_ptr())?; Ok(Self { - libffi_type, + element_type, struct_type, length, field_size, @@ -50,14 +50,18 @@ impl CArr { let fields = type_from_userdata(luatype)?; let carr = lua.create_userdata(Self::new(fields, length)?)?; - set_association(lua, CARR_INNER, carr.clone(), luatype)?; + set_association(lua, CARR_INNER, &carr, luatype)?; Ok(carr) } pub fn get_type(&self) -> Type { - self.libffi_type.clone() + self.struct_type.clone() } + // pub fn get_element_type(&self) -> Type { + // self.element_type.clone() + // } + // Stringify cstruct for pretty printing something like: // pub fn stringify(userdata: &LuaAnyUserData) -> LuaResult { diff --git a/crates/lune-std-ffi/src/c/c_ptr.rs b/crates/lune-std-ffi/src/c/c_ptr.rs index 5fb8845..00a730d 100644 --- a/crates/lune-std-ffi/src/c/c_ptr.rs +++ b/crates/lune-std-ffi/src/c/c_ptr.rs @@ -1,7 +1,5 @@ #![allow(clippy::cargo_common_metadata)] -use std::borrow::Borrow; - use libffi::middle::Type; use mlua::prelude::*; @@ -21,7 +19,7 @@ impl CPtr { ) -> LuaResult> { let value = Self().into_lua(lua)?; - set_association(lua, CPTR_INNER, value.borrow(), inner)?; + set_association(lua, CPTR_INNER, &value, inner)?; Ok(value) } diff --git a/crates/lune-std-ffi/src/c/c_struct.rs b/crates/lune-std-ffi/src/c/c_struct.rs index 9e945ec..58628d5 100644 --- a/crates/lune-std-ffi/src/c/c_struct.rs +++ b/crates/lune-std-ffi/src/c/c_struct.rs @@ -1,6 +1,6 @@ #![allow(clippy::cargo_common_metadata)] -use std::vec::Vec; +use std::{borrow::Borrow, vec::Vec}; use libffi::{ low, @@ -18,17 +18,17 @@ use crate::ffi::ffi_association::{get_association, set_association}; use crate::ffi::ffi_helper::FFI_STATUS_NAMES; pub struct CStruct { - libffi_cif: Cif, - libffi_type: Type, + // libffi_cif: Cif, fields: Vec, + libffi_type: Type, offsets: Vec, size: usize, } impl CStruct { pub fn new(fields: Vec) -> LuaResult { - let libffi_type = Type::structure(fields.clone()); - let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void()); + let libffi_type = Type::structure(fields.iter().cloned()); + // let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void()); // Get field offsets with ffi_get_struct_offsets let mut offsets = Vec::::with_capacity(fields.len()); @@ -52,9 +52,9 @@ impl CStruct { let size = unsafe { (*libffi_type.as_raw_ptr()).size }; Ok(Self { - libffi_cif: libffi_cfi, - libffi_type, + // libffi_cif: libffi_cfi, fields, + libffi_type, offsets, size, }) @@ -69,7 +69,7 @@ impl CStruct { let fields = type_list_from_table(&table)?; let cstruct = lua.create_userdata(Self::new(fields)?)?; table.set_readonly(true); - set_association(lua, CSTRUCT_INNER, cstruct.clone(), table)?; + set_association(lua, CSTRUCT_INNER, &cstruct, table)?; Ok(cstruct) } diff --git a/crates/lune-std-ffi/src/c/c_type.rs b/crates/lune-std-ffi/src/c/c_type.rs index 58d3364..7ed7bca 100644 --- a/crates/lune-std-ffi/src/c/c_type.rs +++ b/crates/lune-std-ffi/src/c/c_type.rs @@ -1,44 +1,38 @@ #![allow(clippy::cargo_common_metadata)] -use core::ffi::{ - c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, - c_ulong, c_ulonglong, c_ushort, c_void, -}; - -use libffi::middle::{Cif, Type}; +use libffi::middle::Type; use mlua::prelude::*; use super::c_arr::CArr; use super::c_helper::get_ensured_size; use super::c_ptr::CPtr; use crate::ffi::ffi_helper::get_ptr_from_userdata; -use crate::ffi::ffi_platform::CHAR_IS_SIGNED; -// use libffi::raw::{ffi_cif, ffi_ptrarray_to_raw}; pub struct CType { - libffi_cif: Cif, + // for ffi_ptrarray_to_raw? + // libffi_cif: Cif, libffi_type: Type, size: usize, name: Option, // Write converted data from luavalue into some ptr - pub luavalue_into_ptr: fn(value: LuaValue, ptr: *mut c_void) -> LuaResult<()>, + pub luavalue_into_ptr: fn(value: LuaValue, ptr: *mut ()) -> LuaResult<()>, // Read luavalue from some ptr - pub ptr_into_luavalue: fn(lua: &Lua, ptr: *mut c_void) -> LuaResult, + pub ptr_into_luavalue: fn(lua: &Lua, ptr: *mut ()) -> LuaResult, } impl CType { pub fn new( libffi_type: Type, name: Option, - luavalue_into_ptr: fn(value: LuaValue, ptr: *mut c_void) -> LuaResult<()>, - ptr_into_luavalue: fn(lua: &Lua, ptr: *mut c_void) -> LuaResult, + luavalue_into_ptr: fn(value: LuaValue, ptr: *mut ()) -> LuaResult<()>, + ptr_into_luavalue: fn(lua: &Lua, ptr: *mut ()) -> LuaResult, ) -> LuaResult { - let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void()); + // let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void()); let size = get_ensured_size(libffi_type.as_raw_ptr())?; Ok(Self { - libffi_cif: libffi_cfi, + // libffi_cif: libffi_cfi, libffi_type, size, name, @@ -117,122 +111,3 @@ impl LuaUserData for CType { }); } } - -// export all default c-types -#[allow(clippy::too_many_lines)] -pub fn create_all_types(lua: &Lua) -> LuaResult> { - Ok(vec![ - ( - "int", - CType::new( - Type::c_int(), - Some(String::from("int")), - |data, ptr| { - let value = match data { - LuaValue::Integer(t) => t, - _ => { - return Err(LuaError::external(format!( - "Integer expected, got {}", - data.type_name() - ))) - } - } as c_int; - unsafe { - *(ptr.cast::()) = value; - } - Ok(()) - }, - |lua: &Lua, ptr: *mut c_void| { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; - Ok(value) - }, - )? - .into_lua(lua)?, - ), - ( - "long", - CType::new( - Type::c_long(), - Some(String::from("long")), - |data, ptr| { - let value = match data { - LuaValue::Integer(t) => t, - _ => { - return Err(LuaError::external(format!( - "Integer expected, got {}", - data.type_name() - ))) - } - } as c_long; - unsafe { - *(ptr.cast::()) = value; - } - Ok(()) - }, - |lua: &Lua, ptr: *mut c_void| { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; - Ok(value) - }, - )? - .into_lua(lua)?, - ), - ( - "longlong", - CType::new( - Type::c_longlong(), - Some(String::from("longlong")), - |data, ptr| { - let value = match data { - LuaValue::Integer(t) => t, - _ => { - return Err(LuaError::external(format!( - "Integer expected, got {}", - data.type_name() - ))) - } - } as c_longlong; - unsafe { - *(ptr.cast::()) = value; - } - Ok(()) - }, - |lua: &Lua, ptr: *mut c_void| { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; - Ok(value) - }, - )? - .into_lua(lua)?, - ), - ( - "char", - CType::new( - if CHAR_IS_SIGNED { - Type::c_schar() - } else { - Type::c_uchar() - }, - Some(String::from("char")), - |data, ptr| { - let value = match data { - LuaValue::Integer(t) => t, - _ => { - return Err(LuaError::external(format!( - "Integer expected, got {}", - data.type_name() - ))) - } - } as c_char; - unsafe { - *(ptr.cast::()) = value; - } - Ok(()) - }, - |lua: &Lua, ptr: *mut c_void| { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; - Ok(value) - }, - )? - .into_lua(lua)?, - ), - ]) -} diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index 803fa62..25db176 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -12,3 +12,133 @@ mod association_names { pub const CARR_INNER: &str = "__carr_inner"; pub const CSTRUCT_INNER: &str = "__cstruct_inner"; } + +use core::ffi::{ + c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, + c_ulong, c_ulonglong, c_ushort, c_void, +}; + +use libffi::middle::Type; +use mlua::prelude::*; + +use self::c_type::CType; +use crate::ffi::ffi_platform::CHAR_IS_SIGNED; + +// export all default c-types +#[allow(clippy::too_many_lines)] +pub fn create_all_types(lua: &Lua) -> LuaResult> { + Ok(vec![ + ( + "int", + CType::new( + Type::c_int(), + Some(String::from("int")), + |data, ptr| { + let value = match data { + LuaValue::Integer(t) => t, + _ => { + return Err(LuaError::external(format!( + "Integer expected, got {}", + data.type_name() + ))) + } + } as c_int; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + }, + |lua: &Lua, ptr: *mut ()| { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + }, + )? + .into_lua(lua)?, + ), + ( + "long", + CType::new( + Type::c_long(), + Some(String::from("long")), + |data, ptr| { + let value = match data { + LuaValue::Integer(t) => t, + _ => { + return Err(LuaError::external(format!( + "Integer expected, got {}", + data.type_name() + ))) + } + } as c_long; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + }, + |lua: &Lua, ptr: *mut ()| { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + }, + )? + .into_lua(lua)?, + ), + ( + "longlong", + CType::new( + Type::c_longlong(), + Some(String::from("longlong")), + |data, ptr| { + let value = match data { + LuaValue::Integer(t) => t, + _ => { + return Err(LuaError::external(format!( + "Integer expected, got {}", + data.type_name() + ))) + } + } as c_longlong; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + }, + |lua: &Lua, ptr: *mut ()| { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + }, + )? + .into_lua(lua)?, + ), + ( + "char", + CType::new( + if CHAR_IS_SIGNED { + Type::c_schar() + } else { + Type::c_uchar() + }, + Some(String::from("char")), + |data, ptr| { + let value = match data { + LuaValue::Integer(t) => t, + _ => { + return Err(LuaError::external(format!( + "Integer expected, got {}", + data.type_name() + ))) + } + } as c_char; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + }, + |lua: &Lua, ptr: *mut ()| { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + }, + )? + .into_lua(lua)?, + ), + ]) +} diff --git a/crates/lune-std-ffi/src/ffi/ffi_bounds.rs b/crates/lune-std-ffi/src/ffi/ffi_bounds.rs new file mode 100644 index 0000000..5c73bb3 --- /dev/null +++ b/crates/lune-std-ffi/src/ffi/ffi_bounds.rs @@ -0,0 +1,67 @@ +// Memory range for ref or box data. For boundary checking +pub struct FfiRefBounds { + // Indicates how much data is above the pointer + pub(crate) high: usize, + // Indicates how much data is below the pointer + pub(crate) low: usize, +} + +impl FfiRefBounds { + pub fn new(high: usize, low: usize) -> Self { + Self { high, low } + } + + // Check boundary + pub fn check(&self, offset: isize) -> bool { + let sign = offset.signum(); + let offset_abs = offset.unsigned_abs(); + if sign == -1 { + self.high >= offset_abs + } else if sign == 1 { + self.low >= offset_abs + } else { + // sign == 0 + true + } + } + + // Check boundary + pub fn check_sized(&self, offset: isize, size: usize) -> bool { + let end = offset + (size as isize) - 1; + let sign = end.signum(); + let end_abs = end.unsigned_abs(); + if sign == -1 { + self.high >= end_abs + } else if sign == 1 { + self.low >= end_abs + } else { + // sign == 0 + true + } + } + + // Calculate new bounds from bounds and offset + // No boundary checking in here + pub fn offset(&self, offset: isize) -> Self { + let sign = offset.signum(); + let offset_abs = offset.unsigned_abs(); + + let high: usize = if sign == -1 { + self.high - offset_abs + } else if sign == 1 { + self.high + offset_abs + } else { + self.high + }; + + let low: usize = if sign == -1 { + self.low + offset_abs + } else if sign == 1 { + self.low - offset_abs + } else { + self.low + }; + + Self { high, low } + } +} diff --git a/crates/lune-std-ffi/src/ffi/ffi_box.rs b/crates/lune-std-ffi/src/ffi/ffi_box.rs index 49fb1d2..f7d593c 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_box.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_box.rs @@ -11,12 +11,11 @@ use std::boxed::Box; -use core::ffi::c_void; use mlua::prelude::*; -use super::association_names::BOX_REF_INNER; +use super::association_names::REF_INNER; use super::ffi_association::set_association; -use super::ffi_ref::FfiRange; +use super::ffi_bounds::FfiRefBounds; use super::ffi_ref::FfiRef; pub struct FfiBox(Box<[u8]>); @@ -36,29 +35,10 @@ impl FfiBox { Self(vec_heap.into_boxed_slice()) } - pub fn size(&self) -> usize { - self.0.len() - } - // pub fn copy(&self, target: &mut FfiBox) {} - pub fn get_ptr(&self) -> *mut c_void { - self.0.as_ptr() as *mut c_void - } - + // Todo: if too big, print as another format pub fn stringify(&self) -> String { - let mut buff = String::from(" "); - for i in &self.0 { - buff.push_str(i.to_string().as_str()); - buff.push_str(", "); - } - buff.pop(); - buff.pop(); - buff.push(' '); - buff - } - - pub fn binary_print(&self) -> String { let mut buff: String = String::with_capacity(self.size() * 10 - 2); for (pos, value) in self.0.iter().enumerate() { for i in 0..8 { @@ -75,42 +55,51 @@ impl FfiBox { buff } - // bad naming. i have no idea what should i use + // Make FfiRef from box, with boundary checking pub fn luaref<'lua>( lua: &'lua Lua, this: LuaAnyUserData<'lua>, offset: Option, ) -> LuaResult> { - let target = this.borrow::()?; - let ptr = if let Some(t) = offset { - if t < 0 || t >= (target.size() as isize) { + let mut target = this.borrow_mut::()?; + let mut bounds = FfiRefBounds::new(0, target.size()); + let mut ptr = target.get_ptr(); + + // Calculate offset + if let Some(t) = offset { + if !bounds.check(t) { return Err(LuaError::external(format!( "Offset is out of bounds. box.size: {}. offset got {}", target.size(), t ))); } - unsafe { target.get_ptr().offset(t) } - } else { - target.get_ptr() - }; + ptr = unsafe { target.get_ptr().offset(t) }; + bounds = bounds.offset(t); + } - let luaref = lua.create_userdata(FfiRef::new( - ptr, - Some(FfiRange { - low: 0, - high: target.size() as isize, - }), - ))?; + let luaref = lua.create_userdata(FfiRef::new(ptr.cast(), Some(bounds)))?; - set_association(lua, BOX_REF_INNER, luaref.clone(), this.clone())?; + // Makes box alive longer then ref + set_association(lua, REF_INNER, &luaref, &this)?; Ok(luaref) } + // Fill every field with 0 pub fn zero(&mut self) { self.0.fill(0u8); } + + // Get size of box + pub fn size(&self) -> usize { + self.0.len() + } + + // Get raw ptr + pub fn get_ptr(&mut self) -> *mut u8 { + self.0.as_mut_ptr() + } } impl LuaUserData for FfiBox { @@ -119,6 +108,7 @@ impl LuaUserData for FfiBox { } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + // For convenience, :zero returns self. methods.add_function_mut("zero", |_, this: LuaAnyUserData| { this.borrow_mut::()?.zero(); Ok(this) @@ -130,8 +120,6 @@ impl LuaUserData for FfiBox { Ok(luaref) }, ); - methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| { - Ok(this.binary_print()) - }); + methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| Ok(this.stringify())); } } diff --git a/crates/lune-std-ffi/src/ffi/ffi_helper.rs b/crates/lune-std-ffi/src/ffi/ffi_helper.rs index ffa32f2..87a905e 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_helper.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_helper.rs @@ -1,5 +1,3 @@ -use std::ffi::c_void; - use mlua::prelude::*; use super::ffi_box::FfiBox; @@ -13,12 +11,14 @@ pub const FFI_STATUS_NAMES: [&str; 4] = [ "ffi_status_FFI_BAD_ARGTYPE", ]; +// Get raw pointer from userdata +// TODO: boundary check pub unsafe fn get_ptr_from_userdata( userdata: &LuaAnyUserData, offset: Option, -) -> LuaResult<*mut c_void> { +) -> LuaResult<*mut ()> { let ptr = if userdata.is::() { - userdata.borrow::()?.get_ptr() + userdata.borrow_mut::()?.get_ptr().cast() } else if userdata.is::() { userdata.borrow::()?.get_ptr() } else { @@ -26,7 +26,7 @@ pub unsafe fn get_ptr_from_userdata( }; let ptr = if let Some(t) = offset { - ptr.offset(t) + ptr.cast::().offset(t).cast() } else { ptr }; diff --git a/crates/lune-std-ffi/src/ffi/ffi_lib.rs b/crates/lune-std-ffi/src/ffi/ffi_lib.rs index bf87015..70c81c6 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_lib.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_lib.rs @@ -39,9 +39,9 @@ impl FfiLib { .map_err(|err| LuaError::external(format!("{err}")))? }; - let luasym = lua.create_userdata(FfiRef::new(*sym, None))?; + let luasym = lua.create_userdata(FfiRef::new((*sym).cast(), None))?; - set_association(lua, SYM_INNER, luasym.clone(), this.clone())?; + set_association(lua, SYM_INNER, &luasym, &this)?; Ok(luasym) } diff --git a/crates/lune-std-ffi/src/ffi/ffi_raw.rs b/crates/lune-std-ffi/src/ffi/ffi_raw.rs index 6a82cd9..c32ca76 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_raw.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_raw.rs @@ -1,5 +1,5 @@ -use core::ffi::c_void; -use std::{convert, mem::transmute, ptr}; +// use core::ffi::c_void; +// use std::{convert, mem::transmute, ptr}; // This is raw data coming from outside. // Users must convert it to a Lua value, reference, or box to use it. diff --git a/crates/lune-std-ffi/src/ffi/ffi_ref.rs b/crates/lune-std-ffi/src/ffi/ffi_ref.rs index a5ebc70..1150eb1 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref.rs @@ -1,10 +1,10 @@ -use core::ffi::c_void; use std::ptr; use mlua::prelude::*; use super::association_names::REF_INNER; -use super::ffi_association::set_association; +use super::ffi_association::{get_association, set_association}; +use super::ffi_bounds::FfiRefBounds; // 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 @@ -12,22 +12,17 @@ use super::ffi_association::set_association; // If it references an area managed by Lua, // the box will remain as long as this reference is alive. -pub struct FfiRange { - pub(crate) high: isize, - pub(crate) low: isize, -} - pub struct FfiRef { - ptr: *mut c_void, - range: Option, + ptr: *mut (), + range: Option, } impl FfiRef { - pub fn new(ptr: *mut c_void, range: Option) -> Self { + pub fn new(ptr: *mut (), range: Option) -> Self { Self { ptr, range } } - // bad naming. i have no idea what should i use + // Make FfiRef from ref pub fn luaref<'lua>( lua: &'lua Lua, this: LuaAnyUserData<'lua>, @@ -35,52 +30,59 @@ impl FfiRef { let target = this.borrow::()?; let luaref = lua.create_userdata(FfiRef::new( - ptr::from_ref(&target.ptr) as *mut c_void, - Some(FfiRange { + ptr::from_ref(&target.ptr) as *mut (), + Some(FfiRefBounds { low: 0, - high: size_of::() as isize, + high: size_of::(), }), ))?; - set_association(lua, REF_INNER, luaref.clone(), this.clone())?; + // If the ref holds a box, make sure the new ref also holds the box + if let Some(t) = get_association(lua, REF_INNER, &this)? { + set_association(lua, REF_INNER, &luaref, t)?; + } Ok(luaref) } - pub fn get_ptr(&self) -> *mut c_void { + pub fn get_ptr(&self) -> *mut () { self.ptr } pub unsafe fn deref(&self) -> Self { - Self::new(*self.ptr.cast::<*mut c_void>(), None) + Self::new(*self.ptr.cast::<*mut ()>(), None) } pub unsafe fn offset(&self, offset: isize) -> LuaResult { - let range = if let Some(ref t) = self.range { - let high = t.high - offset; - let low = t.low - offset; - - if low > 0 || high < 0 { + if let Some(ref t) = self.range { + if !t.check(offset) { return Err(LuaError::external(format!( - "Offset is out of bounds. low: {}, high: {}. offset got {}", - t.low, t.high, offset + "Offset is out of bounds. high: {}, low: {}. offset got {}", + t.high, t.low, offset ))); } + } + let range = self.range.as_ref().map(|t| t.offset(offset)); - Some(FfiRange { high, low }) - } else { - None - }; - - Ok(Self::new(self.ptr.offset(offset), range)) + Ok(Self::new( + self.ptr.cast::().offset(offset).cast(), + range, + )) } } impl LuaUserData for FfiRef { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { - methods.add_method("deref", |_, this, ()| { - let ffiref = unsafe { this.deref() }; - Ok(ffiref) + methods.add_function("deref", |lua, this: LuaAnyUserData| { + let inner = get_association(lua, REF_INNER, &this)?; + let ffiref = this.borrow::()?; + let result = lua.create_userdata(unsafe { ffiref.deref() })?; + + if let Some(t) = inner { + set_association(lua, REF_INNER, &result, &t)?; + } + + Ok(result) }); methods.add_method("offset", |_, this, offset: isize| { let ffiref = unsafe { this.offset(offset)? }; diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index 4812028..dd36905 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -1,4 +1,5 @@ pub(super) mod ffi_association; +pub(super) mod ffi_bounds; pub(super) mod ffi_box; pub(super) mod ffi_helper; pub(super) mod ffi_lib; @@ -8,6 +9,5 @@ pub(super) mod ffi_ref; // Named registry table names mod association_names { - pub const BOX_REF_INNER: &str = "__box_ref"; pub const REF_INNER: &str = "__ref_inner"; } diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs index 1bcfbe0..4a51975 100644 --- a/crates/lune-std-ffi/src/lib.rs +++ b/crates/lune-std-ffi/src/lib.rs @@ -6,13 +6,10 @@ use mlua::prelude::*; mod c; mod ffi; -use crate::c::c_fn::CFn; -use crate::c::c_struct::CStruct; -use crate::c::c_type::create_all_types; -use crate::ffi::ffi_association::get_table; -use crate::ffi::ffi_box::FfiBox; -use crate::ffi::ffi_lib::FfiLib; -use crate::ffi::ffi_platform::get_platform_value; +use crate::c::{c_fn::CFn, c_struct::CStruct, create_all_types}; +use crate::ffi::{ + ffi_association::get_table, ffi_box::FfiBox, ffi_lib::FfiLib, ffi_platform::get_platform_value, +}; /** Creates the `ffi` standard library module. diff --git a/crates/lune-std-ffi/todo.md b/crates/lune-std-ffi/todo.md index 9eed077..f0a0ab8 100644 --- a/crates/lune-std-ffi/todo.md +++ b/crates/lune-std-ffi/todo.md @@ -1,11 +1,3 @@ -use libffi::raw::{ffi_cif, ffi_ptrarray_to_raw}; - -// pub fn ffi_get_struct_offsets( -// abi: ffi_abi, -// struct_type: *mut ffi_type, -// offsets: *mut usize, -// ) -> ffi_status; - - last thing to do - [ ] Add tests - [ ] Add docs @@ -23,8 +15,9 @@ use libffi::raw::{ffi_cif, ffi_ptrarray_to_raw}; - [x] ffi.box(size) - [x] .size - [x] :zero() -- [?] :ref(offset?=0) => ref - - offset is not impled +- [x] :ref(offset?=0) => ref +- [x] tostring + - [~] :copy(box,size?=-1,offset?=0) - working on it