From b54ea519ba17a51fe92018f91a73144e46808334 Mon Sep 17 00:00:00 2001 From: qwreey Date: Wed, 28 Aug 2024 16:39:35 +0000 Subject: [PATCH] Implement boundary check (#243) --- crates/lune-std-ffi/src/c/c_arr.rs | 18 +- crates/lune-std-ffi/src/c/c_fn.rs | 6 +- crates/lune-std-ffi/src/c/c_helper.rs | 75 ++++-- crates/lune-std-ffi/src/c/c_ptr.rs | 10 +- crates/lune-std-ffi/src/c/c_struct.rs | 163 +++++++++--- crates/lune-std-ffi/src/c/c_type.rs | 184 +++++++------- crates/lune-std-ffi/src/c/c_void.rs | 0 crates/lune-std-ffi/src/c/mod.rs | 26 +- crates/lune-std-ffi/src/c/types/f32.rs | 26 +- crates/lune-std-ffi/src/c/types/f64.rs | 26 +- crates/lune-std-ffi/src/c/types/i128.rs | 26 +- crates/lune-std-ffi/src/c/types/i16.rs | 28 ++- crates/lune-std-ffi/src/c/types/i32.rs | 26 +- crates/lune-std-ffi/src/c/types/i64.rs | 26 +- crates/lune-std-ffi/src/c/types/i8.rs | 26 +- crates/lune-std-ffi/src/c/types/isize.rs | 26 +- crates/lune-std-ffi/src/c/types/mod.rs | 233 +++++++++++++----- crates/lune-std-ffi/src/c/types/u128.rs | 26 +- crates/lune-std-ffi/src/c/types/u16.rs | 26 +- crates/lune-std-ffi/src/c/types/u32.rs | 26 +- crates/lune-std-ffi/src/c/types/u64.rs | 26 +- crates/lune-std-ffi/src/c/types/u8.rs | 26 +- crates/lune-std-ffi/src/c/types/usize.rs | 26 +- .../lune-std-ffi/src/ffi/ffi_association.rs | 5 +- crates/lune-std-ffi/src/ffi/ffi_box.rs | 51 +++- crates/lune-std-ffi/src/ffi/ffi_helper.rs | 29 +-- .../lune-std-ffi/src/ffi/ffi_native/cast.rs | 35 +-- .../src/ffi/ffi_native/convert.rs | 47 +--- crates/lune-std-ffi/src/ffi/ffi_native/mod.rs | 17 +- .../src/ffi/ffi_native/readwrite.rs | 40 +++ crates/lune-std-ffi/src/ffi/ffi_raw.rs | 2 + crates/lune-std-ffi/src/ffi/ffi_ref/bounds.rs | 12 +- crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs | 2 +- crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs | 37 ++- crates/lune-std-ffi/src/ffi/mod.rs | 49 +++- crates/lune-std-ffi/src/lib.rs | 9 +- 36 files changed, 925 insertions(+), 491 deletions(-) create mode 100644 crates/lune-std-ffi/src/c/c_void.rs create mode 100644 crates/lune-std-ffi/src/ffi/ffi_native/readwrite.rs diff --git a/crates/lune-std-ffi/src/c/c_arr.rs b/crates/lune-std-ffi/src/c/c_arr.rs index 063b93a..e1deff7 100644 --- a/crates/lune-std-ffi/src/c/c_arr.rs +++ b/crates/lune-std-ffi/src/c/c_arr.rs @@ -2,7 +2,7 @@ use libffi::middle::Type; use mlua::prelude::*; use super::association_names::CARR_INNER; -use super::c_helper::{get_ensured_size, pretty_format_userdata, type_from_userdata}; +use super::c_helper::{get_ensured_size, libffi_type_from_userdata, pretty_format_userdata}; use super::c_ptr::CPtr; use crate::ffi::ffi_association::{get_association, set_association}; @@ -44,13 +44,21 @@ impl CArr { luatype: &LuaAnyUserData<'lua>, length: usize, ) -> LuaResult> { - let fields = type_from_userdata(lua, luatype)?; + let fields = libffi_type_from_userdata(lua, luatype)?; let carr = lua.create_userdata(Self::new(fields, length)?)?; set_association(lua, CARR_INNER, &carr, luatype)?; Ok(carr) } + pub fn get_size(&self) -> usize { + self.size + } + + pub fn get_length(&self) -> usize { + self.length + } + pub fn get_type(&self) -> &Type { &self.struct_type } @@ -83,8 +91,8 @@ impl CArr { impl LuaUserData for CArr { 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("length", |_, this| Ok(this.length)); + fields.add_field_method_get("size", |_, this| Ok(this.get_size())); + fields.add_field_method_get("length", |_, this| Ok(this.get_length())); fields.add_field_function_get("inner", |lua, this: LuaAnyUserData| { let inner: LuaValue = get_association(lua, CARR_INNER, this)? // It shouldn't happen. @@ -102,7 +110,7 @@ impl LuaUserData for CArr { } }); methods.add_function("ptr", |lua, this: LuaAnyUserData| { - let pointer = CPtr::from_lua_userdata(lua, &this)?; + let pointer = CPtr::new_from_lua_userdata(lua, &this)?; Ok(pointer) }); methods.add_meta_function(LuaMetaMethod::ToString, |lua, this: LuaAnyUserData| { diff --git a/crates/lune-std-ffi/src/c/c_fn.rs b/crates/lune-std-ffi/src/c/c_fn.rs index 7a4bce3..d83ecf7 100644 --- a/crates/lune-std-ffi/src/c/c_fn.rs +++ b/crates/lune-std-ffi/src/c/c_fn.rs @@ -1,7 +1,7 @@ use libffi::middle::{Cif, Type}; use mlua::prelude::*; -use super::c_helper::{type_from_userdata, type_list_from_table}; +use super::c_helper::{libffi_type_from_userdata, libffi_type_list_from_table}; // cfn is a type declaration for a function. // Basically, when calling an external function, this type declaration @@ -36,8 +36,8 @@ impl CFn { } pub fn new_from_lua_table(lua: &Lua, args: LuaTable, ret: LuaAnyUserData) -> LuaResult { - let args = type_list_from_table(lua, &args)?; - let ret = type_from_userdata(lua, &ret)?; + let args = libffi_type_list_from_table(lua, &args)?; + let ret = libffi_type_from_userdata(lua, &ret)?; Ok(Self::new(args, ret)) } } diff --git a/crates/lune-std-ffi/src/c/c_helper.rs b/crates/lune-std-ffi/src/c/c_helper.rs index 2310180..6d0ac97 100644 --- a/crates/lune-std-ffi/src/c/c_helper.rs +++ b/crates/lune-std-ffi/src/c/c_helper.rs @@ -1,3 +1,5 @@ +#![allow(clippy::inline_always)] + use std::ptr::{self, null_mut}; use libffi::{low, middle::Type, raw}; @@ -5,31 +7,70 @@ use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; use mlua::prelude::*; use super::association_names::CTYPE_STATIC; -use super::c_arr::CArr; -use super::c_ptr::CPtr; -use super::c_struct::CStruct; use super::c_type::CTypeStatic; -use crate::ffi::ffi_association::get_association; -use crate::ffi::ffi_helper::FFI_STATUS_NAMES; +use super::types::get_ctype_conv; +use super::{CArr, CPtr, CStruct}; +use crate::ffi::{ffi_association::get_association, NativeConvert, FFI_STATUS_NAMES}; + +// Get the NativeConvert handle from the type UserData +// this is intended to avoid constant table lookups. (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 NativeConvert> { + if userdata.is::() { + Ok(userdata.to_pointer().cast::() as *const dyn NativeConvert) + } else { + unsafe { get_ctype_conv(userdata) } + } +} +pub unsafe fn get_conv_list_from_table( + table: &LuaTable, +) -> LuaResult> { + let len: usize = table.raw_len(); + let mut conv_list = Vec::<*const dyn NativeConvert>::with_capacity(len); + + for i in 0..len { + let value: LuaValue = table.raw_get(i + 1)?; + + if let LuaValue::UserData(field_type) = value { + conv_list.push(get_conv(&field_type)?); + } else { + return Err(LuaError::external(format!( + "Unexpected field. CStruct, CType or CArr is required for element but got {}", + pretty_format_value(&value, &ValueFormatConfig::new()) + ))); + } + } + + Ok(conv_list) +} + +// #[inline(always)] +// pub fn type_size_from_userdata(this: &LuaAnyUserData) -> LuaResult { +// if this.is::() { +// Ok(this.borrow::()?.get_size()) +// } else if this.is::() { +// Ok(this.borrow::()?.get_size()) +// } else { +// ctype_size_from_userdata(this) +// } +// } // get Vec from table(array) of c-types userdata -pub fn type_list_from_table(lua: &Lua, table: &LuaTable) -> LuaResult> { +pub fn libffi_type_list_from_table(lua: &Lua, table: &LuaTable) -> LuaResult> { let len: usize = table.raw_len(); let mut fields = Vec::with_capacity(len); for i in 0..len { // Test required let value = table.raw_get(i + 1)?; - match value { - LuaValue::UserData(field_type) => { - fields.push(type_from_userdata(lua, &field_type)?); - } - _ => { - return Err(LuaError::external(format!( - "Unexpected field. CStruct, CType or CArr is required for element but got {}", - pretty_format_value(&value, &ValueFormatConfig::new()) - ))); - } + if let LuaValue::UserData(field_type) = value { + fields.push(libffi_type_from_userdata(lua, &field_type)?); + } else { + return Err(LuaError::external(format!( + "Unexpected field. CStruct, CType or CArr is required for element but got {}", + value.type_name() + ))); } } @@ -37,7 +78,7 @@ pub fn type_list_from_table(lua: &Lua, table: &LuaTable) -> LuaResult> } // get libffi_type from any c-type userdata -pub fn type_from_userdata(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { +pub fn libffi_type_from_userdata(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { if userdata.is::() { Ok(userdata.borrow::()?.get_type().to_owned()) } else if let Some(t) = get_association(lua, CTYPE_STATIC, userdata)? { diff --git a/crates/lune-std-ffi/src/c/c_ptr.rs b/crates/lune-std-ffi/src/c/c_ptr.rs index ced880b..08d9d33 100644 --- a/crates/lune-std-ffi/src/c/c_ptr.rs +++ b/crates/lune-std-ffi/src/c/c_ptr.rs @@ -1,11 +1,7 @@ -#![allow(clippy::cargo_common_metadata)] - use libffi::middle::Type; use mlua::prelude::*; -use super::association_names::CPTR_INNER; -use super::c_arr::CArr; -use super::c_helper::pretty_format_userdata; +use super::{association_names::CPTR_INNER, c_helper::pretty_format_userdata, CArr}; use crate::ffi::ffi_association::{get_association, set_association}; pub struct CPtr(); @@ -13,7 +9,7 @@ pub struct CPtr(); impl CPtr { // Create pointer type with '.inner' field // inner can be CArr, CType or CStruct - pub fn from_lua_userdata<'lua>( + pub fn new_from_lua_userdata<'lua>( lua: &'lua Lua, inner: &LuaAnyUserData, ) -> LuaResult> { @@ -56,7 +52,7 @@ impl LuaUserData for CPtr { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { methods.add_function("ptr", |lua, this: LuaAnyUserData| { - let pointer = CPtr::from_lua_userdata(lua, &this)?; + let pointer = CPtr::new_from_lua_userdata(lua, &this)?; Ok(pointer) }); methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| { diff --git a/crates/lune-std-ffi/src/c/c_struct.rs b/crates/lune-std-ffi/src/c/c_struct.rs index 16e2f8f..39df226 100644 --- a/crates/lune-std-ffi/src/c/c_struct.rs +++ b/crates/lune-std-ffi/src/c/c_struct.rs @@ -1,32 +1,38 @@ -#![allow(clippy::cargo_common_metadata)] - -use std::vec::Vec; +use std::{cell::Ref, vec::Vec}; use libffi::{low, middle::Type, raw}; use mlua::prelude::*; -use super::association_names::CSTRUCT_INNER; -use super::c_arr::CArr; -use super::c_helper::{pretty_format_userdata, type_list_from_table}; -use super::c_ptr::CPtr; -use crate::ffi::ffi_association::{get_association, set_association}; -use crate::ffi::ffi_helper::FFI_STATUS_NAMES; +use super::{ + association_names::CSTRUCT_INNER, + c_helper::{get_conv_list_from_table, libffi_type_list_from_table, pretty_format_userdata}, + CArr, CPtr, +}; +use crate::ffi::{ + ffi_association::{get_association, set_association}, + FfiBox, GetNativeDataHandle, NativeConvert, NativeDataHandle, NativeSignedness, NativeSize, + FFI_STATUS_NAMES, +}; pub struct CStruct { // libffi_cif: Cif, - fields: Vec, + // fields: Vec, struct_type: Type, offsets: Vec, size: usize, + conv: Vec<*const dyn NativeConvert>, } impl CStruct { - pub fn new(fields: Vec) -> LuaResult { - let struct_type = Type::structure(fields.iter().cloned()); + pub fn new(fields: Vec, conv: Vec<*const dyn NativeConvert>) -> LuaResult { + let len = fields.len(); + let mut offsets = Vec::::with_capacity(len); + let struct_type = Type::structure(fields); + // let struct_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()); + // let mut offsets = Vec::::with_capacity(fields.len()); unsafe { let offset_result: raw::ffi_status = raw::ffi_get_struct_offsets( low::ffi_abi_FFI_DEFAULT_ABI, @@ -48,10 +54,11 @@ impl CStruct { Ok(Self { // libffi_cif: libffi_cfi, - fields, + // fields, struct_type, offsets, size, + conv, }) } @@ -61,8 +68,11 @@ impl CStruct { lua: &'lua Lua, table: LuaTable<'lua>, ) -> LuaResult> { - let fields = type_list_from_table(lua, &table)?; - let cstruct = lua.create_userdata(Self::new(fields)?)?; + let cstruct = lua.create_userdata(Self::new( + libffi_type_list_from_table(lua, &table)?, + unsafe { get_conv_list_from_table(&table)? }, + )?)?; + table.set_readonly(true); set_association(lua, CSTRUCT_INNER, &cstruct, table)?; Ok(cstruct) @@ -71,15 +81,12 @@ impl CStruct { // Stringify cstruct for pretty printing something like: // pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { - let field: LuaValue = userdata.get("inner")?; - if field.is_table() { - let table = field - .as_table() - .ok_or(LuaError::external("failed to get inner type table."))?; - // iterate for field + if let LuaValue::Table(fields) = get_association(lua, CSTRUCT_INNER, userdata)? + .ok_or(LuaError::external("Field table not found"))? + { let mut result = String::from(" "); - for i in 0..table.raw_len() { - let child: LuaAnyUserData = table.raw_get(i + 1)?; + for i in 0..fields.raw_len() { + let child: LuaAnyUserData = fields.raw_get(i + 1)?; result.push_str(pretty_format_userdata(lua, &child)?.as_str()); } @@ -101,20 +108,72 @@ impl CStruct { Ok(offset) } - pub fn get_fields(&self) -> &Vec { - &self.fields - } + // pub fn get_fields(&self) -> &Vec { + // &self.fields + // } pub fn get_type(&self) -> &Type { &self.struct_type } } -impl LuaUserData for CStruct { - fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("size", |_, this| Ok(this.size)); +impl NativeSize for CStruct { + fn get_size(&self) -> usize { + self.size + } +} +impl NativeSignedness for CStruct { + fn get_signedness(&self) -> bool { + false + } +} +impl NativeConvert for CStruct { + // FIXME: FfiBox, FfiRef support required + unsafe fn luavalue_into<'lua>( + &self, + lua: &'lua Lua, + offset: isize, + data_handle: &Ref, + value: LuaValue<'lua>, + ) -> LuaResult<()> { + let LuaValue::Table(ref table) = value else { + return Err(LuaError::external("Value is not a table")); + }; + for (i, conv) in self.conv.iter().enumerate() { + let field_offset = self.offset(i)? as isize; + let data: LuaValue = table.get(i + 1)?; + + conv.as_ref() + .unwrap() + .luavalue_into(lua, field_offset + offset, data_handle, data)?; + } + Ok(()) } + unsafe fn luavalue_from<'lua>( + &self, + lua: &'lua Lua, + offset: isize, + data_handle: &Ref, + ) -> LuaResult> { + let table = lua.create_table_with_capacity(self.conv.len(), 0)?; + for (i, conv) in self.conv.iter().enumerate() { + let field_offset = self.offset(i)? as isize; + table.set( + i + 1, + conv.as_ref() + .unwrap() + .luavalue_from(lua, field_offset + offset, data_handle)?, + )?; + } + Ok(LuaValue::Table(table)) + } +} + +impl LuaUserData for CStruct { + fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("size", |_, this| Ok(this.get_size())); + } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { methods.add_method("offset", |_, this, index: usize| { let offset = this.offset(index)?; @@ -123,17 +182,55 @@ impl LuaUserData for CStruct { // Simply pass type in the locked table used when first creating this object. // By referencing the table to struct, the types inside do not disappear methods.add_function("field", |lua, (this, field): (LuaAnyUserData, usize)| { - if let LuaValue::Table(t) = get_association(lua, CSTRUCT_INNER, this)? + if let LuaValue::Table(fields) = get_association(lua, CSTRUCT_INNER, this)? .ok_or(LuaError::external("Field table not found"))? { - let value: LuaValue = t.get(field + 1)?; + let value: LuaValue = fields.raw_get(field + 1)?; Ok(value) } else { Err(LuaError::external("Failed to read field table")) } }); + methods.add_method("box", |lua, this, table: LuaValue| { + let result = lua.create_userdata(FfiBox::new(this.get_size()))?; + + unsafe { this.luavalue_into(lua, 0, &result.get_data_handle()?, table)? }; + Ok(result) + }); + methods.add_method( + "from", + |lua, this, (userdata, offset): (LuaAnyUserData, Option)| { + let offset = offset.unwrap_or(0); + + let data_handle = &userdata.get_data_handle()?; + if !data_handle.check_boundary(offset, this.get_size()) { + return Err(LuaError::external("Out of bounds")); + } + if !data_handle.check_readable(&userdata, offset, this.get_size()) { + return Err(LuaError::external("Unreadable data handle")); + } + + unsafe { this.luavalue_from(lua, offset, data_handle) } + }, + ); + methods.add_method( + "into", + |lua, this, (userdata, value, offset): (LuaAnyUserData, LuaValue, Option)| { + let offset = offset.unwrap_or(0); + + let data_handle = &userdata.get_data_handle()?; + if !data_handle.check_boundary(offset, this.size) { + return Err(LuaError::external("Out of bounds")); + } + if !data_handle.checek_writable(&userdata, offset, this.size) { + return Err(LuaError::external("Unwritable data handle")); + } + + unsafe { this.luavalue_into(lua, offset, data_handle, value) } + }, + ); methods.add_function("ptr", |lua, this: LuaAnyUserData| { - let pointer = CPtr::from_lua_userdata(lua, &this)?; + let pointer = CPtr::new_from_lua_userdata(lua, &this)?; Ok(pointer) }); methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| { diff --git a/crates/lune-std-ffi/src/c/c_type.rs b/crates/lune-std-ffi/src/c/c_type.rs index 17c6171..6cc763a 100644 --- a/crates/lune-std-ffi/src/c/c_type.rs +++ b/crates/lune-std-ffi/src/c/c_type.rs @@ -1,18 +1,16 @@ -#![allow(clippy::cargo_common_metadata)] +#![allow(clippy::inline_always)] -use std::marker::PhantomData; +use std::{cell::Ref, marker::PhantomData}; use libffi::middle::Type; use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::{ - association_names::CTYPE_STATIC, c_arr::CArr, c_helper::get_ensured_size, c_ptr::CPtr, -}; +use super::{association_names::CTYPE_STATIC, c_helper::get_ensured_size, CArr, CPtr}; use crate::ffi::{ - ffi_association::set_association, - ffi_native::{NativeCast, NativeConvert}, + ffi_association::set_association, native_num_cast, FfiBox, GetNativeDataHandle, NativeConvert, + NativeDataHandle, NativeSignedness, NativeSize, }; // We can't get a CType through mlua, something like @@ -38,6 +36,58 @@ impl CTypeStatic { } impl LuaUserData for CTypeStatic {} +// Cast native data +pub trait CTypeCast { + #[inline(always)] + fn try_cast_num( + &self, + ctype: &LuaAnyUserData, + from: &Ref, + into: &Ref, + ) -> LuaResult> + where + T: AsPrimitive, + U: 'static + Copy, + { + if ctype.is::>() { + native_num_cast::(from, into)?; + Ok(Some(())) + } else { + Ok(None) + } + } + + #[inline(always)] + fn cast( + &self, + from_ctype: &LuaAnyUserData, + into_ctype: &LuaAnyUserData, + _from: &Ref, + _into: &Ref, + ) -> LuaResult<()> { + Err(Self::cast_failed_with(self, from_ctype, into_ctype)) + } + + fn cast_failed_with( + &self, + from_ctype: &LuaAnyUserData, + into_ctype: &LuaAnyUserData, + ) -> LuaError { + let config = ValueFormatConfig::new(); + LuaError::external(format!( + "Cannot cast {} to {}", + pretty_format_value(&LuaValue::UserData(from_ctype.to_owned()), &config), + pretty_format_value(&LuaValue::UserData(into_ctype.to_owned()), &config), + )) + } +} + +impl NativeSize for CType { + fn get_size(&self) -> usize { + self.size + } +} + pub struct CType { // for ffi_ptrarray_to_raw? // libffi_cif: Cif, @@ -49,7 +99,7 @@ pub struct CType { impl CType where T: 'static, - Self: NativeConvert + CTypeCast + CTypeSignedness, + Self: CTypeCast + NativeSignedness + NativeConvert, { pub fn new_with_libffi_type<'lua>( lua: &'lua Lua, @@ -82,101 +132,66 @@ where } } } -impl NativeCast for CType {} - -// Cast native data -pub trait CTypeCast -where - Self: NativeCast, -{ - fn try_cast_num( - &self, - ctype: &LuaAnyUserData, - from: &LuaAnyUserData, - into: &LuaAnyUserData, - ) -> LuaResult> - where - T: AsPrimitive, - U: 'static + Copy, - { - if ctype.is::>() { - Self::cast_num::(self, from, into)?; - Ok(Some(())) - } else { - Ok(None) - } - } - - fn cast( - &self, - from_ctype: &LuaAnyUserData, - into_ctype: &LuaAnyUserData, - from: &LuaAnyUserData, - into: &LuaAnyUserData, - ) -> LuaResult<()> { - Err(Self::cast_failed_with(self, from_ctype, into_ctype)) - } - - fn cast_failed_with( - &self, - from_ctype: &LuaAnyUserData, - into_ctype: &LuaAnyUserData, - ) -> LuaError { - let config = ValueFormatConfig::new(); - LuaError::external(format!( - "Cannot cast {} to {}", - pretty_format_value(&LuaValue::UserData(from_ctype.to_owned()), &config), - pretty_format_value(&LuaValue::UserData(into_ctype.to_owned()), &config), - )) - } -} - -pub trait CTypeSignedness { - fn get_signedness(&self) -> bool { - true - } -} impl LuaUserData for CType where T: 'static, - Self: CTypeCast + CTypeSignedness + NativeCast + NativeConvert, + Self: CTypeCast + NativeSignedness + NativeConvert, { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("size", |_, this| Ok(this.size)); + fields.add_field_method_get("size", |_, this| Ok(this.get_size())); fields.add_meta_field(LuaMetaMethod::Type, "CType"); fields.add_field_method_get("signedness", |_, this| Ok(this.get_signedness())); } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { methods.add_function("ptr", |lua, this: LuaAnyUserData| { - CPtr::from_lua_userdata(lua, &this) + CPtr::new_from_lua_userdata(lua, &this) + }); + methods.add_method("box", |lua, this, value: LuaValue| { + let result = lua.create_userdata(FfiBox::new(this.get_size()))?; + + unsafe { this.luavalue_into(lua, 0, &result.get_data_handle()?, value)? }; + Ok(result) }); methods.add_function( "from", - |lua, - (ctype, userdata, offset): ( - LuaAnyUserData, - LuaAnyUserData, - Option, - )| unsafe { - ctype - .borrow::>()? - .read_userdata(&ctype, lua, &userdata, offset) + |lua, (this, userdata, offset): (LuaAnyUserData, LuaAnyUserData, Option)| { + let ctype = this.borrow::()?; + let offset = offset.unwrap_or(0); + + let data_handle = &userdata.get_data_handle()?; + if !data_handle.check_boundary(offset, ctype.get_size()) { + return Err(LuaError::external("Out of bounds")); + } + if !data_handle.check_readable(&userdata, offset, ctype.get_size()) { + return Err(LuaError::external("Unreadable data handle")); + } + + unsafe { ctype.luavalue_from(lua, offset, data_handle) } }, ); methods.add_function( "into", |lua, - (ctype, value, userdata, offset): ( + (this, userdata, value, offset): ( + LuaAnyUserData, LuaAnyUserData, LuaValue, - LuaAnyUserData, Option, - )| unsafe { - ctype - .borrow::>()? - .write_userdata(&ctype, lua, value, userdata, offset) + )| { + let ctype = this.borrow::()?; + let offset = offset.unwrap_or(0); + + let data_handle = &userdata.get_data_handle()?; + if !data_handle.check_boundary(offset, ctype.get_size()) { + return Err(LuaError::external("Out of bounds")); + } + if !data_handle.checek_writable(&userdata, offset, ctype.get_size()) { + return Err(LuaError::external("Unwritable data handle")); + } + + unsafe { ctype.luavalue_into(lua, offset, data_handle, value) } }, ); methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| { @@ -191,9 +206,12 @@ where LuaAnyUserData, LuaAnyUserData, )| { - from_type - .borrow::()? - .cast(&from_type, &into_type, &from, &into) + from_type.borrow::()?.cast( + &from_type, + &into_type, + &from.get_data_handle()?, + &into.get_data_handle()?, + ) }, ); methods.add_meta_method(LuaMetaMethod::ToString, |lua, this, ()| { diff --git a/crates/lune-std-ffi/src/c/c_void.rs b/crates/lune-std-ffi/src/c/c_void.rs new file mode 100644 index 0000000..e69de29 diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index 7b510d7..34c8044 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -1,15 +1,23 @@ +mod c_arr; +mod c_fn; +pub mod c_helper; +mod c_ptr; +mod c_string; +mod c_struct; +mod c_type; +mod types; + +pub use self::{ + c_arr::CArr, + c_fn::CFn, + c_ptr::CPtr, + c_struct::CStruct, + c_type::{CType, CTypeCast}, +}; + pub use types::create_all_c_types; pub use types::create_all_types; -pub mod c_arr; -pub mod c_fn; -pub mod c_helper; -pub mod c_ptr; -pub mod c_string; -pub mod c_struct; -pub mod c_type; -pub mod types; - // Named registry table names mod association_names { pub const CPTR_INNER: &str = "__cptr_inner"; diff --git a/crates/lune-std-ffi/src/c/types/f32.rs b/crates/lune-std-ffi/src/c/types/f32.rs index 79baa3e..ffe72ef 100644 --- a/crates/lune-std-ffi/src/c/types/f32.rs +++ b/crates/lune-std-ffi/src/c/types/f32.rs @@ -1,23 +1,26 @@ +use std::cell::Ref; + use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::{CType, CTypeSignedness}; -use crate::ffi::ffi_native::NativeConvert; +use super::super::c_type::CType; +use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; -impl CTypeSignedness for CType { +impl NativeSignedness for CType { fn get_signedness(&self) -> bool { true } } impl NativeConvert for CType { - fn luavalue_into_ptr<'lua>( + unsafe fn luavalue_into<'lua>( &self, - _this: &LuaAnyUserData<'lua>, _lua: &'lua Lua, + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, value: LuaValue<'lua>, - ptr: *mut (), ) -> LuaResult<()> { let value: f32 = match value { LuaValue::Integer(t) => t.as_(), @@ -34,17 +37,18 @@ impl NativeConvert for CType { } }; unsafe { - *(ptr.cast::()) = value; + *(data_handle.get_pointer(offset).cast::()) = value; } Ok(()) } - fn ptr_into_luavalue<'lua>( + unsafe fn luavalue_from<'lua>( &self, - _this: &LuaAnyUserData<'lua>, lua: &'lua Lua, - ptr: *mut (), + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; Ok(value) } } diff --git a/crates/lune-std-ffi/src/c/types/f64.rs b/crates/lune-std-ffi/src/c/types/f64.rs index 7dec899..6970c43 100644 --- a/crates/lune-std-ffi/src/c/types/f64.rs +++ b/crates/lune-std-ffi/src/c/types/f64.rs @@ -1,23 +1,26 @@ +use std::cell::Ref; + use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::{CType, CTypeSignedness}; -use crate::ffi::ffi_native::NativeConvert; +use super::super::c_type::CType; +use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; -impl CTypeSignedness for CType { +impl NativeSignedness for CType { fn get_signedness(&self) -> bool { true } } impl NativeConvert for CType { - fn luavalue_into_ptr<'lua>( + unsafe fn luavalue_into<'lua>( &self, - _this: &LuaAnyUserData<'lua>, _lua: &'lua Lua, + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, value: LuaValue<'lua>, - ptr: *mut (), ) -> LuaResult<()> { let value: f64 = match value { LuaValue::Integer(t) => t.as_(), @@ -34,17 +37,18 @@ impl NativeConvert for CType { } }; unsafe { - *(ptr.cast::()) = value; + *(data_handle.get_pointer(offset).cast::()) = value; } Ok(()) } - fn ptr_into_luavalue<'lua>( + unsafe fn luavalue_from<'lua>( &self, - _this: &LuaAnyUserData<'lua>, lua: &'lua Lua, - ptr: *mut (), + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; Ok(value) } } diff --git a/crates/lune-std-ffi/src/c/types/i128.rs b/crates/lune-std-ffi/src/c/types/i128.rs index 8f75d9c..320f673 100644 --- a/crates/lune-std-ffi/src/c/types/i128.rs +++ b/crates/lune-std-ffi/src/c/types/i128.rs @@ -1,23 +1,26 @@ +use std::cell::Ref; + use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::{CType, CTypeSignedness}; -use crate::ffi::ffi_native::NativeConvert; +use super::super::c_type::CType; +use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; -impl CTypeSignedness for CType { +impl NativeSignedness for CType { fn get_signedness(&self) -> bool { true } } impl NativeConvert for CType { - fn luavalue_into_ptr<'lua>( + unsafe fn luavalue_into<'lua>( &self, - _this: &LuaAnyUserData<'lua>, _lua: &'lua Lua, + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, value: LuaValue<'lua>, - ptr: *mut (), ) -> LuaResult<()> { let value: i128 = match value { LuaValue::Integer(t) => t.as_(), @@ -34,17 +37,18 @@ impl NativeConvert for CType { } }; unsafe { - *(ptr.cast::()) = value; + *(data_handle.get_pointer(offset).cast::()) = value; } Ok(()) } - fn ptr_into_luavalue<'lua>( + unsafe fn luavalue_from<'lua>( &self, - _this: &LuaAnyUserData<'lua>, lua: &'lua Lua, - ptr: *mut (), + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; Ok(value) } } diff --git a/crates/lune-std-ffi/src/c/types/i16.rs b/crates/lune-std-ffi/src/c/types/i16.rs index e9a33cc..d3b883f 100644 --- a/crates/lune-std-ffi/src/c/types/i16.rs +++ b/crates/lune-std-ffi/src/c/types/i16.rs @@ -1,23 +1,26 @@ +use std::cell::Ref; + use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::{CType, CTypeSignedness}; -use crate::ffi::ffi_native::NativeConvert; +use super::super::c_type::CType; +use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; -impl CTypeSignedness for CType { +impl NativeSignedness for CType { fn get_signedness(&self) -> bool { true } } impl NativeConvert for CType { - fn luavalue_into_ptr<'lua>( + unsafe fn luavalue_into<'lua>( &self, - _this: &LuaAnyUserData<'lua>, _lua: &'lua Lua, + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, value: LuaValue<'lua>, - ptr: *mut (), ) -> LuaResult<()> { let value: i16 = match value { LuaValue::Integer(t) => t.as_(), @@ -34,17 +37,18 @@ impl NativeConvert for CType { } }; unsafe { - *(ptr.cast::()) = value; + *(data_handle.get_pointer(offset).cast::()) = value; } Ok(()) } - fn ptr_into_luavalue<'lua>( + unsafe fn luavalue_from<'lua>( &self, - _this: &LuaAnyUserData<'lua>, lua: &'lua Lua, - ptr: *mut (), + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; Ok(value) } } @@ -52,6 +56,6 @@ impl NativeConvert for CType { pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { Ok(( "i16", - CType::::new_with_libffi_type(lua, Type::i16(), Some("f32"))?, + CType::::new_with_libffi_type(lua, Type::i16(), Some("i16"))?, )) } diff --git a/crates/lune-std-ffi/src/c/types/i32.rs b/crates/lune-std-ffi/src/c/types/i32.rs index 6478370..b4108c4 100644 --- a/crates/lune-std-ffi/src/c/types/i32.rs +++ b/crates/lune-std-ffi/src/c/types/i32.rs @@ -1,23 +1,26 @@ +use std::cell::Ref; + use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::{CType, CTypeSignedness}; -use crate::ffi::ffi_native::NativeConvert; +use super::super::c_type::CType; +use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; -impl CTypeSignedness for CType { +impl NativeSignedness for CType { fn get_signedness(&self) -> bool { true } } impl NativeConvert for CType { - fn luavalue_into_ptr<'lua>( + unsafe fn luavalue_into<'lua>( &self, - _this: &LuaAnyUserData<'lua>, _lua: &'lua Lua, + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, value: LuaValue<'lua>, - ptr: *mut (), ) -> LuaResult<()> { let value: i32 = match value { LuaValue::Integer(t) => t.as_(), @@ -34,17 +37,18 @@ impl NativeConvert for CType { } }; unsafe { - *(ptr.cast::()) = value; + *(data_handle.get_pointer(offset).cast::()) = value; } Ok(()) } - fn ptr_into_luavalue<'lua>( + unsafe fn luavalue_from<'lua>( &self, - _this: &LuaAnyUserData<'lua>, lua: &'lua Lua, - ptr: *mut (), + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; Ok(value) } } diff --git a/crates/lune-std-ffi/src/c/types/i64.rs b/crates/lune-std-ffi/src/c/types/i64.rs index ff1e228..c553984 100644 --- a/crates/lune-std-ffi/src/c/types/i64.rs +++ b/crates/lune-std-ffi/src/c/types/i64.rs @@ -1,23 +1,26 @@ +use std::cell::Ref; + use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::{CType, CTypeSignedness}; -use crate::ffi::ffi_native::NativeConvert; +use super::super::c_type::CType; +use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; -impl CTypeSignedness for CType { +impl NativeSignedness for CType { fn get_signedness(&self) -> bool { true } } impl NativeConvert for CType { - fn luavalue_into_ptr<'lua>( + unsafe fn luavalue_into<'lua>( &self, - _this: &LuaAnyUserData<'lua>, _lua: &'lua Lua, + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, value: LuaValue<'lua>, - ptr: *mut (), ) -> LuaResult<()> { let value: i64 = match value { LuaValue::Integer(t) => t.as_(), @@ -34,17 +37,18 @@ impl NativeConvert for CType { } }; unsafe { - *(ptr.cast::()) = value; + *(data_handle.get_pointer(offset).cast::()) = value; } Ok(()) } - fn ptr_into_luavalue<'lua>( + unsafe fn luavalue_from<'lua>( &self, - _this: &LuaAnyUserData<'lua>, lua: &'lua Lua, - ptr: *mut (), + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; Ok(value) } } diff --git a/crates/lune-std-ffi/src/c/types/i8.rs b/crates/lune-std-ffi/src/c/types/i8.rs index 0c8cc28..367723e 100644 --- a/crates/lune-std-ffi/src/c/types/i8.rs +++ b/crates/lune-std-ffi/src/c/types/i8.rs @@ -1,23 +1,26 @@ +use std::cell::Ref; + use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::{CType, CTypeSignedness}; -use crate::ffi::ffi_native::NativeConvert; +use super::super::c_type::CType; +use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; -impl CTypeSignedness for CType { +impl NativeSignedness for CType { fn get_signedness(&self) -> bool { true } } impl NativeConvert for CType { - fn luavalue_into_ptr<'lua>( + unsafe fn luavalue_into<'lua>( &self, - _this: &LuaAnyUserData<'lua>, _lua: &'lua Lua, + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, value: LuaValue<'lua>, - ptr: *mut (), ) -> LuaResult<()> { let value: i8 = match value { LuaValue::Integer(t) => t.as_(), @@ -30,17 +33,18 @@ impl NativeConvert for CType { } }; unsafe { - *(ptr.cast::()) = value; + *(data_handle.get_pointer(offset).cast::()) = value; } Ok(()) } - fn ptr_into_luavalue<'lua>( + unsafe fn luavalue_from<'lua>( &self, - _this: &LuaAnyUserData<'lua>, lua: &'lua Lua, - ptr: *mut (), + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; Ok(value) } } diff --git a/crates/lune-std-ffi/src/c/types/isize.rs b/crates/lune-std-ffi/src/c/types/isize.rs index 634d7bf..f7a779a 100644 --- a/crates/lune-std-ffi/src/c/types/isize.rs +++ b/crates/lune-std-ffi/src/c/types/isize.rs @@ -1,23 +1,26 @@ +use std::cell::Ref; + use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::{CType, CTypeSignedness}; -use crate::ffi::ffi_native::NativeConvert; +use super::super::c_type::CType; +use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; -impl CTypeSignedness for CType { +impl NativeSignedness for CType { fn get_signedness(&self) -> bool { true } } impl NativeConvert for CType { - fn luavalue_into_ptr<'lua>( + unsafe fn luavalue_into<'lua>( &self, - _this: &LuaAnyUserData<'lua>, _lua: &'lua Lua, + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, value: LuaValue<'lua>, - ptr: *mut (), ) -> LuaResult<()> { let value: isize = match value { LuaValue::Integer(t) => t.as_(), @@ -34,17 +37,18 @@ impl NativeConvert for CType { } }; unsafe { - *(ptr.cast::()) = value; + *(data_handle.get_pointer(offset).cast::()) = value; } Ok(()) } - fn ptr_into_luavalue<'lua>( + unsafe fn luavalue_from<'lua>( &self, - _this: &LuaAnyUserData<'lua>, lua: &'lua Lua, - ptr: *mut (), + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; Ok(value) } } diff --git a/crates/lune-std-ffi/src/c/types/mod.rs b/crates/lune-std-ffi/src/c/types/mod.rs index a059967..5b8a700 100644 --- a/crates/lune-std-ffi/src/c/types/mod.rs +++ b/crates/lune-std-ffi/src/c/types/mod.rs @@ -1,12 +1,15 @@ +#![allow(clippy::inline_always)] + use core::ffi::*; -use std::any::TypeId; +use std::cell::Ref; +use std::{any::TypeId, ops::Deref}; use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::c_type::CType; -use super::c_type::CTypeCast; +use super::{CType, CTypeCast}; +use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; pub mod f32; pub mod f64; @@ -23,6 +26,14 @@ pub mod u64; pub mod u8; pub mod usize; +macro_rules! cast_nums { + ($T:ident, $self:ident, $from_ctype:ident, $into_ctype:ident, $from:ident, $into:ident, $t:ty, $($c:ty),*) => { + $self + .try_cast_num::<$T, $t>($into_ctype, $from, $into)? + $(.or($self.try_cast_num::<$T, $c>($into_ctype, $from, $into)?))* + .ok_or_else(|| $self.cast_failed_with($from_ctype, $into_ctype)) + }; +} impl CTypeCast for CType where T: AsPrimitive @@ -44,28 +55,25 @@ where &self, from_ctype: &LuaAnyUserData, into_ctype: &LuaAnyUserData, - from: &LuaAnyUserData, - into: &LuaAnyUserData, + from: &Ref, + into: &Ref, ) -> LuaResult<()> { - self.try_cast_num::(into_ctype, from, into)? - .or(self.try_cast_num::(into_ctype, from, into)?) - .or(self.try_cast_num::(into_ctype, from, into)?) - .or(self.try_cast_num::(into_ctype, from, into)?) - .or(self.try_cast_num::(into_ctype, from, into)?) - .or(self.try_cast_num::(into_ctype, from, into)?) - .or(self.try_cast_num::(into_ctype, from, into)?) - .or(self.try_cast_num::(into_ctype, from, into)?) - .or(self.try_cast_num::(into_ctype, from, into)?) - .or(self.try_cast_num::(into_ctype, from, into)?) - .or(self.try_cast_num::(into_ctype, from, into)?) - .or(self.try_cast_num::(into_ctype, from, into)?) - .or(self.try_cast_num::(into_ctype, from, into)?) - .or(self.try_cast_num::(into_ctype, from, into)?) - .ok_or_else(|| self.cast_failed_with(from_ctype, into_ctype)) + cast_nums!( + T, self, into_ctype, from_ctype, from, into, u8, u16, u32, u64, u128, i8, i16, i128, + f32, f64, usize, isize + ) } } // export all default c-types +macro_rules! define_c_types { + ( $lua:ident, $n:expr, $t:ident ) => { + ( + $n, + CType::<$t>::new_with_libffi_type($lua, Type::$t(), Some($n))?, + ) + }; +} pub fn create_all_c_types(lua: &Lua) -> LuaResult> { Ok(vec![ ( @@ -77,51 +85,7 @@ pub fn create_all_c_types(lua: &Lua) -> LuaResult::new_with_libffi_type(lua, Type::c_uchar(), Some("uchar"))?, - ), - ( - "schar", - CType::::new_with_libffi_type(lua, Type::c_schar(), Some("schar"))?, - ), - ( - "short", - CType::::new_with_libffi_type(lua, Type::c_short(), Some("short"))?, - ), - ( - "ushort", - CType::::new_with_libffi_type(lua, Type::c_ushort(), Some("ushort"))?, - ), - ( - "int", - CType::::new_with_libffi_type(lua, Type::c_int(), Some("int"))?, - ), - ( - "uint", - CType::::new_with_libffi_type(lua, Type::c_uint(), Some("uint"))?, - ), - ( - "long", - CType::::new_with_libffi_type(lua, Type::c_long(), Some("long"))?, - ), - ( - "ulong", - CType::::new_with_libffi_type(lua, Type::c_ulong(), Some("ulong"))?, - ), - ( - "longlong", - CType::::new_with_libffi_type(lua, Type::c_longlong(), Some("longlong"))?, - ), - ( - "ulonglong", - CType::::new_with_libffi_type( - lua, - Type::c_ulonglong(), - Some("ulonglong"), + Some("char"), )?, ), ( @@ -132,6 +96,16 @@ pub fn create_all_c_types(lua: &Lua) -> LuaResult::new_with_libffi_type(lua, Type::f64(), Some("double"))?, ), + define_c_types!(lua, "uchar", c_uchar), + define_c_types!(lua, "schar", c_schar), + define_c_types!(lua, "short", c_short), + define_c_types!(lua, "ushort", c_ushort), + define_c_types!(lua, "int", c_int), + define_c_types!(lua, "uint", c_uint), + define_c_types!(lua, "long", c_long), + define_c_types!(lua, "ulong", c_ulong), + define_c_types!(lua, "longlong", c_longlong), + define_c_types!(lua, "ulonglong", c_ulonglong), ]) } @@ -154,3 +128,132 @@ pub fn create_all_types(lua: &Lua) -> LuaResult { + if $t.is::>() { + Ok(size_of::<$f>()) + }$( else if $t.is::>() { + Ok(size_of::<$c>()) + })* else { + Err(LuaError::external("Unexpected type")) + } + }; +} +#[inline(always)] +pub fn ctype_size_from_userdata(this: &LuaAnyUserData) -> LuaResult { + define_ctype_size_from_userdata!( + this, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64 + ) +} + +macro_rules! define_ctype_luavalue_into_ptr { + ($lua:ident, $this:ident, $offset:ident, $data_handle:ident, $value:ident, $f:ty, $( $c:ty ),*) => { + if $this.is::>() { + let ctype = $this.borrow::>()?; + ctype.luavalue_into($lua, $offset, $data_handle, $value) + }$( else if $this.is::>() { + let ctype = $this.borrow::>()?; + ctype.luavalue_into($lua, $offset, $data_handle, $value) + })* else { + Err(LuaError::external("Unexpected type")) + } + }; +} +#[inline(always)] +pub unsafe fn ctype_luavalue_into_ptr<'lua>( + lua: &'lua Lua, + this: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, + value: LuaValue<'lua>, +) -> LuaResult<()> { + define_ctype_luavalue_into_ptr!( + lua, + this, + offset, + data_handle, + value, + u8, + u16, + u32, + u64, + u128, + i8, + i16, + i32, + i64, + i128, + f32, + f64 + ) +} + +macro_rules! define_ctype_luavalue_from_ptr { + ($lua:ident, $this:ident, $offset:ident, $data_handle:ident, $f:ty, $( $c:ty ),*) => { + if $this.is::>() { + $this.borrow::>()?.luavalue_from($lua, $offset, $data_handle) + }$( else if $this.is::>() { + $this.borrow::>()?.luavalue_from($lua, $offset, $data_handle) + })* else { + Err(LuaError::external("Unexpected type")) + } + }; +} +#[inline(always)] +pub unsafe fn ctype_luavalue_from_ptr<'lua>( + lua: &'lua Lua, + this: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, +) -> LuaResult> { + define_ctype_luavalue_from_ptr!( + lua, + this, + offset, + data_handle, + u8, + u16, + u32, + u64, + u128, + i8, + i16, + i32, + i64, + i128, + f32, + f64 + ) +} + +// struct CastCache<'a> { +// conv: &'a [for<'lua> fn(lua: &'lua Lua)], +// ud: Box<[*const dyn NativeConvert]>, +// } + +// fn test<'a>(ud: &'a LuaAnyUserData) -> LuaResult>> { +// Box::new([(ud.to_pointer() as *const CType) as *const dyn NativeConvert]) +// let ff: for<'lua> unsafe fn( +// lua: &'lua Lua, +// type_userdata: &LuaAnyUserData<'lua>, +// offset: isize, +// data_handle: &Ref, +// value: LuaValue<'lua>, +// ) -> LuaResult<()> = || CType::::luavalue_into; +// } + +macro_rules! define_get_ctype_conv { + ($userdata:ident, $f:ty, $( $c:ty ),*) => { + if $userdata.is::>() { + Ok($userdata.to_pointer().cast::>() as *const dyn NativeConvert) + }$( else if $userdata.is::>() { + Ok($userdata.to_pointer().cast::>() as *const dyn NativeConvert) + })* else { + Err(LuaError::external("Unexpected type")) + } + }; +} +pub unsafe fn get_ctype_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn NativeConvert> { + define_get_ctype_conv!(userdata, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64) +} diff --git a/crates/lune-std-ffi/src/c/types/u128.rs b/crates/lune-std-ffi/src/c/types/u128.rs index 80ff621..71e7576 100644 --- a/crates/lune-std-ffi/src/c/types/u128.rs +++ b/crates/lune-std-ffi/src/c/types/u128.rs @@ -1,23 +1,26 @@ +use std::cell::Ref; + use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::{CType, CTypeSignedness}; -use crate::ffi::ffi_native::NativeConvert; +use super::super::c_type::CType; +use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; -impl CTypeSignedness for CType { +impl NativeSignedness for CType { fn get_signedness(&self) -> bool { false } } impl NativeConvert for CType { - fn luavalue_into_ptr<'lua>( + unsafe fn luavalue_into<'lua>( &self, - _this: &LuaAnyUserData<'lua>, _lua: &'lua Lua, + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, value: LuaValue<'lua>, - ptr: *mut (), ) -> LuaResult<()> { let value: u128 = match value { LuaValue::Integer(t) => t.as_(), @@ -34,17 +37,18 @@ impl NativeConvert for CType { } }; unsafe { - *(ptr.cast::()) = value; + *(data_handle.get_pointer(offset).cast::()) = value; } Ok(()) } - fn ptr_into_luavalue<'lua>( + unsafe fn luavalue_from<'lua>( &self, - _this: &LuaAnyUserData<'lua>, lua: &'lua Lua, - ptr: *mut (), + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; Ok(value) } } diff --git a/crates/lune-std-ffi/src/c/types/u16.rs b/crates/lune-std-ffi/src/c/types/u16.rs index b2a172b..4debe03 100644 --- a/crates/lune-std-ffi/src/c/types/u16.rs +++ b/crates/lune-std-ffi/src/c/types/u16.rs @@ -1,11 +1,13 @@ +use std::cell::Ref; + use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::{CType, CTypeSignedness}; -use crate::ffi::ffi_native::NativeConvert; +use super::super::c_type::CType; +use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; -impl CTypeSignedness for CType { +impl NativeSignedness for CType { fn get_signedness(&self) -> bool { false } @@ -13,12 +15,13 @@ impl CTypeSignedness for CType { impl NativeConvert for CType { // Convert luavalue into data, then write into ptr - fn luavalue_into_ptr<'lua>( + unsafe fn luavalue_into<'lua>( &self, - _this: &LuaAnyUserData<'lua>, _lua: &'lua Lua, + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, value: LuaValue<'lua>, - ptr: *mut (), ) -> LuaResult<()> { let value: u16 = match value { LuaValue::Integer(t) => t.as_(), @@ -35,17 +38,18 @@ impl NativeConvert for CType { } }; unsafe { - *(ptr.cast::()) = value; + *(data_handle.get_pointer(offset).cast::()) = value; } Ok(()) } - fn ptr_into_luavalue<'lua>( + unsafe fn luavalue_from<'lua>( &self, - _this: &LuaAnyUserData<'lua>, lua: &'lua Lua, - ptr: *mut (), + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; Ok(value) } } diff --git a/crates/lune-std-ffi/src/c/types/u32.rs b/crates/lune-std-ffi/src/c/types/u32.rs index 3f494c2..6e8e3d4 100644 --- a/crates/lune-std-ffi/src/c/types/u32.rs +++ b/crates/lune-std-ffi/src/c/types/u32.rs @@ -1,23 +1,26 @@ +use std::cell::Ref; + use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::{CType, CTypeSignedness}; -use crate::ffi::ffi_native::NativeConvert; +use super::super::c_type::CType; +use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; -impl CTypeSignedness for CType { +impl NativeSignedness for CType { fn get_signedness(&self) -> bool { false } } impl NativeConvert for CType { - fn luavalue_into_ptr<'lua>( + unsafe fn luavalue_into<'lua>( &self, - _this: &LuaAnyUserData<'lua>, _lua: &'lua Lua, + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, value: LuaValue<'lua>, - ptr: *mut (), ) -> LuaResult<()> { let value: u32 = match value { LuaValue::Integer(t) => t.as_(), @@ -34,17 +37,18 @@ impl NativeConvert for CType { } }; unsafe { - *(ptr.cast::()) = value; + *(data_handle.get_pointer(offset).cast::()) = value; } Ok(()) } - fn ptr_into_luavalue<'lua>( + unsafe fn luavalue_from<'lua>( &self, - _this: &LuaAnyUserData<'lua>, lua: &'lua Lua, - ptr: *mut (), + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; Ok(value) } } diff --git a/crates/lune-std-ffi/src/c/types/u64.rs b/crates/lune-std-ffi/src/c/types/u64.rs index 13cc41a..34972c1 100644 --- a/crates/lune-std-ffi/src/c/types/u64.rs +++ b/crates/lune-std-ffi/src/c/types/u64.rs @@ -1,23 +1,26 @@ +use std::cell::Ref; + use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::{CType, CTypeSignedness}; -use crate::ffi::ffi_native::NativeConvert; +use super::super::c_type::CType; +use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; -impl CTypeSignedness for CType { +impl NativeSignedness for CType { fn get_signedness(&self) -> bool { false } } impl NativeConvert for CType { - fn luavalue_into_ptr<'lua>( + unsafe fn luavalue_into<'lua>( &self, - _this: &LuaAnyUserData<'lua>, _lua: &'lua Lua, + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, value: LuaValue<'lua>, - ptr: *mut (), ) -> LuaResult<()> { let value: u64 = match value { LuaValue::Integer(t) => t.as_(), @@ -34,17 +37,18 @@ impl NativeConvert for CType { } }; unsafe { - *(ptr.cast::()) = value; + *(data_handle.get_pointer(offset).cast::()) = value; } Ok(()) } - fn ptr_into_luavalue<'lua>( + unsafe fn luavalue_from<'lua>( &self, - _this: &LuaAnyUserData<'lua>, lua: &'lua Lua, - ptr: *mut (), + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; Ok(value) } } diff --git a/crates/lune-std-ffi/src/c/types/u8.rs b/crates/lune-std-ffi/src/c/types/u8.rs index 65c81d6..20ac295 100644 --- a/crates/lune-std-ffi/src/c/types/u8.rs +++ b/crates/lune-std-ffi/src/c/types/u8.rs @@ -1,11 +1,13 @@ +use std::cell::Ref; + use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::{CType, CTypeSignedness}; -use crate::ffi::ffi_native::NativeConvert; +use super::super::c_type::CType; +use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; -impl CTypeSignedness for CType { +impl NativeSignedness for CType { fn get_signedness(&self) -> bool { false } @@ -13,12 +15,13 @@ impl CTypeSignedness for CType { impl NativeConvert for CType { // Convert luavalue into data, then write into ptr - fn luavalue_into_ptr<'lua>( + unsafe fn luavalue_into<'lua>( &self, - _this: &LuaAnyUserData<'lua>, _lua: &'lua Lua, + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, value: LuaValue<'lua>, - ptr: *mut (), ) -> LuaResult<()> { let value: u8 = match value { LuaValue::Integer(t) => t.as_(), @@ -31,19 +34,20 @@ impl NativeConvert for CType { } }; unsafe { - *(ptr.cast::()) = value; + *(data_handle.get_pointer(offset).cast::()) = value; } Ok(()) } // Read data from ptr, then convert into luavalue - fn ptr_into_luavalue<'lua>( + unsafe fn luavalue_from<'lua>( &self, - _this: &LuaAnyUserData<'lua>, lua: &'lua Lua, - ptr: *mut (), + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; Ok(value) } } diff --git a/crates/lune-std-ffi/src/c/types/usize.rs b/crates/lune-std-ffi/src/c/types/usize.rs index 8b959d6..063db46 100644 --- a/crates/lune-std-ffi/src/c/types/usize.rs +++ b/crates/lune-std-ffi/src/c/types/usize.rs @@ -1,23 +1,26 @@ +use std::cell::Ref; + use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::{CType, CTypeSignedness}; -use crate::ffi::ffi_native::NativeConvert; +use super::super::c_type::CType; +use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; -impl CTypeSignedness for CType { +impl NativeSignedness for CType { fn get_signedness(&self) -> bool { false } } impl NativeConvert for CType { - fn luavalue_into_ptr<'lua>( + unsafe fn luavalue_into<'lua>( &self, - _this: &LuaAnyUserData<'lua>, _lua: &'lua Lua, + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, value: LuaValue<'lua>, - ptr: *mut (), ) -> LuaResult<()> { let value: usize = match value { LuaValue::Integer(t) => t.as_(), @@ -34,17 +37,18 @@ impl NativeConvert for CType { } }; unsafe { - *(ptr.cast::()) = value; + *(data_handle.get_pointer(offset).cast::()) = value; } Ok(()) } - fn ptr_into_luavalue<'lua>( + unsafe fn luavalue_from<'lua>( &self, - _this: &LuaAnyUserData<'lua>, lua: &'lua Lua, - ptr: *mut (), + // _type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; Ok(value) } } diff --git a/crates/lune-std-ffi/src/ffi/ffi_association.rs b/crates/lune-std-ffi/src/ffi/ffi_association.rs index 6990938..bf1a2cd 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_association.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_association.rs @@ -1,4 +1,4 @@ -#![allow(clippy::cargo_common_metadata)] +#![allow(clippy::inline_always)] use mlua::prelude::*; @@ -29,6 +29,8 @@ use mlua::prelude::*; // 'value' can only hold one value. If you want to keep something else, // use a table with a different name. // You can delete the relationship by changing 'associated' to nil + +#[inline(always)] pub fn set_association<'lua, T, U>( lua: &'lua Lua, regname: &str, @@ -60,6 +62,7 @@ where // returns the Lua value that 'value' keeps. // If there is no table in registry, it returns None. // If there is no value in table, it returns LuaNil. +#[inline(always)] pub fn get_association<'lua, T>( lua: &'lua Lua, regname: &str, diff --git a/crates/lune-std-ffi/src/ffi/ffi_box.rs b/crates/lune-std-ffi/src/ffi/ffi_box.rs index f31a825..7035ff4 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_box.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_box.rs @@ -1,5 +1,3 @@ -#![allow(clippy::cargo_common_metadata)] - use std::boxed::Box; use std::sync::LazyLock; @@ -7,6 +5,7 @@ use mlua::prelude::*; use super::association_names::REF_INNER; use super::ffi_association::set_association; +use super::ffi_native::NativeDataHandle; use super::ffi_ref::{FfiRef, FfiRefBounds, FfiRefFlag, FfiRefFlagList}; static BOX_REF_FLAGS: LazyLock = LazyLock::new(|| { @@ -26,7 +25,15 @@ static BOX_REF_FLAGS: LazyLock = LazyLock::new(|| { // rather, it creates more heap space, so it should be used appropriately // where necessary. -pub struct FfiBox(Box<[u8]>); +struct RefData { + address: usize, + offset: usize, +} + +pub struct FfiBox { + data: Box<[u8]>, + refs: Vec, +} impl FfiBox { // For efficiency, it is initialized non-zeroed. @@ -40,7 +47,10 @@ impl FfiBox { vec_heap.set_len(size); } - Self(vec_heap.into_boxed_slice()) + Self { + data: vec_heap.into_boxed_slice(), + refs: vec![], + } } // pub fn copy(&self, target: &mut FfiBox) {} @@ -48,7 +58,7 @@ impl FfiBox { // Todo: if too big, print as another format pub fn stringify(&self) -> String { let mut buff: String = String::with_capacity(self.size() * 2); - for value in &self.0 { + for value in &self.data { buff.push_str(format!("{:x}", value.to_be()).as_str()); } buff @@ -66,7 +76,7 @@ impl FfiBox { // Calculate offset if let Some(t) = offset { - if !bounds.check(t) { + if !bounds.check_boundary(t) { return Err(LuaError::external(format!( "Offset is out of bounds. box.size: {}. offset got {}", target.size(), @@ -92,17 +102,37 @@ impl FfiBox { // Fill every field with 0 pub fn zero(&mut self) { - self.0.fill(0u8); + self.data.fill(0u8); } // Get size of box pub fn size(&self) -> usize { - self.0.len() + self.data.len() } // Get raw ptr - pub fn get_ptr(&mut self) -> *mut u8 { - self.0.as_mut_ptr() + pub fn get_ptr(&self) -> *mut u8 { + self.data.as_ptr() as *mut u8 + } +} + +impl NativeDataHandle for FfiBox { + fn check_boundary(&self, offset: isize, size: usize) -> bool { + if offset < 0 { + return false; + } + self.size() > ((offset as usize) + size) + } + // FIXME + fn checek_writable(&self, userdata: &LuaAnyUserData, offset: isize, size: usize) -> bool { + true + } + // FIXME + fn check_readable(&self, userdata: &LuaAnyUserData, offset: isize, size: usize) -> bool { + true + } + unsafe fn get_pointer(&self, offset: isize) -> *mut () { + self.get_ptr().byte_offset(offset) as *mut () } } @@ -110,7 +140,6 @@ impl LuaUserData for FfiBox { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { fields.add_field_method_get("size", |_, this| Ok(this.size())); } - fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { // For convenience, :zero returns self. methods.add_function_mut("zero", |_, this: LuaAnyUserData| { diff --git a/crates/lune-std-ffi/src/ffi/ffi_helper.rs b/crates/lune-std-ffi/src/ffi/ffi_helper.rs index 26be508..3288ed5 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_helper.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_helper.rs @@ -1,7 +1,4 @@ -use mlua::prelude::*; - -use super::ffi_box::FfiBox; -use super::ffi_ref::FfiRef; +#![allow(clippy::inline_always)] // Converts ffi status into &str pub const FFI_STATUS_NAMES: [&str; 4] = [ @@ -11,30 +8,6 @@ pub const FFI_STATUS_NAMES: [&str; 4] = [ "ffi_status_FFI_BAD_ARGTYPE", ]; -// TODO: using trait -// Get raw pointer from userdata -// TODO: boundary check -pub unsafe fn get_ptr_from_userdata( - userdata: &LuaAnyUserData, - offset: Option, -) -> LuaResult<*mut ()> { - let ptr = if userdata.is::() { - userdata.borrow_mut::()?.get_ptr().cast() - } else if userdata.is::() { - userdata.borrow::()?.get_ptr() - } else { - return Err(LuaError::external("Unexpected userdata")); - }; - - let ptr = if let Some(t) = offset { - ptr.cast::().offset(t).cast() - } else { - ptr - }; - - Ok(ptr) -} - #[allow(unused)] pub mod bit_mask { pub const U8_MASK1: u8 = 1; diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/cast.rs b/crates/lune-std-ffi/src/ffi/ffi_native/cast.rs index 50bd651..31d7775 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/cast.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/cast.rs @@ -1,24 +1,29 @@ -#![allow(clippy::cargo_common_metadata)] +#![allow(clippy::inline_always)] + +use std::cell::Ref; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::ffi_helper::get_ptr_from_userdata; +use super::NativeDataHandle; -pub trait NativeCast { - // Cast T as U - fn cast_num(&self, from: &LuaAnyUserData, into: &LuaAnyUserData) -> LuaResult<()> - where - T: AsPrimitive, - U: 'static + Copy, - { - let from_ptr = unsafe { get_ptr_from_userdata(from, None)?.cast::() }; - let into_ptr = unsafe { get_ptr_from_userdata(into, None)?.cast::() }; +// Cast T as U - unsafe { - *into_ptr = (*from_ptr).as_(); - } +#[inline(always)] +pub fn native_num_cast( + from: &Ref, + into: &Ref, +) -> LuaResult<()> +where + T: AsPrimitive, + U: 'static + Copy, +{ + let from_ptr = unsafe { from.get_pointer(0).cast::() }; + let into_ptr = unsafe { into.get_pointer(0).cast::() }; - Ok(()) + unsafe { + *into_ptr = (*from_ptr).as_(); } + + Ok(()) } diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/convert.rs b/crates/lune-std-ffi/src/ffi/ffi_native/convert.rs index e3b5d19..7600750 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/convert.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/convert.rs @@ -1,52 +1,29 @@ -#![allow(clippy::cargo_common_metadata)] +#![allow(clippy::inline_always)] + +use std::cell::Ref; use mlua::prelude::*; -use super::super::ffi_helper::get_ptr_from_userdata; +use super::NativeDataHandle; // Handle native data, provide type conversion between luavalue and native types pub trait NativeConvert { // Convert luavalue into data, then write into ptr - fn luavalue_into_ptr<'lua>( + unsafe fn luavalue_into<'lua>( &self, - this: &LuaAnyUserData<'lua>, lua: &'lua Lua, + // type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, value: LuaValue<'lua>, - ptr: *mut (), ) -> LuaResult<()>; // Read data from ptr, then convert into luavalue - fn ptr_into_luavalue<'lua>( + unsafe fn luavalue_from<'lua>( &self, - this: &LuaAnyUserData<'lua>, lua: &'lua Lua, - ptr: *mut (), + // type_userdata: &LuaAnyUserData<'lua>, + offset: isize, + data_handle: &Ref, ) -> LuaResult>; - - // Read data from userdata (such as box or ref) and convert it into luavalue - unsafe fn read_userdata<'lua>( - &self, - this: &LuaAnyUserData<'lua>, - lua: &'lua Lua, - userdata: &LuaAnyUserData<'lua>, - offset: Option, - ) -> LuaResult> { - let ptr = unsafe { get_ptr_from_userdata(userdata, offset)? }; - let value = Self::ptr_into_luavalue(self, this, lua, ptr)?; - Ok(value) - } - - // Write data into userdata (such as box or ref) from luavalue - unsafe fn write_userdata<'lua>( - &self, - this: &LuaAnyUserData<'lua>, - lua: &'lua Lua, - luavalue: LuaValue<'lua>, - userdata: LuaAnyUserData<'lua>, - offset: Option, - ) -> LuaResult<()> { - let ptr = unsafe { get_ptr_from_userdata(&userdata, offset)? }; - Self::luavalue_into_ptr(self, this, lua, luavalue, ptr)?; - Ok(()) - } } diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs b/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs index 16490b5..e083fe5 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs @@ -1,5 +1,18 @@ mod cast; mod convert; +mod readwrite; -pub use self::cast::NativeCast; -pub use self::convert::NativeConvert; +pub trait NativeSize { + fn get_size(&self) -> usize; +} + +pub trait NativeSignedness { + fn get_signedness(&self) -> bool { + false + } +} + +pub use self::{ + cast::native_num_cast, convert::NativeConvert, readwrite::GetNativeDataHandle, + readwrite::NativeDataHandle, +}; diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/readwrite.rs b/crates/lune-std-ffi/src/ffi/ffi_native/readwrite.rs new file mode 100644 index 0000000..a7d98dc --- /dev/null +++ b/crates/lune-std-ffi/src/ffi/ffi_native/readwrite.rs @@ -0,0 +1,40 @@ +use std::cell::Ref; + +use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; +use mlua::prelude::*; + +use super::super::{FfiBox, FfiRef}; + +pub trait NativeDataHandle { + fn check_boundary(&self, offset: isize, size: usize) -> bool; + fn check_readable(&self, userdata: &LuaAnyUserData, offset: isize, size: usize) -> bool; + fn checek_writable(&self, userdata: &LuaAnyUserData, offset: isize, size: usize) -> bool; + unsafe fn get_pointer(&self, offset: isize) -> *mut (); +} + +pub trait GetNativeDataHandle { + fn get_data_handle(&self) -> LuaResult>; +} + +// I tried to remove dyn (which have little bit costs) +// But, maybe this is best option for now. +// If remove dyn, we must spam self.is::<>() / self.borrow::<>()? +// more costly.... +impl GetNativeDataHandle for LuaAnyUserData<'_> { + fn get_data_handle(&self) -> LuaResult> { + if self.is::() { + Ok(self.borrow::()? as Ref) + } else if self.is::() { + Ok(self.borrow::()? as Ref) + // } else if self.is::() { + // Ok(self.borrow::()? as Ref) + } else { + let config = ValueFormatConfig::new(); + Err(LuaError::external(format!( + "Expected FfiBox, FfiRef or FfiRaw. got {}", + // what? + pretty_format_value(&LuaValue::UserData(self.to_owned()), &config) + ))) + } + } +} diff --git a/crates/lune-std-ffi/src/ffi/ffi_raw.rs b/crates/lune-std-ffi/src/ffi/ffi_raw.rs index c32ca76..8348b3d 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_raw.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_raw.rs @@ -9,3 +9,5 @@ // This will help you distinguish between safe operations and // relatively insecure operations, and help ensure that as little // data copy as possible occurs, while allowing you to do little restrictions. + +pub struct FfiRaw(); diff --git a/crates/lune-std-ffi/src/ffi/ffi_ref/bounds.rs b/crates/lune-std-ffi/src/ffi/ffi_ref/bounds.rs index 89c7f21..3e3bd00 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/bounds.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/bounds.rs @@ -21,7 +21,7 @@ impl FfiRefBounds { } // Check boundary - pub fn check(&self, offset: isize) -> bool { + pub fn check_boundary(&self, offset: isize) -> bool { if self.is_unsized() { return true; } @@ -38,16 +38,20 @@ impl FfiRefBounds { } // Check boundary + // Check required here pub fn check_sized(&self, offset: isize, size: usize) -> bool { if self.is_unsized() { return true; } + if offset < 0 && self.above < offset.unsigned_abs() { + return true; + } let end = offset + (size as isize) - 1; - let sign = end.signum(); + let end_sign = end.signum(); let end_abs = end.unsigned_abs(); - if sign == -1 { + if end_sign == -1 { self.above >= end_abs - } else if sign == 1 { + } else if end_sign == 1 { self.below >= end_abs } else { // sign == 0 diff --git a/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs b/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs index faf969e..12055c5 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs @@ -1,4 +1,4 @@ -use super::super::ffi_helper::bit_mask::*; +use super::super::bit_mask::*; pub enum FfiRefFlag { Dereferenceable, diff --git a/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs b/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs index 19aa6f4..1c3cdcb 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs @@ -4,6 +4,7 @@ use mlua::prelude::*; use super::association_names::REF_INNER; use super::ffi_association::{get_association, set_association}; +use super::ffi_native::NativeDataHandle; mod bounds; mod flags; @@ -21,8 +22,8 @@ pub use self::flags::{FfiRefFlag, FfiRefFlagList}; pub struct FfiRef { ptr: *mut (), - flags: FfiRefFlagList, - boundary: FfiRefBounds, + pub flags: FfiRefFlagList, + pub boundary: FfiRefBounds, } impl FfiRef { @@ -97,15 +98,19 @@ impl FfiRef { .ok_or(LuaError::external("This pointer is not offsetable."))?; // Check boundary, if exceed, return error - self.boundary.check(offset).then_some(()).ok_or_else(|| { - LuaError::external(format!( - "Offset is out of bounds. high: {}, low: {}. offset got {}", - self.boundary.above, self.boundary.below, offset - )) - })?; + self.boundary + .check_boundary(offset) + .then_some(()) + .ok_or_else(|| { + LuaError::external(format!( + "Offset is out of bounds. high: {}, low: {}. offset got {}", + self.boundary.above, self.boundary.below, offset + )) + })?; let boundary = self.boundary.offset(offset); + // TODO Ok(Self::new( self.ptr.byte_offset(offset), self.flags.clone(), @@ -114,6 +119,22 @@ impl FfiRef { } } +impl NativeDataHandle for FfiRef { + fn check_boundary(&self, offset: isize, size: usize) -> bool { + self.boundary.check_sized(offset, size) + } + fn checek_writable(&self, userdata: &LuaAnyUserData, offset: isize, size: usize) -> bool { + self.flags.is_writable() + } + // TODO: if ref points box , check box too + fn check_readable(&self, userdata: &LuaAnyUserData, offset: isize, size: usize) -> bool { + self.flags.is_readable() + } + unsafe fn get_pointer(&self, offset: isize) -> *mut () { + self.get_ptr().byte_offset(offset) + } +} + impl LuaUserData for FfiRef { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { methods.add_function("deref", |lua, this: LuaAnyUserData| { diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index c13f88a..5f57be8 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -1,12 +1,49 @@ pub mod ffi_association; -pub mod ffi_box; -pub mod ffi_helper; -pub mod ffi_lib; -pub mod ffi_native; -pub mod ffi_raw; -pub mod ffi_ref; +mod ffi_box; +mod ffi_lib; +mod ffi_native; +mod ffi_raw; +mod ffi_ref; + +pub use self::{ + ffi_box::FfiBox, + ffi_lib::FfiLib, + ffi_native::{ + native_num_cast, GetNativeDataHandle, NativeConvert, NativeDataHandle, NativeSignedness, + NativeSize, + }, + ffi_ref::{create_nullptr, FfiRef}, +}; // Named registry table names mod association_names { pub const REF_INNER: &str = "__ref_inner"; } + +// Converts ffi status into &str +pub const FFI_STATUS_NAMES: [&str; 4] = [ + "ffi_status_FFI_OK", + "ffi_status_FFI_BAD_TYPEDEF", + "ffi_status_FFI_BAD_ABI", + "ffi_status_FFI_BAD_ARGTYPE", +]; + +#[allow(unused)] +pub mod bit_mask { + pub const U8_MASK1: u8 = 1; + pub const U8_MASK2: u8 = 2; + pub const U8_MASK3: u8 = 4; + pub const U8_MASK4: u8 = 8; + pub const U8_MASK5: u8 = 16; + pub const U8_MASK6: u8 = 32; + pub const U8_MASK7: u8 = 64; + pub const U8_MASK8: u8 = 128; + + macro_rules! U8_TEST { + ($val:expr, $mask:ident) => { + ($val & $mask != 0) + }; + } + + pub(crate) use U8_TEST; +} diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs index 36549a9..18b6c24 100644 --- a/crates/lune-std-ffi/src/lib.rs +++ b/crates/lune-std-ffi/src/lib.rs @@ -3,12 +3,14 @@ use lune_utils::TableBuilder; use mlua::prelude::*; -use crate::c::{c_fn::CFn, c_struct::CStruct, create_all_c_types, create_all_types}; -use crate::ffi::{ffi_box::FfiBox, ffi_lib::FfiLib, ffi_ref::create_nullptr}; - mod c; mod ffi; +use crate::{ + c::{create_all_c_types, create_all_types, CFn, CStruct}, + ffi::{create_nullptr, FfiBox, FfiLib}, +}; + /** Creates the `ffi` standard library module. @@ -38,6 +40,7 @@ pub fn module(lua: &Lua) -> LuaResult { #[cfg(debug_assertions)] let result = result.with_function("debug_associate", |lua, str: String| { + println!("WARNING: ffi.debug_associate is GC debug function, which only works for debug build. Do not use this function in production level codes."); crate::ffi::ffi_association::get_table(lua, str.as_ref()) })?;