From 95258e1b514f71b7bce793d627272bda68163659 Mon Sep 17 00:00:00 2001 From: qwreey Date: Wed, 16 Oct 2024 07:57:25 +0000 Subject: [PATCH] Fix pretty-prints for type-define (#243) --- crates/lune-std-ffi/src/c/c_arr.rs | 129 ++++------- .../lune-std-ffi/src/c/{c_fn.rs => c_func.rs} | 84 +++++-- crates/lune-std-ffi/src/c/c_helper.rs | 213 ++++++++++++------ crates/lune-std-ffi/src/c/c_ptr.rs | 76 +++++-- crates/lune-std-ffi/src/c/c_struct.rs | 136 ++++------- crates/lune-std-ffi/src/c/c_type.rs | 102 +++------ crates/lune-std-ffi/src/c/mod.rs | 8 +- crates/lune-std-ffi/src/c/types/mod.rs | 126 ++++++----- .../lune-std-ffi/src/ffi/ffi_association.rs | 8 +- crates/lune-std-ffi/src/ffi/ffi_lib.rs | 26 +-- crates/lune-std-ffi/src/ffi/ffi_raw.rs | 20 -- crates/lune-std-ffi/src/ffi/mod.rs | 1 - crates/lune-std-ffi/src/lib.rs | 6 +- print-ignore-me.luau | 12 + tests/ffi/pretty-print.luau | 29 +++ tests/ffi/ref-hold-box.luau | 15 -- 16 files changed, 507 insertions(+), 484 deletions(-) rename crates/lune-std-ffi/src/c/{c_fn.rs => c_func.rs} (58%) delete mode 100644 crates/lune-std-ffi/src/ffi/ffi_raw.rs create mode 100644 print-ignore-me.luau create mode 100644 tests/ffi/pretty-print.luau delete mode 100644 tests/ffi/ref-hold-box.luau diff --git a/crates/lune-std-ffi/src/c/c_arr.rs b/crates/lune-std-ffi/src/c/c_arr.rs index 0f22de2..9ecefb3 100644 --- a/crates/lune-std-ffi/src/c/c_arr.rs +++ b/crates/lune-std-ffi/src/c/c_arr.rs @@ -3,19 +3,13 @@ use std::cell::Ref; use libffi::middle::Type; use mlua::prelude::*; -use super::{ - association_names::CARR_INNER, - c_helper::{get_conv, libffi_type_from_userdata, pretty_format_userdata}, - CPtr, -}; +use super::{association_names::CARR_INNER, c_helper, method_provider}; use crate::ffi::{ ffi_association::{get_association, set_association}, - FfiBox, GetNativeData, NativeConvert, NativeData, NativeSize, + NativeConvert, NativeData, NativeSize, }; use crate::libffi_helper::get_ensured_size; -// FIXME: unsized array - // This is a series of some type. // It provides the final size and the offset of the index, // but does not allow multidimensional arrays because of API complexity. @@ -26,43 +20,42 @@ use crate::libffi_helper::get_ensured_size; // See: https://stackoverflow.com/a/43525176 pub struct CArr { - // element_type: Type, struct_type: Type, length: usize, - field_size: usize, size: usize, - conv: *const dyn NativeConvert, + inner_size: usize, + inner_conv: *const dyn NativeConvert, } impl CArr { pub fn new( element_type: Type, length: usize, - conv: *const dyn NativeConvert, + inner_conv: *const dyn NativeConvert, ) -> LuaResult { - let field_size = get_ensured_size(element_type.as_raw_ptr())?; + let inner_size = get_ensured_size(element_type.as_raw_ptr())?; let struct_type = Type::structure(vec![element_type.clone(); length]); Ok(Self { // element_type, struct_type, length, - field_size, - size: field_size * length, - conv, + size: inner_size * length, + inner_size, + inner_conv, }) } - pub fn new_from_lua_userdata<'lua>( + pub fn from_userdata<'lua>( lua: &'lua Lua, - luatype: &LuaAnyUserData<'lua>, + type_userdata: &LuaAnyUserData<'lua>, length: usize, ) -> LuaResult> { - let fields = libffi_type_from_userdata(lua, luatype)?; - let conv = unsafe { get_conv(luatype)? }; + let fields = c_helper::get_middle_type(type_userdata)?; + let conv = unsafe { c_helper::get_conv(type_userdata)? }; let carr = lua.create_userdata(Self::new(fields, length, conv)?)?; - set_association(lua, CARR_INNER, &carr, luatype)?; + set_association(lua, CARR_INNER, &carr, type_userdata)?; Ok(carr) } @@ -70,29 +63,21 @@ impl CArr { self.length } - pub fn get_type(&self) -> &Type { - &self.struct_type + pub fn get_type(&self) -> Type { + self.struct_type.clone() } - // pub fn get_element_type(&self) -> &Type { - // &self.element_type - // } - - // Stringify cstruct for pretty printing something like: - // + // Stringify for pretty printing like: + // pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { - let inner: LuaValue = userdata.get("inner")?; - let carr = userdata.borrow::()?; - - if inner.is_userdata() { - let inner = inner - .as_userdata() - .ok_or(LuaError::external("failed to get inner type userdata."))?; - + let this = userdata.borrow::()?; + if let Some(LuaValue::UserData(inner_userdata)) = + get_association(lua, CARR_INNER, userdata)? + { Ok(format!( - "{}*{}", - pretty_format_userdata(lua, inner)?, - carr.length, + " {}, length = {} ", + c_helper::pretty_format(lua, &inner_userdata)?, + this.length, )) } else { Err(LuaError::external("failed to get inner type userdata.")) @@ -118,10 +103,10 @@ impl NativeConvert for CArr { return Err(LuaError::external("Value is not a table")); }; for i in 0..self.length { - let field_offset = (i * self.field_size) as isize; + let field_offset = (i * self.inner_size) as isize; let data: LuaValue = table.get(i + 1)?; - self.conv.as_ref().unwrap().luavalue_into( + self.inner_conv.as_ref().unwrap().luavalue_into( lua, field_offset + offset, data_handle, @@ -139,10 +124,10 @@ impl NativeConvert for CArr { ) -> LuaResult> { let table = lua.create_table_with_capacity(self.length, 0)?; for i in 0..self.length { - let field_offset = (i * self.field_size) as isize; + let field_offset = (i * self.inner_size) as isize; table.set( i + 1, - self.conv.as_ref().unwrap().luavalue_from( + self.inner_conv.as_ref().unwrap().luavalue_from( lua, field_offset + offset, data_handle, @@ -166,55 +151,23 @@ impl LuaUserData for CArr { } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + // Subtype + method_provider::provide_ptr(methods); + + // ToString + method_provider::provide_to_string(methods); + + // Realize + method_provider::provide_box(methods); + method_provider::provide_from(methods); + method_provider::provide_into(methods); + methods.add_method("offset", |_, this, offset: isize| { if this.length > (offset as usize) && offset >= 0 { - Ok(this.field_size * (offset as usize)) + Ok(this.inner_size * (offset as usize)) } else { Err(LuaError::external("Out of index")) } }); - 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")); - } - - 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.is_writable() { - 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::new_from_lua_userdata(lua, &this)?; - Ok(pointer) - }); - methods.add_meta_function(LuaMetaMethod::ToString, |lua, this: LuaAnyUserData| { - let result = CArr::stringify(lua, &this)?; - Ok(result) - }); } } diff --git a/crates/lune-std-ffi/src/c/c_fn.rs b/crates/lune-std-ffi/src/c/c_func.rs similarity index 58% rename from crates/lune-std-ffi/src/c/c_fn.rs rename to crates/lune-std-ffi/src/c/c_func.rs index ef1bc0d..68d8e49 100644 --- a/crates/lune-std-ffi/src/c/c_fn.rs +++ b/crates/lune-std-ffi/src/c/c_func.rs @@ -3,14 +3,15 @@ use std::ptr; use libffi::middle::{Cif, Type}; use mlua::prelude::*; -use super::c_helper::{get_size, get_userdata}; use super::{ association_names::{CALLABLE_CFN, CALLABLE_REF, CFN_ARGS, CFN_RESULT}, - c_helper::{get_conv, libffi_type_from_userdata, libffi_type_list_from_table}, + c_helper, method_provider, }; use crate::ffi::{ - bit_mask::u8_test_not, ffi_association::set_association, FfiCallable, FfiRef, FfiRefFlag, - NativeArgInfo, NativeData, NativeResultInfo, + bit_mask::u8_test_not, + ffi_association::{get_association, set_association}, + FfiCallable, FfiRef, FfiRefFlag, NativeArgInfo, NativeData, NativeResultInfo, NativeSignedness, + NativeSize, }; // cfn is a type declaration for a function. @@ -29,15 +30,24 @@ use crate::ffi::{ // The name cfn is intentional. This is because any *c_void is // moved to a Lua function or vice versa. -pub struct CFn { +pub struct CFunc { cif: Cif, arg_info_list: Vec, result_info: NativeResultInfo, } -// support: Cfn as function pointer +impl NativeSignedness for CFunc { + fn get_signedness(&self) -> bool { + false + } +} +impl NativeSize for CFunc { + fn get_size(&self) -> usize { + size_of::<*mut ()>() + } +} -impl CFn { +impl CFunc { pub fn new( args: Vec, ret: Type, @@ -53,26 +63,26 @@ impl CFn { }) } - pub fn new_from_lua_table<'lua>( + pub fn new_from_table<'lua>( lua: &'lua Lua, arg_table: LuaTable, ret: LuaAnyUserData, ) -> LuaResult> { - let args_types = libffi_type_list_from_table(lua, &arg_table)?; - let ret_type = libffi_type_from_userdata(lua, &ret)?; + let args_types = c_helper::get_middle_type_list(&arg_table)?; + let ret_type = c_helper::get_middle_type(&ret)?; let arg_len = arg_table.raw_len(); let mut arg_info_list = Vec::::with_capacity(arg_len); for index in 0..arg_len { - let userdata = get_userdata(arg_table.raw_get(index + 1)?)?; + let userdata = c_helper::get_userdata(arg_table.raw_get(index + 1)?)?; arg_info_list.push(NativeArgInfo { - conv: unsafe { get_conv(&userdata)? }, - size: get_size(&userdata)?, + conv: unsafe { c_helper::get_conv(&userdata)? }, + size: c_helper::get_size(&userdata)?, }); } let result_info = NativeResultInfo { - conv: unsafe { get_conv(&ret)? }, - size: get_size(&ret)?, + conv: unsafe { c_helper::get_conv(&ret)? }, + size: c_helper::get_size(&ret)?, }; let cfn = @@ -84,17 +94,55 @@ impl CFn { Ok(cfn) } + + // Stringify for pretty printing like: + // u8 )> + pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { + let mut result = String::from(" ("); + if let (Some(LuaValue::Table(arg_table)), Some(LuaValue::UserData(result_userdata))) = ( + get_association(lua, CFN_ARGS, userdata)?, + get_association(lua, CFN_RESULT, userdata)?, + ) { + let len = arg_table.raw_len(); + for arg_index in 1..=len { + let arg_userdata: LuaAnyUserData = arg_table.raw_get(arg_index)?; + let pretty_formatted = c_helper::pretty_format(lua, &arg_userdata)?; + result.push_str( + (if len == arg_index { + pretty_formatted + } else { + format!("{pretty_formatted}, ") + }) + .as_str(), + ); + } + result.push_str( + format!(") -> {} ", c_helper::pretty_format(lua, &result_userdata)?,).as_str(), + ); + Ok(result) + } else { + Err(LuaError::external("failed to get inner type userdata.")) + } + } } -impl LuaUserData for CFn { +impl LuaUserData for CFunc { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + // Subtype + method_provider::provide_ptr(methods); + method_provider::provide_arr(methods); + + // ToString + method_provider::provide_to_string(methods); + + // Realize // methods.add_method("closure", |lua, this, func: LuaFunction| { // lua.create_userdata(FfiClosure::new(this.cif, userdata)) // }) methods.add_function( - "caller", + "callable", |lua, (cfn, function_ref): (LuaAnyUserData, LuaAnyUserData)| { - let this = cfn.borrow::()?; + let this = cfn.borrow::()?; if !function_ref.is::() { return Err(LuaError::external("argument 0 must be ffiref")); diff --git a/crates/lune-std-ffi/src/c/c_helper.rs b/crates/lune-std-ffi/src/c/c_helper.rs index 2db7361..cb03f62 100644 --- a/crates/lune-std-ffi/src/c/c_helper.rs +++ b/crates/lune-std-ffi/src/c/c_helper.rs @@ -1,14 +1,94 @@ -#![allow(clippy::inline_always)] - use libffi::middle::Type; use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; use mlua::prelude::*; -use super::{ - types::{get_ctype_conv, get_ctype_size}, - CArr, CPtr, CStruct, -}; -use crate::ffi::{ffi_association::get_association, NativeConvert, NativeSize}; +use super::{c_type_helper, CArr, CFunc, CPtr, CStruct}; +use crate::ffi::{FfiBox, GetNativeData, NativeConvert, NativeSize}; + +pub mod method_provider { + use super::*; + pub fn provide_to_string<'lua, Target, M>(methods: &mut M) + where + M: LuaUserDataMethods<'lua, Target>, + { + methods.add_meta_function(LuaMetaMethod::ToString, |lua, this: LuaAnyUserData| { + stringify(lua, &this) + }); + } + + pub fn provide_ptr<'lua, Target, M>(methods: &mut M) + where + M: LuaUserDataMethods<'lua, Target>, + { + methods.add_function("ptr", |lua, this: LuaAnyUserData| { + CPtr::from_userdata(lua, &this) + }); + } + + pub fn provide_arr<'lua, Target, M>(methods: &mut M) + where + M: LuaUserDataMethods<'lua, Target>, + { + methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| { + CArr::from_userdata(lua, &this, length) + }); + } + + pub fn provide_from<'lua, Target, M>(methods: &mut M) + where + Target: NativeSize + NativeConvert, + M: LuaUserDataMethods<'lua, Target>, + { + 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")); + } + + unsafe { this.luavalue_from(lua, offset, data_handle) } + }, + ); + } + + pub fn provide_into<'lua, Target, M>(methods: &mut M) + where + Target: NativeSize + NativeConvert, + M: LuaUserDataMethods<'lua, Target>, + { + 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.get_size()) { + return Err(LuaError::external("Out of bounds")); + } + if !data_handle.is_writable() { + return Err(LuaError::external("Unwritable data handle")); + } + + unsafe { this.luavalue_into(lua, offset, data_handle, value) } + }, + ); + } + + pub fn provide_box<'lua, Target, M>(methods: &mut M) + where + Target: NativeSize + NativeConvert, + M: LuaUserDataMethods<'lua, Target>, + { + 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) + }); + } +} pub fn get_userdata(value: LuaValue) -> LuaResult { if let LuaValue::UserData(field_type) = value { @@ -28,14 +108,17 @@ pub fn get_userdata(value: LuaValue) -> LuaResult { pub unsafe fn get_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn NativeConvert> { 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 if userdata.is::() { + Ok(userdata.to_pointer().cast::() as *const dyn NativeConvert) } else { - get_ctype_conv(userdata) + c_type_helper::get_conv(userdata) + // TODO: struct and more } } -pub unsafe fn get_conv_list_from_table( - table: &LuaTable, -) -> LuaResult> { +pub unsafe fn get_conv_list(table: &LuaTable) -> LuaResult> { let len: usize = table.raw_len(); let mut conv_list = Vec::<*const dyn NativeConvert>::with_capacity(len); @@ -52,44 +135,21 @@ pub fn get_size(this: &LuaAnyUserData) -> LuaResult { Ok(this.borrow::()?.get_size()) } else if this.is::() { Ok(this.borrow::()?.get_size()) + } else if this.is::() { + Ok(this.borrow::()?.get_size()) } else { - get_ctype_size(this) + c_type_helper::get_size(this) } } -// 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); - - for i in 0..len { - // Test required - let value = table.raw_get(i + 1)?; - 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() - ))); - } - } - - Ok(fields) -} - // get libffi_type from any c-type userdata -pub fn libffi_type_from_userdata(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { +pub fn get_middle_type(userdata: &LuaAnyUserData) -> LuaResult { if userdata.is::() { - Ok(userdata.borrow::()?.get_type().to_owned()) - } else if let Some(t) = get_association(lua, CTYPE_STATIC, userdata)? { - Ok(t.as_userdata() - .ok_or_else(|| LuaError::external("Failed to get static ctype from userdata"))? - .borrow::()? - .libffi_type - .clone()) + Ok(userdata.borrow::()?.get_type()) + } else if let Some(middle_type) = c_type_helper::get_middle_type(userdata)? { + Ok(middle_type) } else if userdata.is::() { - Ok(userdata.borrow::()?.get_type().to_owned()) + Ok(userdata.borrow::()?.get_type()) } else if userdata.is::() { Ok(CPtr::get_type()) } else { @@ -105,59 +165,70 @@ pub fn libffi_type_from_userdata(lua: &Lua, userdata: &LuaAnyUserData) -> LuaRes } } +// get Vec from table(array) of c-type userdata +pub fn get_middle_type_list(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)?; + if let LuaValue::UserData(field_type) = value { + fields.push(get_middle_type(&field_type)?); + } else { + return Err(LuaError::external(format!( + "Unexpected field. CStruct, CType or CArr is required for element but got {}", + value.type_name() + ))); + } + } + + Ok(fields) +} + // stringify any c-type userdata (for recursive) -pub fn stringify_userdata(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { +pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { if userdata.is::() { - let name = CStruct::stringify(lua, userdata)?; - Ok(name) + CStruct::stringify(lua, userdata) } else if userdata.is::() { - let name = CArr::stringify(lua, userdata)?; - Ok(name) + CArr::stringify(lua, userdata) } else if userdata.is::() { - let name: String = CPtr::stringify(lua, userdata)?; - Ok(name) - // Get CTypeStatic from CType - } else if let Some(t) = get_association(lua, CTYPE_STATIC, userdata)? { - Ok(String::from( - t.as_userdata() - .ok_or_else(|| LuaError::external("Failed to get static ctype from userdata"))? - .borrow::()? - .name - .unwrap_or("unnamed"), - )) + CPtr::stringify(lua, userdata) + } else if userdata.is::() { + CFunc::stringify(lua, userdata) + } else if let Some(name) = c_type_helper::get_name(userdata)? { + Ok(String::from(name)) } else { - Ok(String::from("unnamed")) + Ok(String::from("unknown")) } } // get name tag for any c-type userdata -pub fn tagname_from_userdata(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { +pub fn get_tag_name(userdata: &LuaAnyUserData) -> LuaResult { Ok(if userdata.is::() { String::from("CStruct") } else if userdata.is::() { String::from("CArr") } else if userdata.is::() { String::from("CPtr") - } else if userdata_is_ctype(lua, userdata)? { + } else if userdata.is::() { + String::from("CFunc") + } else if c_type_helper::is_ctype(userdata) { String::from("CType") } else { - String::from("unnamed") + String::from("Unknown") }) } -pub fn userdata_is_ctype(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { - Ok(get_association(lua, CTYPE_STATIC, userdata)?.is_some()) -} - // emulate 'print' for ctype userdata, but ctype is simplified -pub fn pretty_format_userdata(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { - if userdata_is_ctype(lua, userdata)? { - stringify_userdata(lua, userdata) +pub fn pretty_format(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { + if c_type_helper::is_ctype(userdata) { + stringify(lua, userdata) } else { Ok(format!( "<{}({})>", - tagname_from_userdata(lua, userdata)?, - stringify_userdata(lua, userdata)? + get_tag_name(userdata)?, + stringify(lua, userdata)? )) } } diff --git a/crates/lune-std-ffi/src/c/c_ptr.rs b/crates/lune-std-ffi/src/c/c_ptr.rs index 08d9d33..99375b4 100644 --- a/crates/lune-std-ffi/src/c/c_ptr.rs +++ b/crates/lune-std-ffi/src/c/c_ptr.rs @@ -1,15 +1,53 @@ +use std::cell::Ref; + use libffi::middle::Type; use mlua::prelude::*; -use super::{association_names::CPTR_INNER, c_helper::pretty_format_userdata, CArr}; -use crate::ffi::ffi_association::{get_association, set_association}; +use super::{association_names::CPTR_INNER, c_helper, c_type_helper, method_provider}; +use crate::ffi::{ + ffi_association::{get_association, set_association}, + NativeConvert, NativeData, NativeSignedness, NativeSize, +}; pub struct CPtr(); +impl NativeSignedness for CPtr { + fn get_signedness(&self) -> bool { + false + } +} +impl NativeSize for CPtr { + fn get_size(&self) -> usize { + size_of::<*mut ()>() + } +} +impl NativeConvert for CPtr { + // Convert luavalue into data, then write into ptr + unsafe fn luavalue_into<'lua>( + &self, + _lua: &'lua Lua, + _offset: isize, + _data_handle: &Ref, + _value: LuaValue<'lua>, + ) -> LuaResult<()> { + Err(LuaError::external("Conversion of pointer is not allowed")) + } + + // Read data from ptr, then convert into luavalue + unsafe fn luavalue_from<'lua>( + &self, + _lua: &'lua Lua, + _offset: isize, + _data_handle: &Ref, + ) -> LuaResult> { + Err(LuaError::external("Conversion of pointer is not allowed")) + } +} + impl CPtr { // Create pointer type with '.inner' field // inner can be CArr, CType or CStruct - pub fn new_from_lua_userdata<'lua>( + pub fn from_userdata<'lua>( lua: &'lua Lua, inner: &LuaAnyUserData, ) -> LuaResult> { @@ -22,13 +60,13 @@ impl CPtr { // Stringify CPtr with inner ctype pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { - let inner: LuaValue = userdata.get("inner")?; - - if inner.is_userdata() { - let inner = inner - .as_userdata() - .ok_or(LuaError::external("failed to get inner type userdata."))?; - pretty_format_userdata(lua, inner) + if let LuaValue::UserData(inner_userdata) = userdata.get("inner")? { + let pretty_formatted = c_helper::pretty_format(lua, &inner_userdata)?; + Ok(if c_type_helper::is_ctype(&inner_userdata) { + pretty_formatted + } else { + format!(" {pretty_formatted} ") + }) } else { Err(LuaError::external("failed to get inner type userdata.")) } @@ -51,17 +89,11 @@ 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::new_from_lua_userdata(lua, &this)?; - Ok(pointer) - }); - methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| { - let carr = CArr::new_from_lua_userdata(lua, &this, length)?; - Ok(carr) - }); - methods.add_meta_function(LuaMetaMethod::ToString, |lua, this: LuaAnyUserData| { - let name: Result = CPtr::stringify(lua, &this); - Ok(name) - }); + // Subtype + method_provider::provide_ptr(methods); + method_provider::provide_arr(methods); + + // ToString + method_provider::provide_to_string(methods); } } diff --git a/crates/lune-std-ffi/src/c/c_struct.rs b/crates/lune-std-ffi/src/c/c_struct.rs index f34a98e..92e0217 100644 --- a/crates/lune-std-ffi/src/c/c_struct.rs +++ b/crates/lune-std-ffi/src/c/c_struct.rs @@ -3,41 +3,34 @@ use std::{cell::Ref, vec::Vec}; use libffi::{low, middle::Type, raw}; use mlua::prelude::*; -use super::{ - association_names::CSTRUCT_INNER, - c_helper::{get_conv_list_from_table, libffi_type_list_from_table, pretty_format_userdata}, - CArr, CPtr, -}; +use super::{association_names::CSTRUCT_INNER, c_helper, method_provider, CArr, CPtr}; use crate::ffi::{ ffi_association::{get_association, set_association}, - FfiBox, GetNativeData, NativeConvert, NativeData, NativeSignedness, NativeSize, - FFI_STATUS_NAMES, + NativeConvert, NativeData, NativeSignedness, NativeSize, FFI_STATUS_NAMES, }; pub struct CStruct { - // libffi_cif: Cif, - // fields: Vec, - struct_type: Type, - offsets: Vec, + middle_type: Type, size: usize, - conv: Vec<*const dyn NativeConvert>, + inner_offset_list: Vec, + inner_conv_list: Vec<*const dyn NativeConvert>, } impl CStruct { - pub fn new(fields: Vec, conv: Vec<*const dyn NativeConvert>) -> LuaResult { + pub fn new( + fields: Vec, + inner_conv_list: 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()); + let mut inner_offset_list = Vec::::with_capacity(len); + let middle_type = Type::structure(fields); // Get field offsets with ffi_get_struct_offsets - // 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, - struct_type.as_raw_ptr(), - offsets.as_mut_ptr(), + middle_type.as_raw_ptr(), + inner_offset_list.as_mut_ptr(), ); if offset_result != raw::ffi_status_FFI_OK { return Err(LuaError::external(format!( @@ -45,33 +38,31 @@ impl CStruct { FFI_STATUS_NAMES[0], FFI_STATUS_NAMES[offset_result as usize] ))); } - offsets.set_len(offsets.capacity()); + inner_offset_list.set_len(len); } // Get tailing padded size of struct // See http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html - // In here, using get_ensured_size is waste - let size = unsafe { (*struct_type.as_raw_ptr()).size }; + // In here, using get_ensured_size is not required + let size = unsafe { (*middle_type.as_raw_ptr()).size }; Ok(Self { - // libffi_cif: libffi_cfi, - // fields, - struct_type, - offsets, + middle_type, size, - conv, + inner_offset_list, + inner_conv_list, }) } // Create new CStruct UserData with LuaTable. // Lock and hold table for .inner ref - pub fn new_from_lua_table<'lua>( + pub fn new_from_table<'lua>( lua: &'lua Lua, table: LuaTable<'lua>, ) -> LuaResult> { let cstruct = lua.create_userdata(Self::new( - libffi_type_list_from_table(lua, &table)?, - unsafe { get_conv_list_from_table(&table)? }, + c_helper::get_middle_type_list(&table)?, + unsafe { c_helper::get_conv_list(&table)? }, )?)?; table.set_readonly(true); @@ -79,7 +70,7 @@ impl CStruct { Ok(cstruct) } - // Stringify cstruct for pretty printing something like: + // Stringify cstruct for pretty printing like: // pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { if let LuaValue::Table(fields) = get_association(lua, CSTRUCT_INNER, userdata)? @@ -88,7 +79,8 @@ impl CStruct { let mut result = String::from(" "); 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()); + let pretty_formatted = c_helper::pretty_format(lua, &child)?; + result.push_str(format!("{pretty_formatted}, ").as_str()); } // size of @@ -103,19 +95,15 @@ impl CStruct { // Get byte offset of nth field pub fn offset(&self, index: usize) -> LuaResult { let offset = self - .offsets + .inner_offset_list .get(index) .ok_or(LuaError::external("Out of index"))? .to_owned(); Ok(offset) } - // pub fn get_fields(&self) -> &Vec { - // &self.fields - // } - - pub fn get_type(&self) -> &Type { - &self.struct_type + pub fn get_type(&self) -> Type { + self.middle_type.clone() } } @@ -141,7 +129,7 @@ impl NativeConvert for CStruct { let LuaValue::Table(ref table) = value else { return Err(LuaError::external("Value is not a table")); }; - for (i, conv) in self.conv.iter().enumerate() { + for (i, conv) in self.inner_conv_list.iter().enumerate() { let field_offset = self.offset(i)? as isize; let data: LuaValue = table.get(i + 1)?; @@ -158,8 +146,8 @@ impl NativeConvert for CStruct { 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 table = lua.create_table_with_capacity(self.inner_conv_list.len(), 0)?; + for (i, conv) in self.inner_conv_list.iter().enumerate() { let field_offset = self.offset(i)? as isize; table.set( i + 1, @@ -177,6 +165,18 @@ impl LuaUserData for CStruct { fields.add_field_method_get("size", |_, this| Ok(this.get_size())); } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + // Subtype + method_provider::provide_ptr(methods); + method_provider::provide_arr(methods); + + // ToString + method_provider::provide_to_string(methods); + + // Realize + method_provider::provide_box(methods); + method_provider::provide_from(methods); + method_provider::provide_into(methods); + methods.add_method("offset", |_, this, index: usize| { let offset = this.offset(index)?; Ok(offset) @@ -193,55 +193,5 @@ impl LuaUserData for CStruct { 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.is_readable() { - 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.get_size()) { - return Err(LuaError::external("Out of bounds")); - } - if !data_handle.is_writable() { - 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::new_from_lua_userdata(lua, &this)?; - Ok(pointer) - }); - methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| { - let carr = CArr::new_from_lua_userdata(lua, &this, length)?; - Ok(carr) - }); - methods.add_meta_function(LuaMetaMethod::ToString, |lua, this: LuaAnyUserData| { - let result = CStruct::stringify(lua, &this)?; - Ok(result) - }); } } diff --git a/crates/lune-std-ffi/src/c/c_type.rs b/crates/lune-std-ffi/src/c/c_type.rs index 67cfdda..55c8c0b 100644 --- a/crates/lune-std-ffi/src/c/c_type.rs +++ b/crates/lune-std-ffi/src/c/c_type.rs @@ -7,8 +7,11 @@ use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; use mlua::prelude::*; use super::{CArr, CPtr}; -use crate::ffi::{FfiBox, GetNativeData, NativeConvert, NativeData, NativeSignedness, NativeSize}; -use crate::libffi_helper::get_ensured_size; +use crate::{ + c::method_provider, + ffi::{GetNativeData, NativeConvert, NativeData, NativeSignedness, NativeSize}, + libffi_helper::get_ensured_size, +}; // Cast native data pub trait CTypeCast { @@ -38,34 +41,33 @@ pub trait CTypeCast { } } +pub struct CType { + middle_type: Type, + size: usize, + name: &'static str, + _phantom: PhantomData, +} + impl NativeSize for CType { fn get_size(&self) -> usize { self.size } } -pub struct CType { - // for ffi_ptrarray_to_raw? - // libffi_cif: Cif, - libffi_type: Type, - size: usize, - name: Option<&'static str>, - _phantom: PhantomData, -} impl CType where T: 'static, - Self: CTypeCast + NativeSignedness + NativeConvert, + Self: CTypeCast + NativeSignedness + NativeConvert + NativeSize, { pub fn new_with_libffi_type<'lua>( lua: &'lua Lua, libffi_type: Type, - name: Option<&'static str>, + name: &'static str, ) -> LuaResult> { let size = get_ensured_size(libffi_type.as_raw_ptr())?; let ctype = Self { - libffi_type, + middle_type: libffi_type, size, name, _phantom: PhantomData, @@ -75,18 +77,19 @@ where Ok(userdata) } - pub fn stringify(&self) -> &str { - match self.name { - Some(t) => t, - None => "unnamed", - } + pub fn get_name(&self) -> &'static str { + self.name + } + + pub fn get_type(&self) -> Type { + self.middle_type.clone() } } impl LuaUserData for CType where T: 'static, - Self: CTypeCast + NativeSignedness + NativeConvert, + Self: CTypeCast + NativeSignedness + NativeConvert + NativeSize, { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { fields.add_field_method_get("size", |_, this| Ok(this.get_size())); @@ -95,58 +98,18 @@ where } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { - methods.add_function("ptr", |lua, this: LuaAnyUserData| { - 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()))?; + // Subtype + method_provider::provide_ptr(methods); + method_provider::provide_arr(methods); - unsafe { this.luavalue_into(lua, 0, &result.get_data_handle()?, value)? }; - Ok(result) - }); - methods.add_function( - "from", - |lua, (this, userdata, offset): (LuaAnyUserData, LuaAnyUserData, Option)| { - let ctype = this.borrow::()?; - let offset = offset.unwrap_or(0); + // ToString + method_provider::provide_to_string(methods); - 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.is_readable() { - return Err(LuaError::external("Unreadable data handle")); - } + // Realize + method_provider::provide_box(methods); + method_provider::provide_from(methods); + method_provider::provide_into(methods); - unsafe { ctype.luavalue_from(lua, offset, data_handle) } - }, - ); - methods.add_function( - "into", - |lua, - (this, userdata, value, offset): ( - LuaAnyUserData, - LuaAnyUserData, - LuaValue, - 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.is_writable() { - 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)| { - CArr::new_from_lua_userdata(lua, &this, length) - }); methods.add_function( "cast", |_, @@ -164,8 +127,5 @@ where ) }, ); - methods.add_meta_method(LuaMetaMethod::ToString, |lua, this, ()| { - lua.create_string(this.stringify()) - }); } } diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index e99b9c9..75635f7 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -1,5 +1,5 @@ mod c_arr; -mod c_fn; +mod c_func; pub mod c_helper; mod c_ptr; mod c_string; @@ -9,14 +9,14 @@ mod types; pub use self::{ c_arr::CArr, - c_fn::CFn, + c_func::CFunc, + c_helper::method_provider, c_ptr::CPtr, c_struct::CStruct, c_type::{CType, CTypeCast}, + types::{c_type_helper, export_ctypes}, }; -pub use types::export_ctypes; - // Named registry table names mod association_names { pub const CPTR_INNER: &str = "__cptr_inner"; diff --git a/crates/lune-std-ffi/src/c/types/mod.rs b/crates/lune-std-ffi/src/c/types/mod.rs index 87df517..8c8840a 100644 --- a/crates/lune-std-ffi/src/c/types/mod.rs +++ b/crates/lune-std-ffi/src/c/types/mod.rs @@ -30,7 +30,7 @@ macro_rules! create_ctypes { ($lua:ident, $(( $name:expr, $rust_type:ty, $libffi_type:expr ),)* ) => { Ok(vec![$(( $name, - CType::<$rust_type>::new_with_libffi_type($lua, $libffi_type, Some($name))?, + CType::<$rust_type>::new_with_libffi_type($lua, $libffi_type, $name)?, ),)*]) }; } @@ -118,58 +118,80 @@ where } } -// To prevent drop NativeConvert, we must use ffi_association to ensure children keep alive -macro_rules! define_get_conv { - ($userdata:ident, $( $rust_type:ty )*) => { - $( if $userdata.is::>() { - Ok($userdata.to_pointer().cast::>() as *const dyn NativeConvert) - } else )* { - Err(LuaError::external("Unexpected type")) - } - }; -} -pub fn get_ctype_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn NativeConvert> { - define_get_conv!(userdata, u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize) -} +pub mod c_type_helper { + use super::*; -// Get size of ctype (not includes struct, arr, ... only CType<*>) -macro_rules! define_get_size { - ($userdata:ident, $( $rust_type:ty )*) => { - $( if $userdata.is::>() { - Ok($userdata.borrow::>()?.get_size()) - } else )* { - Err(LuaError::external("Unexpected type")) - } - }; -} -pub fn get_ctype_size(userdata: &LuaAnyUserData) -> LuaResult { - define_get_size!(userdata, u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize) -} + // To prevent drop NativeConvert, we must use ffi_association to ensure children keep alive + macro_rules! define_get_conv { + ($userdata:ident, $( $rust_type:ty )*) => { + $( if $userdata.is::>() { + Ok($userdata.to_pointer().cast::>() as *const dyn NativeConvert) + } else )* { + Err(LuaError::external("Unexpected type")) + } + }; + } + #[inline] + pub fn get_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn NativeConvert> { + define_get_conv!(userdata, u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize) + } -// Get name of ctype -macro_rules! define_get_name { - ($userdata:ident, $( $rust_type:ty )*) => { - $( if $userdata.is::>() { - Ok($userdata.borrow::>()?.stringify()) - } else )* { - Err(LuaError::external("Unexpected type")) - } - }; -} -pub fn get_ctype_name(userdata: &LuaAnyUserData) -> LuaResult<&str> { - define_get_name!(userdata, u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize) -} + // Get size of ctype (not includes struct, arr, ... only CType<*>) + macro_rules! define_get_size { + ($userdata:ident, $( $rust_type:ty )*) => { + $( if $userdata.is::>() { + Ok($userdata.borrow::>()?.get_size()) + } else )* { + Err(LuaError::external("Unexpected type")) + } + }; + } + #[inline] + pub fn get_size(userdata: &LuaAnyUserData) -> LuaResult { + define_get_size!(userdata, u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize) + } -// Get libffi_type of ctype -macro_rules! define_get_libffi_type { - ($userdata:ident, $( $rust_type:ty )*) => { - $( if $userdata.is::>() { - Ok($userdata.borrow::>()?.get_size()) - } else )* { - Err(LuaError::external("Unexpected type")) - } - }; -} -pub fn get_ctype_libffi_type(userdata: &LuaAnyUserData) -> LuaResult { - define_get_libffi_type!(userdata, u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize) + // Get name of ctype + macro_rules! define_get_name { + ($userdata:ident, $( $rust_type:ty )*) => { + $( if $userdata.is::>() { + Ok(Some($userdata.borrow::>()?.get_name())) + } else )* { + Ok(None) + } + }; + } + #[inline] + pub fn get_name(userdata: &LuaAnyUserData) -> LuaResult> { + define_get_name!(userdata, u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize) + } + + // Get libffi_type of ctype + macro_rules! define_get_middle_type { + ($userdata:ident, $( $rust_type:ty )*) => { + $( if $userdata.is::>() { + Ok(Some($userdata.borrow::>()?.get_type())) + } else )* { + Ok(None) + } + }; + } + #[inline] + pub fn get_middle_type(userdata: &LuaAnyUserData) -> LuaResult> { + define_get_middle_type!(userdata, u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize) + } + + macro_rules! define_is_ctype { + ($userdata:ident, $( $rust_type:ty )*) => { + $( if $userdata.is::>() { + true + } else )* { + false + } + }; + } + #[inline] + pub fn is_ctype(userdata: &LuaAnyUserData) -> bool { + define_is_ctype!(userdata, u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize) + } } diff --git a/crates/lune-std-ffi/src/ffi/ffi_association.rs b/crates/lune-std-ffi/src/ffi/ffi_association.rs index bf1a2cd..be15a65 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_association.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_association.rs @@ -1,5 +1,3 @@ -#![allow(clippy::inline_always)] - use mlua::prelude::*; // This is a small library that helps you set the dependencies of data in Lua. @@ -30,7 +28,7 @@ use mlua::prelude::*; // use a table with a different name. // You can delete the relationship by changing 'associated' to nil -#[inline(always)] +#[inline] pub fn set_association<'lua, T, U>( lua: &'lua Lua, regname: &str, @@ -62,7 +60,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)] +#[inline] pub fn get_association<'lua, T>( lua: &'lua Lua, regname: &str, @@ -81,7 +79,7 @@ where // Allows reading of registry tables for debugging. // This helps keep track of data being gc'd. // However, for security and safety reasons, -// this will not be allowed unless it is a debug build. +// this will not be allowed unless debug build. #[cfg(debug_assertions)] pub fn get_table<'lua>(lua: &'lua Lua, regname: &str) -> LuaResult>> { match lua.named_registry_value::(regname)? { diff --git a/crates/lune-std-ffi/src/ffi/ffi_lib.rs b/crates/lune-std-ffi/src/ffi/ffi_lib.rs index 87d81bd..b071257 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_lib.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_lib.rs @@ -1,5 +1,3 @@ -use core::ffi::c_void; - use dlopen2::raw::Library; use mlua::prelude::*; @@ -16,15 +14,6 @@ const LIB_REF_FLAGS: u8 = FfiRefFlag::Offsetable.value() pub struct FfiLib(Library); -// COMMENT HERE -// For convenience, it would be nice to provide a way to get -// symbols from a table with type and field names specified. -// But right now, we are starting from the lowest level, so we will make it later. - -// I wanted to provide something like cdef, -// but that is beyond the scope of lune's support. -// Higher-level bindings for convenience are much preferable written in Lua. - impl FfiLib { pub fn new(libname: String) -> LuaResult { match Library::open(libname) { @@ -41,21 +30,16 @@ impl FfiLib { let lib = this.borrow::()?; let sym = unsafe { lib.0 - .symbol::<*const c_void>(name.as_str()) + .symbol::<*const ()>(name.as_str()) .map_err(|err| LuaError::external(format!("{err}")))? }; - let ptr = sym.cast::<()>().cast_mut(); - // unsafe { - // let f = transmute::<*mut (), unsafe extern "C" fn(i32, i32) -> i32>(ptr); - // dbg!(f(1, 2)); - // } + let ffi_ref = + lua.create_userdata(FfiRef::new(sym.cast_mut(), LIB_REF_FLAGS, UNSIZED_BOUNDS))?; - let luasym = lua.create_userdata(FfiRef::new(ptr, LIB_REF_FLAGS, UNSIZED_BOUNDS))?; + set_association(lua, SYM_INNER, &ffi_ref, &this)?; - set_association(lua, SYM_INNER, &luasym, &this)?; - - Ok(luasym) + Ok(ffi_ref) } } diff --git a/crates/lune-std-ffi/src/ffi/ffi_raw.rs b/crates/lune-std-ffi/src/ffi/ffi_raw.rs deleted file mode 100644 index 8e98677..0000000 --- a/crates/lune-std-ffi/src/ffi/ffi_raw.rs +++ /dev/null @@ -1,20 +0,0 @@ -use mlua::prelude::*; - -// This is raw data coming from outside. -// Users must convert it to a Lua value, reference, or box to use it. -// The biggest reason for providing this is to allow the user to -// decide whether to move the data to a heap that Lua can manage (box), -// move it directly to Lua's data, or think of it as a pointer. -// 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(*const ()); - -impl FfiRaw { - pub fn new(pointer: *const ()) -> Self { - Self(pointer) - } -} - -impl LuaUserData for FfiRaw {} diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index 50dd8f8..ef4ae64 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -4,7 +4,6 @@ mod ffi_callable; mod ffi_closure; mod ffi_lib; mod ffi_native; -mod ffi_raw; mod ffi_ref; use mlua::prelude::*; diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs index d2f593a..661f073 100644 --- a/crates/lune-std-ffi/src/lib.rs +++ b/crates/lune-std-ffi/src/lib.rs @@ -9,7 +9,7 @@ mod ffi; mod libffi_helper; use crate::{ - c::{export_ctypes, CFn, CStruct}, + c::{export_ctypes, CFunc, CStruct}, ffi::{create_nullptr, is_integer, FfiBox, FfiLib}, }; @@ -27,13 +27,13 @@ pub fn module(lua: &Lua) -> LuaResult { .with_function("box", |_lua, size: usize| Ok(FfiBox::new(size)))? .with_function("open", |_lua, name: String| FfiLib::new(name))? .with_function("structInfo", |lua, types: LuaTable| { - CStruct::new_from_lua_table(lua, types) + CStruct::new_from_table(lua, types) })? .with_function("uninitRef", |_lua, ()| Ok(FfiRef::new_uninit()))? .with_function("isInteger", |_lua, num: LuaValue| Ok(is_integer(num)))? .with_function( "funcInfo", - |lua, (args, ret): (LuaTable, LuaAnyUserData)| CFn::new_from_lua_table(lua, args, ret), + |lua, (args, ret): (LuaTable, LuaAnyUserData)| CFunc::new_from_table(lua, args, ret), )?; #[cfg(debug_assertions)] diff --git a/print-ignore-me.luau b/print-ignore-me.luau new file mode 100644 index 0000000..3686c9e --- /dev/null +++ b/print-ignore-me.luau @@ -0,0 +1,12 @@ +local ffi = require("@lune/ffi") + +print(ffi.int) +print(ffi.int:ptr()) +print(ffi.int:arr(5):ptr()) +print(ffi.int:arr(5)) + +print(ffi.funcInfo({ ffi.int }, ffi.int)) +print(ffi.funcInfo({ ffi.int, ffi.double }, ffi.int:ptr())) +print(ffi.funcInfo({ ffi.int, ffi.double }, ffi.int:ptr():ptr())) + +print(ffi.structInfo({ ffi.int, ffi.char })) diff --git a/tests/ffi/pretty-print.luau b/tests/ffi/pretty-print.luau new file mode 100644 index 0000000..7e92e32 --- /dev/null +++ b/tests/ffi/pretty-print.luau @@ -0,0 +1,29 @@ +local ffi = require("@lune/ffi") + +assert(typeof(ffi.int) == "CType") +assert(tostring(ffi.int) == "int") + +assert(typeof(ffi.int:ptr()) == "CPtr") +assert(tostring(ffi.int:ptr()) == "int") +assert(tostring(ffi.int:arr(5):ptr()) == " ") + +assert(typeof(ffi.int:arr(5)) == "CArr") +assert(tostring(ffi.int:arr(5)) == " int, length = 5 ") +assert(tostring(ffi.int:ptr():arr(5)) == " , length = 5 ") + +assert(typeof(ffi.funcInfo({ ffi.int }, ffi.int)) == "CFunc") +assert(tostring(ffi.funcInfo({ ffi.int }, ffi.int)) == " (int) -> int ") +assert(tostring(ffi.funcInfo({ ffi.int, ffi.double }, ffi.int)) == " (int, double) -> int ") +assert(tostring(ffi.funcInfo({ ffi.int:ptr() }, ffi.int)) == " () -> int ") +assert(tostring(ffi.funcInfo({ ffi.int }, ffi.int:ptr())) == " (int) -> ") +assert(tostring(ffi.funcInfo({ ffi.int:ptr() }, ffi.int:ptr())) == " () -> ") +assert( + tostring(ffi.funcInfo({ ffi.int:ptr(), ffi.int:ptr() }, ffi.int:ptr())) + == " (, ) -> " +) + +assert(typeof(ffi.structInfo({ ffi.int, ffi.char })) == "CStruct") +assert( + tostring(ffi.structInfo({ ffi.int, ffi.char:ptr() })) + == ` int, , size = {ffi.structInfo({ ffi.int, ffi.char:ptr() }).size} ` +) diff --git a/tests/ffi/ref-hold-box.luau b/tests/ffi/ref-hold-box.luau deleted file mode 100644 index f6f1490..0000000 --- a/tests/ffi/ref-hold-box.luau +++ /dev/null @@ -1,15 +0,0 @@ ---!nocheck ---!nolint - -local ffi = require("@lune/ffi") -local box = ffi.box(ffi.i32.size) -local ref = box:ref() - -local wt = setmetatable({}, { __mode = "v" }) - -wt[1] = box -box = nll - -collectgarbage("collect") - -assert(wt[1] ~= nil, "ref hold box failed")