diff --git a/crates/lune-std-ffi/src/c/c_fn.rs b/crates/lune-std-ffi/src/c/c_fn.rs index c1877a6b..dd6e2fcb 100644 --- a/crates/lune-std-ffi/src/c/c_fn.rs +++ b/crates/lune-std-ffi/src/c/c_fn.rs @@ -1,10 +1,13 @@ +use libffi::low::ffi_cif; use libffi::middle::{Cif, Type}; use mlua::prelude::*; use super::c_helper::{ get_conv, get_conv_list_from_table, libffi_type_from_userdata, libffi_type_list_from_table, }; -use crate::ffi::NativeConvert; +use crate::ffi::{ + FfiClosure, NativeArgInfo, NativeArgType, NativeConvert, NativeResultInfo, NativeResultType, +}; // cfn is a type declaration for a function. // Basically, when calling an external function, this type declaration @@ -23,41 +26,52 @@ use crate::ffi::NativeConvert; // moved to a Lua function or vice versa. pub struct CFn { - libffi_cif: Cif, - args_conv: Vec<*const dyn NativeConvert>, - ret_conv: *const dyn NativeConvert, + cif: *mut ffi_cif, + arg_info_list: Vec, + result_info: NativeResultInfo, } +// support: Cfn as function pointer + impl CFn { pub fn new( args: Vec, ret: Type, - args_conv: Vec<*const dyn NativeConvert>, - ret_conv: *const dyn NativeConvert, + arg_info_list: Vec, + result_info: NativeResultInfo, ) -> Self { - let libffi_cif: Cif = Cif::new(args.clone(), ret.clone()); Self { - libffi_cif, - args_conv, - ret_conv, + cif: Cif::new(args.clone(), ret.clone()).as_raw_ptr(), + arg_info_list, + result_info, } } pub fn new_from_lua_table(lua: &Lua, args: LuaTable, ret: LuaAnyUserData) -> LuaResult { - let args_type = libffi_type_list_from_table(lua, &args)?; + let args_types = libffi_type_list_from_table(lua, &args)?; let ret_type = libffi_type_from_userdata(lua, &ret)?; - Ok(Self::new( - args_type, - ret_type, - unsafe { get_conv_list_from_table(&args)? }, - unsafe { get_conv(&ret)? }, - )) + let len = args.raw_len(); + let mut arg_info_list = Vec::::with_capacity(len); + + for conv in unsafe { get_conv_list_from_table(&args)? } { + arg_info_list.push(NativeArgInfo { conv }) + } + + // get_conv_list_from_table(&args)?.iter().map(|conv| { + // conv.to_owned() + // }).collect() + + Ok(Self::new(args_types, ret_type, unsafe {}, unsafe { + get_conv(&ret)? + })) } } impl LuaUserData for CFn { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { - // methods.add_method("from", | this, |) + methods.add_method("closure", |lua, this, func: LuaFunction| { + lua.create_userdata(FfiClosure::new(this.cif, userdata)) + }) } } diff --git a/crates/lune-std-ffi/src/c/c_helper.rs b/crates/lune-std-ffi/src/c/c_helper.rs index 3338c727..f4a2e186 100644 --- a/crates/lune-std-ffi/src/c/c_helper.rs +++ b/crates/lune-std-ffi/src/c/c_helper.rs @@ -9,7 +9,9 @@ use mlua::prelude::*; use super::{ association_names::CTYPE_STATIC, types::get_ctype_conv, CArr, CPtr, CStruct, CTypeStatic, }; -use crate::ffi::{ffi_association::get_association, NativeConvert, FFI_STATUS_NAMES}; +use crate::ffi::{ + ffi_association::get_association, NativeConvert, NativeSignedness, NativeSize, FFI_STATUS_NAMES, +}; // Get the NativeConvert handle from the type UserData // this is intended to avoid lookup userdata and lua table every time. (eg: struct) @@ -22,6 +24,7 @@ pub unsafe fn get_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn Native unsafe { get_ctype_conv(userdata) } } } + pub unsafe fn get_conv_list_from_table( table: &LuaTable, ) -> LuaResult> { @@ -55,7 +58,7 @@ pub unsafe fn get_conv_list_from_table( // } // } -// get Vec from table(array) of c-types userdata +// get Vec from table(array) of c-type userdata 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); @@ -82,9 +85,7 @@ pub fn libffi_type_from_userdata(lua: &Lua, userdata: &LuaAnyUserData) -> LuaRes Ok(userdata.borrow::()?.get_type().to_owned()) } else if let Some(t) = get_association(lua, CTYPE_STATIC, userdata)? { Ok(t.as_userdata() - .ok_or(LuaError::external( - "Failed to get static ctype from userdata", - ))? + .ok_or_else(|| LuaError::external("Failed to get static ctype from userdata"))? .borrow::()? .libffi_type .clone()) @@ -120,9 +121,7 @@ pub fn stringify_userdata(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult()? .name .unwrap_or("unnamed"), diff --git a/crates/lune-std-ffi/src/c/c_struct.rs b/crates/lune-std-ffi/src/c/c_struct.rs index ff51b44e..f34a98ec 100644 --- a/crates/lune-std-ffi/src/c/c_struct.rs +++ b/crates/lune-std-ffi/src/c/c_struct.rs @@ -208,7 +208,7 @@ impl LuaUserData for CStruct { if !data_handle.check_boundary(offset, this.get_size()) { return Err(LuaError::external("Out of bounds")); } - if !data_handle.check_readable(offset, this.get_size()) { + if !data_handle.is_readable() { return Err(LuaError::external("Unreadable data handle")); } @@ -224,7 +224,7 @@ impl LuaUserData for CStruct { if !data_handle.check_boundary(offset, this.get_size()) { return Err(LuaError::external("Out of bounds")); } - if !data_handle.checek_writable(offset, this.get_size()) { + if !data_handle.is_writable() { return Err(LuaError::external("Unwritable data handle")); } diff --git a/crates/lune-std-ffi/src/c/c_type.rs b/crates/lune-std-ffi/src/c/c_type.rs index bf1ff458..98ab565c 100644 --- a/crates/lune-std-ffi/src/c/c_type.rs +++ b/crates/lune-std-ffi/src/c/c_type.rs @@ -164,7 +164,7 @@ where if !data_handle.check_boundary(offset, ctype.get_size()) { return Err(LuaError::external("Out of bounds")); } - if !data_handle.check_readable(offset, ctype.get_size()) { + if !data_handle.is_readable() { return Err(LuaError::external("Unreadable data handle")); } @@ -187,7 +187,7 @@ where if !data_handle.check_boundary(offset, ctype.get_size()) { return Err(LuaError::external("Out of bounds")); } - if !data_handle.checek_writable(offset, ctype.get_size()) { + if !data_handle.is_writable() { return Err(LuaError::external("Unwritable data handle")); } diff --git a/crates/lune-std-ffi/src/ffi/ffi_box/flag.rs b/crates/lune-std-ffi/src/ffi/ffi_box/flag.rs index 34e712f5..dfb4757d 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_box/flag.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_box/flag.rs @@ -1,14 +1,12 @@ use super::super::bit_mask::*; pub enum FfiBoxFlag { - Dropped, Leaked, } impl FfiBoxFlag { pub const fn value(&self) -> u8 { match self { - Self::Dropped => U8_MASK1, Self::Leaked => U8_MASK2, } } diff --git a/crates/lune-std-ffi/src/ffi/ffi_box/mod.rs b/crates/lune-std-ffi/src/ffi/ffi_box/mod.rs index 6e61eeca..9832455f 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_box/mod.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_box/mod.rs @@ -6,7 +6,7 @@ use super::{ association_names::REF_INNER, bit_mask::*, ffi_association::set_association, - ffi_ref::{FfiRef, FfiRefBounds, FfiRefFlag, FfiRefFlagList}, + ffi_ref::{FfiRef, FfiRefBounds, FfiRefFlag}, NativeData, }; @@ -14,15 +14,9 @@ mod flag; pub use self::flag::FfiBoxFlag; -const BOX_REF_FLAGS: FfiRefFlagList = FfiRefFlagList::new( - FfiRefFlag::Offsetable.value() | FfiRefFlag::Readable.value() | FfiRefFlag::Writable.value(), -); -const BOX_MUT_REF_FLAGS: FfiRefFlagList = FfiRefFlagList::new( - FfiRefFlag::Offsetable.value() - | FfiRefFlag::Readable.value() - | FfiRefFlag::Writable.value() - | FfiRefFlag::Mutable.value(), -); +// Ref which created by lua should not be dereferenceable, +const BOX_REF_FLAGS: u8 = + FfiRefFlag::Readable.value() | FfiRefFlag::Writable.value() | FfiRefFlag::Offsetable.value(); // It is an untyped, sized memory area that Lua can manage. // This area is safe within Lua. Operations have their boundaries checked. @@ -143,6 +137,12 @@ impl NativeData for FfiBox { .cast_mut() .cast::<()>() } + fn is_readable(&self) -> bool { + true + } + fn is_writable(&self) -> bool { + true + } } impl LuaUserData for FfiBox { diff --git a/crates/lune-std-ffi/src/ffi/ffi_callable.rs b/crates/lune-std-ffi/src/ffi/ffi_callable.rs new file mode 100644 index 00000000..b9752e8c --- /dev/null +++ b/crates/lune-std-ffi/src/ffi/ffi_callable.rs @@ -0,0 +1,109 @@ +use core::ffi::c_void; +use std::cell::Ref; +// use std::ptr; + +use libffi::{ + // low::{closure_alloc, ffi_cif, CodePtr, RawCallback}, + low::{ffi_cif, CodePtr}, + // middle::Cif, + // raw::ffi_prep_closure_loc, +}; +use mlua::prelude::*; + +use super::{ + bit_mask::u8_test_not, ffi_native::NativeArgInfo, FfiRef, FfiRefFlag, GetNativeData, + NativeConvert, NativeData, +}; + +// unsafe extern "C" fn callback() { +// _cif: ffi_cif, +// result: &mut +// } + +// pub type RawCallback = unsafe extern "C" fn(cif: *mut ffi_cif, result: *mut c_void, args: *mut *mut c_void, userdata: *mut c_void); +// pub unsafe extern "C" fn ffi_prep_raw_closure( +// arg1: *mut ffi_raw_closure, +// cif: *mut ffi_cif, +// fun: Option, +// user_data: *mut c_void +// ) -> u32 + +// pub fn ffi_prep_raw_closure_loc( +// arg1: *mut ffi_raw_closure, +// cif: *mut ffi_cif, +// fun: Option< +// unsafe extern "C" fn( +// arg1: *mut ffi_cif, +// arg2: *mut c_void, +// arg3: *mut ffi_raw, +// arg4: *mut c_void, +// ), +// >, +// user_data: *mut c_void, +// codeloc: *mut c_void, +// ) -> ffi_status; + +pub struct FfiCallable { + cif: *mut ffi_cif, + arg_type_list: Vec, + result_size: usize, + code: CodePtr, +} + +impl FfiCallable { + pub unsafe fn new( + cif: *mut ffi_cif, + arg_type_list: Vec, + result_size: usize, + function_ref: FfiRef, + ) -> LuaResult { + if u8_test_not(function_ref.flags, FfiRefFlag::Function.value()) { + return Err(LuaError::external("ref is not function pointer")); + } + Ok(Self { + cif, + arg_type_list, + result_size, + code: CodePtr::from_ptr(function_ref.get_pointer(0).cast::()), + }) + } + + pub unsafe fn call(&self, result: &Ref, args: LuaMultiValue) -> LuaResult<()> { + result + .check_boundary(0, self.result_size) + .then_some(()) + .ok_or_else(|| LuaError::external("result boundary check failed")) + } + // pub fn new_from_lua_table(lua: &Lua, args: LuaTable, ret: LuaAnyUserData) -> LuaResult { + // let args_types = libffi_type_list_from_table(lua, &args)?; + // let ret_type = libffi_type_from_userdata(lua, &ret)?; + + // Ok(Self::new( + // args_types, + // ret_type, + // unsafe { get_conv_list_from_table(&args)? }, + // unsafe { get_conv(&ret)? }, + // )) + // } + // pub fn call() { + + // } +} + +impl LuaUserData for FfiCallable { + fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_method( + "call", + |_lua, this: &FfiCallable, mut args: LuaMultiValue| { + let LuaValue::UserData(result) = args.pop_front().ok_or_else(|| { + LuaError::external("first argument must be result data handle") + })? + else { + return Err(LuaError::external("")); + }; + let call_result = unsafe { this.call(&result.get_data_handle()?, args) }; + call_result + }, + ) + } +} diff --git a/crates/lune-std-ffi/src/ffi/ffi_closure.rs b/crates/lune-std-ffi/src/ffi/ffi_closure.rs new file mode 100644 index 00000000..7afca469 --- /dev/null +++ b/crates/lune-std-ffi/src/ffi/ffi_closure.rs @@ -0,0 +1,106 @@ +use core::ffi::c_void; +use std::ptr; + +use libffi::{ + low::{closure_alloc, closure_free, ffi_cif, CodePtr}, + raw::{ffi_closure, ffi_prep_closure_loc}, +}; +use mlua::prelude::*; + +use super::{ + ffi_ref::{FfiRefBounds, FfiRefFlag}, + FfiRef, FFI_STATUS_NAMES, +}; + +pub struct FfiClosure<'a> { + closure: *mut ffi_closure, + code: CodePtr, + userdata: CallbackUserdata<'a>, +} + +impl<'a> Drop for FfiClosure<'a> { + fn drop(&mut self) { + unsafe { + closure_free(self.closure); + } + } +} + +#[allow(unused)] +pub struct CallbackUserdata<'a> { + pub func: LuaFunction<'a>, + pub lua: &'a Lua, + pub arg_ref_flags: Vec, + pub arg_ref_size: Vec, + pub result_size: usize, +} + +const RESULT_REF_FLAGS: u8 = FfiRefFlag::Leaked.value() | FfiRefFlag::Writable.value(); + +unsafe extern "C" fn callback( + cif: *mut ffi_cif, + result_pointer: *mut c_void, + arg_pointers: *mut *mut c_void, + userdata: *mut c_void, +) { + let userdata = userdata.cast::(); + let len = (*cif).nargs as usize; + let mut args = Vec::::with_capacity(len + 1); + + // Push result pointer (ref) + args.push(LuaValue::UserData( + (*userdata) + .lua + .create_userdata(FfiRef::new( + result_pointer.cast::<()>(), + RESULT_REF_FLAGS, + FfiRefBounds::new(0, (*userdata).result_size), + )) + .unwrap(), + )); + + // Push arg pointer (ref) + for i in 0..len { + args.push(LuaValue::UserData( + (*userdata) + .lua + .create_userdata(FfiRef::new( + (*arg_pointers.add(i)).cast::<()>(), + (*userdata).arg_ref_flags.get(i).unwrap().to_owned(), + FfiRefBounds::new(0, (*userdata).arg_ref_size.get(i).unwrap().to_owned()), + )) + .unwrap(), + )); + } + + (*userdata).func.call::<_, ()>(args).unwrap(); +} + +impl<'a> FfiClosure<'a> { + pub unsafe fn new( + cif: *mut ffi_cif, + userdata: CallbackUserdata<'a>, + ) -> LuaResult> { + let (closure, code) = closure_alloc(); + let prep_result = ffi_prep_closure_loc( + closure, + cif, + Some(callback), + ptr::from_ref(&userdata).cast::().cast_mut(), + code.as_mut_ptr(), + ); + + if prep_result != 0 { + Err(LuaError::external(format!( + "ffi_get_struct_offsets failed. expected result {}, got {}", + FFI_STATUS_NAMES[0], FFI_STATUS_NAMES[prep_result as usize] + ))) + } else { + Ok(FfiClosure { + closure, + code, + userdata, + }) + } + } +} diff --git a/crates/lune-std-ffi/src/ffi/ffi_lib.rs b/crates/lune-std-ffi/src/ffi/ffi_lib.rs index 4d924621..8bc0524d 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_lib.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_lib.rs @@ -6,15 +6,13 @@ use mlua::prelude::*; use super::{ association_names::SYM_INNER, ffi_association::set_association, - ffi_ref::{FfiRef, FfiRefFlag, FfiRefFlagList, UNSIZED_BOUNDS}, + ffi_ref::{FfiRef, FfiRefFlag, UNSIZED_BOUNDS}, }; -const LIB_REF_FLAGS: FfiRefFlagList = FfiRefFlagList::new( - FfiRefFlag::Offsetable.value() - | FfiRefFlag::Readable.value() - | FfiRefFlag::Dereferenceable.value() - | FfiRefFlag::Function.value(), -); +const LIB_REF_FLAGS: u8 = FfiRefFlag::Offsetable.value() + | FfiRefFlag::Readable.value() + | FfiRefFlag::Dereferenceable.value() + | FfiRefFlag::Function.value(); pub struct FfiLib(Library); diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/arg.rs b/crates/lune-std-ffi/src/ffi/ffi_native/arg.rs new file mode 100644 index 00000000..c324f2dd --- /dev/null +++ b/crates/lune-std-ffi/src/ffi/ffi_native/arg.rs @@ -0,0 +1,15 @@ +use super::NativeConvert; + +pub struct FfiArgRefOption { + pub flag: u8, +} + +pub enum NativeArgType { + FfiBox, + FfiRef(FfiArgRefOption), +} + +pub struct NativeArgInfo { + pub conv: *const dyn NativeConvert, + pub kind: NativeArgType, +} diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/call.rs b/crates/lune-std-ffi/src/ffi/ffi_native/call.rs deleted file mode 100644 index 164bfbc0..00000000 --- a/crates/lune-std-ffi/src/ffi/ffi_native/call.rs +++ /dev/null @@ -1,19 +0,0 @@ -use std::cell::Ref; - -use mlua::prelude::*; - -use super::NativeData; - -// Handle native data, provide type conversion between luavalue and native types -pub trait NativeCall { - // Call native function - unsafe fn call_native( - &self, - lua: &Lua, - arg: LuaMultiValue, - ret: &Ref, - ) -> LuaResult<()>; - - // Call lua closure - unsafe fn call_lua(&self, lua: &Lua, arg: LuaMultiValue, ret: *mut ()) -> LuaResult<()>; -} 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 073b0802..2629a8a3 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/convert.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/convert.rs @@ -4,15 +4,17 @@ use std::cell::Ref; use mlua::prelude::*; -use super::NativeData; +use super::{NativeData, NativeSize}; // Handle native data, provide type conversion between luavalue and native types -pub trait NativeConvert { +pub trait NativeConvert +where + Self: NativeSize, +{ // Convert luavalue into data, then write into ptr unsafe fn luavalue_into<'lua>( &self, lua: &'lua Lua, - // type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, value: LuaValue<'lua>, @@ -22,7 +24,6 @@ pub trait NativeConvert { unsafe fn luavalue_from<'lua>( &self, lua: &'lua Lua, - // type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult>; diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/data.rs b/crates/lune-std-ffi/src/ffi/ffi_native/data.rs index 471eb506..513ab937 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/data.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/data.rs @@ -8,6 +8,8 @@ use super::super::{FfiBox, FfiRef}; pub trait NativeData { fn check_boundary(&self, offset: isize, size: usize) -> bool; unsafe fn get_pointer(&self, offset: isize) -> *mut (); + fn is_writable(&self) -> bool; + fn is_readable(&self) -> bool; } pub trait GetNativeData { 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 af7ac725..c835deb0 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs @@ -1,7 +1,8 @@ -mod call; +mod arg; mod cast; mod convert; mod data; +mod result; pub trait NativeSize { fn get_size(&self) -> usize; @@ -14,6 +15,7 @@ pub trait NativeSignedness { } pub use self::{ - call::NativeCall, cast::native_num_cast, convert::NativeConvert, data::GetNativeData, - data::NativeData, + arg::FfiArgRefOption, arg::NativeArgInfo, arg::NativeArgType, cast::native_num_cast, + convert::NativeConvert, data::GetNativeData, data::NativeData, result::NativeResultInfo, + result::NativeResultType, }; diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/result.rs b/crates/lune-std-ffi/src/ffi/ffi_native/result.rs new file mode 100644 index 00000000..b25995fb --- /dev/null +++ b/crates/lune-std-ffi/src/ffi/ffi_native/result.rs @@ -0,0 +1,11 @@ +use super::NativeConvert; + +pub enum NativeResultType { + FfiBox, + FfiRef, +} + +pub struct NativeResultInfo { + conv: *const dyn NativeConvert, + kind: NativeResultType, +} diff --git a/crates/lune-std-ffi/src/ffi/ffi_raw.rs b/crates/lune-std-ffi/src/ffi/ffi_raw.rs index 2827ffc0..8e986774 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_raw.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_raw.rs @@ -1,5 +1,4 @@ -// use core::ffi::c_void; -// use std::{convert, mem::transmute, ptr}; +use mlua::prelude::*; // This is raw data coming from outside. // Users must convert it to a Lua value, reference, or box to use it. @@ -11,3 +10,11 @@ // data copy as possible occurs, while allowing you to do little restrictions. pub struct FfiRaw(*const ()); + +impl FfiRaw { + pub fn new(pointer: *const ()) -> Self { + Self(pointer) + } +} + +impl LuaUserData for 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 3e3bd004..1df4b2bc 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/bounds.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/bounds.rs @@ -1,3 +1,5 @@ +use std::clone; + // Memory range for ref or box data. For boundary checking pub struct FfiRefBounds { // Indicates how much data is above the pointer @@ -87,3 +89,12 @@ impl FfiRefBounds { } } } + +impl Clone for FfiRefBounds { + fn clone(&self) -> Self { + Self { + above: self.above, + below: self.below, + } + } +} diff --git a/crates/lune-std-ffi/src/ffi/ffi_ref/flag.rs b/crates/lune-std-ffi/src/ffi/ffi_ref/flag.rs new file mode 100644 index 00000000..5dd4ec12 --- /dev/null +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/flag.rs @@ -0,0 +1,24 @@ +use super::super::bit_mask::*; + +pub enum FfiRefFlag { + Leaked, + Dereferenceable, + Readable, + Writable, + Offsetable, + Function, + Uninit, +} +impl FfiRefFlag { + pub const fn value(&self) -> u8 { + match self { + Self::Leaked => U8_MASK1, + Self::Dereferenceable => U8_MASK2, + Self::Writable => U8_MASK3, + Self::Readable => U8_MASK4, + Self::Offsetable => U8_MASK5, + Self::Function => U8_MASK6, + Self::Uninit => U8_MASK7, + } + } +} diff --git a/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs b/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs deleted file mode 100644 index b1dbfdee..00000000 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs +++ /dev/null @@ -1,84 +0,0 @@ -use super::super::bit_mask::*; - -pub enum FfiRefFlag { - // Dereferenceable, - // Readable, - // Writable, - // Offsetable, - // Function, - // Mutable, -} -impl FfiRefFlag { - pub const fn value(&self) -> u8 { - match self { - Self::Dereferenceable => U8_MASK1, - Self::Readable => U8_MASK2, - Self::Writable => U8_MASK3, - Self::Offsetable => U8_MASK4, - Self::Function => U8_MASK5, - Self::Mutable => U8_MASK6, - } - } -} - -pub struct FfiRefFlagList(u8); -#[allow(unused)] -impl FfiRefFlagList { - pub const fn zero() -> Self { - Self(0) - } - pub const fn new(flags: u8) -> Self { - Self(flags) - } - pub const fn all() -> Self { - Self( - FfiRefFlag::Dereferenceable.value() - | FfiRefFlag::Readable.value() - | FfiRefFlag::Writable.value() - | FfiRefFlag::Offsetable.value() - | FfiRefFlag::Function.value(), - ) - } - fn set(&mut self, value: bool, mask: u8) { - if value { - self.0 |= mask; - } else { - self.0 &= !mask; - } - } - pub fn is_dereferenceable(&self) -> bool { - U8_TEST!(self.0, FfiRefFlag::Dereferenceable.value()) - } - pub fn set_dereferenceable(&mut self, value: bool) { - self.set(value, FfiRefFlag::Dereferenceable.value()); - } - pub fn is_readable(&self) -> bool { - U8_TEST!(self.0, FfiRefFlag::Readable.value()) - } - pub fn set_readable(&mut self, value: bool) { - self.set(value, FfiRefFlag::Readable.value()); - } - pub fn is_writable(&self) -> bool { - U8_TEST!(self.0, FfiRefFlag::Writable.value()) - } - pub fn set_writable(&mut self, value: bool) { - self.set(value, FfiRefFlag::Writable.value()); - } - pub fn is_offsetable(&self) -> bool { - U8_TEST!(self.0, FfiRefFlag::Offsetable.value()) - } - pub fn set_offsetable(&mut self, value: bool) { - self.set(value, FfiRefFlag::Offsetable.value()); - } - pub fn is_mutable(&self) -> bool { - U8_TEST!(self.0, FfiRefFlag::Mutable.value()) - } - pub fn set_mutable(&mut self, value: bool) { - self.set(value, FfiRefFlag::Mutable.value()); - } -} -impl Clone for FfiRefFlagList { - fn clone(&self) -> Self { - Self(self.0) - } -} 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 d65178f7..d0a54042 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs @@ -4,20 +4,21 @@ use mlua::prelude::*; use super::{ association_names::REF_INNER, + bit_mask::u8_test, ffi_association::{get_association, set_association}, NativeData, }; mod bounds; -mod flags; +mod flag; pub use self::{ bounds::{FfiRefBounds, UNSIZED_BOUNDS}, - flags::{FfiRefFlag, FfiRefFlagList}, + flag::FfiRefFlag, }; // Box:ref():ref() should not be able to modify, Only for external -const BOX_REF_REF_FLAGS: FfiRefFlagList = FfiRefFlagList::zero(); +const BOX_REF_REF_FLAGS: u8 = 0; // 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 @@ -27,12 +28,12 @@ const BOX_REF_REF_FLAGS: FfiRefFlagList = FfiRefFlagList::zero(); pub struct FfiRef { ptr: *mut (), - pub flags: FfiRefFlagList, + pub flags: u8, pub boundary: FfiRefBounds, } impl FfiRef { - pub fn new(ptr: *mut (), flags: FfiRefFlagList, boundary: FfiRefBounds) -> Self { + pub fn new(ptr: *mut (), flags: u8, boundary: FfiRefBounds) -> Self { Self { ptr, flags, @@ -40,6 +41,14 @@ impl FfiRef { } } + pub fn new_uninit() -> Self { + Self { + ptr: ptr::null_mut(), + flags: FfiRefFlag::Uninit.value(), + boundary: UNSIZED_BOUNDS, + } + } + // Make FfiRef from ref pub fn luaref<'lua>( lua: &'lua Lua, @@ -63,8 +72,7 @@ impl FfiRef { } pub unsafe fn deref(&self) -> LuaResult { - self.flags - .is_dereferenceable() + u8_test(self.flags, FfiRefFlag::Dereferenceable.value()) .then_some(()) .ok_or(LuaError::external("This pointer is not dereferenceable."))?; @@ -78,7 +86,7 @@ impl FfiRef { // FIXME flags Ok(Self::new( *self.ptr.cast::<*mut ()>(), - self.flags.clone(), + self.flags, UNSIZED_BOUNDS, )) } @@ -88,8 +96,7 @@ impl FfiRef { } pub unsafe fn offset(&self, offset: isize) -> LuaResult { - self.flags - .is_offsetable() + u8_test(self.flags, FfiRefFlag::Offsetable.value()) .then_some(()) .ok_or(LuaError::external("This pointer is not offsetable."))?; @@ -109,7 +116,7 @@ impl FfiRef { // TODO Ok(Self::new( self.ptr.byte_offset(offset), - self.flags.clone(), + self.flags, boundary, )) } @@ -122,6 +129,12 @@ impl NativeData for FfiRef { unsafe fn get_pointer(&self, offset: isize) -> *mut () { self.ptr.byte_offset(offset) } + fn is_readable(&self) -> bool { + u8_test(self.flags, FfiRefFlag::Readable.value()) + } + fn is_writable(&self) -> bool { + u8_test(self.flags, FfiRefFlag::Writable.value()) + } } impl LuaUserData for FfiRef { @@ -161,7 +174,7 @@ pub fn create_nullptr(lua: &Lua) -> LuaResult { // https://en.cppreference.com/w/cpp/types/nullptr_t lua.create_userdata(FfiRef::new( ptr::null_mut::<()>().cast(), - FfiRefFlagList::zero(), + 0, // usize::MAX means that nullptr is can be 'any' pointer type // We check size of inner data. give ffi.box(1):ref() as argument which typed as i32:ptr() will fail, // throw lua error diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index 97687e0f..4196bcee 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -1,5 +1,7 @@ pub mod ffi_association; mod ffi_box; +mod ffi_callable; +mod ffi_closure; mod ffi_lib; mod ffi_native; mod ffi_raw; @@ -9,11 +11,16 @@ use mlua::prelude::*; pub use self::{ ffi_box::FfiBox, + ffi_callable::FfiCallable, + ffi_closure::FfiClosure, ffi_lib::FfiLib, ffi_native::{ - native_num_cast, GetNativeData, NativeConvert, NativeData, NativeSignedness, NativeSize, + native_num_cast, FfiArgRefOption, GetNativeData, NativeArgInfo, NativeArgType, + NativeConvert, NativeData, NativeResultInfo, NativeResultType, NativeSignedness, + NativeSize, }, - ffi_ref::{create_nullptr, FfiRef}, + ffi_raw::FfiRaw, + ffi_ref::{create_nullptr, FfiRef, FfiRefFlag}, }; // Named registry table names @@ -41,14 +48,17 @@ pub mod bit_mask { pub const U8_MASK7: u8 = 64; pub const U8_MASK8: u8 = 128; + #[inline] pub fn u8_test(bits: u8, mask: u8) -> bool { bits & mask != 0 } + #[inline] pub fn u8_test_not(bits: u8, mask: u8) -> bool { bits & mask == 0 } + #[inline] pub fn u8_set(bits: u8, mask: u8, val: bool) -> u8 { if val { bits | mask @@ -58,6 +68,7 @@ pub mod bit_mask { } } +#[inline] pub fn is_integer(num: LuaValue) -> bool { num.is_integer() } diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs index ad1aad06..9df4bd7a 100644 --- a/crates/lune-std-ffi/src/lib.rs +++ b/crates/lune-std-ffi/src/lib.rs @@ -1,5 +1,6 @@ #![allow(clippy::cargo_common_metadata)] +use ffi::FfiRef; use lune_utils::TableBuilder; use mlua::prelude::*; @@ -23,20 +24,15 @@ pub fn module(lua: &Lua) -> LuaResult { .with_values(create_all_types(lua)?)? .with_values(create_all_c_types(lua)?)? .with_value("nullptr", create_nullptr(lua)?)? - .with_function("box", |_, size: usize| Ok(FfiBox::new(size)))? - // TODO: discuss about function name. matching with io.open is better? - .with_function("open", |_, name: String| { - let lib = FfiLib::new(name)?; - Ok(lib) - })? + .with_function("box", |_lua, size: usize| Ok(FfiBox::new(size)))? + .with_function("open", |_lua, name: String| FfiLib::new(name))? .with_function("struct", |lua, types: LuaTable| { - let cstruct = CStruct::new_from_lua_table(lua, types)?; - Ok(cstruct) + CStruct::new_from_lua_table(lua, types) })? + .with_function("ref", |_lua, ()| Ok(FfiRef::new_uninit()))? .with_function("isInteger", |_lua, num: LuaValue| Ok(is_integer(num)))? .with_function("fn", |lua, (args, ret): (LuaTable, LuaAnyUserData)| { - let cfn = CFn::new_from_lua_table(lua, args, ret)?; - Ok(cfn) + CFn::new_from_lua_table(lua, args, ret) })?; #[cfg(debug_assertions)]