From af08c59e3bcb4e54e1fe24047587ae284b4daa9e Mon Sep 17 00:00:00 2001 From: qwreey Date: Thu, 22 Aug 2024 01:30:21 +0900 Subject: [PATCH 01/79] Add lune-std-ffi crate (#243) --- .vscode/settings.json | 4 + Cargo.lock | 54 +++++++ Cargo.toml | 1 + crates/lune-std-ffi/Cargo.toml | 22 +++ crates/lune-std-ffi/readme.md | 129 ++++++++++++++++ crates/lune-std-ffi/src/association.rs | 84 ++++++++++ crates/lune-std-ffi/src/carr.rs | 24 +++ crates/lune-std-ffi/src/cfn.rs | 45 ++++++ crates/lune-std-ffi/src/cstring.rs | 6 + crates/lune-std-ffi/src/cstruct.rs | 127 ++++++++++++++++ crates/lune-std-ffi/src/ctype.rs | 203 +++++++++++++++++++++++++ crates/lune-std-ffi/src/ffibox.rs | 85 +++++++++++ crates/lune-std-ffi/src/ffilib.rs | 57 +++++++ crates/lune-std-ffi/src/ffiraw.rs | 8 + crates/lune-std-ffi/src/ffiref.rs | 59 +++++++ crates/lune-std-ffi/src/lib.rs | 56 +++++++ crates/lune-std-ffi/todo.md | 102 +++++++++++++ crates/lune-std/Cargo.toml | 3 + crates/lune-std/src/library.rs | 7 +- crates/lune/Cargo.toml | 2 + tests/ffi/ptr.luau | 33 ++++ tests/ffi/struct.luau | 2 + types/ffi.luau | 79 ++++++++++ 23 files changed, 1191 insertions(+), 1 deletion(-) create mode 100644 crates/lune-std-ffi/Cargo.toml create mode 100644 crates/lune-std-ffi/readme.md create mode 100644 crates/lune-std-ffi/src/association.rs create mode 100644 crates/lune-std-ffi/src/carr.rs create mode 100644 crates/lune-std-ffi/src/cfn.rs create mode 100644 crates/lune-std-ffi/src/cstring.rs create mode 100644 crates/lune-std-ffi/src/cstruct.rs create mode 100644 crates/lune-std-ffi/src/ctype.rs create mode 100644 crates/lune-std-ffi/src/ffibox.rs create mode 100644 crates/lune-std-ffi/src/ffilib.rs create mode 100644 crates/lune-std-ffi/src/ffiraw.rs create mode 100644 crates/lune-std-ffi/src/ffiref.rs create mode 100644 crates/lune-std-ffi/src/lib.rs create mode 100644 crates/lune-std-ffi/todo.md create mode 100644 tests/ffi/ptr.luau create mode 100644 tests/ffi/struct.luau create mode 100644 types/ffi.luau diff --git a/.vscode/settings.json b/.vscode/settings.json index 95c90cf6..39405698 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -23,5 +23,9 @@ }, "[rust]": { "editor.defaultFormatter": "rust-lang.rust-analyzer" + }, + "files.associations": { + "*.inc": "c", + "random": "c" } } diff --git a/Cargo.lock b/Cargo.lock index 734320ac..4e4b6545 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -786,6 +786,29 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "dlopen2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bc2c7ed06fd72a8513ded8d0d2f6fd2655a85d6885c48cae8625d80faf28c03" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "dunce" version = "1.0.5" @@ -1426,6 +1449,25 @@ version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +[[package]] +name = "libffi" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce826c243048e3d5cec441799724de52e2d42f820468431fc3fceee2341871e2" +dependencies = [ + "libc", + "libffi-sys", +] + +[[package]] +name = "libffi-sys" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36115160c57e8529781b4183c2bb51fdc1f6d6d1ed345591d84be7703befb3c" +dependencies = [ + "cc", +] + [[package]] name = "libloading" version = "0.8.5" @@ -1557,6 +1599,7 @@ name = "lune-std" version = "0.1.4" dependencies = [ "lune-std-datetime", + "lune-std-ffi", "lune-std-fs", "lune-std-luau", "lune-std-net", @@ -1585,6 +1628,17 @@ dependencies = [ "thiserror", ] +[[package]] +name = "lune-std-ffi" +version = "0.1.1" +dependencies = [ + "dlopen2", + "libffi", + "lune-utils", + "mlua", + "mlua-sys", +] + [[package]] name = "lune-std-fs" version = "0.1.2" diff --git a/Cargo.toml b/Cargo.toml index 221a0fb0..f32f08fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ members = [ "crates/lune-std-serde", "crates/lune-std-stdio", "crates/lune-std-task", + "crates/lune-std-ffi", "crates/lune-utils", "crates/mlua-luau-scheduler", ] diff --git a/crates/lune-std-ffi/Cargo.toml b/crates/lune-std-ffi/Cargo.toml new file mode 100644 index 00000000..b867401e --- /dev/null +++ b/crates/lune-std-ffi/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "lune-std-ffi" +version = "0.1.1" +edition = "2021" +license = "MPL-2.0" +repository = "https://github.com/lune-org/lune" +description = "Lune standard library - FFI" + +[lib] +path = "src/lib.rs" + +[lints] +workspace = true + +[dependencies] +mlua = { version = "0.9.9", features = ["luau"] } +mlua-sys = { version = "0.6.2", features = ["luau"] } +dlopen2 = "0.6" + +libffi = "3.2.0" + +lune-utils = { version = "0.1.3", path = "../lune-utils" } diff --git a/crates/lune-std-ffi/readme.md b/crates/lune-std-ffi/readme.md new file mode 100644 index 00000000..e61256bb --- /dev/null +++ b/crates/lune-std-ffi/readme.md @@ -0,0 +1,129 @@ +TODO: rewrite docs + +# Raw + +Data received from external. You can move this data into a box, use it as a ref, or change it directly to a Lua value. +The raw data is not on Lua's heap. + +Raw:toRef() +Convert data into ref. it allocate new lua userdata + +Raw:toBox() +Convert data into box. it allocate new lua userdata + +Raw:intoBox() +Raw:intoRef() + +See type:fromRaw() + +# Box + +`ffi.box(size)` + +Create new userdata with sized by `size` argument. Box is untyped, and have no ABI information. You can write some data into box with `type` + +All operation with box will boundary checked. GC will free heap well. + +일반적으로 포인터를 넘겨주기 위해서 사용됩니다. 박스의 공간은 ref 할 수 있으며. 함수를 수행한 후 루아에서 읽어볼 수 있습니다. + +## :zero() +박스를 0 으로 채워넣습니다. 기본적으로 박스는 초기화될 때 0 으로 채워지기 때문에 박스를 다시 0 으로 초기화하고 싶을 경우에 사용하십시오. + +## :copy(targetbox,size,offset?=0,targetoffset?=0) +박스 안의 값을 다른 박스에 복사합니다. 바운더리가 확인되어지므로 안전합니다. + +## .size +이 박스의 크기입니다. + +## :ref(offset?=0) => ref +이 박스를 참조합니다. 참조가 살아있는 동안 박스는 수거되지 않습니다. 일반적으로 외부의 함수에 포인터를 넘겨주기 위해서 사용됩니다. + +## more stuffs (not planned at this time) + +ref=>buffer conversion, or bit/byte related? + +# Ref (Unsafe) + +바운더리를 처리하지 않는 포인터입니다. 외부에서 받은 포인터, 또는 박스로부터 만들어진 포인터입니다. +ref 는 바운더리를 검사하지 않으므로 안전하지 않습니다. + +## :offset(bytes) + +이 ref 와 상대적인 위치에 있는 ref 를 구합니다. + +## :writefromRef() +다른 ref 안의 값을 읽어와 이 ref 안에 씁니다. 아래와 비슷한 연산을 합니다 +```c +int a = 100,b; +``` + +## :writefromBox() +box 값을 읽어와서 쓰기 + +# Type + +`type` is abstract class that helps encoding data into `box` or decode data from `box` + +## :toBox(luavalue) +Convert lua value to box. box will sized with `type.size` + +## :fromBox(box,offset?=0) +Read data from box, and convert into lua value. +Boundary will checked + +## :intoBox(luavalue,box,offset?=0) +Convert lua value, and write into box +Boundary will checked + +## :fromRef(ref,offset?=0) +포인터가 가르키는 곳의 데이터를 읽어서 루아의 데이터로 변환합니다. + +## :intoRef(luavalue,ref,offset?=0) +포인터가 가르키는 곳에 데이터를 작성합니다. + +## :fromRaw(raw,offset?=0) + + +## :ptr() -> Ptr +Get pointer type + +## :arr(len) -> Arr +Get array type + +## .size + +Byte size of this type. you can initialize box with + +## :cast(box,type) TODO + +# Ptr +Pointer type of some type. + +Ptr is not data converter. It only works for type hint of `struct` or `fn` + +## .inner +Inner type + +## .size +Size of `usize` + +:ptr() +:arr() + +## Arr + +## Void + +`ffi.void` + +Zero sized type. + +## Fn +Prototype type of some function. converts lua function into native function pointer or native function pointer into lua function. + +`ffi.fn({ type }, type) -> fn` + +:toLua( ref ) -> luafunction +:toBox( luafunction ) -> ref + +> TODO: rust, and another ABI support diff --git a/crates/lune-std-ffi/src/association.rs b/crates/lune-std-ffi/src/association.rs new file mode 100644 index 00000000..49f9c8a0 --- /dev/null +++ b/crates/lune-std-ffi/src/association.rs @@ -0,0 +1,84 @@ +#![allow(clippy::cargo_common_metadata)] + +// This is a small library that helps you set the dependencies of data in Lua. +// In FFI, there is often data that is dependent on other data. +// However, if you use user_value to inform Lua of the dependency, +// a table will be created for each userdata. +// To prevent this, we place a weak reference table in the registry +// and simulate what mlua does. +// Since mlua does not provide Lua state (private), +// uservalue operations cannot be performed directly, +// so this is the best solution for now. +// If the dependency is deep, the value may be completely destroyed when +// gc is performed multiple times. As an example, there is the following case: +// +// ffi.i32:ptr():ptr() +// box:ref():ref() +// +// Since the outermost pointer holds the definition for the pointer +// type inside it, only the outermost type will be removed on the first gc. +// It doesn't matter much. But if there is a cleaner way, we should choose it +use mlua::prelude::*; + +// Forces 'associated' to persist as long as 'value' is alive. +// 'value' can only hold one value. If you want to keep something else, +// use a table with a different name. +// You can delete the relationship by changing 'associated' to nil +pub fn set_association<'lua, T, U>( + lua: &'lua Lua, + regname: &str, + value: T, + associated: U, +) -> LuaResult<()> +where + T: IntoLua<'lua>, + U: IntoLua<'lua>, +{ + let table = match lua.named_registry_value::(regname)? { + LuaValue::Nil => { + let table = lua.create_table()?; + lua.set_named_registry_value(regname, table.clone())?; + let meta = lua.create_table()?; + meta.set("__mode", "k")?; + table.set_metatable(Some(meta)); + table + } + LuaValue::Table(t) => t, + _ => panic!(""), + }; + + table.set(value, associated)?; + + Ok(()) +} + +// 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. +pub fn get_association<'lua, T>( + lua: &'lua Lua, + regname: &str, + value: T, +) -> LuaResult>> +where + T: IntoLua<'lua>, +{ + match lua.named_registry_value::(regname)? { + LuaValue::Nil => Ok(None), + LuaValue::Table(t) => Ok(Some(t.get(value)?)), + _ => panic!(), + } +} + +// 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. +#[cfg(debug_assertions)] +pub fn get_table<'lua>(lua: &'lua Lua, regname: &str) -> LuaResult>> { + match lua.named_registry_value::(regname)? { + LuaValue::Nil => Ok(None), + LuaValue::Table(t) => Ok(Some(t)), + _ => panic!(), + } +} diff --git a/crates/lune-std-ffi/src/carr.rs b/crates/lune-std-ffi/src/carr.rs new file mode 100644 index 00000000..9258e897 --- /dev/null +++ b/crates/lune-std-ffi/src/carr.rs @@ -0,0 +1,24 @@ +use libffi::middle::Type; +use mlua::prelude::*; + +// 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. +// However, multidimensional arrays are not impossible to implement +// because they are a series of transcribed one-dimensional arrays. + +// See: https://stackoverflow.com/a/43525176 + +struct CArr { + libffi_type: Type, + length: usize, + size: usize, +} + +impl CArr { + fn new(libffi_type: Type, length: usize) { + Self { libffi_type } + } +} + +impl LuaUserData for CArr {} diff --git a/crates/lune-std-ffi/src/cfn.rs b/crates/lune-std-ffi/src/cfn.rs new file mode 100644 index 00000000..f029cfcb --- /dev/null +++ b/crates/lune-std-ffi/src/cfn.rs @@ -0,0 +1,45 @@ +use libffi::middle::{Cif, Type}; +use mlua::prelude::*; + +use crate::ctype::{libffi_type_from_userdata, libffi_types_from_table}; + +// cfn is a type declaration for a function. +// Basically, when calling an external function, this type declaration +// is referred to and type conversion is automatically assisted. + +// However, in order to save on type conversion costs, +// users keep values ​​they will use continuously in a box and use them multiple times. +// Alternatively, if the types are the same,you can save the cost of creating +// a new space by directly passing FfiRaw, +// the result value of another function or the argument value of the callback. + +// Defining cfn simply lists the function's actual argument positions and conversions. +// You must decide how to process the data in Lua. + +// The name cfn is intentional. This is because any *c_void is +// moved to a Lua function or vice versa. + +pub struct CFn { + libffi_cif: Cif, + args: Vec, + ret: Type, +} + +impl CFn { + pub fn new(args: Vec, ret: Type) -> Self { + let libffi_cif = Cif::new(args.clone(), ret.clone()); + Self { + libffi_cif, + args, + ret, + } + } + + pub fn from_lua_table(args: LuaTable, ret: LuaAnyUserData) -> LuaResult { + let args = libffi_types_from_table(&args)?; + let ret = libffi_type_from_userdata(&ret)?; + Ok(Self::new(args, ret)) + } +} + +impl LuaUserData for CFn {} diff --git a/crates/lune-std-ffi/src/cstring.rs b/crates/lune-std-ffi/src/cstring.rs new file mode 100644 index 00000000..cf79b487 --- /dev/null +++ b/crates/lune-std-ffi/src/cstring.rs @@ -0,0 +1,6 @@ +// This is a string type that can be given to an external function. +// To be exact, it converts the Lua string into a c_char array and puts it in the box. +// For this part, initially, i wanted to allow box("lua string"), +// but separated it for clarity. +// This also allows operations such as ffi.string:intoBox(). +// (Write a string to an already existing box) diff --git a/crates/lune-std-ffi/src/cstruct.rs b/crates/lune-std-ffi/src/cstruct.rs new file mode 100644 index 00000000..b5aa47ea --- /dev/null +++ b/crates/lune-std-ffi/src/cstruct.rs @@ -0,0 +1,127 @@ +#![allow(clippy::cargo_common_metadata)] + +use mlua::prelude::*; + +use libffi::low::ffi_abi_FFI_DEFAULT_ABI; +use libffi::middle::{Cif, Type}; +use libffi::raw::ffi_get_struct_offsets; +use std::vec::Vec; + +use crate::association::{get_association, set_association}; +use crate::ctype::{libffi_types_from_table, type_name_from_userdata}; + +use super::ctype::CType; + +pub struct CStruct { + libffi_cif: Cif, + libffi_type: Type, + fields: Vec, + offsets: Vec, + size: usize, +} + +const CSTRUCT_INNER: &str = "__cstruct_inner"; + +impl CStruct { + pub fn new(fields: Vec) -> Self { + let libffi_type = Type::structure(fields.clone()); + let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void()); + let size = unsafe { (*libffi_type.as_raw_ptr()).size }; + let mut offsets = Vec::::with_capacity(fields.len()); + unsafe { + ffi_get_struct_offsets( + ffi_abi_FFI_DEFAULT_ABI, + libffi_type.as_raw_ptr(), + offsets.as_mut_ptr(), + ); + offsets.set_len(offsets.capacity()); + } + + Self { + libffi_cif: libffi_cfi, + libffi_type, + fields, + offsets, + size, + } + } + + pub fn from_lua_table<'lua>( + lua: &'lua Lua, + table: LuaTable<'lua>, + ) -> LuaResult> { + let fields = libffi_types_from_table(&table)?; + let cstruct = lua.create_userdata(Self::new(fields))?; + table.set_readonly(true); + set_association(lua, CSTRUCT_INNER, cstruct.clone(), table)?; + Ok(cstruct) + } + + // Stringify cstruct for pretty printing something like: + // + pub fn stringify(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 table."))?; + + // iterate for field + let mut result = String::from(" "); + for i in 0..table.raw_len() { + let child: LuaAnyUserData = table.raw_get(i + 1)?; + result.push_str(format!("{}, ", type_name_from_userdata(&child)?).as_str()); + } + + // size of + result.push_str(format!("size = {} ", userdata.borrow::()?.size).as_str()); + Ok(result) + } else { + Ok(String::from("unnamed")) + } + } + + pub fn get_type(&self) -> Type { + self.libffi_type.clone() + } + + // Get byte offset of nth field + pub fn offset(&self, index: usize) -> LuaResult { + let offset = self + .offsets + .get(index) + .ok_or(LuaError::external("Out of index"))? + .to_owned(); + Ok(offset) + } +} + +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)); + + // Simply pass in the locked table used when first creating this object. + // By strongly referencing the table, the types inside do not disappear + // and the user can read the contents as needed. (good recycling!) + fields.add_field_function_get("inner", |lua, this: LuaAnyUserData| { + let table: LuaValue = get_association(lua, CSTRUCT_INNER, this)? + // It shouldn't happen. + .ok_or(LuaError::external("inner field not found"))?; + Ok(table) + }); + } + fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_method("offset", |_, this, index: usize| { + let offset = this.offset(index)?; + Ok(offset) + }); + methods.add_function("ptr", |lua, this: LuaAnyUserData| { + let pointer = CType::pointer(lua, &this)?; + Ok(pointer) + }); + methods.add_meta_function(LuaMetaMethod::ToString, |_, this: LuaAnyUserData| { + let result = CStruct::stringify(&this)?; + Ok(result) + }); + } +} diff --git a/crates/lune-std-ffi/src/ctype.rs b/crates/lune-std-ffi/src/ctype.rs new file mode 100644 index 00000000..fe223c59 --- /dev/null +++ b/crates/lune-std-ffi/src/ctype.rs @@ -0,0 +1,203 @@ +#![allow(clippy::cargo_common_metadata)] + +use std::borrow::Borrow; + +use super::association::{get_association, set_association}; +use super::cstruct::CStruct; +use libffi::middle::{Cif, Type}; +use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; +use mlua::prelude::*; +// use libffi::raw::{ffi_cif, ffi_ptrarray_to_raw}; + +const POINTER_INNER: &str = "__pointer_inner"; + +pub struct CType { + libffi_cif: Cif, + libffi_type: Type, + size: usize, + name: Option, +} + +// TODO: ARR +// TODO: convert + +impl CType { + pub fn new(libffi_type: Type, name: Option) -> Self { + let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void()); + let size = unsafe { (*libffi_type.as_raw_ptr()).size }; + Self { + libffi_cif: libffi_cfi, + libffi_type, + size, + name, + } + } + + pub fn get_type(&self) -> Type { + self.libffi_type.clone() + } + + pub fn pointer<'lua>(lua: &'lua Lua, inner: &LuaAnyUserData) -> LuaResult> { + let value = Self { + libffi_cif: Cif::new(vec![Type::pointer()], Type::void()), + libffi_type: Type::pointer(), + size: size_of::(), + name: Some(format!( + "Ptr<{}({})>", + { + if inner.is::() { + "CStruct" + } else if inner.is::() { + "CType" + } else { + "unnamed" + } + }, + type_name_from_userdata(inner)? + )), + } + .into_lua(lua)?; + + set_association(lua, POINTER_INNER, value.borrow(), inner)?; + + Ok(value) + } + + pub fn stringify(&self) -> String { + match &self.name { + Some(t) => t.to_owned(), + None => String::from("unnamed"), + } + } +} + +impl LuaUserData for CType { + fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("size", |_, this| Ok(this.size)); + fields.add_field_function_get("inner", |lua, this| { + let inner = get_association(lua, POINTER_INNER, this)?; + match inner { + Some(t) => Ok(t), + None => Ok(LuaNil), + } + }); + } + + fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_function("ptr", |lua, this: LuaAnyUserData| { + let pointer = CType::pointer(lua, &this)?; + Ok(pointer) + }); + + methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| { + let name = this.stringify(); + Ok(name) + }); + } +} + +// export all default c-types +pub fn create_all_types(lua: &Lua) -> LuaResult> { + Ok(vec![ + ( + "u8", + CType::new(Type::u8(), Some(String::from("u8"))).into_lua(lua)?, + ), + ( + "u16", + CType::new(Type::u16(), Some(String::from("u16"))).into_lua(lua)?, + ), + ( + "u32", + CType::new(Type::u32(), Some(String::from("u32"))).into_lua(lua)?, + ), + ( + "u64", + CType::new(Type::u64(), Some(String::from("u64"))).into_lua(lua)?, + ), + ( + "i8", + CType::new(Type::i8(), Some(String::from("i8"))).into_lua(lua)?, + ), + ( + "i16", + CType::new(Type::i16(), Some(String::from("i16"))).into_lua(lua)?, + ), + ( + "i32", + CType::new(Type::i32(), Some(String::from("i32"))).into_lua(lua)?, + ), + ( + "i64", + CType::new(Type::i64(), Some(String::from("i64"))).into_lua(lua)?, + ), + ( + "f32", + CType::new(Type::f32(), Some(String::from("f32"))).into_lua(lua)?, + ), + ( + "f64", + CType::new(Type::f64(), Some(String::from("f64"))).into_lua(lua)?, + ), + ( + "void", + CType::new(Type::void(), Some(String::from("void"))).into_lua(lua)?, + ), + ]) +} + +// get Vec from table(array) of c-types userdata +pub fn libffi_types_from_table(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(libffi_type_from_userdata(&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()) + ))); + } + } + } + + Ok(fields) +} + +// get libffi_type from any c-types userdata +pub fn libffi_type_from_userdata(userdata: &LuaAnyUserData) -> LuaResult { + if userdata.is::() { + Ok(userdata.borrow::()?.get_type()) + } else if userdata.is::() { + Ok(userdata.borrow::()?.get_type()) + } else { + Err(LuaError::external(format!( + "Unexpected field. CStruct, CType or CArr is required for element but got {}", + pretty_format_value( + // Since the data is in the Lua location, + // there is no problem with the clone. + &LuaValue::UserData(userdata.to_owned()), + &ValueFormatConfig::new() + ) + ))) + } +} + +// stringify any c-types userdata (for recursive) +pub fn type_name_from_userdata(userdata: &LuaAnyUserData) -> LuaResult { + if userdata.is::() { + let name = userdata.borrow::()?.stringify(); + Ok(name) + } else if userdata.is::() { + let name = CStruct::stringify(userdata)?; + Ok(name) + } else { + Ok(String::from("unnamed")) + } +} diff --git a/crates/lune-std-ffi/src/ffibox.rs b/crates/lune-std-ffi/src/ffibox.rs new file mode 100644 index 00000000..94f1f99d --- /dev/null +++ b/crates/lune-std-ffi/src/ffibox.rs @@ -0,0 +1,85 @@ +#![allow(clippy::cargo_common_metadata)] + +// It is an untyped, sized memory area that Lua can manage. +// This area is safe within Lua. Operations have their boundaries checked. +// It is basically intended to implement passing a pointed space to the outside. +// It also helps you handle data that Lua cannot handle. +// Depending on the type, operations such as sum, mul, and mod may be implemented. +// There is no need to enclose all data in a box; +// rather, it creates more heap space, so it should be used appropriately +// where necessary. + +use super::association::set_association; +use super::ffiref::FfiRef; +use core::ffi::c_void; +use mlua::prelude::*; +use std::boxed::Box; + +const BOX_REF_INNER: &str = "__box_ref"; + +pub struct FfiBox(Box<[u8]>); + +impl FfiBox { + pub fn new(size: usize) -> Self { + Self(vec![0u8; size].into_boxed_slice()) + } + + pub fn size(&self) -> usize { + self.0.len() + } + + // pub fn copy(&self, target: &mut FfiBox) {} + + pub fn get_ptr(&self) -> *mut c_void { + self.0.as_ptr() as *mut c_void + } + + // bad naming. i have no idea what should i use + pub fn luaref<'lua>( + lua: &'lua Lua, + this: LuaAnyUserData<'lua>, + ) -> LuaResult> { + let target = this.borrow::()?; + + let luaref = lua.create_userdata(FfiRef::new(target.get_ptr()))?; + + set_association(lua, BOX_REF_INNER, luaref.clone(), this.clone())?; + + Ok(luaref) + } + + pub fn zero(&mut self) { + self.0.fill(0u8); + } +} + +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) { + methods.add_method_mut("zero", |_, this, ()| { + this.zero(); + Ok(()) + }); + methods.add_function("ref", |lua, this: LuaAnyUserData| { + let luaref = FfiBox::luaref(lua, this)?; + Ok(luaref) + }); + methods.add_meta_method(LuaMetaMethod::Len, |_, this, ()| Ok(this.size())); + methods.add_meta_method(LuaMetaMethod::ToString, |lua, this, ()| { + dbg!(&this.0.len()); + let mut buff = String::from("[ "); + for i in &this.0 { + buff.push_str(i.to_owned().to_string().as_str()); + buff.push_str(", "); + } + buff.pop(); + buff.pop(); + buff.push_str(" ]"); + let luastr = lua.create_string(buff.as_bytes())?; + Ok(luastr) + }); + } +} diff --git a/crates/lune-std-ffi/src/ffilib.rs b/crates/lune-std-ffi/src/ffilib.rs new file mode 100644 index 00000000..9dfbf3ba --- /dev/null +++ b/crates/lune-std-ffi/src/ffilib.rs @@ -0,0 +1,57 @@ +use std::ffi::c_void; + +use super::association::set_association; +use dlopen2::symbor::Library; +use mlua::prelude::*; + +use crate::ffiref::FfiRef; + +pub struct FfiLib(Library); + +const SYM_INNER: &str = "__syn_inner"; + +// 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) { + Ok(t) => Ok(Self(t)), + Err(err) => Err(LuaError::external(format!("{err}"))), + } + } + + pub fn get_sym<'lua>( + lua: &'lua Lua, + this: LuaAnyUserData<'lua>, + name: String, + ) -> LuaResult> { + let lib = this.borrow::()?; + let sym = unsafe { + lib.0 + .symbol::<*mut c_void>(name.as_str()) + .map_err(|err| LuaError::external(format!("{err}")))? + }; + + let luasym = lua.create_userdata(FfiRef::new(*sym))?; + + set_association(lua, SYM_INNER, luasym.clone(), this.clone())?; + + Ok(luasym) + } +} + +impl LuaUserData for FfiLib { + fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_function("dlsym", |lua, (this, name): (LuaAnyUserData, String)| { + let luasym = FfiLib::get_sym(lua, this, name)?; + Ok(luasym) + }); + } +} diff --git a/crates/lune-std-ffi/src/ffiraw.rs b/crates/lune-std-ffi/src/ffiraw.rs new file mode 100644 index 00000000..6d64e58b --- /dev/null +++ b/crates/lune-std-ffi/src/ffiraw.rs @@ -0,0 +1,8 @@ +// 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. diff --git a/crates/lune-std-ffi/src/ffiref.rs b/crates/lune-std-ffi/src/ffiref.rs new file mode 100644 index 00000000..5b179665 --- /dev/null +++ b/crates/lune-std-ffi/src/ffiref.rs @@ -0,0 +1,59 @@ +use super::association::set_association; +use core::ffi::c_void; +use mlua::prelude::*; +use std::ptr; + +// A referenced space. It is possible to read and write through types. +// This operation is not safe. This may cause a memory error in Lua +// if use it incorrectly. +// If it references an area managed by Lua, +// the box will remain as long as this reference is alive. + +pub struct FfiRef(*mut c_void); + +const REF_INNER: &str = "__ref_inner"; + +impl FfiRef { + pub fn new(target: *mut c_void) -> Self { + Self(target) + } + + // bad naming. i have no idea what should i use + pub fn luaref<'lua>( + lua: &'lua Lua, + this: LuaAnyUserData<'lua>, + ) -> LuaResult> { + let target = this.borrow::()?; + + let luaref = lua.create_userdata(FfiRef::new(ptr::from_ref(&target.0) as *mut c_void))?; + + set_association(lua, REF_INNER, luaref.clone(), this.clone())?; + + Ok(luaref) + } + + pub unsafe fn deref(&self) -> Self { + Self::new(*self.0.cast::<*mut c_void>()) + } + + pub unsafe fn offset(&self, offset: isize) -> Self { + Self::new(self.0.offset(offset)) + } +} + +impl LuaUserData for FfiRef { + fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_method("deref", |_, this, ()| { + let ffiref = unsafe { this.deref() }; + Ok(ffiref) + }); + methods.add_method("offset", |_, this, offset: isize| { + let ffiref = unsafe { this.offset(offset) }; + Ok(ffiref) + }); + methods.add_function("ref", |lua, this: LuaAnyUserData| { + let ffiref = FfiRef::luaref(lua, this)?; + Ok(ffiref) + }); + } +} diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs new file mode 100644 index 00000000..52916167 --- /dev/null +++ b/crates/lune-std-ffi/src/lib.rs @@ -0,0 +1,56 @@ +#![allow(clippy::cargo_common_metadata)] + +use lune_utils::TableBuilder; +use mlua::prelude::*; + +mod association; +mod carr; +mod cfn; +mod cstring; +mod cstruct; +mod ctype; +mod ffibox; +mod ffilib; +mod ffiraw; +mod ffiref; + +use self::association::get_table; +use self::cfn::CFn; +use self::cstruct::CStruct; +use self::ctype::create_all_types; +use self::ffibox::FfiBox; +use self::ffilib::FfiLib; + +/** + Creates the `ffi` standard library module. + + # Errors + + Errors when out of memory. +*/ +pub fn module(lua: &Lua) -> LuaResult { + let ctypes = create_all_types(lua)?; + let result = TableBuilder::new(lua)? + .with_values(ctypes)? + .with_function("box", |_, size: usize| Ok(FfiBox::new(size)))? + // TODO: discuss about function name. matching with io.open is better? + .with_function("dlopen", |_, name: String| { + let lib = FfiLib::new(name)?; + Ok(lib) + })? + .with_function("struct", |lua, types: LuaTable| { + let cstruct = CStruct::from_lua_table(lua, types)?; + Ok(cstruct) + })? + .with_function("fn", |_, (args, ret): (LuaTable, LuaAnyUserData)| { + let cfn = CFn::from_lua_table(args, ret)?; + Ok(cfn) + })?; + + #[cfg(debug_assertions)] + let result = result.with_function("debug_associate", |lua, str: String| { + get_table(lua, str.as_ref()) + })?; + + result.build_readonly() +} diff --git a/crates/lune-std-ffi/todo.md b/crates/lune-std-ffi/todo.md new file mode 100644 index 00000000..307b29ad --- /dev/null +++ b/crates/lune-std-ffi/todo.md @@ -0,0 +1,102 @@ + +use libffi::raw::{ffi_cif, ffi_ptrarray_to_raw}; + +// pub fn ffi_get_struct_offsets( +// abi: ffi_abi, +// struct_type: *mut ffi_type, +// offsets: *mut usize, +// ) -> ffi_status; + +- last thing to do +- [ ] Add tests +- [ ] Add docs +- [ ] Typing + +# Raw + +- [ ] Raw:toRef() +- [ ] Raw:toBox() +- [ ] Raw:intoBox() +- [ ] Raw:intoRef() + +# Box + +- [x] ffi.box(size) +- [x] .size +- [x] :zero() +- [?] :ref(offset?=0) => ref + - offset is not impled +- [~] :copy(box,size?=-1,offset?=0) + - working on it + +# Ref (Unsafe) + +- [x] ref:deref() -> ref +- [x] ref:offset(bytes) -> ref +- [x] ref:ref() -> ref + +~~- [ ] ref:fromRef(size,offset?=0) ?? what is this~~ +~~- [ ] ref:fromBox(size,offset?=0) ?? what is this~~ + +# Struct + +- [x] :offset(index) +- [x] :ptr() +- [x] .inner[n] +- [!] .size +- [ ] # +- [x] tostring + +size, offset is strange. maybe related to cif state. + +# Type + +- [ ] :toBox(luavalue) + +Very stupid idea. +from(box|ref|raw, offset) is better idea i think. + +- [ ] :fromBox(box,offset?=0) +- [ ] :intoBox(luavalue,box,offset?=0) +- [ ] :fromRef(ref,offset?=0) +- [ ] :intoRef(luavalue,ref,offset?=0) +- [ ] :fromRaw(raw,offset?=0) + +- [ ] :castBox(box,type) TODO +- [ ] + +- [ ] :sum +- [ ] :mul +- [ ] :sub + +## subtype +- [x] :ptr() -> Ptr +- [~] :arr(len) -> Arr +- [x] .size + + + +# Ptr + +- [x] .inner +- [x] .size +- [x] :ptr() +- [~] :arr() + +## Arr + +## Void + +`ffi.void` + +Zero sized type. + +## Fn +Prototype type of some function. converts lua function into native function pointer or native function pointer into lua function. + +`ffi.fn({ type }, type) -> fn` + +:toLua( ref ) -> luafunction +:toBox( luafunction ) -> ref + +> TODO: rust, and another ABI support diff --git a/crates/lune-std/Cargo.toml b/crates/lune-std/Cargo.toml index 132338f8..9121ce3f 100644 --- a/crates/lune-std/Cargo.toml +++ b/crates/lune-std/Cargo.toml @@ -24,6 +24,7 @@ default = [ "serde", "stdio", "task", + "ffi", ] datetime = ["dep:lune-std-datetime"] @@ -36,6 +37,7 @@ roblox = ["dep:lune-std-roblox"] serde = ["dep:lune-std-serde"] stdio = ["dep:lune-std-stdio"] task = ["dep:lune-std-task"] +ffi = ["dep:lune-std-ffi"] [dependencies] mlua = { version = "0.9.9", features = ["luau"] } @@ -57,3 +59,4 @@ lune-std-roblox = { optional = true, version = "0.1.3", path = "../lune-std-robl lune-std-serde = { optional = true, version = "0.1.2", path = "../lune-std-serde" } lune-std-stdio = { optional = true, version = "0.1.2", path = "../lune-std-stdio" } lune-std-task = { optional = true, version = "0.1.2", path = "../lune-std-task" } +lune-std-ffi = { optional = true, version = "0.1.1", path = "../lune-std-ffi" } diff --git a/crates/lune-std/src/library.rs b/crates/lune-std/src/library.rs index 9a301f57..2ac783e0 100644 --- a/crates/lune-std/src/library.rs +++ b/crates/lune-std/src/library.rs @@ -3,7 +3,7 @@ use std::str::FromStr; use mlua::prelude::*; /** - A standard library provided by Lune. + A standard library probloxrovided by Lune. */ #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] #[rustfmt::skip] @@ -18,6 +18,7 @@ pub enum LuneStandardLibrary { #[cfg(feature = "serde")] Serde, #[cfg(feature = "stdio")] Stdio, #[cfg(feature = "roblox")] Roblox, + #[cfg(feature = "ffi")] Ffi, } impl LuneStandardLibrary { @@ -36,6 +37,7 @@ impl LuneStandardLibrary { #[cfg(feature = "serde")] Self::Serde, #[cfg(feature = "stdio")] Self::Stdio, #[cfg(feature = "roblox")] Self::Roblox, + #[cfg(feature = "ffi")] Self::Ffi, ]; /** @@ -56,6 +58,7 @@ impl LuneStandardLibrary { #[cfg(feature = "serde")] Self::Serde => "serde", #[cfg(feature = "stdio")] Self::Stdio => "stdio", #[cfg(feature = "roblox")] Self::Roblox => "roblox", + #[cfg(feature = "ffi")] Self::Ffi => "ffi", _ => unreachable!("no standard library enabled"), } @@ -82,6 +85,7 @@ impl LuneStandardLibrary { #[cfg(feature = "serde")] Self::Serde => lune_std_serde::module(lua), #[cfg(feature = "stdio")] Self::Stdio => lune_std_stdio::module(lua), #[cfg(feature = "roblox")] Self::Roblox => lune_std_roblox::module(lua), + #[cfg(feature = "ffi")] Self::Ffi => lune_std_ffi::module(lua), _ => unreachable!("no standard library enabled"), }; @@ -111,6 +115,7 @@ impl FromStr for LuneStandardLibrary { #[cfg(feature = "serde")] "serde" => Self::Serde, #[cfg(feature = "stdio")] "stdio" => Self::Stdio, #[cfg(feature = "roblox")] "roblox" => Self::Roblox, + #[cfg(feature = "ffi")] "ffi" => Self::Ffi, _ => { return Err(format!( diff --git a/crates/lune/Cargo.toml b/crates/lune/Cargo.toml index c784669e..a95aab84 100644 --- a/crates/lune/Cargo.toml +++ b/crates/lune/Cargo.toml @@ -30,6 +30,7 @@ std-roblox = ["dep:lune-std", "lune-std/roblox", "dep:lune-roblox"] std-serde = ["dep:lune-std", "lune-std/serde"] std-stdio = ["dep:lune-std", "lune-std/stdio"] std-task = ["dep:lune-std", "lune-std/task"] +std-ffi = ["dep:lune-std", "lune-std/ffi"] std = [ "std-datetime", @@ -42,6 +43,7 @@ std = [ "std-serde", "std-stdio", "std-task", + "std-ffi", ] cli = ["dep:clap", "dep:include_dir", "dep:rustyline", "dep:zip_next"] diff --git a/tests/ffi/ptr.luau b/tests/ffi/ptr.luau new file mode 100644 index 00000000..c62eadf3 --- /dev/null +++ b/tests/ffi/ptr.luau @@ -0,0 +1,33 @@ + +local ffi = require("@lune/ffi") + +-- ptr size test +assert( + ffi.i32:ptr().size == ffi.i64:ptr().size, + "All of Ptr.size must be same.\n".. + "ffi.i32:ptr().size == ffi.i64:ptr().size failed" +) + +-- inner test +local i32ptr = ffi.i32:ptr() +assert( + rawequal(ffi.i32, i32ptr.inner), + "Ptr.inner must be same with their parent\n".. + "raweq ffi.i32 == ffi.i32:ptr().inner failed" +) +assert( + rawequal(i32ptr, i32ptr:ptr().inner), + "Ptr.inner must be same with their parent\n".. + "raweq i32ptr == i32ptr:ptr().inner failed" +) +assert( + rawequal(i32ptr, i32ptr:ptr().inner:ptr().inner:ptr().inner), + "Ptr.inner must be same with their parent\n".. + "raweq i32ptr == i32ptr:ptr().inner:ptr().inner:ptr().inner failed" +) + +-- deep ptr test +local ok,err = pcall(function() + i32ptr:ptr():ptr():ptr():ptr():ptr():ptr():ptr() +end) +assert(ok,`Deep ptr test failed.\n{err}`) diff --git a/tests/ffi/struct.luau b/tests/ffi/struct.luau new file mode 100644 index 00000000..e1c1f8df --- /dev/null +++ b/tests/ffi/struct.luau @@ -0,0 +1,2 @@ + +local ffi = require("@lune/ffi") diff --git a/types/ffi.luau b/types/ffi.luau new file mode 100644 index 00000000..fb452081 --- /dev/null +++ b/types/ffi.luau @@ -0,0 +1,79 @@ +--[=[ + @interface Box + @within FFI + + Box is an untyped, sized memory area that Lua can manage. + This area is safe within Lua. Operations have their boundaries checked. + + You can passing box as raw arguments or as pointer to outside. + It also helps you handle data that Lua cannot handle. or you can reuse box to save cost from convertsion. + Depending on the type, operations such as sum, mul, and mod may be implemented. See Types + + ```lua + ffi.box(size) + ``` + This is a dictionary that will contain the following values: + + * `readOnly` - If the target path is read-only or not +]=] + +export type Box = { + size: number, + ref: (self: Box)->Ref, +} +export type BoxConstructor = (size: number)->Box + +export type Type = {} + +---! FIXME: better typing for PointerSize +export type PointerSize = number -- typeof(5) | typeof(8) + +export type Arr = { + inner: T, + size: number, + ptr: (self: Arr) -> any, +} + +--[=[ + @interface Ptr + @within FFI + +]=] +---! FIXME: due to recursive type limition. hardcoded 6 depth. better idea? +export type Ptr = { + inner: T, + size: PointerSize, + ptr: (self: Ptr)->PtrPtr>, + arr: (self: Ptr, size: number) -> Arr>, +} +export type PtrPtr = { + inner: T, + size: PointerSize, + ptr: (self: PtrPtr)->PtrPtrPtr>, + arr: (self: PtrPtr, size: number) -> Arr>, +} +export type PtrPtrPtr = { + inner: T, + size: PointerSize, + ptr: (self: PtrPtrPtr)->PtrPtrPtrPtr>, + arr: (self: PtrPtrPtr, size: number) -> Arr>, +} +export type PtrPtrPtrPtr = { + inner: T, + size: PointerSize, + ptr: (self: PtrPtrPtrPtr)->PtrPtrPtrPtrPtr>, + arr: (self: PtrPtrPtrPtr, size: number) -> Arr>, +} +export type PtrPtrPtrPtrPtr = { + inner: T, + size: PointerSize, + ptr: (self: PtrPtrPtrPtrPtr)->PtrPtrPtrPtrPtrPtr>, + arr: (self: PtrPtrPtrPtrPtr, size: number) -> Arr>, +} +export type PtrPtrPtrPtrPtrPtr = { + inner: T, + size: PointerSize, + ptr: (self: PtrPtrPtrPtrPtrPtr)->any, -- Yes. At this point. more type is useless. + arr: (self: PtrPtrPtrPtrPtrPtr, size: number) -> Arr>, +} + From 8c38aef32d86838d6e1e22c49f385e5894200d77 Mon Sep 17 00:00:00 2001 From: qwreey Date: Fri, 23 Aug 2024 20:02:57 +0900 Subject: [PATCH 02/79] Implement struct and arr (#243) struct.size: Returns a non-zero actual size rewrite use super:: => use crate:: --- crates/lune-std-ffi/src/carr.rs | 20 ++++++++++-- crates/lune-std-ffi/src/cstruct.rs | 52 +++++++++++++++++++----------- crates/lune-std-ffi/src/ctype.rs | 39 ++++++++++++++++++---- crates/lune-std-ffi/src/ffibox.rs | 8 +++-- crates/lune-std-ffi/src/ffilib.rs | 2 +- crates/lune-std-ffi/src/ffiref.rs | 6 ++-- crates/lune-std-ffi/src/lib.rs | 19 +++++++---- 7 files changed, 107 insertions(+), 39 deletions(-) diff --git a/crates/lune-std-ffi/src/carr.rs b/crates/lune-std-ffi/src/carr.rs index 9258e897..fc38e8bb 100644 --- a/crates/lune-std-ffi/src/carr.rs +++ b/crates/lune-std-ffi/src/carr.rs @@ -1,6 +1,8 @@ use libffi::middle::Type; use mlua::prelude::*; +use crate::ctype::libffi_type_ensured_size; + // 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. @@ -9,15 +11,29 @@ use mlua::prelude::*; // See: https://stackoverflow.com/a/43525176 +// Padding after each field inside the struct is set to next field can follow the alignment. +// There is no problem even if you create a struct with n fields of a single type within the struct. Array adheres to the condition that there is no additional padding between each element. Padding to a struct is padding inside the struct. Simply think of the padding byte as a trailing unnamed field. + struct CArr { libffi_type: Type, + struct_type: Type, length: usize, + field_size: usize, size: usize, } impl CArr { - fn new(libffi_type: Type, length: usize) { - Self { libffi_type } + fn new(libffi_type: Type, length: usize) -> LuaResult { + let struct_type = Type::structure(vec![libffi_type.clone(); length]); + let field_size = libffi_type_ensured_size(libffi_type.as_raw_ptr())?; + + Ok(Self { + libffi_type, + struct_type, + length, + field_size, + size: field_size * length, + }) } } diff --git a/crates/lune-std-ffi/src/cstruct.rs b/crates/lune-std-ffi/src/cstruct.rs index b5aa47ea..f0152a64 100644 --- a/crates/lune-std-ffi/src/cstruct.rs +++ b/crates/lune-std-ffi/src/cstruct.rs @@ -1,16 +1,17 @@ #![allow(clippy::cargo_common_metadata)] -use mlua::prelude::*; - -use libffi::low::ffi_abi_FFI_DEFAULT_ABI; -use libffi::middle::{Cif, Type}; -use libffi::raw::ffi_get_struct_offsets; use std::vec::Vec; -use crate::association::{get_association, set_association}; -use crate::ctype::{libffi_types_from_table, type_name_from_userdata}; +use libffi::{ + low, + middle::{Cif, Type}, + raw, +}; +use mlua::prelude::*; -use super::ctype::CType; +use crate::association::{get_association, set_association}; +use crate::ctype::{libffi_types_from_table, type_name_from_userdata, CType}; +use crate::FFI_STATUS_NAMES; pub struct CStruct { libffi_cif: Cif, @@ -23,35 +24,48 @@ pub struct CStruct { const CSTRUCT_INNER: &str = "__cstruct_inner"; impl CStruct { - pub fn new(fields: Vec) -> Self { + pub fn new(fields: Vec) -> LuaResult { let libffi_type = Type::structure(fields.clone()); let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void()); - let size = unsafe { (*libffi_type.as_raw_ptr()).size }; + + // Get field offsets with ffi_get_struct_offsets let mut offsets = Vec::::with_capacity(fields.len()); unsafe { - ffi_get_struct_offsets( - ffi_abi_FFI_DEFAULT_ABI, + let offset_result: raw::ffi_status = raw::ffi_get_struct_offsets( + low::ffi_abi_FFI_DEFAULT_ABI, libffi_type.as_raw_ptr(), offsets.as_mut_ptr(), ); + if offset_result != raw::ffi_status_FFI_OK { + return Err(LuaError::external(format!( + "ffi_get_struct_offsets failed. expected result {}, got {}", + FFI_STATUS_NAMES[0], FFI_STATUS_NAMES[offset_result as usize] + ))); + } offsets.set_len(offsets.capacity()); } - Self { + // Get tailing padded size of struct + // See http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html + let size = unsafe { (*libffi_type.as_raw_ptr()).size }; + + Ok(Self { libffi_cif: libffi_cfi, libffi_type, fields, offsets, size, - } + }) } + // Create new CStruct UserData with LuaTable. + // Lock and hold table for .inner ref pub fn from_lua_table<'lua>( lua: &'lua Lua, table: LuaTable<'lua>, ) -> LuaResult> { let fields = libffi_types_from_table(&table)?; - let cstruct = lua.create_userdata(Self::new(fields))?; + let cstruct = lua.create_userdata(Self::new(fields)?)?; table.set_readonly(true); set_association(lua, CSTRUCT_INNER, cstruct.clone(), table)?; Ok(cstruct) @@ -81,10 +95,6 @@ impl CStruct { } } - pub fn get_type(&self) -> Type { - self.libffi_type.clone() - } - // Get byte offset of nth field pub fn offset(&self, index: usize) -> LuaResult { let offset = self @@ -94,6 +104,10 @@ impl CStruct { .to_owned(); Ok(offset) } + + pub fn get_type(&self) -> Type { + self.libffi_type.clone() + } } impl LuaUserData for CStruct { diff --git a/crates/lune-std-ffi/src/ctype.rs b/crates/lune-std-ffi/src/ctype.rs index fe223c59..6531aba0 100644 --- a/crates/lune-std-ffi/src/ctype.rs +++ b/crates/lune-std-ffi/src/ctype.rs @@ -1,12 +1,19 @@ #![allow(clippy::cargo_common_metadata)] use std::borrow::Borrow; +use std::ptr::{self, null_mut}; -use super::association::{get_association, set_association}; -use super::cstruct::CStruct; -use libffi::middle::{Cif, Type}; +use libffi::{ + low, + middle::{Cif, Type}, + raw, +}; use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; use mlua::prelude::*; + +use crate::association::{get_association, set_association}; +use crate::cstruct::CStruct; +use crate::FFI_STATUS_NAMES; // use libffi::raw::{ffi_cif, ffi_ptrarray_to_raw}; const POINTER_INNER: &str = "__pointer_inner"; @@ -18,9 +25,6 @@ pub struct CType { name: Option, } -// TODO: ARR -// TODO: convert - impl CType { pub fn new(libffi_type: Type, name: Option) -> Self { let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void()); @@ -201,3 +205,26 @@ pub fn type_name_from_userdata(userdata: &LuaAnyUserData) -> LuaResult { Ok(String::from("unnamed")) } } + +// Ensure sizeof c-type (raw::libffi_type) +// See: http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html +pub fn libffi_type_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult { + let mut cif: low::ffi_cif = Default::default(); + let result = unsafe { + raw::ffi_prep_cif( + ptr::from_mut(&mut cif), + raw::ffi_abi_FFI_DEFAULT_ABI, + 0, + ffi_type, + null_mut(), + ) + }; + + if result != raw::ffi_status_FFI_OK { + return Err(LuaError::external(format!( + "ffi_get_struct_offsets failed. expected result {}, got {}", + FFI_STATUS_NAMES[0], FFI_STATUS_NAMES[result as usize] + ))); + } + unsafe { Ok((*ffi_type).size) } +} diff --git a/crates/lune-std-ffi/src/ffibox.rs b/crates/lune-std-ffi/src/ffibox.rs index 94f1f99d..b9d0df8e 100644 --- a/crates/lune-std-ffi/src/ffibox.rs +++ b/crates/lune-std-ffi/src/ffibox.rs @@ -9,11 +9,13 @@ // rather, it creates more heap space, so it should be used appropriately // where necessary. -use super::association::set_association; -use super::ffiref::FfiRef; +use std::boxed::Box; + use core::ffi::c_void; use mlua::prelude::*; -use std::boxed::Box; + +use crate::association::set_association; +use crate::ffiref::FfiRef; const BOX_REF_INNER: &str = "__box_ref"; diff --git a/crates/lune-std-ffi/src/ffilib.rs b/crates/lune-std-ffi/src/ffilib.rs index 9dfbf3ba..23958682 100644 --- a/crates/lune-std-ffi/src/ffilib.rs +++ b/crates/lune-std-ffi/src/ffilib.rs @@ -1,9 +1,9 @@ use std::ffi::c_void; -use super::association::set_association; use dlopen2::symbor::Library; use mlua::prelude::*; +use crate::association::set_association; use crate::ffiref::FfiRef; pub struct FfiLib(Library); diff --git a/crates/lune-std-ffi/src/ffiref.rs b/crates/lune-std-ffi/src/ffiref.rs index 5b179665..79473fa2 100644 --- a/crates/lune-std-ffi/src/ffiref.rs +++ b/crates/lune-std-ffi/src/ffiref.rs @@ -1,8 +1,10 @@ -use super::association::set_association; use core::ffi::c_void; -use mlua::prelude::*; use std::ptr; +use mlua::prelude::*; + +use crate::association::set_association; + // A referenced space. It is possible to read and write through types. // This operation is not safe. This may cause a memory error in Lua // if use it incorrectly. diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs index 52916167..d2fdd8ea 100644 --- a/crates/lune-std-ffi/src/lib.rs +++ b/crates/lune-std-ffi/src/lib.rs @@ -14,12 +14,19 @@ mod ffilib; mod ffiraw; mod ffiref; -use self::association::get_table; -use self::cfn::CFn; -use self::cstruct::CStruct; -use self::ctype::create_all_types; -use self::ffibox::FfiBox; -use self::ffilib::FfiLib; +use crate::association::get_table; +use crate::cfn::CFn; +use crate::cstruct::CStruct; +use crate::ctype::create_all_types; +use crate::ffibox::FfiBox; +use crate::ffilib::FfiLib; + +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", +]; /** Creates the `ffi` standard library module. From b36948cf1b524b798a6bbdac24953f1808605fd8 Mon Sep 17 00:00:00 2001 From: qwreey Date: Sat, 24 Aug 2024 06:33:29 +0000 Subject: [PATCH 03/79] Implement carr, cstruct, ctype and cptr (#243) --- crates/lune-std-ffi/src/carr.rs | 78 +++++++++++++++++++-- crates/lune-std-ffi/src/cptr.rs | 78 +++++++++++++++++++++ crates/lune-std-ffi/src/cstruct.rs | 33 +++++++-- crates/lune-std-ffi/src/ctype.rs | 105 ++++++++++++++--------------- crates/lune-std-ffi/src/lib.rs | 1 + 5 files changed, 230 insertions(+), 65 deletions(-) create mode 100644 crates/lune-std-ffi/src/cptr.rs diff --git a/crates/lune-std-ffi/src/carr.rs b/crates/lune-std-ffi/src/carr.rs index fc38e8bb..886a01fe 100644 --- a/crates/lune-std-ffi/src/carr.rs +++ b/crates/lune-std-ffi/src/carr.rs @@ -1,7 +1,11 @@ use libffi::middle::Type; use mlua::prelude::*; -use crate::ctype::libffi_type_ensured_size; +use crate::association::{get_association, set_association}; +use crate::cptr::CPtr; +use crate::ctype::{ + libffi_type_ensured_size, libffi_type_from_userdata, type_userdata_stringify, CType, +}; // This is a series of some type. // It provides the final size and the offset of the index, @@ -14,7 +18,9 @@ use crate::ctype::libffi_type_ensured_size; // Padding after each field inside the struct is set to next field can follow the alignment. // There is no problem even if you create a struct with n fields of a single type within the struct. Array adheres to the condition that there is no additional padding between each element. Padding to a struct is padding inside the struct. Simply think of the padding byte as a trailing unnamed field. -struct CArr { +const CARR_INNER: &str = "__carr_inner"; + +pub struct CArr { libffi_type: Type, struct_type: Type, length: usize, @@ -23,7 +29,7 @@ struct CArr { } impl CArr { - fn new(libffi_type: Type, length: usize) -> LuaResult { + pub fn new(libffi_type: Type, length: usize) -> LuaResult { let struct_type = Type::structure(vec![libffi_type.clone(); length]); let field_size = libffi_type_ensured_size(libffi_type.as_raw_ptr())?; @@ -35,6 +41,70 @@ impl CArr { size: field_size * length, }) } + + pub fn from_lua_userdata<'lua>( + lua: &'lua Lua, + luatype: &LuaAnyUserData<'lua>, + length: usize, + ) -> LuaResult> { + let fields = libffi_type_from_userdata(luatype)?; + let carr = lua.create_userdata(Self::new(fields, length)?)?; + + set_association(lua, CARR_INNER, carr.clone(), luatype)?; + Ok(carr) + } + + pub fn get_type(&self) -> Type { + self.libffi_type.clone() + } + + // Stringify cstruct for pretty printing something like: + // + pub fn stringify(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."))?; + Ok(format!( + " {} ; {} ", + type_userdata_stringify(inner)?, + carr.length + )) + } else { + Err(LuaError::external("failed to get inner type userdata.")) + } + } } -impl LuaUserData for 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_function_get("inner", |lua, this: LuaAnyUserData| { + let inner: LuaValue = get_association(lua, CARR_INNER, this)? + // It shouldn't happen. + .ok_or(LuaError::external("inner field not found"))?; + Ok(inner) + }); + } + + fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_method("offset", |_, this, offset: isize| { + if this.length > (offset as usize) && offset >= 0 { + Ok(this.field_size * (offset as usize)) + } else { + Err(LuaError::external("Out of index")) + } + }); + methods.add_function("ptr", |lua, this: LuaAnyUserData| { + let pointer = CPtr::from_lua_userdata(lua, &this)?; + Ok(pointer) + }); + methods.add_meta_function(LuaMetaMethod::ToString, |_, this: LuaAnyUserData| { + let result = CArr::stringify(&this)?; + Ok(result) + }); + } +} diff --git a/crates/lune-std-ffi/src/cptr.rs b/crates/lune-std-ffi/src/cptr.rs new file mode 100644 index 00000000..62324d1c --- /dev/null +++ b/crates/lune-std-ffi/src/cptr.rs @@ -0,0 +1,78 @@ +#![allow(clippy::cargo_common_metadata)] + +use std::borrow::Borrow; + +use libffi::middle::Type; +use mlua::prelude::*; + +use crate::association::{get_association, set_association}; +use crate::carr::CArr; +use crate::ctype::{type_name_from_userdata, type_userdata_stringify}; + +const POINTER_INNER: &str = "__pointer_inner"; + +pub struct CPtr(); + +impl CPtr { + // Create pointer type with '.inner' field + // inner can be CArr, CType or CStruct + pub fn from_lua_userdata<'lua>( + lua: &'lua Lua, + inner: &LuaAnyUserData, + ) -> LuaResult> { + let value = Self().into_lua(lua)?; + + set_association(lua, POINTER_INNER, value.borrow(), inner)?; + + Ok(value) + } + + // Stringify CPtr with inner ctype + pub fn stringify(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."))?; + Ok(format!( + " <{}({})> ", + type_name_from_userdata(inner), + type_userdata_stringify(inner)?, + )) + } else { + Err(LuaError::external("failed to get inner type userdata.")) + } + } + + // Return void* + pub fn get_type() -> Type { + Type::pointer() + } +} + +impl LuaUserData for CPtr { + fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("size", |_, _| Ok(size_of::())); + fields.add_field_function_get("inner", |lua, this| { + let inner = get_association(lua, POINTER_INNER, this)? + .ok_or(LuaError::external("inner type not found"))?; + Ok(inner) + }); + } + + 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)?; + Ok(pointer) + }); + methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| { + let carr = CArr::from_lua_userdata(lua, &this, length)?; + Ok(carr) + }); + methods.add_meta_function(LuaMetaMethod::ToString, |_, this: LuaAnyUserData| { + let name: Result = CPtr::stringify(&this); + Ok(name) + }); + } +} diff --git a/crates/lune-std-ffi/src/cstruct.rs b/crates/lune-std-ffi/src/cstruct.rs index f0152a64..9a554dae 100644 --- a/crates/lune-std-ffi/src/cstruct.rs +++ b/crates/lune-std-ffi/src/cstruct.rs @@ -9,9 +9,13 @@ use libffi::{ }; use mlua::prelude::*; -use crate::association::{get_association, set_association}; -use crate::ctype::{libffi_types_from_table, type_name_from_userdata, CType}; +use crate::ctype::{libffi_types_from_table, type_userdata_stringify, CType}; use crate::FFI_STATUS_NAMES; +use crate::{ + association::{get_association, set_association}, + ctype::type_name_from_userdata, +}; +use crate::{carr::CArr, cptr::CPtr}; pub struct CStruct { libffi_cif: Cif, @@ -78,20 +82,30 @@ impl CStruct { if field.is_table() { let table = field .as_table() - .ok_or(LuaError::external("failed to get inner table."))?; - + .ok_or(LuaError::external("failed to get inner type table."))?; // iterate for field let mut result = String::from(" "); for i in 0..table.raw_len() { let child: LuaAnyUserData = table.raw_get(i + 1)?; - result.push_str(format!("{}, ", type_name_from_userdata(&child)?).as_str()); + if child.is::() { + result.push_str(format!("{}, ", type_userdata_stringify(&child)?).as_str()); + } else { + result.push_str( + format!( + "<{}({})>, ", + type_name_from_userdata(&child), + type_userdata_stringify(&child)? + ) + .as_str(), + ); + } } // size of result.push_str(format!("size = {} ", userdata.borrow::()?.size).as_str()); Ok(result) } else { - Ok(String::from("unnamed")) + Err(LuaError::external("failed to get inner type table.")) } } @@ -124,15 +138,20 @@ impl LuaUserData for CStruct { Ok(table) }); } + fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { methods.add_method("offset", |_, this, index: usize| { let offset = this.offset(index)?; Ok(offset) }); methods.add_function("ptr", |lua, this: LuaAnyUserData| { - let pointer = CType::pointer(lua, &this)?; + let pointer = CPtr::from_lua_userdata(lua, &this)?; Ok(pointer) }); + methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| { + let carr = CArr::from_lua_userdata(lua, &this, length)?; + Ok(carr) + }); methods.add_meta_function(LuaMetaMethod::ToString, |_, this: LuaAnyUserData| { let result = CStruct::stringify(&this)?; Ok(result) diff --git a/crates/lune-std-ffi/src/ctype.rs b/crates/lune-std-ffi/src/ctype.rs index 6531aba0..7fe6b157 100644 --- a/crates/lune-std-ffi/src/ctype.rs +++ b/crates/lune-std-ffi/src/ctype.rs @@ -12,6 +12,8 @@ use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; use mlua::prelude::*; use crate::association::{get_association, set_association}; +use crate::carr::CArr; +use crate::cptr::CPtr; use crate::cstruct::CStruct; use crate::FFI_STATUS_NAMES; // use libffi::raw::{ffi_cif, ffi_ptrarray_to_raw}; @@ -26,47 +28,21 @@ pub struct CType { } impl CType { - pub fn new(libffi_type: Type, name: Option) -> Self { + pub fn new(libffi_type: Type, name: Option) -> LuaResult { let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void()); - let size = unsafe { (*libffi_type.as_raw_ptr()).size }; - Self { + let size = libffi_type_ensured_size(libffi_type.as_raw_ptr())?; + Ok(Self { libffi_cif: libffi_cfi, libffi_type, size, name, - } + }) } pub fn get_type(&self) -> Type { self.libffi_type.clone() } - pub fn pointer<'lua>(lua: &'lua Lua, inner: &LuaAnyUserData) -> LuaResult> { - let value = Self { - libffi_cif: Cif::new(vec![Type::pointer()], Type::void()), - libffi_type: Type::pointer(), - size: size_of::(), - name: Some(format!( - "Ptr<{}({})>", - { - if inner.is::() { - "CStruct" - } else if inner.is::() { - "CType" - } else { - "unnamed" - } - }, - type_name_from_userdata(inner)? - )), - } - .into_lua(lua)?; - - set_association(lua, POINTER_INNER, value.borrow(), inner)?; - - Ok(value) - } - pub fn stringify(&self) -> String { match &self.name { Some(t) => t.to_owned(), @@ -78,21 +54,17 @@ impl CType { impl LuaUserData for CType { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { fields.add_field_method_get("size", |_, this| Ok(this.size)); - fields.add_field_function_get("inner", |lua, this| { - let inner = get_association(lua, POINTER_INNER, this)?; - match inner { - Some(t) => Ok(t), - None => Ok(LuaNil), - } - }); } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { methods.add_function("ptr", |lua, this: LuaAnyUserData| { - let pointer = CType::pointer(lua, &this)?; + let pointer = CPtr::from_lua_userdata(lua, &this)?; Ok(pointer) }); - + methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| { + let carr = CArr::from_lua_userdata(lua, &this, length)?; + Ok(carr) + }); methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| { let name = this.stringify(); Ok(name) @@ -105,47 +77,47 @@ pub fn create_all_types(lua: &Lua) -> LuaResult> { Ok(vec![ ( "u8", - CType::new(Type::u8(), Some(String::from("u8"))).into_lua(lua)?, + CType::new(Type::u8(), Some(String::from("u8")))?.into_lua(lua)?, ), ( "u16", - CType::new(Type::u16(), Some(String::from("u16"))).into_lua(lua)?, + CType::new(Type::u16(), Some(String::from("u16")))?.into_lua(lua)?, ), ( "u32", - CType::new(Type::u32(), Some(String::from("u32"))).into_lua(lua)?, + CType::new(Type::u32(), Some(String::from("u32")))?.into_lua(lua)?, ), ( "u64", - CType::new(Type::u64(), Some(String::from("u64"))).into_lua(lua)?, + CType::new(Type::u64(), Some(String::from("u64")))?.into_lua(lua)?, ), ( "i8", - CType::new(Type::i8(), Some(String::from("i8"))).into_lua(lua)?, + CType::new(Type::i8(), Some(String::from("i8")))?.into_lua(lua)?, ), ( "i16", - CType::new(Type::i16(), Some(String::from("i16"))).into_lua(lua)?, + CType::new(Type::i16(), Some(String::from("i16")))?.into_lua(lua)?, ), ( "i32", - CType::new(Type::i32(), Some(String::from("i32"))).into_lua(lua)?, + CType::new(Type::i32(), Some(String::from("i32")))?.into_lua(lua)?, ), ( "i64", - CType::new(Type::i64(), Some(String::from("i64"))).into_lua(lua)?, + CType::new(Type::i64(), Some(String::from("i64")))?.into_lua(lua)?, ), ( "f32", - CType::new(Type::f32(), Some(String::from("f32"))).into_lua(lua)?, + CType::new(Type::f32(), Some(String::from("f32")))?.into_lua(lua)?, ), ( "f64", - CType::new(Type::f64(), Some(String::from("f64"))).into_lua(lua)?, + CType::new(Type::f64(), Some(String::from("f64")))?.into_lua(lua)?, ), ( "void", - CType::new(Type::void(), Some(String::from("void"))).into_lua(lua)?, + CType::new(Type::void(), Some(String::from("void")))?.into_lua(lua)?, ), ]) } @@ -174,15 +146,19 @@ pub fn libffi_types_from_table(table: &LuaTable) -> LuaResult> { Ok(fields) } -// get libffi_type from any c-types userdata +// get libffi_type from any c-type userdata pub fn libffi_type_from_userdata(userdata: &LuaAnyUserData) -> LuaResult { if userdata.is::() { Ok(userdata.borrow::()?.get_type()) } else if userdata.is::() { Ok(userdata.borrow::()?.get_type()) + } else if userdata.is::() { + Ok(userdata.borrow::()?.get_type()) + } else if userdata.is::() { + Ok(CPtr::get_type()) } else { Err(LuaError::external(format!( - "Unexpected field. CStruct, CType or CArr is required for element but got {}", + "Unexpected field. CStruct, CType, CString or CArr is required for element but got {}", pretty_format_value( // Since the data is in the Lua location, // there is no problem with the clone. @@ -193,19 +169,40 @@ pub fn libffi_type_from_userdata(userdata: &LuaAnyUserData) -> LuaResult { } } -// stringify any c-types userdata (for recursive) -pub fn type_name_from_userdata(userdata: &LuaAnyUserData) -> LuaResult { +// stringify any c-type userdata (for recursive) +pub fn type_userdata_stringify(userdata: &LuaAnyUserData) -> LuaResult { if userdata.is::() { let name = userdata.borrow::()?.stringify(); Ok(name) } else if userdata.is::() { let name = CStruct::stringify(userdata)?; Ok(name) + } else if userdata.is::() { + let name = CArr::stringify(userdata)?; + Ok(name) + } else if userdata.is::() { + let name: String = CPtr::stringify(userdata)?; + Ok(name) } else { Ok(String::from("unnamed")) } } +// get name tag for any c-type userdata +pub fn type_name_from_userdata(userdata: &LuaAnyUserData) -> String { + if userdata.is::() { + String::from("CStruct") + } else if userdata.is::() { + String::from("CType") + } else if userdata.is::() { + String::from("CArr") + } else if userdata.is::() { + String::from("CPtr") + } else { + String::from("unnamed") + } +} + // Ensure sizeof c-type (raw::libffi_type) // See: http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html pub fn libffi_type_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult { diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs index d2fdd8ea..a8a5adcc 100644 --- a/crates/lune-std-ffi/src/lib.rs +++ b/crates/lune-std-ffi/src/lib.rs @@ -6,6 +6,7 @@ use mlua::prelude::*; mod association; mod carr; mod cfn; +mod cptr; mod cstring; mod cstruct; mod ctype; From 6f131e95124ea4de1414417f6a0b59bd46eb4578 Mon Sep 17 00:00:00 2001 From: qwreey Date: Sat, 24 Aug 2024 08:21:28 +0000 Subject: [PATCH 04/79] Implement chelper, ffiref, ffibox (#243) --- .../lune-std-ffi/src/{carr.rs => c/c_arr.rs} | 37 ++- crates/lune-std-ffi/src/c/c_cast.rs | 1 + crates/lune-std-ffi/src/{cfn.rs => c/c_fn.rs} | 6 +- crates/lune-std-ffi/src/c/c_helper.rs | 115 +++++++++ .../lune-std-ffi/src/{cptr.rs => c/c_ptr.rs} | 17 +- .../src/{cstring.rs => c/c_string.rs} | 0 .../src/{cstruct.rs => c/c_struct.rs} | 24 +- crates/lune-std-ffi/src/c/c_type.rs | 238 ++++++++++++++++++ crates/lune-std-ffi/src/c/mod.rs | 14 ++ crates/lune-std-ffi/src/ctype.rs | 227 ----------------- .../ffi_association.rs} | 0 crates/lune-std-ffi/src/ffi/ffi_box.rs | 137 ++++++++++ crates/lune-std-ffi/src/ffi/ffi_helper.rs | 35 +++ .../src/{ffilib.rs => ffi/ffi_lib.rs} | 6 +- crates/lune-std-ffi/src/ffi/ffi_platform.rs | 22 ++ .../src/{ffiraw.rs => ffi/ffi_raw.rs} | 3 + crates/lune-std-ffi/src/ffi/ffi_ref.rs | 94 +++++++ crates/lune-std-ffi/src/ffi/mod.rs | 13 + crates/lune-std-ffi/src/ffibox.rs | 87 ------- crates/lune-std-ffi/src/ffiref.rs | 61 ----- crates/lune-std-ffi/src/lib.rs | 34 +-- crates/lune-std-ffi/todo.md | 22 +- 22 files changed, 743 insertions(+), 450 deletions(-) rename crates/lune-std-ffi/src/{carr.rs => c/c_arr.rs} (80%) create mode 100644 crates/lune-std-ffi/src/c/c_cast.rs rename crates/lune-std-ffi/src/{cfn.rs => c/c_fn.rs} (87%) create mode 100644 crates/lune-std-ffi/src/c/c_helper.rs rename crates/lune-std-ffi/src/{cptr.rs => c/c_ptr.rs} (82%) rename crates/lune-std-ffi/src/{cstring.rs => c/c_string.rs} (100%) rename crates/lune-std-ffi/src/{cstruct.rs => c/c_struct.rs} (89%) create mode 100644 crates/lune-std-ffi/src/c/c_type.rs create mode 100644 crates/lune-std-ffi/src/c/mod.rs delete mode 100644 crates/lune-std-ffi/src/ctype.rs rename crates/lune-std-ffi/src/{association.rs => ffi/ffi_association.rs} (100%) create mode 100644 crates/lune-std-ffi/src/ffi/ffi_box.rs create mode 100644 crates/lune-std-ffi/src/ffi/ffi_helper.rs rename crates/lune-std-ffi/src/{ffilib.rs => ffi/ffi_lib.rs} (91%) create mode 100644 crates/lune-std-ffi/src/ffi/ffi_platform.rs rename crates/lune-std-ffi/src/{ffiraw.rs => ffi/ffi_raw.rs} (88%) create mode 100644 crates/lune-std-ffi/src/ffi/ffi_ref.rs create mode 100644 crates/lune-std-ffi/src/ffi/mod.rs delete mode 100644 crates/lune-std-ffi/src/ffibox.rs delete mode 100644 crates/lune-std-ffi/src/ffiref.rs diff --git a/crates/lune-std-ffi/src/carr.rs b/crates/lune-std-ffi/src/c/c_arr.rs similarity index 80% rename from crates/lune-std-ffi/src/carr.rs rename to crates/lune-std-ffi/src/c/c_arr.rs index 886a01fe..6fbd9641 100644 --- a/crates/lune-std-ffi/src/carr.rs +++ b/crates/lune-std-ffi/src/c/c_arr.rs @@ -1,11 +1,13 @@ use libffi::middle::Type; use mlua::prelude::*; -use crate::association::{get_association, set_association}; -use crate::cptr::CPtr; -use crate::ctype::{ - libffi_type_ensured_size, libffi_type_from_userdata, type_userdata_stringify, CType, +use super::association_names::CARR_INNER; +use super::c_helper::{ + get_ensured_size, name_from_userdata, stringify_userdata, type_from_userdata, }; +use super::c_ptr::CPtr; +use super::c_type::CType; +use crate::ffi::ffi_association::{get_association, set_association}; // This is a series of some type. // It provides the final size and the offset of the index, @@ -18,8 +20,6 @@ use crate::ctype::{ // Padding after each field inside the struct is set to next field can follow the alignment. // There is no problem even if you create a struct with n fields of a single type within the struct. Array adheres to the condition that there is no additional padding between each element. Padding to a struct is padding inside the struct. Simply think of the padding byte as a trailing unnamed field. -const CARR_INNER: &str = "__carr_inner"; - pub struct CArr { libffi_type: Type, struct_type: Type, @@ -31,7 +31,7 @@ pub struct CArr { impl CArr { pub fn new(libffi_type: Type, length: usize) -> LuaResult { let struct_type = Type::structure(vec![libffi_type.clone(); length]); - let field_size = libffi_type_ensured_size(libffi_type.as_raw_ptr())?; + let field_size = get_ensured_size(libffi_type.as_raw_ptr())?; Ok(Self { libffi_type, @@ -47,7 +47,7 @@ impl CArr { luatype: &LuaAnyUserData<'lua>, length: usize, ) -> LuaResult> { - let fields = libffi_type_from_userdata(luatype)?; + let fields = type_from_userdata(luatype)?; let carr = lua.create_userdata(Self::new(fields, length)?)?; set_association(lua, CARR_INNER, carr.clone(), luatype)?; @@ -63,15 +63,26 @@ impl CArr { pub fn stringify(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."))?; - Ok(format!( - " {} ; {} ", - type_userdata_stringify(inner)?, - carr.length - )) + + if inner.is::() { + Ok(format!( + " {} ; {} ", + stringify_userdata(inner)?, + carr.length + )) + } else { + Ok(format!( + " <{}({})> ; {} ", + name_from_userdata(inner), + stringify_userdata(inner)?, + carr.length + )) + } } else { Err(LuaError::external("failed to get inner type userdata.")) } diff --git a/crates/lune-std-ffi/src/c/c_cast.rs b/crates/lune-std-ffi/src/c/c_cast.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/crates/lune-std-ffi/src/c/c_cast.rs @@ -0,0 +1 @@ + diff --git a/crates/lune-std-ffi/src/cfn.rs b/crates/lune-std-ffi/src/c/c_fn.rs similarity index 87% rename from crates/lune-std-ffi/src/cfn.rs rename to crates/lune-std-ffi/src/c/c_fn.rs index f029cfcb..315497e9 100644 --- a/crates/lune-std-ffi/src/cfn.rs +++ b/crates/lune-std-ffi/src/c/c_fn.rs @@ -1,7 +1,7 @@ use libffi::middle::{Cif, Type}; use mlua::prelude::*; -use crate::ctype::{libffi_type_from_userdata, libffi_types_from_table}; +use super::c_helper::{type_from_userdata, 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 from_lua_table(args: LuaTable, ret: LuaAnyUserData) -> LuaResult { - let args = libffi_types_from_table(&args)?; - let ret = libffi_type_from_userdata(&ret)?; + let args = type_list_from_table(&args)?; + let ret = type_from_userdata(&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 new file mode 100644 index 00000000..d25843c9 --- /dev/null +++ b/crates/lune-std-ffi/src/c/c_helper.rs @@ -0,0 +1,115 @@ +use std::ptr::{self, null_mut}; + +use libffi::{low, middle::Type, raw}; +use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; +use mlua::prelude::*; + +use super::c_arr::CArr; +use super::c_ptr::CPtr; +use super::c_struct::CStruct; +use super::c_type::CType; +use crate::ffi::ffi_helper::FFI_STATUS_NAMES; + +// get Vec from table(array) of c-types userdata +pub fn type_list_from_table(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(&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()) + ))); + } + } + } + + Ok(fields) +} + +// get libffi_type from any c-type userdata +pub fn type_from_userdata(userdata: &LuaAnyUserData) -> LuaResult { + if userdata.is::() { + Ok(userdata.borrow::()?.get_type()) + } else if userdata.is::() { + Ok(userdata.borrow::()?.get_type()) + } else if userdata.is::() { + Ok(userdata.borrow::()?.get_type()) + } else if userdata.is::() { + Ok(CPtr::get_type()) + } else { + Err(LuaError::external(format!( + "Unexpected field. CStruct, CType, CString or CArr is required for element but got {}", + pretty_format_value( + // Since the data is in the Lua location, + // there is no problem with the clone. + &LuaValue::UserData(userdata.to_owned()), + &ValueFormatConfig::new() + ) + ))) + } +} + +// stringify any c-type userdata (for recursive) +pub fn stringify_userdata(userdata: &LuaAnyUserData) -> LuaResult { + if userdata.is::() { + let name = userdata.borrow::()?.stringify(); + Ok(name) + } else if userdata.is::() { + let name = CStruct::stringify(userdata)?; + Ok(name) + } else if userdata.is::() { + let name = CArr::stringify(userdata)?; + Ok(name) + } else if userdata.is::() { + let name: String = CPtr::stringify(userdata)?; + Ok(name) + } else { + Ok(String::from("unnamed")) + } +} + +// get name tag for any c-type userdata +pub fn name_from_userdata(userdata: &LuaAnyUserData) -> String { + if userdata.is::() { + String::from("CStruct") + } else if userdata.is::() { + String::from("CType") + } else if userdata.is::() { + String::from("CArr") + } else if userdata.is::() { + String::from("CPtr") + } else { + String::from("unnamed") + } +} + +// Ensure sizeof c-type (raw::libffi_type) +// See: http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html +pub fn get_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult { + let mut cif = low::ffi_cif::default(); + let result = unsafe { + raw::ffi_prep_cif( + ptr::from_mut(&mut cif), + raw::ffi_abi_FFI_DEFAULT_ABI, + 0, + ffi_type, + null_mut(), + ) + }; + + if result != raw::ffi_status_FFI_OK { + return Err(LuaError::external(format!( + "ffi_get_struct_offsets failed. expected result {}, got {}", + FFI_STATUS_NAMES[0], FFI_STATUS_NAMES[result as usize] + ))); + } + unsafe { Ok((*ffi_type).size) } +} diff --git a/crates/lune-std-ffi/src/cptr.rs b/crates/lune-std-ffi/src/c/c_ptr.rs similarity index 82% rename from crates/lune-std-ffi/src/cptr.rs rename to crates/lune-std-ffi/src/c/c_ptr.rs index 62324d1c..5fb88459 100644 --- a/crates/lune-std-ffi/src/cptr.rs +++ b/crates/lune-std-ffi/src/c/c_ptr.rs @@ -5,11 +5,10 @@ use std::borrow::Borrow; use libffi::middle::Type; use mlua::prelude::*; -use crate::association::{get_association, set_association}; -use crate::carr::CArr; -use crate::ctype::{type_name_from_userdata, type_userdata_stringify}; - -const POINTER_INNER: &str = "__pointer_inner"; +use super::association_names::CPTR_INNER; +use super::c_arr::CArr; +use super::c_helper::{name_from_userdata, stringify_userdata}; +use crate::ffi::ffi_association::{get_association, set_association}; pub struct CPtr(); @@ -22,7 +21,7 @@ impl CPtr { ) -> LuaResult> { let value = Self().into_lua(lua)?; - set_association(lua, POINTER_INNER, value.borrow(), inner)?; + set_association(lua, CPTR_INNER, value.borrow(), inner)?; Ok(value) } @@ -37,8 +36,8 @@ impl CPtr { .ok_or(LuaError::external("failed to get inner type userdata."))?; Ok(format!( " <{}({})> ", - type_name_from_userdata(inner), - type_userdata_stringify(inner)?, + name_from_userdata(inner), + stringify_userdata(inner)?, )) } else { Err(LuaError::external("failed to get inner type userdata.")) @@ -55,7 +54,7 @@ impl LuaUserData for CPtr { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { fields.add_field_method_get("size", |_, _| Ok(size_of::())); fields.add_field_function_get("inner", |lua, this| { - let inner = get_association(lua, POINTER_INNER, this)? + let inner = get_association(lua, CPTR_INNER, this)? .ok_or(LuaError::external("inner type not found"))?; Ok(inner) }); diff --git a/crates/lune-std-ffi/src/cstring.rs b/crates/lune-std-ffi/src/c/c_string.rs similarity index 100% rename from crates/lune-std-ffi/src/cstring.rs rename to crates/lune-std-ffi/src/c/c_string.rs diff --git a/crates/lune-std-ffi/src/cstruct.rs b/crates/lune-std-ffi/src/c/c_struct.rs similarity index 89% rename from crates/lune-std-ffi/src/cstruct.rs rename to crates/lune-std-ffi/src/c/c_struct.rs index 9a554dae..9e945ece 100644 --- a/crates/lune-std-ffi/src/cstruct.rs +++ b/crates/lune-std-ffi/src/c/c_struct.rs @@ -9,13 +9,13 @@ use libffi::{ }; use mlua::prelude::*; -use crate::ctype::{libffi_types_from_table, type_userdata_stringify, CType}; -use crate::FFI_STATUS_NAMES; -use crate::{ - association::{get_association, set_association}, - ctype::type_name_from_userdata, -}; -use crate::{carr::CArr, cptr::CPtr}; +use super::association_names::CSTRUCT_INNER; +use super::c_arr::CArr; +use super::c_helper::{name_from_userdata, stringify_userdata, type_list_from_table}; +use super::c_ptr::CPtr; +use super::c_type::CType; +use crate::ffi::ffi_association::{get_association, set_association}; +use crate::ffi::ffi_helper::FFI_STATUS_NAMES; pub struct CStruct { libffi_cif: Cif, @@ -25,8 +25,6 @@ pub struct CStruct { size: usize, } -const CSTRUCT_INNER: &str = "__cstruct_inner"; - impl CStruct { pub fn new(fields: Vec) -> LuaResult { let libffi_type = Type::structure(fields.clone()); @@ -68,7 +66,7 @@ impl CStruct { lua: &'lua Lua, table: LuaTable<'lua>, ) -> LuaResult> { - let fields = libffi_types_from_table(&table)?; + let fields = type_list_from_table(&table)?; let cstruct = lua.create_userdata(Self::new(fields)?)?; table.set_readonly(true); set_association(lua, CSTRUCT_INNER, cstruct.clone(), table)?; @@ -88,13 +86,13 @@ impl CStruct { for i in 0..table.raw_len() { let child: LuaAnyUserData = table.raw_get(i + 1)?; if child.is::() { - result.push_str(format!("{}, ", type_userdata_stringify(&child)?).as_str()); + result.push_str(format!("{}, ", stringify_userdata(&child)?).as_str()); } else { result.push_str( format!( "<{}({})>, ", - type_name_from_userdata(&child), - type_userdata_stringify(&child)? + name_from_userdata(&child), + stringify_userdata(&child)? ) .as_str(), ); diff --git a/crates/lune-std-ffi/src/c/c_type.rs b/crates/lune-std-ffi/src/c/c_type.rs new file mode 100644 index 00000000..58d3364f --- /dev/null +++ b/crates/lune-std-ffi/src/c/c_type.rs @@ -0,0 +1,238 @@ +#![allow(clippy::cargo_common_metadata)] + +use core::ffi::{ + c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, + c_ulong, c_ulonglong, c_ushort, c_void, +}; + +use libffi::middle::{Cif, Type}; +use mlua::prelude::*; + +use super::c_arr::CArr; +use super::c_helper::get_ensured_size; +use super::c_ptr::CPtr; +use crate::ffi::ffi_helper::get_ptr_from_userdata; +use crate::ffi::ffi_platform::CHAR_IS_SIGNED; +// use libffi::raw::{ffi_cif, ffi_ptrarray_to_raw}; + +pub struct CType { + libffi_cif: Cif, + libffi_type: Type, + size: usize, + name: Option, + + // Write converted data from luavalue into some ptr + pub luavalue_into_ptr: fn(value: LuaValue, ptr: *mut c_void) -> LuaResult<()>, + + // Read luavalue from some ptr + pub ptr_into_luavalue: fn(lua: &Lua, ptr: *mut c_void) -> LuaResult, +} + +impl CType { + pub fn new( + libffi_type: Type, + name: Option, + luavalue_into_ptr: fn(value: LuaValue, ptr: *mut c_void) -> LuaResult<()>, + ptr_into_luavalue: fn(lua: &Lua, ptr: *mut c_void) -> LuaResult, + ) -> LuaResult { + let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void()); + let size = get_ensured_size(libffi_type.as_raw_ptr())?; + Ok(Self { + libffi_cif: libffi_cfi, + libffi_type, + size, + name, + luavalue_into_ptr, + ptr_into_luavalue, + }) + } + + pub fn get_type(&self) -> Type { + self.libffi_type.clone() + } + + pub fn stringify(&self) -> String { + match &self.name { + Some(t) => t.to_owned(), + None => String::from("unnamed"), + } + } + + // Read data from ptr and convert it into luavalue + pub unsafe fn read_ptr<'lua>( + &self, + lua: &'lua Lua, + userdata: LuaAnyUserData<'lua>, + offset: Option, + ) -> LuaResult> { + let ptr = unsafe { get_ptr_from_userdata(&userdata, offset)? }; + let value = (self.ptr_into_luavalue)(lua, ptr)?; + Ok(value) + } + + // Write converted data from luavalue into ptr + pub unsafe fn write_ptr<'lua>( + &self, + luavalue: LuaValue<'lua>, + userdata: LuaAnyUserData<'lua>, + offset: Option, + ) -> LuaResult<()> { + let ptr = unsafe { get_ptr_from_userdata(&userdata, offset)? }; + (self.luavalue_into_ptr)(luavalue, ptr)?; + Ok(()) + } +} + +impl LuaUserData for CType { + 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) { + methods.add_function("ptr", |lua, this: LuaAnyUserData| { + let pointer = CPtr::from_lua_userdata(lua, &this)?; + Ok(pointer) + }); + methods.add_method( + "from", + |lua, ctype, (userdata, offset): (LuaAnyUserData, Option)| { + let value = unsafe { ctype.read_ptr(lua, userdata, offset)? }; + Ok(value) + }, + ); + methods.add_method( + "into", + |_, ctype, (value, userdata, offset): (LuaValue, LuaAnyUserData, Option)| { + unsafe { ctype.write_ptr(value, userdata, offset)? }; + Ok(()) + }, + ); + methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| { + let carr = CArr::from_lua_userdata(lua, &this, length)?; + Ok(carr) + }); + methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| { + let name = this.stringify(); + Ok(name) + }); + } +} + +// export all default c-types +#[allow(clippy::too_many_lines)] +pub fn create_all_types(lua: &Lua) -> LuaResult> { + Ok(vec![ + ( + "int", + CType::new( + Type::c_int(), + Some(String::from("int")), + |data, ptr| { + let value = match data { + LuaValue::Integer(t) => t, + _ => { + return Err(LuaError::external(format!( + "Integer expected, got {}", + data.type_name() + ))) + } + } as c_int; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + }, + |lua: &Lua, ptr: *mut c_void| { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + }, + )? + .into_lua(lua)?, + ), + ( + "long", + CType::new( + Type::c_long(), + Some(String::from("long")), + |data, ptr| { + let value = match data { + LuaValue::Integer(t) => t, + _ => { + return Err(LuaError::external(format!( + "Integer expected, got {}", + data.type_name() + ))) + } + } as c_long; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + }, + |lua: &Lua, ptr: *mut c_void| { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + }, + )? + .into_lua(lua)?, + ), + ( + "longlong", + CType::new( + Type::c_longlong(), + Some(String::from("longlong")), + |data, ptr| { + let value = match data { + LuaValue::Integer(t) => t, + _ => { + return Err(LuaError::external(format!( + "Integer expected, got {}", + data.type_name() + ))) + } + } as c_longlong; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + }, + |lua: &Lua, ptr: *mut c_void| { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + }, + )? + .into_lua(lua)?, + ), + ( + "char", + CType::new( + if CHAR_IS_SIGNED { + Type::c_schar() + } else { + Type::c_uchar() + }, + Some(String::from("char")), + |data, ptr| { + let value = match data { + LuaValue::Integer(t) => t, + _ => { + return Err(LuaError::external(format!( + "Integer expected, got {}", + data.type_name() + ))) + } + } as c_char; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + }, + |lua: &Lua, ptr: *mut c_void| { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + }, + )? + .into_lua(lua)?, + ), + ]) +} diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs new file mode 100644 index 00000000..803fa626 --- /dev/null +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -0,0 +1,14 @@ +pub(super) mod c_arr; +pub(super) mod c_fn; +pub(super) mod c_helper; +pub(super) mod c_ptr; +pub(super) mod c_string; +pub(super) mod c_struct; +pub(super) mod c_type; + +// Named registry table names +mod association_names { + pub const CPTR_INNER: &str = "__cptr_inner"; + pub const CARR_INNER: &str = "__carr_inner"; + pub const CSTRUCT_INNER: &str = "__cstruct_inner"; +} diff --git a/crates/lune-std-ffi/src/ctype.rs b/crates/lune-std-ffi/src/ctype.rs deleted file mode 100644 index 7fe6b157..00000000 --- a/crates/lune-std-ffi/src/ctype.rs +++ /dev/null @@ -1,227 +0,0 @@ -#![allow(clippy::cargo_common_metadata)] - -use std::borrow::Borrow; -use std::ptr::{self, null_mut}; - -use libffi::{ - low, - middle::{Cif, Type}, - raw, -}; -use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; -use mlua::prelude::*; - -use crate::association::{get_association, set_association}; -use crate::carr::CArr; -use crate::cptr::CPtr; -use crate::cstruct::CStruct; -use crate::FFI_STATUS_NAMES; -// use libffi::raw::{ffi_cif, ffi_ptrarray_to_raw}; - -const POINTER_INNER: &str = "__pointer_inner"; - -pub struct CType { - libffi_cif: Cif, - libffi_type: Type, - size: usize, - name: Option, -} - -impl CType { - pub fn new(libffi_type: Type, name: Option) -> LuaResult { - let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void()); - let size = libffi_type_ensured_size(libffi_type.as_raw_ptr())?; - Ok(Self { - libffi_cif: libffi_cfi, - libffi_type, - size, - name, - }) - } - - pub fn get_type(&self) -> Type { - self.libffi_type.clone() - } - - pub fn stringify(&self) -> String { - match &self.name { - Some(t) => t.to_owned(), - None => String::from("unnamed"), - } - } -} - -impl LuaUserData for CType { - 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) { - methods.add_function("ptr", |lua, this: LuaAnyUserData| { - let pointer = CPtr::from_lua_userdata(lua, &this)?; - Ok(pointer) - }); - methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| { - let carr = CArr::from_lua_userdata(lua, &this, length)?; - Ok(carr) - }); - methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| { - let name = this.stringify(); - Ok(name) - }); - } -} - -// export all default c-types -pub fn create_all_types(lua: &Lua) -> LuaResult> { - Ok(vec![ - ( - "u8", - CType::new(Type::u8(), Some(String::from("u8")))?.into_lua(lua)?, - ), - ( - "u16", - CType::new(Type::u16(), Some(String::from("u16")))?.into_lua(lua)?, - ), - ( - "u32", - CType::new(Type::u32(), Some(String::from("u32")))?.into_lua(lua)?, - ), - ( - "u64", - CType::new(Type::u64(), Some(String::from("u64")))?.into_lua(lua)?, - ), - ( - "i8", - CType::new(Type::i8(), Some(String::from("i8")))?.into_lua(lua)?, - ), - ( - "i16", - CType::new(Type::i16(), Some(String::from("i16")))?.into_lua(lua)?, - ), - ( - "i32", - CType::new(Type::i32(), Some(String::from("i32")))?.into_lua(lua)?, - ), - ( - "i64", - CType::new(Type::i64(), Some(String::from("i64")))?.into_lua(lua)?, - ), - ( - "f32", - CType::new(Type::f32(), Some(String::from("f32")))?.into_lua(lua)?, - ), - ( - "f64", - CType::new(Type::f64(), Some(String::from("f64")))?.into_lua(lua)?, - ), - ( - "void", - CType::new(Type::void(), Some(String::from("void")))?.into_lua(lua)?, - ), - ]) -} - -// get Vec from table(array) of c-types userdata -pub fn libffi_types_from_table(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(libffi_type_from_userdata(&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()) - ))); - } - } - } - - Ok(fields) -} - -// get libffi_type from any c-type userdata -pub fn libffi_type_from_userdata(userdata: &LuaAnyUserData) -> LuaResult { - if userdata.is::() { - Ok(userdata.borrow::()?.get_type()) - } else if userdata.is::() { - Ok(userdata.borrow::()?.get_type()) - } else if userdata.is::() { - Ok(userdata.borrow::()?.get_type()) - } else if userdata.is::() { - Ok(CPtr::get_type()) - } else { - Err(LuaError::external(format!( - "Unexpected field. CStruct, CType, CString or CArr is required for element but got {}", - pretty_format_value( - // Since the data is in the Lua location, - // there is no problem with the clone. - &LuaValue::UserData(userdata.to_owned()), - &ValueFormatConfig::new() - ) - ))) - } -} - -// stringify any c-type userdata (for recursive) -pub fn type_userdata_stringify(userdata: &LuaAnyUserData) -> LuaResult { - if userdata.is::() { - let name = userdata.borrow::()?.stringify(); - Ok(name) - } else if userdata.is::() { - let name = CStruct::stringify(userdata)?; - Ok(name) - } else if userdata.is::() { - let name = CArr::stringify(userdata)?; - Ok(name) - } else if userdata.is::() { - let name: String = CPtr::stringify(userdata)?; - Ok(name) - } else { - Ok(String::from("unnamed")) - } -} - -// get name tag for any c-type userdata -pub fn type_name_from_userdata(userdata: &LuaAnyUserData) -> String { - if userdata.is::() { - String::from("CStruct") - } else if userdata.is::() { - String::from("CType") - } else if userdata.is::() { - String::from("CArr") - } else if userdata.is::() { - String::from("CPtr") - } else { - String::from("unnamed") - } -} - -// Ensure sizeof c-type (raw::libffi_type) -// See: http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html -pub fn libffi_type_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult { - let mut cif: low::ffi_cif = Default::default(); - let result = unsafe { - raw::ffi_prep_cif( - ptr::from_mut(&mut cif), - raw::ffi_abi_FFI_DEFAULT_ABI, - 0, - ffi_type, - null_mut(), - ) - }; - - if result != raw::ffi_status_FFI_OK { - return Err(LuaError::external(format!( - "ffi_get_struct_offsets failed. expected result {}, got {}", - FFI_STATUS_NAMES[0], FFI_STATUS_NAMES[result as usize] - ))); - } - unsafe { Ok((*ffi_type).size) } -} diff --git a/crates/lune-std-ffi/src/association.rs b/crates/lune-std-ffi/src/ffi/ffi_association.rs similarity index 100% rename from crates/lune-std-ffi/src/association.rs rename to crates/lune-std-ffi/src/ffi/ffi_association.rs diff --git a/crates/lune-std-ffi/src/ffi/ffi_box.rs b/crates/lune-std-ffi/src/ffi/ffi_box.rs new file mode 100644 index 00000000..49fb1d2e --- /dev/null +++ b/crates/lune-std-ffi/src/ffi/ffi_box.rs @@ -0,0 +1,137 @@ +#![allow(clippy::cargo_common_metadata)] + +// It is an untyped, sized memory area that Lua can manage. +// This area is safe within Lua. Operations have their boundaries checked. +// It is basically intended to implement passing a pointed space to the outside. +// It also helps you handle data that Lua cannot handle. +// Depending on the type, operations such as sum, mul, and mod may be implemented. +// There is no need to enclose all data in a box; +// rather, it creates more heap space, so it should be used appropriately +// where necessary. + +use std::boxed::Box; + +use core::ffi::c_void; +use mlua::prelude::*; + +use super::association_names::BOX_REF_INNER; +use super::ffi_association::set_association; +use super::ffi_ref::FfiRange; +use super::ffi_ref::FfiRef; + +pub struct FfiBox(Box<[u8]>); + +impl FfiBox { + // For efficiency, it is initialized non-zeroed. + pub fn new(size: usize) -> Self { + // Create new vector to allocate heap memory. sized with 'size' + let mut vec_heap = Vec::::with_capacity(size); + + // It is safe to have a length equal to the capacity + #[allow(clippy::uninit_vec)] + unsafe { + vec_heap.set_len(size); + } + + Self(vec_heap.into_boxed_slice()) + } + + pub fn size(&self) -> usize { + self.0.len() + } + + // pub fn copy(&self, target: &mut FfiBox) {} + + pub fn get_ptr(&self) -> *mut c_void { + self.0.as_ptr() as *mut c_void + } + + pub fn stringify(&self) -> String { + let mut buff = String::from(" "); + for i in &self.0 { + buff.push_str(i.to_string().as_str()); + buff.push_str(", "); + } + buff.pop(); + buff.pop(); + buff.push(' '); + buff + } + + pub fn binary_print(&self) -> String { + let mut buff: String = String::with_capacity(self.size() * 10 - 2); + for (pos, value) in self.0.iter().enumerate() { + for i in 0..8 { + if (value & (1 << i)) == 0 { + buff.push('0'); + } else { + buff.push('1'); + } + } + if pos < self.size() - 1 { + buff.push_str(", "); + } + } + buff + } + + // bad naming. i have no idea what should i use + pub fn luaref<'lua>( + lua: &'lua Lua, + this: LuaAnyUserData<'lua>, + offset: Option, + ) -> LuaResult> { + let target = this.borrow::()?; + let ptr = if let Some(t) = offset { + if t < 0 || t >= (target.size() as isize) { + return Err(LuaError::external(format!( + "Offset is out of bounds. box.size: {}. offset got {}", + target.size(), + t + ))); + } + unsafe { target.get_ptr().offset(t) } + } else { + target.get_ptr() + }; + + let luaref = lua.create_userdata(FfiRef::new( + ptr, + Some(FfiRange { + low: 0, + high: target.size() as isize, + }), + ))?; + + set_association(lua, BOX_REF_INNER, luaref.clone(), this.clone())?; + + Ok(luaref) + } + + pub fn zero(&mut self) { + self.0.fill(0u8); + } +} + +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) { + methods.add_function_mut("zero", |_, this: LuaAnyUserData| { + this.borrow_mut::()?.zero(); + Ok(this) + }); + methods.add_function( + "ref", + |lua, (this, offset): (LuaAnyUserData, Option)| { + let luaref = FfiBox::luaref(lua, this, offset)?; + Ok(luaref) + }, + ); + methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| { + Ok(this.binary_print()) + }); + } +} diff --git a/crates/lune-std-ffi/src/ffi/ffi_helper.rs b/crates/lune-std-ffi/src/ffi/ffi_helper.rs new file mode 100644 index 00000000..ffa32f2f --- /dev/null +++ b/crates/lune-std-ffi/src/ffi/ffi_helper.rs @@ -0,0 +1,35 @@ +use std::ffi::c_void; + +use mlua::prelude::*; + +use super::ffi_box::FfiBox; +use super::ffi_ref::FfiRef; + +// 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", +]; + +pub unsafe fn get_ptr_from_userdata( + userdata: &LuaAnyUserData, + offset: Option, +) -> LuaResult<*mut c_void> { + let ptr = if userdata.is::() { + userdata.borrow::()?.get_ptr() + } else if userdata.is::() { + userdata.borrow::()?.get_ptr() + } else { + return Err(LuaError::external("asdf")); + }; + + let ptr = if let Some(t) = offset { + ptr.offset(t) + } else { + ptr + }; + + Ok(ptr) +} diff --git a/crates/lune-std-ffi/src/ffilib.rs b/crates/lune-std-ffi/src/ffi/ffi_lib.rs similarity index 91% rename from crates/lune-std-ffi/src/ffilib.rs rename to crates/lune-std-ffi/src/ffi/ffi_lib.rs index 23958682..bf870154 100644 --- a/crates/lune-std-ffi/src/ffilib.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_lib.rs @@ -3,8 +3,8 @@ use std::ffi::c_void; use dlopen2::symbor::Library; use mlua::prelude::*; -use crate::association::set_association; -use crate::ffiref::FfiRef; +use super::ffi_association::set_association; +use super::ffi_ref::FfiRef; pub struct FfiLib(Library); @@ -39,7 +39,7 @@ impl FfiLib { .map_err(|err| LuaError::external(format!("{err}")))? }; - let luasym = lua.create_userdata(FfiRef::new(*sym))?; + let luasym = lua.create_userdata(FfiRef::new(*sym, None))?; set_association(lua, SYM_INNER, luasym.clone(), this.clone())?; diff --git a/crates/lune-std-ffi/src/ffi/ffi_platform.rs b/crates/lune-std-ffi/src/ffi/ffi_platform.rs new file mode 100644 index 00000000..c7371aaf --- /dev/null +++ b/crates/lune-std-ffi/src/ffi/ffi_platform.rs @@ -0,0 +1,22 @@ +use core::ffi::c_char; +use std::env::consts; +use std::vec::Vec; + +pub const CHAR_IS_SIGNED: bool = c_char::MIN as u8 != u8::MIN; +pub const IS_LITTLE_ENDIAN: bool = cfg!(target_endian = "little"); + +pub fn get_platform_value() -> Vec<(&'static str, &'static str)> { + vec![ + // https://doc.rust-lang.org/std/env/consts/constant.ARCH.html + ("arch", consts::ARCH), + // https://doc.rust-lang.org/std/env/consts/constant.OS.html + ("os", consts::OS), + // https://doc.rust-lang.org/std/env/consts/constant.FAMILY.html + ("family", consts::FAMILY), + ("endian", if IS_LITTLE_ENDIAN { "little" } else { "big" }), + ( + "char_variant", + if CHAR_IS_SIGNED { "schar" } else { "uchar" }, + ), + ] +} diff --git a/crates/lune-std-ffi/src/ffiraw.rs b/crates/lune-std-ffi/src/ffi/ffi_raw.rs similarity index 88% rename from crates/lune-std-ffi/src/ffiraw.rs rename to crates/lune-std-ffi/src/ffi/ffi_raw.rs index 6d64e58b..6a82cd97 100644 --- a/crates/lune-std-ffi/src/ffiraw.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_raw.rs @@ -1,3 +1,6 @@ +use core::ffi::c_void; +use std::{convert, mem::transmute, ptr}; + // This is raw data coming from outside. // Users must convert it to a Lua value, reference, or box to use it. // The biggest reason for providing this is to allow the user to diff --git a/crates/lune-std-ffi/src/ffi/ffi_ref.rs b/crates/lune-std-ffi/src/ffi/ffi_ref.rs new file mode 100644 index 00000000..a5ebc708 --- /dev/null +++ b/crates/lune-std-ffi/src/ffi/ffi_ref.rs @@ -0,0 +1,94 @@ +use core::ffi::c_void; +use std::ptr; + +use mlua::prelude::*; + +use super::association_names::REF_INNER; +use super::ffi_association::set_association; + +// A referenced space. It is possible to read and write through types. +// This operation is not safe. This may cause a memory error in Lua +// if use it incorrectly. +// If it references an area managed by Lua, +// the box will remain as long as this reference is alive. + +pub struct FfiRange { + pub(crate) high: isize, + pub(crate) low: isize, +} + +pub struct FfiRef { + ptr: *mut c_void, + range: Option, +} + +impl FfiRef { + pub fn new(ptr: *mut c_void, range: Option) -> Self { + Self { ptr, range } + } + + // bad naming. i have no idea what should i use + pub fn luaref<'lua>( + lua: &'lua Lua, + this: LuaAnyUserData<'lua>, + ) -> LuaResult> { + let target = this.borrow::()?; + + let luaref = lua.create_userdata(FfiRef::new( + ptr::from_ref(&target.ptr) as *mut c_void, + Some(FfiRange { + low: 0, + high: size_of::() as isize, + }), + ))?; + + set_association(lua, REF_INNER, luaref.clone(), this.clone())?; + + Ok(luaref) + } + + pub fn get_ptr(&self) -> *mut c_void { + self.ptr + } + + pub unsafe fn deref(&self) -> Self { + Self::new(*self.ptr.cast::<*mut c_void>(), None) + } + + pub unsafe fn offset(&self, offset: isize) -> LuaResult { + let range = if let Some(ref t) = self.range { + let high = t.high - offset; + let low = t.low - offset; + + if low > 0 || high < 0 { + return Err(LuaError::external(format!( + "Offset is out of bounds. low: {}, high: {}. offset got {}", + t.low, t.high, offset + ))); + } + + Some(FfiRange { high, low }) + } else { + None + }; + + Ok(Self::new(self.ptr.offset(offset), range)) + } +} + +impl LuaUserData for FfiRef { + fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_method("deref", |_, this, ()| { + let ffiref = unsafe { this.deref() }; + Ok(ffiref) + }); + methods.add_method("offset", |_, this, offset: isize| { + let ffiref = unsafe { this.offset(offset)? }; + Ok(ffiref) + }); + methods.add_function("ref", |lua, this: LuaAnyUserData| { + let ffiref = FfiRef::luaref(lua, this)?; + Ok(ffiref) + }); + } +} diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs new file mode 100644 index 00000000..4812028f --- /dev/null +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -0,0 +1,13 @@ +pub(super) mod ffi_association; +pub(super) mod ffi_box; +pub(super) mod ffi_helper; +pub(super) mod ffi_lib; +pub(super) mod ffi_platform; +pub(super) mod ffi_raw; +pub(super) mod ffi_ref; + +// Named registry table names +mod association_names { + pub const BOX_REF_INNER: &str = "__box_ref"; + pub const REF_INNER: &str = "__ref_inner"; +} diff --git a/crates/lune-std-ffi/src/ffibox.rs b/crates/lune-std-ffi/src/ffibox.rs deleted file mode 100644 index b9d0df8e..00000000 --- a/crates/lune-std-ffi/src/ffibox.rs +++ /dev/null @@ -1,87 +0,0 @@ -#![allow(clippy::cargo_common_metadata)] - -// It is an untyped, sized memory area that Lua can manage. -// This area is safe within Lua. Operations have their boundaries checked. -// It is basically intended to implement passing a pointed space to the outside. -// It also helps you handle data that Lua cannot handle. -// Depending on the type, operations such as sum, mul, and mod may be implemented. -// There is no need to enclose all data in a box; -// rather, it creates more heap space, so it should be used appropriately -// where necessary. - -use std::boxed::Box; - -use core::ffi::c_void; -use mlua::prelude::*; - -use crate::association::set_association; -use crate::ffiref::FfiRef; - -const BOX_REF_INNER: &str = "__box_ref"; - -pub struct FfiBox(Box<[u8]>); - -impl FfiBox { - pub fn new(size: usize) -> Self { - Self(vec![0u8; size].into_boxed_slice()) - } - - pub fn size(&self) -> usize { - self.0.len() - } - - // pub fn copy(&self, target: &mut FfiBox) {} - - pub fn get_ptr(&self) -> *mut c_void { - self.0.as_ptr() as *mut c_void - } - - // bad naming. i have no idea what should i use - pub fn luaref<'lua>( - lua: &'lua Lua, - this: LuaAnyUserData<'lua>, - ) -> LuaResult> { - let target = this.borrow::()?; - - let luaref = lua.create_userdata(FfiRef::new(target.get_ptr()))?; - - set_association(lua, BOX_REF_INNER, luaref.clone(), this.clone())?; - - Ok(luaref) - } - - pub fn zero(&mut self) { - self.0.fill(0u8); - } -} - -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) { - methods.add_method_mut("zero", |_, this, ()| { - this.zero(); - Ok(()) - }); - methods.add_function("ref", |lua, this: LuaAnyUserData| { - let luaref = FfiBox::luaref(lua, this)?; - Ok(luaref) - }); - methods.add_meta_method(LuaMetaMethod::Len, |_, this, ()| Ok(this.size())); - methods.add_meta_method(LuaMetaMethod::ToString, |lua, this, ()| { - dbg!(&this.0.len()); - let mut buff = String::from("[ "); - for i in &this.0 { - buff.push_str(i.to_owned().to_string().as_str()); - buff.push_str(", "); - } - buff.pop(); - buff.pop(); - buff.push_str(" ]"); - let luastr = lua.create_string(buff.as_bytes())?; - Ok(luastr) - }); - } -} diff --git a/crates/lune-std-ffi/src/ffiref.rs b/crates/lune-std-ffi/src/ffiref.rs deleted file mode 100644 index 79473fa2..00000000 --- a/crates/lune-std-ffi/src/ffiref.rs +++ /dev/null @@ -1,61 +0,0 @@ -use core::ffi::c_void; -use std::ptr; - -use mlua::prelude::*; - -use crate::association::set_association; - -// A referenced space. It is possible to read and write through types. -// This operation is not safe. This may cause a memory error in Lua -// if use it incorrectly. -// If it references an area managed by Lua, -// the box will remain as long as this reference is alive. - -pub struct FfiRef(*mut c_void); - -const REF_INNER: &str = "__ref_inner"; - -impl FfiRef { - pub fn new(target: *mut c_void) -> Self { - Self(target) - } - - // bad naming. i have no idea what should i use - pub fn luaref<'lua>( - lua: &'lua Lua, - this: LuaAnyUserData<'lua>, - ) -> LuaResult> { - let target = this.borrow::()?; - - let luaref = lua.create_userdata(FfiRef::new(ptr::from_ref(&target.0) as *mut c_void))?; - - set_association(lua, REF_INNER, luaref.clone(), this.clone())?; - - Ok(luaref) - } - - pub unsafe fn deref(&self) -> Self { - Self::new(*self.0.cast::<*mut c_void>()) - } - - pub unsafe fn offset(&self, offset: isize) -> Self { - Self::new(self.0.offset(offset)) - } -} - -impl LuaUserData for FfiRef { - fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { - methods.add_method("deref", |_, this, ()| { - let ffiref = unsafe { this.deref() }; - Ok(ffiref) - }); - methods.add_method("offset", |_, this, offset: isize| { - let ffiref = unsafe { this.offset(offset) }; - Ok(ffiref) - }); - methods.add_function("ref", |lua, this: LuaAnyUserData| { - let ffiref = FfiRef::luaref(lua, this)?; - Ok(ffiref) - }); - } -} diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs index a8a5adcc..1bcfbe03 100644 --- a/crates/lune-std-ffi/src/lib.rs +++ b/crates/lune-std-ffi/src/lib.rs @@ -3,31 +3,16 @@ use lune_utils::TableBuilder; use mlua::prelude::*; -mod association; -mod carr; -mod cfn; -mod cptr; -mod cstring; -mod cstruct; -mod ctype; -mod ffibox; -mod ffilib; -mod ffiraw; -mod ffiref; +mod c; +mod ffi; -use crate::association::get_table; -use crate::cfn::CFn; -use crate::cstruct::CStruct; -use crate::ctype::create_all_types; -use crate::ffibox::FfiBox; -use crate::ffilib::FfiLib; - -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", -]; +use crate::c::c_fn::CFn; +use crate::c::c_struct::CStruct; +use crate::c::c_type::create_all_types; +use crate::ffi::ffi_association::get_table; +use crate::ffi::ffi_box::FfiBox; +use crate::ffi::ffi_lib::FfiLib; +use crate::ffi::ffi_platform::get_platform_value; /** Creates the `ffi` standard library module. @@ -40,6 +25,7 @@ pub fn module(lua: &Lua) -> LuaResult { let ctypes = create_all_types(lua)?; let result = TableBuilder::new(lua)? .with_values(ctypes)? + .with_values(get_platform_value())? .with_function("box", |_, size: usize| Ok(FfiBox::new(size)))? // TODO: discuss about function name. matching with io.open is better? .with_function("dlopen", |_, name: String| { diff --git a/crates/lune-std-ffi/todo.md b/crates/lune-std-ffi/todo.md index 307b29ad..9eed0774 100644 --- a/crates/lune-std-ffi/todo.md +++ b/crates/lune-std-ffi/todo.md @@ -1,10 +1,9 @@ - use libffi::raw::{ffi_cif, ffi_ptrarray_to_raw}; // pub fn ffi_get_struct_offsets( -// abi: ffi_abi, -// struct_type: *mut ffi_type, -// offsets: *mut usize, +// abi: ffi_abi, +// struct_type: *mut ffi_type, +// offsets: *mut usize, // ) -> ffi_status; - last thing to do @@ -14,10 +13,10 @@ use libffi::raw::{ffi_cif, ffi_ptrarray_to_raw}; # Raw -- [ ] Raw:toRef() -- [ ] Raw:toBox() -- [ ] Raw:intoBox() -- [ ] Raw:intoRef() +- [ ] Raw:toRef() +- [ ] Raw:toBox() +- [ ] Raw:intoBox() +- [ ] Raw:intoRef() # Box @@ -31,6 +30,9 @@ use libffi::raw::{ffi_cif, ffi_ptrarray_to_raw}; # Ref (Unsafe) +- [ ] high, low Boundaries +- [ ] iter + - [x] ref:deref() -> ref - [x] ref:offset(bytes) -> ref - [x] ref:ref() -> ref @@ -70,12 +72,11 @@ from(box|ref|raw, offset) is better idea i think. - [ ] :sub ## subtype + - [x] :ptr() -> Ptr - [~] :arr(len) -> Arr - [x] .size - - # Ptr - [x] .inner @@ -92,6 +93,7 @@ from(box|ref|raw, offset) is better idea i think. Zero sized type. ## Fn + Prototype type of some function. converts lua function into native function pointer or native function pointer into lua function. `ffi.fn({ type }, type) -> fn` From 26706d935515d4b82d1c6443df32f3bcfb95396b Mon Sep 17 00:00:00 2001 From: qwreey Date: Sun, 25 Aug 2024 14:37:31 +0000 Subject: [PATCH 05/79] Improve ctype export and Refactor (#243) --- crates/lune-std-ffi/src/c/c_arr.rs | 18 +-- crates/lune-std-ffi/src/c/c_ptr.rs | 4 +- crates/lune-std-ffi/src/c/c_struct.rs | 16 +-- crates/lune-std-ffi/src/c/c_type.rs | 143 ++-------------------- crates/lune-std-ffi/src/c/mod.rs | 130 ++++++++++++++++++++ crates/lune-std-ffi/src/ffi/ffi_bounds.rs | 67 ++++++++++ crates/lune-std-ffi/src/ffi/ffi_box.rs | 72 +++++------ crates/lune-std-ffi/src/ffi/ffi_helper.rs | 10 +- crates/lune-std-ffi/src/ffi/ffi_lib.rs | 4 +- crates/lune-std-ffi/src/ffi/ffi_raw.rs | 4 +- crates/lune-std-ffi/src/ffi/ffi_ref.rs | 68 +++++----- crates/lune-std-ffi/src/ffi/mod.rs | 2 +- crates/lune-std-ffi/src/lib.rs | 11 +- crates/lune-std-ffi/todo.md | 13 +- 14 files changed, 308 insertions(+), 254 deletions(-) create mode 100644 crates/lune-std-ffi/src/ffi/ffi_bounds.rs diff --git a/crates/lune-std-ffi/src/c/c_arr.rs b/crates/lune-std-ffi/src/c/c_arr.rs index 6fbd9641..2b2b94b6 100644 --- a/crates/lune-std-ffi/src/c/c_arr.rs +++ b/crates/lune-std-ffi/src/c/c_arr.rs @@ -21,7 +21,7 @@ use crate::ffi::ffi_association::{get_association, set_association}; // There is no problem even if you create a struct with n fields of a single type within the struct. Array adheres to the condition that there is no additional padding between each element. Padding to a struct is padding inside the struct. Simply think of the padding byte as a trailing unnamed field. pub struct CArr { - libffi_type: Type, + element_type: Type, struct_type: Type, length: usize, field_size: usize, @@ -29,12 +29,12 @@ pub struct CArr { } impl CArr { - pub fn new(libffi_type: Type, length: usize) -> LuaResult { - let struct_type = Type::structure(vec![libffi_type.clone(); length]); - let field_size = get_ensured_size(libffi_type.as_raw_ptr())?; + pub fn new(element_type: Type, length: usize) -> LuaResult { + let struct_type = Type::structure(vec![element_type.clone(); length]); + let field_size = get_ensured_size(element_type.as_raw_ptr())?; Ok(Self { - libffi_type, + element_type, struct_type, length, field_size, @@ -50,14 +50,18 @@ impl CArr { let fields = type_from_userdata(luatype)?; let carr = lua.create_userdata(Self::new(fields, length)?)?; - set_association(lua, CARR_INNER, carr.clone(), luatype)?; + set_association(lua, CARR_INNER, &carr, luatype)?; Ok(carr) } pub fn get_type(&self) -> Type { - self.libffi_type.clone() + self.struct_type.clone() } + // pub fn get_element_type(&self) -> Type { + // self.element_type.clone() + // } + // Stringify cstruct for pretty printing something like: // pub fn stringify(userdata: &LuaAnyUserData) -> LuaResult { diff --git a/crates/lune-std-ffi/src/c/c_ptr.rs b/crates/lune-std-ffi/src/c/c_ptr.rs index 5fb88459..00a730d7 100644 --- a/crates/lune-std-ffi/src/c/c_ptr.rs +++ b/crates/lune-std-ffi/src/c/c_ptr.rs @@ -1,7 +1,5 @@ #![allow(clippy::cargo_common_metadata)] -use std::borrow::Borrow; - use libffi::middle::Type; use mlua::prelude::*; @@ -21,7 +19,7 @@ impl CPtr { ) -> LuaResult> { let value = Self().into_lua(lua)?; - set_association(lua, CPTR_INNER, value.borrow(), inner)?; + set_association(lua, CPTR_INNER, &value, inner)?; Ok(value) } diff --git a/crates/lune-std-ffi/src/c/c_struct.rs b/crates/lune-std-ffi/src/c/c_struct.rs index 9e945ece..58628d56 100644 --- a/crates/lune-std-ffi/src/c/c_struct.rs +++ b/crates/lune-std-ffi/src/c/c_struct.rs @@ -1,6 +1,6 @@ #![allow(clippy::cargo_common_metadata)] -use std::vec::Vec; +use std::{borrow::Borrow, vec::Vec}; use libffi::{ low, @@ -18,17 +18,17 @@ use crate::ffi::ffi_association::{get_association, set_association}; use crate::ffi::ffi_helper::FFI_STATUS_NAMES; pub struct CStruct { - libffi_cif: Cif, - libffi_type: Type, + // libffi_cif: Cif, fields: Vec, + libffi_type: Type, offsets: Vec, size: usize, } impl CStruct { pub fn new(fields: Vec) -> LuaResult { - let libffi_type = Type::structure(fields.clone()); - let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void()); + let libffi_type = Type::structure(fields.iter().cloned()); + // let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void()); // Get field offsets with ffi_get_struct_offsets let mut offsets = Vec::::with_capacity(fields.len()); @@ -52,9 +52,9 @@ impl CStruct { let size = unsafe { (*libffi_type.as_raw_ptr()).size }; Ok(Self { - libffi_cif: libffi_cfi, - libffi_type, + // libffi_cif: libffi_cfi, fields, + libffi_type, offsets, size, }) @@ -69,7 +69,7 @@ impl CStruct { let fields = type_list_from_table(&table)?; let cstruct = lua.create_userdata(Self::new(fields)?)?; table.set_readonly(true); - set_association(lua, CSTRUCT_INNER, cstruct.clone(), table)?; + set_association(lua, CSTRUCT_INNER, &cstruct, table)?; Ok(cstruct) } diff --git a/crates/lune-std-ffi/src/c/c_type.rs b/crates/lune-std-ffi/src/c/c_type.rs index 58d3364f..7ed7bcaa 100644 --- a/crates/lune-std-ffi/src/c/c_type.rs +++ b/crates/lune-std-ffi/src/c/c_type.rs @@ -1,44 +1,38 @@ #![allow(clippy::cargo_common_metadata)] -use core::ffi::{ - c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, - c_ulong, c_ulonglong, c_ushort, c_void, -}; - -use libffi::middle::{Cif, Type}; +use libffi::middle::Type; use mlua::prelude::*; use super::c_arr::CArr; use super::c_helper::get_ensured_size; use super::c_ptr::CPtr; use crate::ffi::ffi_helper::get_ptr_from_userdata; -use crate::ffi::ffi_platform::CHAR_IS_SIGNED; -// use libffi::raw::{ffi_cif, ffi_ptrarray_to_raw}; pub struct CType { - libffi_cif: Cif, + // for ffi_ptrarray_to_raw? + // libffi_cif: Cif, libffi_type: Type, size: usize, name: Option, // Write converted data from luavalue into some ptr - pub luavalue_into_ptr: fn(value: LuaValue, ptr: *mut c_void) -> LuaResult<()>, + pub luavalue_into_ptr: fn(value: LuaValue, ptr: *mut ()) -> LuaResult<()>, // Read luavalue from some ptr - pub ptr_into_luavalue: fn(lua: &Lua, ptr: *mut c_void) -> LuaResult, + pub ptr_into_luavalue: fn(lua: &Lua, ptr: *mut ()) -> LuaResult, } impl CType { pub fn new( libffi_type: Type, name: Option, - luavalue_into_ptr: fn(value: LuaValue, ptr: *mut c_void) -> LuaResult<()>, - ptr_into_luavalue: fn(lua: &Lua, ptr: *mut c_void) -> LuaResult, + luavalue_into_ptr: fn(value: LuaValue, ptr: *mut ()) -> LuaResult<()>, + ptr_into_luavalue: fn(lua: &Lua, ptr: *mut ()) -> LuaResult, ) -> LuaResult { - let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void()); + // let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void()); let size = get_ensured_size(libffi_type.as_raw_ptr())?; Ok(Self { - libffi_cif: libffi_cfi, + // libffi_cif: libffi_cfi, libffi_type, size, name, @@ -117,122 +111,3 @@ impl LuaUserData for CType { }); } } - -// export all default c-types -#[allow(clippy::too_many_lines)] -pub fn create_all_types(lua: &Lua) -> LuaResult> { - Ok(vec![ - ( - "int", - CType::new( - Type::c_int(), - Some(String::from("int")), - |data, ptr| { - let value = match data { - LuaValue::Integer(t) => t, - _ => { - return Err(LuaError::external(format!( - "Integer expected, got {}", - data.type_name() - ))) - } - } as c_int; - unsafe { - *(ptr.cast::()) = value; - } - Ok(()) - }, - |lua: &Lua, ptr: *mut c_void| { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; - Ok(value) - }, - )? - .into_lua(lua)?, - ), - ( - "long", - CType::new( - Type::c_long(), - Some(String::from("long")), - |data, ptr| { - let value = match data { - LuaValue::Integer(t) => t, - _ => { - return Err(LuaError::external(format!( - "Integer expected, got {}", - data.type_name() - ))) - } - } as c_long; - unsafe { - *(ptr.cast::()) = value; - } - Ok(()) - }, - |lua: &Lua, ptr: *mut c_void| { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; - Ok(value) - }, - )? - .into_lua(lua)?, - ), - ( - "longlong", - CType::new( - Type::c_longlong(), - Some(String::from("longlong")), - |data, ptr| { - let value = match data { - LuaValue::Integer(t) => t, - _ => { - return Err(LuaError::external(format!( - "Integer expected, got {}", - data.type_name() - ))) - } - } as c_longlong; - unsafe { - *(ptr.cast::()) = value; - } - Ok(()) - }, - |lua: &Lua, ptr: *mut c_void| { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; - Ok(value) - }, - )? - .into_lua(lua)?, - ), - ( - "char", - CType::new( - if CHAR_IS_SIGNED { - Type::c_schar() - } else { - Type::c_uchar() - }, - Some(String::from("char")), - |data, ptr| { - let value = match data { - LuaValue::Integer(t) => t, - _ => { - return Err(LuaError::external(format!( - "Integer expected, got {}", - data.type_name() - ))) - } - } as c_char; - unsafe { - *(ptr.cast::()) = value; - } - Ok(()) - }, - |lua: &Lua, ptr: *mut c_void| { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; - Ok(value) - }, - )? - .into_lua(lua)?, - ), - ]) -} diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index 803fa626..25db1767 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -12,3 +12,133 @@ mod association_names { pub const CARR_INNER: &str = "__carr_inner"; pub const CSTRUCT_INNER: &str = "__cstruct_inner"; } + +use core::ffi::{ + c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, + c_ulong, c_ulonglong, c_ushort, c_void, +}; + +use libffi::middle::Type; +use mlua::prelude::*; + +use self::c_type::CType; +use crate::ffi::ffi_platform::CHAR_IS_SIGNED; + +// export all default c-types +#[allow(clippy::too_many_lines)] +pub fn create_all_types(lua: &Lua) -> LuaResult> { + Ok(vec![ + ( + "int", + CType::new( + Type::c_int(), + Some(String::from("int")), + |data, ptr| { + let value = match data { + LuaValue::Integer(t) => t, + _ => { + return Err(LuaError::external(format!( + "Integer expected, got {}", + data.type_name() + ))) + } + } as c_int; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + }, + |lua: &Lua, ptr: *mut ()| { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + }, + )? + .into_lua(lua)?, + ), + ( + "long", + CType::new( + Type::c_long(), + Some(String::from("long")), + |data, ptr| { + let value = match data { + LuaValue::Integer(t) => t, + _ => { + return Err(LuaError::external(format!( + "Integer expected, got {}", + data.type_name() + ))) + } + } as c_long; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + }, + |lua: &Lua, ptr: *mut ()| { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + }, + )? + .into_lua(lua)?, + ), + ( + "longlong", + CType::new( + Type::c_longlong(), + Some(String::from("longlong")), + |data, ptr| { + let value = match data { + LuaValue::Integer(t) => t, + _ => { + return Err(LuaError::external(format!( + "Integer expected, got {}", + data.type_name() + ))) + } + } as c_longlong; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + }, + |lua: &Lua, ptr: *mut ()| { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + }, + )? + .into_lua(lua)?, + ), + ( + "char", + CType::new( + if CHAR_IS_SIGNED { + Type::c_schar() + } else { + Type::c_uchar() + }, + Some(String::from("char")), + |data, ptr| { + let value = match data { + LuaValue::Integer(t) => t, + _ => { + return Err(LuaError::external(format!( + "Integer expected, got {}", + data.type_name() + ))) + } + } as c_char; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + }, + |lua: &Lua, ptr: *mut ()| { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + }, + )? + .into_lua(lua)?, + ), + ]) +} diff --git a/crates/lune-std-ffi/src/ffi/ffi_bounds.rs b/crates/lune-std-ffi/src/ffi/ffi_bounds.rs new file mode 100644 index 00000000..5c73bb32 --- /dev/null +++ b/crates/lune-std-ffi/src/ffi/ffi_bounds.rs @@ -0,0 +1,67 @@ +// Memory range for ref or box data. For boundary checking +pub struct FfiRefBounds { + // Indicates how much data is above the pointer + pub(crate) high: usize, + // Indicates how much data is below the pointer + pub(crate) low: usize, +} + +impl FfiRefBounds { + pub fn new(high: usize, low: usize) -> Self { + Self { high, low } + } + + // Check boundary + pub fn check(&self, offset: isize) -> bool { + let sign = offset.signum(); + let offset_abs = offset.unsigned_abs(); + if sign == -1 { + self.high >= offset_abs + } else if sign == 1 { + self.low >= offset_abs + } else { + // sign == 0 + true + } + } + + // Check boundary + pub fn check_sized(&self, offset: isize, size: usize) -> bool { + let end = offset + (size as isize) - 1; + let sign = end.signum(); + let end_abs = end.unsigned_abs(); + if sign == -1 { + self.high >= end_abs + } else if sign == 1 { + self.low >= end_abs + } else { + // sign == 0 + true + } + } + + // Calculate new bounds from bounds and offset + // No boundary checking in here + pub fn offset(&self, offset: isize) -> Self { + let sign = offset.signum(); + let offset_abs = offset.unsigned_abs(); + + let high: usize = if sign == -1 { + self.high - offset_abs + } else if sign == 1 { + self.high + offset_abs + } else { + self.high + }; + + let low: usize = if sign == -1 { + self.low + offset_abs + } else if sign == 1 { + self.low - offset_abs + } else { + self.low + }; + + Self { high, low } + } +} diff --git a/crates/lune-std-ffi/src/ffi/ffi_box.rs b/crates/lune-std-ffi/src/ffi/ffi_box.rs index 49fb1d2e..f7d593c1 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_box.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_box.rs @@ -11,12 +11,11 @@ use std::boxed::Box; -use core::ffi::c_void; use mlua::prelude::*; -use super::association_names::BOX_REF_INNER; +use super::association_names::REF_INNER; use super::ffi_association::set_association; -use super::ffi_ref::FfiRange; +use super::ffi_bounds::FfiRefBounds; use super::ffi_ref::FfiRef; pub struct FfiBox(Box<[u8]>); @@ -36,29 +35,10 @@ impl FfiBox { Self(vec_heap.into_boxed_slice()) } - pub fn size(&self) -> usize { - self.0.len() - } - // pub fn copy(&self, target: &mut FfiBox) {} - pub fn get_ptr(&self) -> *mut c_void { - self.0.as_ptr() as *mut c_void - } - + // Todo: if too big, print as another format pub fn stringify(&self) -> String { - let mut buff = String::from(" "); - for i in &self.0 { - buff.push_str(i.to_string().as_str()); - buff.push_str(", "); - } - buff.pop(); - buff.pop(); - buff.push(' '); - buff - } - - pub fn binary_print(&self) -> String { let mut buff: String = String::with_capacity(self.size() * 10 - 2); for (pos, value) in self.0.iter().enumerate() { for i in 0..8 { @@ -75,42 +55,51 @@ impl FfiBox { buff } - // bad naming. i have no idea what should i use + // Make FfiRef from box, with boundary checking pub fn luaref<'lua>( lua: &'lua Lua, this: LuaAnyUserData<'lua>, offset: Option, ) -> LuaResult> { - let target = this.borrow::()?; - let ptr = if let Some(t) = offset { - if t < 0 || t >= (target.size() as isize) { + let mut target = this.borrow_mut::()?; + let mut bounds = FfiRefBounds::new(0, target.size()); + let mut ptr = target.get_ptr(); + + // Calculate offset + if let Some(t) = offset { + if !bounds.check(t) { return Err(LuaError::external(format!( "Offset is out of bounds. box.size: {}. offset got {}", target.size(), t ))); } - unsafe { target.get_ptr().offset(t) } - } else { - target.get_ptr() - }; + ptr = unsafe { target.get_ptr().offset(t) }; + bounds = bounds.offset(t); + } - let luaref = lua.create_userdata(FfiRef::new( - ptr, - Some(FfiRange { - low: 0, - high: target.size() as isize, - }), - ))?; + let luaref = lua.create_userdata(FfiRef::new(ptr.cast(), Some(bounds)))?; - set_association(lua, BOX_REF_INNER, luaref.clone(), this.clone())?; + // Makes box alive longer then ref + set_association(lua, REF_INNER, &luaref, &this)?; Ok(luaref) } + // Fill every field with 0 pub fn zero(&mut self) { self.0.fill(0u8); } + + // Get size of box + pub fn size(&self) -> usize { + self.0.len() + } + + // Get raw ptr + pub fn get_ptr(&mut self) -> *mut u8 { + self.0.as_mut_ptr() + } } impl LuaUserData for FfiBox { @@ -119,6 +108,7 @@ impl LuaUserData for FfiBox { } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + // For convenience, :zero returns self. methods.add_function_mut("zero", |_, this: LuaAnyUserData| { this.borrow_mut::()?.zero(); Ok(this) @@ -130,8 +120,6 @@ impl LuaUserData for FfiBox { Ok(luaref) }, ); - methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| { - Ok(this.binary_print()) - }); + methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| Ok(this.stringify())); } } diff --git a/crates/lune-std-ffi/src/ffi/ffi_helper.rs b/crates/lune-std-ffi/src/ffi/ffi_helper.rs index ffa32f2f..87a905e8 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_helper.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_helper.rs @@ -1,5 +1,3 @@ -use std::ffi::c_void; - use mlua::prelude::*; use super::ffi_box::FfiBox; @@ -13,12 +11,14 @@ pub const FFI_STATUS_NAMES: [&str; 4] = [ "ffi_status_FFI_BAD_ARGTYPE", ]; +// Get raw pointer from userdata +// TODO: boundary check pub unsafe fn get_ptr_from_userdata( userdata: &LuaAnyUserData, offset: Option, -) -> LuaResult<*mut c_void> { +) -> LuaResult<*mut ()> { let ptr = if userdata.is::() { - userdata.borrow::()?.get_ptr() + userdata.borrow_mut::()?.get_ptr().cast() } else if userdata.is::() { userdata.borrow::()?.get_ptr() } else { @@ -26,7 +26,7 @@ pub unsafe fn get_ptr_from_userdata( }; let ptr = if let Some(t) = offset { - ptr.offset(t) + ptr.cast::().offset(t).cast() } else { ptr }; diff --git a/crates/lune-std-ffi/src/ffi/ffi_lib.rs b/crates/lune-std-ffi/src/ffi/ffi_lib.rs index bf870154..70c81c62 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_lib.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_lib.rs @@ -39,9 +39,9 @@ impl FfiLib { .map_err(|err| LuaError::external(format!("{err}")))? }; - let luasym = lua.create_userdata(FfiRef::new(*sym, None))?; + let luasym = lua.create_userdata(FfiRef::new((*sym).cast(), None))?; - set_association(lua, SYM_INNER, luasym.clone(), this.clone())?; + set_association(lua, SYM_INNER, &luasym, &this)?; Ok(luasym) } diff --git a/crates/lune-std-ffi/src/ffi/ffi_raw.rs b/crates/lune-std-ffi/src/ffi/ffi_raw.rs index 6a82cd97..c32ca765 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_raw.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_raw.rs @@ -1,5 +1,5 @@ -use core::ffi::c_void; -use std::{convert, mem::transmute, ptr}; +// use core::ffi::c_void; +// use std::{convert, mem::transmute, ptr}; // This is raw data coming from outside. // Users must convert it to a Lua value, reference, or box to use it. diff --git a/crates/lune-std-ffi/src/ffi/ffi_ref.rs b/crates/lune-std-ffi/src/ffi/ffi_ref.rs index a5ebc708..1150eb14 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref.rs @@ -1,10 +1,10 @@ -use core::ffi::c_void; use std::ptr; use mlua::prelude::*; use super::association_names::REF_INNER; -use super::ffi_association::set_association; +use super::ffi_association::{get_association, set_association}; +use super::ffi_bounds::FfiRefBounds; // A referenced space. It is possible to read and write through types. // This operation is not safe. This may cause a memory error in Lua @@ -12,22 +12,17 @@ use super::ffi_association::set_association; // If it references an area managed by Lua, // the box will remain as long as this reference is alive. -pub struct FfiRange { - pub(crate) high: isize, - pub(crate) low: isize, -} - pub struct FfiRef { - ptr: *mut c_void, - range: Option, + ptr: *mut (), + range: Option, } impl FfiRef { - pub fn new(ptr: *mut c_void, range: Option) -> Self { + pub fn new(ptr: *mut (), range: Option) -> Self { Self { ptr, range } } - // bad naming. i have no idea what should i use + // Make FfiRef from ref pub fn luaref<'lua>( lua: &'lua Lua, this: LuaAnyUserData<'lua>, @@ -35,52 +30,59 @@ impl FfiRef { let target = this.borrow::()?; let luaref = lua.create_userdata(FfiRef::new( - ptr::from_ref(&target.ptr) as *mut c_void, - Some(FfiRange { + ptr::from_ref(&target.ptr) as *mut (), + Some(FfiRefBounds { low: 0, - high: size_of::() as isize, + high: size_of::(), }), ))?; - set_association(lua, REF_INNER, luaref.clone(), this.clone())?; + // If the ref holds a box, make sure the new ref also holds the box + if let Some(t) = get_association(lua, REF_INNER, &this)? { + set_association(lua, REF_INNER, &luaref, t)?; + } Ok(luaref) } - pub fn get_ptr(&self) -> *mut c_void { + pub fn get_ptr(&self) -> *mut () { self.ptr } pub unsafe fn deref(&self) -> Self { - Self::new(*self.ptr.cast::<*mut c_void>(), None) + Self::new(*self.ptr.cast::<*mut ()>(), None) } pub unsafe fn offset(&self, offset: isize) -> LuaResult { - let range = if let Some(ref t) = self.range { - let high = t.high - offset; - let low = t.low - offset; - - if low > 0 || high < 0 { + if let Some(ref t) = self.range { + if !t.check(offset) { return Err(LuaError::external(format!( - "Offset is out of bounds. low: {}, high: {}. offset got {}", - t.low, t.high, offset + "Offset is out of bounds. high: {}, low: {}. offset got {}", + t.high, t.low, offset ))); } + } + let range = self.range.as_ref().map(|t| t.offset(offset)); - Some(FfiRange { high, low }) - } else { - None - }; - - Ok(Self::new(self.ptr.offset(offset), range)) + Ok(Self::new( + self.ptr.cast::().offset(offset).cast(), + range, + )) } } impl LuaUserData for FfiRef { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { - methods.add_method("deref", |_, this, ()| { - let ffiref = unsafe { this.deref() }; - Ok(ffiref) + methods.add_function("deref", |lua, this: LuaAnyUserData| { + let inner = get_association(lua, REF_INNER, &this)?; + let ffiref = this.borrow::()?; + let result = lua.create_userdata(unsafe { ffiref.deref() })?; + + if let Some(t) = inner { + set_association(lua, REF_INNER, &result, &t)?; + } + + Ok(result) }); methods.add_method("offset", |_, this, offset: isize| { let ffiref = unsafe { this.offset(offset)? }; diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index 4812028f..dd369051 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -1,4 +1,5 @@ pub(super) mod ffi_association; +pub(super) mod ffi_bounds; pub(super) mod ffi_box; pub(super) mod ffi_helper; pub(super) mod ffi_lib; @@ -8,6 +9,5 @@ pub(super) mod ffi_ref; // Named registry table names mod association_names { - pub const BOX_REF_INNER: &str = "__box_ref"; pub const REF_INNER: &str = "__ref_inner"; } diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs index 1bcfbe03..4a519759 100644 --- a/crates/lune-std-ffi/src/lib.rs +++ b/crates/lune-std-ffi/src/lib.rs @@ -6,13 +6,10 @@ use mlua::prelude::*; mod c; mod ffi; -use crate::c::c_fn::CFn; -use crate::c::c_struct::CStruct; -use crate::c::c_type::create_all_types; -use crate::ffi::ffi_association::get_table; -use crate::ffi::ffi_box::FfiBox; -use crate::ffi::ffi_lib::FfiLib; -use crate::ffi::ffi_platform::get_platform_value; +use crate::c::{c_fn::CFn, c_struct::CStruct, create_all_types}; +use crate::ffi::{ + ffi_association::get_table, ffi_box::FfiBox, ffi_lib::FfiLib, ffi_platform::get_platform_value, +}; /** Creates the `ffi` standard library module. diff --git a/crates/lune-std-ffi/todo.md b/crates/lune-std-ffi/todo.md index 9eed0774..f0a0ab8b 100644 --- a/crates/lune-std-ffi/todo.md +++ b/crates/lune-std-ffi/todo.md @@ -1,11 +1,3 @@ -use libffi::raw::{ffi_cif, ffi_ptrarray_to_raw}; - -// pub fn ffi_get_struct_offsets( -// abi: ffi_abi, -// struct_type: *mut ffi_type, -// offsets: *mut usize, -// ) -> ffi_status; - - last thing to do - [ ] Add tests - [ ] Add docs @@ -23,8 +15,9 @@ use libffi::raw::{ffi_cif, ffi_ptrarray_to_raw}; - [x] ffi.box(size) - [x] .size - [x] :zero() -- [?] :ref(offset?=0) => ref - - offset is not impled +- [x] :ref(offset?=0) => ref +- [x] tostring + - [~] :copy(box,size?=-1,offset?=0) - working on it From d60a1b99f65b0b05a6b5a331cff7386d02ea3479 Mon Sep 17 00:00:00 2001 From: qwreey Date: Sun, 25 Aug 2024 19:22:46 +0000 Subject: [PATCH 06/79] Use CType instead of CType (#243) --- crates/lune-std-ffi/src/c/c_arr.rs | 14 ++- crates/lune-std-ffi/src/c/c_helper.rs | 18 +-- crates/lune-std-ffi/src/c/c_struct.rs | 29 ++--- crates/lune-std-ffi/src/c/c_type.rs | 86 +++++++------- crates/lune-std-ffi/src/c/mod.rs | 133 +--------------------- crates/lune-std-ffi/src/c/types/c_int.rs | 38 +++++++ crates/lune-std-ffi/src/c/types/mod.rs | 8 ++ crates/lune-std-ffi/src/ffi/ffi_helper.rs | 2 +- crates/lune-std-ffi/src/ffi/ffi_ref.rs | 2 + 9 files changed, 128 insertions(+), 202 deletions(-) create mode 100644 crates/lune-std-ffi/src/c/types/c_int.rs create mode 100644 crates/lune-std-ffi/src/c/types/mod.rs diff --git a/crates/lune-std-ffi/src/c/c_arr.rs b/crates/lune-std-ffi/src/c/c_arr.rs index 2b2b94b6..2a420190 100644 --- a/crates/lune-std-ffi/src/c/c_arr.rs +++ b/crates/lune-std-ffi/src/c/c_arr.rs @@ -1,3 +1,5 @@ +use std::any::Any; + use libffi::middle::Type; use mlua::prelude::*; @@ -54,13 +56,13 @@ impl CArr { Ok(carr) } - pub fn get_type(&self) -> Type { - self.struct_type.clone() + pub fn get_type(&self) -> &Type { + &self.struct_type } - // pub fn get_element_type(&self) -> Type { - // self.element_type.clone() - // } + pub fn get_element_type(&self) -> &Type { + &self.element_type + } // Stringify cstruct for pretty printing something like: // @@ -73,7 +75,7 @@ impl CArr { .as_userdata() .ok_or(LuaError::external("failed to get inner type userdata."))?; - if inner.is::() { + if inner.is::>() { Ok(format!( " {} ; {} ", stringify_userdata(inner)?, diff --git a/crates/lune-std-ffi/src/c/c_helper.rs b/crates/lune-std-ffi/src/c/c_helper.rs index d25843c9..2a18096f 100644 --- a/crates/lune-std-ffi/src/c/c_helper.rs +++ b/crates/lune-std-ffi/src/c/c_helper.rs @@ -1,3 +1,4 @@ +use std::any::Any; use std::ptr::{self, null_mut}; use libffi::{low, middle::Type, raw}; @@ -37,11 +38,11 @@ pub fn type_list_from_table(table: &LuaTable) -> LuaResult> { // get libffi_type from any c-type userdata pub fn type_from_userdata(userdata: &LuaAnyUserData) -> LuaResult { if userdata.is::() { - Ok(userdata.borrow::()?.get_type()) - } else if userdata.is::() { - Ok(userdata.borrow::()?.get_type()) + Ok(userdata.borrow::()?.get_type().to_owned()) + } else if userdata.is::>() { + Ok(userdata.borrow::>()?.get_type().to_owned()) } else if userdata.is::() { - Ok(userdata.borrow::()?.get_type()) + Ok(userdata.borrow::()?.get_type().to_owned()) } else if userdata.is::() { Ok(CPtr::get_type()) } else { @@ -59,9 +60,10 @@ pub fn type_from_userdata(userdata: &LuaAnyUserData) -> LuaResult { // stringify any c-type userdata (for recursive) pub fn stringify_userdata(userdata: &LuaAnyUserData) -> LuaResult { - if userdata.is::() { - let name = userdata.borrow::()?.stringify(); - Ok(name) + if userdata.is::>() { + Ok(String::from( + userdata.borrow::>()?.stringify(), + )) } else if userdata.is::() { let name = CStruct::stringify(userdata)?; Ok(name) @@ -80,7 +82,7 @@ pub fn stringify_userdata(userdata: &LuaAnyUserData) -> LuaResult { pub fn name_from_userdata(userdata: &LuaAnyUserData) -> String { if userdata.is::() { String::from("CStruct") - } else if userdata.is::() { + } else if userdata.is::>() { String::from("CType") } else if userdata.is::() { String::from("CArr") diff --git a/crates/lune-std-ffi/src/c/c_struct.rs b/crates/lune-std-ffi/src/c/c_struct.rs index 58628d56..8812eb53 100644 --- a/crates/lune-std-ffi/src/c/c_struct.rs +++ b/crates/lune-std-ffi/src/c/c_struct.rs @@ -1,12 +1,9 @@ #![allow(clippy::cargo_common_metadata)] -use std::{borrow::Borrow, vec::Vec}; +use std::any::Any; +use std::vec::Vec; -use libffi::{ - low, - middle::{Cif, Type}, - raw, -}; +use libffi::{low, middle::Type, raw}; use mlua::prelude::*; use super::association_names::CSTRUCT_INNER; @@ -20,14 +17,14 @@ use crate::ffi::ffi_helper::FFI_STATUS_NAMES; pub struct CStruct { // libffi_cif: Cif, fields: Vec, - libffi_type: Type, + struct_type: Type, offsets: Vec, size: usize, } impl CStruct { pub fn new(fields: Vec) -> LuaResult { - let libffi_type = Type::structure(fields.iter().cloned()); + 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 @@ -35,7 +32,7 @@ impl CStruct { unsafe { let offset_result: raw::ffi_status = raw::ffi_get_struct_offsets( low::ffi_abi_FFI_DEFAULT_ABI, - libffi_type.as_raw_ptr(), + struct_type.as_raw_ptr(), offsets.as_mut_ptr(), ); if offset_result != raw::ffi_status_FFI_OK { @@ -49,12 +46,12 @@ impl CStruct { // Get tailing padded size of struct // See http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html - let size = unsafe { (*libffi_type.as_raw_ptr()).size }; + let size = unsafe { (*struct_type.as_raw_ptr()).size }; Ok(Self { // libffi_cif: libffi_cfi, fields, - libffi_type, + struct_type, offsets, size, }) @@ -85,7 +82,7 @@ impl CStruct { let mut result = String::from(" "); for i in 0..table.raw_len() { let child: LuaAnyUserData = table.raw_get(i + 1)?; - if child.is::() { + if child.is::>() { result.push_str(format!("{}, ", stringify_userdata(&child)?).as_str()); } else { result.push_str( @@ -117,8 +114,12 @@ impl CStruct { Ok(offset) } - pub fn get_type(&self) -> Type { - self.libffi_type.clone() + pub fn get_fields(&self) -> &Vec { + &self.fields + } + + pub fn get_type(&self) -> &Type { + &self.struct_type } } diff --git a/crates/lune-std-ffi/src/c/c_type.rs b/crates/lune-std-ffi/src/c/c_type.rs index 7ed7bcaa..3e4ee423 100644 --- a/crates/lune-std-ffi/src/c/c_type.rs +++ b/crates/lune-std-ffi/src/c/c_type.rs @@ -1,5 +1,7 @@ #![allow(clippy::cargo_common_metadata)] +use std::marker::PhantomData; + use libffi::middle::Type; use mlua::prelude::*; @@ -8,27 +10,20 @@ use super::c_helper::get_ensured_size; use super::c_ptr::CPtr; use crate::ffi::ffi_helper::get_ptr_from_userdata; -pub struct CType { +pub struct CType { // for ffi_ptrarray_to_raw? // libffi_cif: Cif, libffi_type: Type, size: usize, - name: Option, - - // Write converted data from luavalue into some ptr - pub luavalue_into_ptr: fn(value: LuaValue, ptr: *mut ()) -> LuaResult<()>, - - // Read luavalue from some ptr - pub ptr_into_luavalue: fn(lua: &Lua, ptr: *mut ()) -> LuaResult, + name: Option<&'static str>, + _phantom: PhantomData, } -impl CType { - pub fn new( - libffi_type: Type, - name: Option, - luavalue_into_ptr: fn(value: LuaValue, ptr: *mut ()) -> LuaResult<()>, - ptr_into_luavalue: fn(lua: &Lua, ptr: *mut ()) -> LuaResult, - ) -> LuaResult { +impl CType +where + T: ?Sized, +{ + pub fn new_with_libffi_type(libffi_type: Type, name: Option<&'static str>) -> LuaResult { // let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void()); let size = get_ensured_size(libffi_type.as_raw_ptr())?; Ok(Self { @@ -36,78 +31,83 @@ impl CType { libffi_type, size, name, - luavalue_into_ptr, - ptr_into_luavalue, + _phantom: PhantomData {}, }) } - pub fn get_type(&self) -> Type { - self.libffi_type.clone() + pub fn get_type(&self) -> &Type { + &self.libffi_type } - pub fn stringify(&self) -> String { - match &self.name { - Some(t) => t.to_owned(), - None => String::from("unnamed"), + pub fn stringify(&self) -> &str { + match self.name { + Some(t) => t, + None => "unnamed", } } +} + +pub trait PtrHandle { + // Convert luavalue into data, then write into ptr + fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()>; + + // Read data from ptr, then convert into luavalue + fn ptr_into_luavalue(lua: &Lua, ptr: *mut ()) -> LuaResult; - // Read data from ptr and convert it into luavalue - pub unsafe fn read_ptr<'lua>( + // Read data from userdata (such as box or ref) and convert it into luavalue + unsafe fn read_userdata<'lua>( &self, lua: &'lua Lua, userdata: LuaAnyUserData<'lua>, offset: Option, ) -> LuaResult> { let ptr = unsafe { get_ptr_from_userdata(&userdata, offset)? }; - let value = (self.ptr_into_luavalue)(lua, ptr)?; + let value = Self::ptr_into_luavalue(lua, ptr)?; Ok(value) } - // Write converted data from luavalue into ptr - pub unsafe fn write_ptr<'lua>( + // Write data into userdata (such as box or ref) from luavalue + unsafe fn write_userdata<'lua>( &self, luavalue: LuaValue<'lua>, userdata: LuaAnyUserData<'lua>, offset: Option, ) -> LuaResult<()> { let ptr = unsafe { get_ptr_from_userdata(&userdata, offset)? }; - (self.luavalue_into_ptr)(luavalue, ptr)?; + Self::luavalue_into_ptr(luavalue, ptr)?; Ok(()) } } -impl LuaUserData for CType { +impl LuaUserData for CType +where + Self: Sized + PtrHandle, +{ 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) { methods.add_function("ptr", |lua, this: LuaAnyUserData| { - let pointer = CPtr::from_lua_userdata(lua, &this)?; - Ok(pointer) + CPtr::from_lua_userdata(lua, &this) }); methods.add_method( "from", - |lua, ctype, (userdata, offset): (LuaAnyUserData, Option)| { - let value = unsafe { ctype.read_ptr(lua, userdata, offset)? }; - Ok(value) + |lua, ctype, (userdata, offset): (LuaAnyUserData, Option)| unsafe { + ctype.read_userdata(lua, userdata, offset) }, ); methods.add_method( "into", - |_, ctype, (value, userdata, offset): (LuaValue, LuaAnyUserData, Option)| { - unsafe { ctype.write_ptr(value, userdata, offset)? }; - Ok(()) + |_, ctype, (value, userdata, offset): (LuaValue, LuaAnyUserData, Option)| unsafe { + ctype.write_userdata(value, userdata, offset) }, ); methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| { - let carr = CArr::from_lua_userdata(lua, &this, length)?; - Ok(carr) + CArr::from_lua_userdata(lua, &this, length) }); - methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| { - let name = this.stringify(); - Ok(name) + 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 25db1767..be3364df 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -5,6 +5,9 @@ pub(super) mod c_ptr; pub(super) mod c_string; pub(super) mod c_struct; pub(super) mod c_type; +pub(super) mod types; + +pub use types::create_all_types; // Named registry table names mod association_names { @@ -12,133 +15,3 @@ mod association_names { pub const CARR_INNER: &str = "__carr_inner"; pub const CSTRUCT_INNER: &str = "__cstruct_inner"; } - -use core::ffi::{ - c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, - c_ulong, c_ulonglong, c_ushort, c_void, -}; - -use libffi::middle::Type; -use mlua::prelude::*; - -use self::c_type::CType; -use crate::ffi::ffi_platform::CHAR_IS_SIGNED; - -// export all default c-types -#[allow(clippy::too_many_lines)] -pub fn create_all_types(lua: &Lua) -> LuaResult> { - Ok(vec![ - ( - "int", - CType::new( - Type::c_int(), - Some(String::from("int")), - |data, ptr| { - let value = match data { - LuaValue::Integer(t) => t, - _ => { - return Err(LuaError::external(format!( - "Integer expected, got {}", - data.type_name() - ))) - } - } as c_int; - unsafe { - *(ptr.cast::()) = value; - } - Ok(()) - }, - |lua: &Lua, ptr: *mut ()| { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; - Ok(value) - }, - )? - .into_lua(lua)?, - ), - ( - "long", - CType::new( - Type::c_long(), - Some(String::from("long")), - |data, ptr| { - let value = match data { - LuaValue::Integer(t) => t, - _ => { - return Err(LuaError::external(format!( - "Integer expected, got {}", - data.type_name() - ))) - } - } as c_long; - unsafe { - *(ptr.cast::()) = value; - } - Ok(()) - }, - |lua: &Lua, ptr: *mut ()| { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; - Ok(value) - }, - )? - .into_lua(lua)?, - ), - ( - "longlong", - CType::new( - Type::c_longlong(), - Some(String::from("longlong")), - |data, ptr| { - let value = match data { - LuaValue::Integer(t) => t, - _ => { - return Err(LuaError::external(format!( - "Integer expected, got {}", - data.type_name() - ))) - } - } as c_longlong; - unsafe { - *(ptr.cast::()) = value; - } - Ok(()) - }, - |lua: &Lua, ptr: *mut ()| { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; - Ok(value) - }, - )? - .into_lua(lua)?, - ), - ( - "char", - CType::new( - if CHAR_IS_SIGNED { - Type::c_schar() - } else { - Type::c_uchar() - }, - Some(String::from("char")), - |data, ptr| { - let value = match data { - LuaValue::Integer(t) => t, - _ => { - return Err(LuaError::external(format!( - "Integer expected, got {}", - data.type_name() - ))) - } - } as c_char; - unsafe { - *(ptr.cast::()) = value; - } - Ok(()) - }, - |lua: &Lua, ptr: *mut ()| { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; - Ok(value) - }, - )? - .into_lua(lua)?, - ), - ]) -} diff --git a/crates/lune-std-ffi/src/c/types/c_int.rs b/crates/lune-std-ffi/src/c/types/c_int.rs new file mode 100644 index 00000000..3e36a696 --- /dev/null +++ b/crates/lune-std-ffi/src/c/types/c_int.rs @@ -0,0 +1,38 @@ +use core::ffi::c_int; + +use libffi::middle::Type; +use mlua::prelude::*; + +use super::super::c_type::{CType, PtrHandle}; + +impl PtrHandle for CType { + fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()> { + let value = match value { + LuaValue::Integer(t) => t, + _ => { + return Err(LuaError::external(format!( + "Integer expected, got {}", + value.type_name() + ))) + } + } as c_int; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + } + fn ptr_into_luavalue(lua: &Lua, ptr: *mut ()) -> LuaResult { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + } +} + +impl CType { + fn new() -> LuaResult { + Self::new_with_libffi_type(Type::c_int(), Some("int")) + } +} + +pub fn get_export(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { + Ok(("int", lua.create_userdata(CType::::new()?)?)) +} diff --git a/crates/lune-std-ffi/src/c/types/mod.rs b/crates/lune-std-ffi/src/c/types/mod.rs new file mode 100644 index 00000000..0d4986d4 --- /dev/null +++ b/crates/lune-std-ffi/src/c/types/mod.rs @@ -0,0 +1,8 @@ +mod c_int; + +use mlua::prelude::*; + +// export all default c-types +pub fn create_all_types(lua: &Lua) -> LuaResult> { + Ok(vec![c_int::get_export(lua)?]) +} diff --git a/crates/lune-std-ffi/src/ffi/ffi_helper.rs b/crates/lune-std-ffi/src/ffi/ffi_helper.rs index 87a905e8..3e9f48a7 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_helper.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_helper.rs @@ -22,7 +22,7 @@ pub unsafe fn get_ptr_from_userdata( } else if userdata.is::() { userdata.borrow::()?.get_ptr() } else { - return Err(LuaError::external("asdf")); + return Err(LuaError::external("Unexpected userdata")); }; let ptr = if let Some(t) = offset { diff --git a/crates/lune-std-ffi/src/ffi/ffi_ref.rs b/crates/lune-std-ffi/src/ffi/ffi_ref.rs index 1150eb14..5e9a9f80 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref.rs @@ -12,6 +12,8 @@ use super::ffi_bounds::FfiRefBounds; // If it references an area managed by Lua, // the box will remain as long as this reference is alive. +// Todo : how to impl ref == nullptr + pub struct FfiRef { ptr: *mut (), range: Option, From 6d0db930f6d4f02a045a9be0f661fe3edb00a42b Mon Sep 17 00:00:00 2001 From: qwreey Date: Mon, 26 Aug 2024 09:14:31 +0000 Subject: [PATCH 07/79] Implement ctype casting (#243) --- Cargo.lock | 58 ++++++++++ crates/lune-std-ffi/Cargo.toml | 1 + crates/lune-std-ffi/src/c/c_arr.rs | 34 ++---- crates/lune-std-ffi/src/c/c_cast.rs | 1 - crates/lune-std-ffi/src/c/c_fn.rs | 12 +- crates/lune-std-ffi/src/c/c_helper.rs | 71 ++++++++---- crates/lune-std-ffi/src/c/c_ptr.rs | 18 ++- crates/lune-std-ffi/src/c/c_struct.rs | 25 +---- crates/lune-std-ffi/src/c/c_type.rs | 103 ++++++++++++++++-- crates/lune-std-ffi/src/c/mod.rs | 1 + crates/lune-std-ffi/src/c/types/c_char.rs | 68 ++++++++++++ crates/lune-std-ffi/src/c/types/c_int.rs | 37 ++++++- crates/lune-std-ffi/src/c/types/mod.rs | 3 +- .../lune-std-ffi/src/ffi/ffi_association.rs | 6 +- crates/lune-std-ffi/src/ffi/ffi_box.rs | 8 +- crates/lune-std-ffi/src/ffi/ffi_helper.rs | 1 + crates/lune-std-ffi/src/ffi/ffi_lib.rs | 2 +- crates/lune-std-ffi/src/ffi/ffi_ref.rs | 36 ++++-- crates/lune-std-ffi/src/lib.rs | 4 +- crates/lune-std-ffi/todo.md | 2 + 20 files changed, 381 insertions(+), 110 deletions(-) delete mode 100644 crates/lune-std-ffi/src/c/c_cast.rs create mode 100644 crates/lune-std-ffi/src/c/types/c_char.rs diff --git a/Cargo.lock b/Cargo.lock index 4e4b6545..4035b8ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1637,6 +1637,7 @@ dependencies = [ "lune-utils", "mlua", "mlua-sys", + "num", ] [[package]] @@ -1933,6 +1934,40 @@ dependencies = [ "winapi", ] +[[package]] +name = "num" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5" +dependencies = [ + "num-traits", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -1948,6 +1983,29 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" diff --git a/crates/lune-std-ffi/Cargo.toml b/crates/lune-std-ffi/Cargo.toml index b867401e..0420f1dc 100644 --- a/crates/lune-std-ffi/Cargo.toml +++ b/crates/lune-std-ffi/Cargo.toml @@ -15,6 +15,7 @@ workspace = true [dependencies] mlua = { version = "0.9.9", features = ["luau"] } mlua-sys = { version = "0.6.2", features = ["luau"] } +num = "0.3.1" dlopen2 = "0.6" libffi = "3.2.0" diff --git a/crates/lune-std-ffi/src/c/c_arr.rs b/crates/lune-std-ffi/src/c/c_arr.rs index 2a420190..ba81bf70 100644 --- a/crates/lune-std-ffi/src/c/c_arr.rs +++ b/crates/lune-std-ffi/src/c/c_arr.rs @@ -1,14 +1,9 @@ -use std::any::Any; - use libffi::middle::Type; use mlua::prelude::*; use super::association_names::CARR_INNER; -use super::c_helper::{ - get_ensured_size, name_from_userdata, stringify_userdata, type_from_userdata, -}; +use super::c_helper::{get_ensured_size, pretty_format_userdata, type_from_userdata}; use super::c_ptr::CPtr; -use super::c_type::CType; use crate::ffi::ffi_association::{get_association, set_association}; // This is a series of some type. @@ -49,7 +44,7 @@ impl CArr { luatype: &LuaAnyUserData<'lua>, length: usize, ) -> LuaResult> { - let fields = type_from_userdata(luatype)?; + let fields = type_from_userdata(lua, luatype)?; let carr = lua.create_userdata(Self::new(fields, length)?)?; set_association(lua, CARR_INNER, &carr, luatype)?; @@ -66,7 +61,7 @@ impl CArr { // Stringify cstruct for pretty printing something like: // - pub fn stringify(userdata: &LuaAnyUserData) -> LuaResult { + pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { let inner: LuaValue = userdata.get("inner")?; let carr = userdata.borrow::()?; @@ -75,20 +70,11 @@ impl CArr { .as_userdata() .ok_or(LuaError::external("failed to get inner type userdata."))?; - if inner.is::>() { - Ok(format!( - " {} ; {} ", - stringify_userdata(inner)?, - carr.length - )) - } else { - Ok(format!( - " <{}({})> ; {} ", - name_from_userdata(inner), - stringify_userdata(inner)?, - carr.length - )) - } + Ok(format!( + "{}*{}", + pretty_format_userdata(lua, inner)?, + carr.length, + )) } else { Err(LuaError::external("failed to get inner type userdata.")) } @@ -119,8 +105,8 @@ impl LuaUserData for CArr { let pointer = CPtr::from_lua_userdata(lua, &this)?; Ok(pointer) }); - methods.add_meta_function(LuaMetaMethod::ToString, |_, this: LuaAnyUserData| { - let result = CArr::stringify(&this)?; + 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_cast.rs b/crates/lune-std-ffi/src/c/c_cast.rs deleted file mode 100644 index 8b137891..00000000 --- a/crates/lune-std-ffi/src/c/c_cast.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/crates/lune-std-ffi/src/c/c_fn.rs b/crates/lune-std-ffi/src/c/c_fn.rs index 315497e9..3dfe3a4f 100644 --- a/crates/lune-std-ffi/src/c/c_fn.rs +++ b/crates/lune-std-ffi/src/c/c_fn.rs @@ -35,11 +35,15 @@ impl CFn { } } - pub fn from_lua_table(args: LuaTable, ret: LuaAnyUserData) -> LuaResult { - let args = type_list_from_table(&args)?; - let ret = type_from_userdata(&ret)?; + pub fn 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)?; Ok(Self::new(args, ret)) } } -impl LuaUserData for CFn {} +impl LuaUserData for CFn { + fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + // methods.add_method("from", | this, |) + } +} diff --git a/crates/lune-std-ffi/src/c/c_helper.rs b/crates/lune-std-ffi/src/c/c_helper.rs index 2a18096f..23101803 100644 --- a/crates/lune-std-ffi/src/c/c_helper.rs +++ b/crates/lune-std-ffi/src/c/c_helper.rs @@ -1,18 +1,19 @@ -use std::any::Any; use std::ptr::{self, null_mut}; use libffi::{low, middle::Type, raw}; 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::CType; +use super::c_type::CTypeStatic; +use crate::ffi::ffi_association::get_association; use crate::ffi::ffi_helper::FFI_STATUS_NAMES; // get Vec from table(array) of c-types userdata -pub fn type_list_from_table(table: &LuaTable) -> LuaResult> { +pub fn type_list_from_table(lua: &Lua, table: &LuaTable) -> LuaResult> { let len: usize = table.raw_len(); let mut fields = Vec::with_capacity(len); @@ -21,7 +22,7 @@ pub fn type_list_from_table(table: &LuaTable) -> LuaResult> { let value = table.raw_get(i + 1)?; match value { LuaValue::UserData(field_type) => { - fields.push(type_from_userdata(&field_type)?); + fields.push(type_from_userdata(lua, &field_type)?); } _ => { return Err(LuaError::external(format!( @@ -36,11 +37,17 @@ pub fn type_list_from_table(table: &LuaTable) -> LuaResult> { } // get libffi_type from any c-type userdata -pub fn type_from_userdata(userdata: &LuaAnyUserData) -> LuaResult { +pub fn type_from_userdata(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { if userdata.is::() { Ok(userdata.borrow::()?.get_type().to_owned()) - } else 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(LuaError::external( + "Failed to get static ctype from userdata", + ))? + .borrow::()? + .libffi_type + .clone()) } else if userdata.is::() { Ok(userdata.borrow::()?.get_type().to_owned()) } else if userdata.is::() { @@ -59,37 +66,61 @@ pub fn type_from_userdata(userdata: &LuaAnyUserData) -> LuaResult { } // stringify any c-type userdata (for recursive) -pub fn stringify_userdata(userdata: &LuaAnyUserData) -> LuaResult { - if userdata.is::>() { - Ok(String::from( - userdata.borrow::>()?.stringify(), - )) - } else if userdata.is::() { - let name = CStruct::stringify(userdata)?; +pub fn stringify_userdata(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { + if userdata.is::() { + let name = CStruct::stringify(lua, userdata)?; Ok(name) } else if userdata.is::() { - let name = CArr::stringify(userdata)?; + let name = CArr::stringify(lua, userdata)?; Ok(name) } else if userdata.is::() { - let name: String = CPtr::stringify(userdata)?; + 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(LuaError::external( + "Failed to get static ctype from userdata", + ))? + .borrow::()? + .name + .unwrap_or("unnamed"), + )) } else { Ok(String::from("unnamed")) } } // get name tag for any c-type userdata -pub fn name_from_userdata(userdata: &LuaAnyUserData) -> String { - if userdata.is::() { +pub fn tagname_from_userdata(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { + Ok(if userdata.is::() { String::from("CStruct") - } else if userdata.is::>() { - String::from("CType") } else if userdata.is::() { String::from("CArr") } else if userdata.is::() { String::from("CPtr") + } else if userdata_is_ctype(lua, userdata)? { + String::from("CType") } else { String::from("unnamed") + }) +} + +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) + } else { + Ok(format!( + "<{}({})>", + tagname_from_userdata(lua, userdata)?, + stringify_userdata(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 00a730d7..00d4e208 100644 --- a/crates/lune-std-ffi/src/c/c_ptr.rs +++ b/crates/lune-std-ffi/src/c/c_ptr.rs @@ -5,7 +5,7 @@ use mlua::prelude::*; use super::association_names::CPTR_INNER; use super::c_arr::CArr; -use super::c_helper::{name_from_userdata, stringify_userdata}; +use super::c_helper::pretty_format_userdata; use crate::ffi::ffi_association::{get_association, set_association}; pub struct CPtr(); @@ -16,8 +16,8 @@ impl CPtr { pub fn from_lua_userdata<'lua>( lua: &'lua Lua, inner: &LuaAnyUserData, - ) -> LuaResult> { - let value = Self().into_lua(lua)?; + ) -> LuaResult> { + let value = lua.create_userdata(Self())?; set_association(lua, CPTR_INNER, &value, inner)?; @@ -25,18 +25,14 @@ impl CPtr { } // Stringify CPtr with inner ctype - pub fn stringify(userdata: &LuaAnyUserData) -> LuaResult { + 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."))?; - Ok(format!( - " <{}({})> ", - name_from_userdata(inner), - stringify_userdata(inner)?, - )) + pretty_format_userdata(lua, inner) } else { Err(LuaError::external("failed to get inner type userdata.")) } @@ -67,8 +63,8 @@ impl LuaUserData for CPtr { let carr = CArr::from_lua_userdata(lua, &this, length)?; Ok(carr) }); - methods.add_meta_function(LuaMetaMethod::ToString, |_, this: LuaAnyUserData| { - let name: Result = CPtr::stringify(&this); + methods.add_meta_function(LuaMetaMethod::ToString, |lua, this: LuaAnyUserData| { + let name: Result = CPtr::stringify(lua, &this); Ok(name) }); } diff --git a/crates/lune-std-ffi/src/c/c_struct.rs b/crates/lune-std-ffi/src/c/c_struct.rs index 8812eb53..24cb008f 100644 --- a/crates/lune-std-ffi/src/c/c_struct.rs +++ b/crates/lune-std-ffi/src/c/c_struct.rs @@ -1,6 +1,5 @@ #![allow(clippy::cargo_common_metadata)] -use std::any::Any; use std::vec::Vec; use libffi::{low, middle::Type, raw}; @@ -8,9 +7,8 @@ use mlua::prelude::*; use super::association_names::CSTRUCT_INNER; use super::c_arr::CArr; -use super::c_helper::{name_from_userdata, stringify_userdata, type_list_from_table}; +use super::c_helper::{pretty_format_userdata, type_list_from_table}; use super::c_ptr::CPtr; -use super::c_type::CType; use crate::ffi::ffi_association::{get_association, set_association}; use crate::ffi::ffi_helper::FFI_STATUS_NAMES; @@ -63,7 +61,7 @@ impl CStruct { lua: &'lua Lua, table: LuaTable<'lua>, ) -> LuaResult> { - let fields = type_list_from_table(&table)?; + let fields = type_list_from_table(lua, &table)?; let cstruct = lua.create_userdata(Self::new(fields)?)?; table.set_readonly(true); set_association(lua, CSTRUCT_INNER, &cstruct, table)?; @@ -72,7 +70,7 @@ impl CStruct { // Stringify cstruct for pretty printing something like: // - pub fn stringify(userdata: &LuaAnyUserData) -> LuaResult { + pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { let field: LuaValue = userdata.get("inner")?; if field.is_table() { let table = field @@ -82,18 +80,7 @@ impl CStruct { let mut result = String::from(" "); for i in 0..table.raw_len() { let child: LuaAnyUserData = table.raw_get(i + 1)?; - if child.is::>() { - result.push_str(format!("{}, ", stringify_userdata(&child)?).as_str()); - } else { - result.push_str( - format!( - "<{}({})>, ", - name_from_userdata(&child), - stringify_userdata(&child)? - ) - .as_str(), - ); - } + result.push_str(pretty_format_userdata(lua, &child)?.as_str()); } // size of @@ -151,8 +138,8 @@ impl LuaUserData for CStruct { let carr = CArr::from_lua_userdata(lua, &this, length)?; Ok(carr) }); - methods.add_meta_function(LuaMetaMethod::ToString, |_, this: LuaAnyUserData| { - let result = CStruct::stringify(&this)?; + 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 3e4ee423..30f73e28 100644 --- a/crates/lune-std-ffi/src/c/c_type.rs +++ b/crates/lune-std-ffi/src/c/c_type.rs @@ -1,13 +1,17 @@ #![allow(clippy::cargo_common_metadata)] +use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; +use num::cast::{AsPrimitive, NumCast}; use std::marker::PhantomData; use libffi::middle::Type; use mlua::prelude::*; +use super::association_names::CTYPE_STATIC; use super::c_arr::CArr; use super::c_helper::get_ensured_size; use super::c_ptr::CPtr; +use crate::ffi::ffi_association::set_association; use crate::ffi::ffi_helper::get_ptr_from_userdata; pub struct CType { @@ -16,23 +20,57 @@ pub struct CType { libffi_type: Type, size: usize, name: Option<&'static str>, + signedness: bool, _phantom: PhantomData, } +// Static CType, for borrow, is operation +pub struct CTypeStatic { + pub libffi_type: Type, + pub size: usize, + pub name: Option<&'static str>, + pub signedness: bool, +} +impl CTypeStatic { + fn new(ctype: &CType) -> Self { + Self { + libffi_type: ctype.libffi_type.clone(), + size: ctype.size, + name: ctype.name, + signedness: ctype.signedness, + } + } +} +impl LuaUserData for CTypeStatic {} + impl CType where - T: ?Sized, + Self: CTypeConvert, + T: 'static, { - pub fn new_with_libffi_type(libffi_type: Type, name: Option<&'static str>) -> LuaResult { + pub fn new_with_libffi_type<'lua>( + lua: &'lua Lua, + libffi_type: Type, + signedness: bool, + name: Option<&'static str>, + ) -> LuaResult> { // let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void()); let size = get_ensured_size(libffi_type.as_raw_ptr())?; - Ok(Self { + + let ctype = Self { // libffi_cif: libffi_cfi, libffi_type, size, name, - _phantom: PhantomData {}, - }) + signedness, + _phantom: PhantomData, + }; + let userdata_static = lua.create_any_userdata(CTypeStatic::new::(&ctype))?; + let userdata = lua.create_userdata(ctype)?; + + set_association(lua, CTYPE_STATIC, &userdata, &userdata_static)?; + + Ok(userdata) } pub fn get_type(&self) -> &Type { @@ -45,9 +83,19 @@ where None => "unnamed", } } + + pub fn cast_failed_with(&self, into_ctype: &LuaAnyUserData) -> LuaError { + let config = ValueFormatConfig::new(); + LuaError::external(format!( + "Cannot cast to {}", + self.stringify(), + pretty_format_value(&LuaValue::UserData(into_ctype.to_owned()), &config) + )) + } } -pub trait PtrHandle { +// Handle C data, provide type conversion between luavalue and c-type +pub trait CTypeConvert { // Convert luavalue into data, then write into ptr fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()>; @@ -79,12 +127,53 @@ pub trait PtrHandle { } } +pub trait CTypeNumCast +where + T: NumCast, +{ + // Cast T as U + fn cast_userdata(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::() }; + + unsafe { + *into_ptr = (*from_ptr).as_(); + } + + Ok(()) + } + + fn cast_userdata_if_type_match( + ctype: &LuaAnyUserData, + from: &LuaAnyUserData, + into: &LuaAnyUserData, + ) -> LuaResult> + where + T: AsPrimitive, + U: 'static + Copy, + { + if ctype.is::>() { + Self::cast_userdata(from, into)?; + Ok(Some(())) + } else { + Ok(None) + } + } +} + impl LuaUserData for CType where - Self: Sized + PtrHandle, + Self: CTypeConvert, + T: 'static, { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { fields.add_field_method_get("size", |_, this| Ok(this.size)); + fields.add_meta_field(LuaMetaMethod::Type, "CType"); + fields.add_field_method_get("signedness", |_, this| Ok(this.signedness)); } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index be3364df..35ba0638 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -14,4 +14,5 @@ mod association_names { pub const CPTR_INNER: &str = "__cptr_inner"; pub const CARR_INNER: &str = "__carr_inner"; pub const CSTRUCT_INNER: &str = "__cstruct_inner"; + pub const CTYPE_STATIC: &str = "__ctype_static"; } diff --git a/crates/lune-std-ffi/src/c/types/c_char.rs b/crates/lune-std-ffi/src/c/types/c_char.rs new file mode 100644 index 00000000..18c0a675 --- /dev/null +++ b/crates/lune-std-ffi/src/c/types/c_char.rs @@ -0,0 +1,68 @@ +use core::ffi::*; + +use libffi::middle::Type; +use mlua::prelude::*; + +use super::super::c_type::{CType, CTypeConvert, CTypeNumCast}; +use crate::ffi::ffi_platform::CHAR_IS_SIGNED; + +impl CTypeConvert for CType { + fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()> { + let value = match value { + LuaValue::Integer(t) => t, + _ => { + return Err(LuaError::external(format!( + "Integer expected, got {}", + value.type_name() + ))) + } + } as c_char; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + } + fn ptr_into_luavalue(lua: &Lua, ptr: *mut ()) -> LuaResult { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + } +} + +impl CType { + fn cast( + &self, + into_ctype: &LuaAnyUserData, + from: &LuaAnyUserData, + into: &LuaAnyUserData, + ) -> LuaResult<()> { + Self::cast_userdata_if_type_match::(into_ctype, from, into)? + .or(Self::cast_userdata_if_type_match::( + into_ctype, from, into, + )?) + .or(Self::cast_userdata_if_type_match::( + into_ctype, from, into, + )?) + .or(Self::cast_userdata_if_type_match::( + into_ctype, from, into, + )?) + .ok_or_else(|| self.cast_failed_with(into_ctype)) + } +} + +impl CTypeNumCast for CType {} + +pub fn get_export(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { + Ok(( + "char", + CType::::new_with_libffi_type( + lua, + if CHAR_IS_SIGNED { + Type::c_schar() + } else { + Type::c_uchar() + }, + CHAR_IS_SIGNED, + Some("char"), + )?, + )) +} diff --git a/crates/lune-std-ffi/src/c/types/c_int.rs b/crates/lune-std-ffi/src/c/types/c_int.rs index 3e36a696..c11a8ebc 100644 --- a/crates/lune-std-ffi/src/c/types/c_int.rs +++ b/crates/lune-std-ffi/src/c/types/c_int.rs @@ -1,11 +1,11 @@ -use core::ffi::c_int; +use core::ffi::*; use libffi::middle::Type; use mlua::prelude::*; -use super::super::c_type::{CType, PtrHandle}; +use super::super::c_type::{CType, CTypeConvert, CTypeNumCast}; -impl PtrHandle for CType { +impl CTypeConvert for CType { fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()> { let value = match value { LuaValue::Integer(t) => t, @@ -28,11 +28,36 @@ impl PtrHandle for CType { } impl CType { - fn new() -> LuaResult { - Self::new_with_libffi_type(Type::c_int(), Some("int")) + fn cast( + &self, + into_ctype: &LuaAnyUserData, + from: &LuaAnyUserData, + into: &LuaAnyUserData, + ) -> LuaResult<()> { + Self::cast_userdata_if_type_match::(into_ctype, from, into)? + .or(Self::cast_userdata_if_type_match::( + into_ctype, from, into, + )?) + .or(Self::cast_userdata_if_type_match::( + into_ctype, from, into, + )?) + .or(Self::cast_userdata_if_type_match::( + into_ctype, from, into, + )?) + .ok_or_else(|| self.cast_failed_with(into_ctype)) } } +impl CTypeNumCast for CType {} + pub fn get_export(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { - Ok(("int", lua.create_userdata(CType::::new()?)?)) + Ok(( + "int", + CType::::new_with_libffi_type( + lua, + Type::c_int(), + c_int::MIN.unsigned_abs() != 0, + Some("int"), + )?, + )) } diff --git a/crates/lune-std-ffi/src/c/types/mod.rs b/crates/lune-std-ffi/src/c/types/mod.rs index 0d4986d4..a543f974 100644 --- a/crates/lune-std-ffi/src/c/types/mod.rs +++ b/crates/lune-std-ffi/src/c/types/mod.rs @@ -1,8 +1,9 @@ +mod c_char; mod c_int; use mlua::prelude::*; // export all default c-types pub fn create_all_types(lua: &Lua) -> LuaResult> { - Ok(vec![c_int::get_export(lua)?]) + Ok(vec![c_int::get_export(lua)?, c_char::get_export(lua)?]) } diff --git a/crates/lune-std-ffi/src/ffi/ffi_association.rs b/crates/lune-std-ffi/src/ffi/ffi_association.rs index 49f9c8a0..be242de5 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_association.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_association.rs @@ -10,10 +10,14 @@ // uservalue operations cannot be performed directly, // so this is the best solution for now. // If the dependency is deep, the value may be completely destroyed when -// gc is performed multiple times. As an example, there is the following case: +// gc is performed multiple times. To prevent this situation, FFI 'copies' +// dependency if possible. // // ffi.i32:ptr():ptr() +// Something like this, every pointer type will have various inner field. +// // box:ref():ref() +// But, in this case, // // Since the outermost pointer holds the definition for the pointer // type inside it, only the outermost type will be removed on the first gc. diff --git a/crates/lune-std-ffi/src/ffi/ffi_box.rs b/crates/lune-std-ffi/src/ffi/ffi_box.rs index f7d593c1..d25362dc 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_box.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_box.rs @@ -74,11 +74,15 @@ impl FfiBox { t ))); } - ptr = unsafe { target.get_ptr().offset(t) }; + ptr = unsafe { target.get_ptr().byte_offset(t) }; bounds = bounds.offset(t); } - let luaref = lua.create_userdata(FfiRef::new(ptr.cast(), Some(bounds)))?; + // Lua should not be able to deref a box that refers to a box managed by Lua. + // To deref a box space is to allow lua to read any space, + // which has security issues and is ultimately dangerous. + // Therefore, box:ref():deref() is not allowed. + let luaref = lua.create_userdata(FfiRef::new(ptr.cast(), false, Some(bounds)))?; // Makes box alive longer then ref set_association(lua, REF_INNER, &luaref, &this)?; diff --git a/crates/lune-std-ffi/src/ffi/ffi_helper.rs b/crates/lune-std-ffi/src/ffi/ffi_helper.rs index 3e9f48a7..00605e7f 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_helper.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_helper.rs @@ -11,6 +11,7 @@ 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( diff --git a/crates/lune-std-ffi/src/ffi/ffi_lib.rs b/crates/lune-std-ffi/src/ffi/ffi_lib.rs index 70c81c62..a4a657f6 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_lib.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_lib.rs @@ -39,7 +39,7 @@ impl FfiLib { .map_err(|err| LuaError::external(format!("{err}")))? }; - let luasym = lua.create_userdata(FfiRef::new((*sym).cast(), None))?; + let luasym = lua.create_userdata(FfiRef::new((*sym).cast(), true, None))?; set_association(lua, SYM_INNER, &luasym, &this)?; diff --git a/crates/lune-std-ffi/src/ffi/ffi_ref.rs b/crates/lune-std-ffi/src/ffi/ffi_ref.rs index 5e9a9f80..8700e726 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref.rs @@ -16,12 +16,17 @@ use super::ffi_bounds::FfiRefBounds; pub struct FfiRef { ptr: *mut (), + dereferenceable: bool, range: Option, } impl FfiRef { - pub fn new(ptr: *mut (), range: Option) -> Self { - Self { ptr, range } + pub fn new(ptr: *mut (), dereferenceable: bool, range: Option) -> Self { + Self { + ptr, + dereferenceable, + range, + } } // Make FfiRef from ref @@ -33,16 +38,15 @@ impl FfiRef { let luaref = lua.create_userdata(FfiRef::new( ptr::from_ref(&target.ptr) as *mut (), + true, Some(FfiRefBounds { low: 0, high: size_of::(), }), ))?; - // If the ref holds a box, make sure the new ref also holds the box - if let Some(t) = get_association(lua, REF_INNER, &this)? { - set_association(lua, REF_INNER, &luaref, t)?; - } + // If the ref holds a box, make sure the new ref also holds the box by holding ref + set_association(lua, REF_INNER, &luaref, &this)?; Ok(luaref) } @@ -52,7 +56,8 @@ impl FfiRef { } pub unsafe fn deref(&self) -> Self { - Self::new(*self.ptr.cast::<*mut ()>(), None) + // FIXME + Self::new(*self.ptr.cast::<*mut ()>(), true, None) } pub unsafe fn offset(&self, offset: isize) -> LuaResult { @@ -67,7 +72,8 @@ impl FfiRef { let range = self.range.as_ref().map(|t| t.offset(offset)); Ok(Self::new( - self.ptr.cast::().offset(offset).cast(), + self.ptr.byte_offset(offset), + self.dereferenceable, range, )) } @@ -81,14 +87,22 @@ impl LuaUserData for FfiRef { let result = lua.create_userdata(unsafe { ffiref.deref() })?; if let Some(t) = inner { + // if let Some(u) = get_association(lua, regname, value) {} set_association(lua, REF_INNER, &result, &t)?; } Ok(result) }); - methods.add_method("offset", |_, this, offset: isize| { - let ffiref = unsafe { this.offset(offset)? }; - Ok(ffiref) + methods.add_function("offset", |lua, (this, offset): (LuaAnyUserData, isize)| { + let ffiref = unsafe { this.borrow::()?.offset(offset)? }; + let userdata = lua.create_userdata(ffiref)?; + + // If the ref holds a box, make sure the new ref also holds the box + if let Some(t) = get_association(lua, REF_INNER, &this)? { + set_association(lua, REF_INNER, &userdata, t)?; + } + + Ok(userdata) }); methods.add_function("ref", |lua, this: LuaAnyUserData| { let ffiref = FfiRef::luaref(lua, this)?; diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs index 4a519759..87ea3eaf 100644 --- a/crates/lune-std-ffi/src/lib.rs +++ b/crates/lune-std-ffi/src/lib.rs @@ -33,8 +33,8 @@ pub fn module(lua: &Lua) -> LuaResult { let cstruct = CStruct::from_lua_table(lua, types)?; Ok(cstruct) })? - .with_function("fn", |_, (args, ret): (LuaTable, LuaAnyUserData)| { - let cfn = CFn::from_lua_table(args, ret)?; + .with_function("fn", |lua, (args, ret): (LuaTable, LuaAnyUserData)| { + let cfn = CFn::from_lua_table(lua, args, ret)?; Ok(cfn) })?; diff --git a/crates/lune-std-ffi/todo.md b/crates/lune-std-ffi/todo.md index f0a0ab8b..fbd89994 100644 --- a/crates/lune-std-ffi/todo.md +++ b/crates/lune-std-ffi/todo.md @@ -3,6 +3,8 @@ - [ ] Add docs - [ ] Typing +pragma pack? + # Raw - [ ] Raw:toRef() From 48d2db4950eaeeefb7f29bdb2d577c65302e15c7 Mon Sep 17 00:00:00 2001 From: qwreey Date: Tue, 27 Aug 2024 10:44:51 +0000 Subject: [PATCH 08/79] Implement luavalue conversion (#243) --- crates/lune-std-ffi/src/c/c_arr.rs | 2 +- crates/lune-std-ffi/src/c/c_fn.rs | 2 +- crates/lune-std-ffi/src/c/c_ptr.rs | 2 +- crates/lune-std-ffi/src/c/c_struct.rs | 4 +- crates/lune-std-ffi/src/c/c_type.rs | 78 ++++++++++++++------- crates/lune-std-ffi/src/c/types/c_char.rs | 35 +++++---- crates/lune-std-ffi/src/c/types/c_double.rs | 59 ++++++++++++++++ crates/lune-std-ffi/src/c/types/c_float.rs | 59 ++++++++++++++++ crates/lune-std-ffi/src/c/types/c_int.rs | 41 ++++++----- crates/lune-std-ffi/src/c/types/c_long.rs | 59 ++++++++++++++++ crates/lune-std-ffi/src/c/types/mod.rs | 11 ++- crates/lune-std-ffi/src/ffi/ffi_box.rs | 17 ++--- crates/lune-std-ffi/src/ffi/ffi_platform.rs | 19 ++--- crates/lune-std-ffi/src/lib.rs | 4 +- 14 files changed, 293 insertions(+), 99 deletions(-) create mode 100644 crates/lune-std-ffi/src/c/types/c_double.rs create mode 100644 crates/lune-std-ffi/src/c/types/c_float.rs create mode 100644 crates/lune-std-ffi/src/c/types/c_long.rs diff --git a/crates/lune-std-ffi/src/c/c_arr.rs b/crates/lune-std-ffi/src/c/c_arr.rs index ba81bf70..063b93ad 100644 --- a/crates/lune-std-ffi/src/c/c_arr.rs +++ b/crates/lune-std-ffi/src/c/c_arr.rs @@ -39,7 +39,7 @@ impl CArr { }) } - pub fn from_lua_userdata<'lua>( + pub fn new_from_lua_userdata<'lua>( lua: &'lua Lua, luatype: &LuaAnyUserData<'lua>, length: usize, diff --git a/crates/lune-std-ffi/src/c/c_fn.rs b/crates/lune-std-ffi/src/c/c_fn.rs index 3dfe3a4f..7a4bce3d 100644 --- a/crates/lune-std-ffi/src/c/c_fn.rs +++ b/crates/lune-std-ffi/src/c/c_fn.rs @@ -35,7 +35,7 @@ impl CFn { } } - pub fn from_lua_table(lua: &Lua, args: LuaTable, ret: LuaAnyUserData) -> LuaResult { + 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)?; Ok(Self::new(args, ret)) diff --git a/crates/lune-std-ffi/src/c/c_ptr.rs b/crates/lune-std-ffi/src/c/c_ptr.rs index 00d4e208..ced880b8 100644 --- a/crates/lune-std-ffi/src/c/c_ptr.rs +++ b/crates/lune-std-ffi/src/c/c_ptr.rs @@ -60,7 +60,7 @@ impl LuaUserData for CPtr { Ok(pointer) }); methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| { - let carr = CArr::from_lua_userdata(lua, &this, length)?; + let carr = CArr::new_from_lua_userdata(lua, &this, length)?; Ok(carr) }); methods.add_meta_function(LuaMetaMethod::ToString, |lua, this: LuaAnyUserData| { diff --git a/crates/lune-std-ffi/src/c/c_struct.rs b/crates/lune-std-ffi/src/c/c_struct.rs index 24cb008f..168d7d20 100644 --- a/crates/lune-std-ffi/src/c/c_struct.rs +++ b/crates/lune-std-ffi/src/c/c_struct.rs @@ -57,7 +57,7 @@ impl CStruct { // Create new CStruct UserData with LuaTable. // Lock and hold table for .inner ref - pub fn from_lua_table<'lua>( + pub fn new_from_lua_table<'lua>( lua: &'lua Lua, table: LuaTable<'lua>, ) -> LuaResult> { @@ -135,7 +135,7 @@ impl LuaUserData for CStruct { Ok(pointer) }); methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| { - let carr = CArr::from_lua_userdata(lua, &this, length)?; + let carr = CArr::new_from_lua_userdata(lua, &this, length)?; Ok(carr) }); methods.add_meta_function(LuaMetaMethod::ToString, |lua, this: LuaAnyUserData| { diff --git a/crates/lune-std-ffi/src/c/c_type.rs b/crates/lune-std-ffi/src/c/c_type.rs index 30f73e28..5300bead 100644 --- a/crates/lune-std-ffi/src/c/c_type.rs +++ b/crates/lune-std-ffi/src/c/c_type.rs @@ -1,7 +1,7 @@ #![allow(clippy::cargo_common_metadata)] use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; -use num::cast::{AsPrimitive, NumCast}; +use num::cast::AsPrimitive; use std::marker::PhantomData; use libffi::middle::Type; @@ -24,13 +24,18 @@ pub struct CType { _phantom: PhantomData, } -// Static CType, for borrow, is operation +// We can't get a CType through mlua, something like +// .is::> will fail. +// So we need data that has a static type. +// each CType userdata instance stores an instance of CTypeStatic. +#[allow(unused)] pub struct CTypeStatic { pub libffi_type: Type, pub size: usize, pub name: Option<&'static str>, pub signedness: bool, } + impl CTypeStatic { fn new(ctype: &CType) -> Self { Self { @@ -45,8 +50,8 @@ impl LuaUserData for CTypeStatic {} impl CType where - Self: CTypeConvert, T: 'static, + Self: CTypeConvert + CTypeCast, { pub fn new_with_libffi_type<'lua>( lua: &'lua Lua, @@ -73,25 +78,12 @@ where Ok(userdata) } - pub fn get_type(&self) -> &Type { - &self.libffi_type - } - pub fn stringify(&self) -> &str { match self.name { Some(t) => t, None => "unnamed", } } - - pub fn cast_failed_with(&self, into_ctype: &LuaAnyUserData) -> LuaError { - let config = ValueFormatConfig::new(); - LuaError::external(format!( - "Cannot cast to {}", - self.stringify(), - pretty_format_value(&LuaValue::UserData(into_ctype.to_owned()), &config) - )) - } } // Handle C data, provide type conversion between luavalue and c-type @@ -127,12 +119,9 @@ pub trait CTypeConvert { } } -pub trait CTypeNumCast -where - T: NumCast, -{ +pub trait CTypeCast { // Cast T as U - fn cast_userdata(from: &LuaAnyUserData, into: &LuaAnyUserData) -> LuaResult<()> + fn cast_num(&self, from: &LuaAnyUserData, into: &LuaAnyUserData) -> LuaResult<()> where T: AsPrimitive, U: 'static + Copy, @@ -147,7 +136,8 @@ where Ok(()) } - fn cast_userdata_if_type_match( + fn try_cast_num( + &self, ctype: &LuaAnyUserData, from: &LuaAnyUserData, into: &LuaAnyUserData, @@ -157,18 +147,42 @@ where U: 'static + Copy, { if ctype.is::>() { - Self::cast_userdata(from, into)?; + Self::cast_num::(self, from, into)?; Ok(Some(())) } else { Ok(None) } } + + #[allow(unused_variables)] + 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), + )) + } } impl LuaUserData for CType where - Self: CTypeConvert, T: 'static, + Self: CTypeConvert + CTypeCast, { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { fields.add_field_method_get("size", |_, this| Ok(this.size)); @@ -193,8 +207,22 @@ where }, ); methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| { - CArr::from_lua_userdata(lua, &this, length) + CArr::new_from_lua_userdata(lua, &this, length) }); + methods.add_function( + "cast", + |_, + (from_type, into_type, from, into): ( + LuaAnyUserData, + LuaAnyUserData, + LuaAnyUserData, + LuaAnyUserData, + )| { + from_type + .borrow::()? + .cast(&from_type, &into_type, &from, &into) + }, + ); methods.add_meta_method(LuaMetaMethod::ToString, |lua, this, ()| { lua.create_string(this.stringify()) }); diff --git a/crates/lune-std-ffi/src/c/types/c_char.rs b/crates/lune-std-ffi/src/c/types/c_char.rs index 18c0a675..adaec6a9 100644 --- a/crates/lune-std-ffi/src/c/types/c_char.rs +++ b/crates/lune-std-ffi/src/c/types/c_char.rs @@ -2,21 +2,23 @@ use core::ffi::*; use libffi::middle::Type; use mlua::prelude::*; +use num::cast::AsPrimitive; -use super::super::c_type::{CType, CTypeConvert, CTypeNumCast}; +use super::super::c_type::{CType, CTypeCast, CTypeConvert}; use crate::ffi::ffi_platform::CHAR_IS_SIGNED; impl CTypeConvert for CType { fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()> { - let value = match value { - LuaValue::Integer(t) => t, + let value: c_char = match value { + LuaValue::Integer(t) => t.as_(), + LuaValue::String(t) => t.as_bytes().first().map_or(0, u8::to_owned).as_(), _ => { return Err(LuaError::external(format!( - "Integer expected, got {}", + "Argument LuaValue expected a Integer or String, got {}", value.type_name() ))) } - } as c_char; + }; unsafe { *(ptr.cast::()) = value; } @@ -28,29 +30,24 @@ impl CTypeConvert for CType { } } -impl CType { +impl CTypeCast for CType { fn cast( &self, + from_ctype: &LuaAnyUserData, into_ctype: &LuaAnyUserData, from: &LuaAnyUserData, into: &LuaAnyUserData, ) -> LuaResult<()> { - Self::cast_userdata_if_type_match::(into_ctype, from, into)? - .or(Self::cast_userdata_if_type_match::( - into_ctype, from, into, - )?) - .or(Self::cast_userdata_if_type_match::( - into_ctype, from, into, - )?) - .or(Self::cast_userdata_if_type_match::( - into_ctype, from, into, - )?) - .ok_or_else(|| self.cast_failed_with(into_ctype)) + 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)) } } -impl CTypeNumCast for CType {} - pub fn get_export(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { Ok(( "char", diff --git a/crates/lune-std-ffi/src/c/types/c_double.rs b/crates/lune-std-ffi/src/c/types/c_double.rs new file mode 100644 index 00000000..9f63f992 --- /dev/null +++ b/crates/lune-std-ffi/src/c/types/c_double.rs @@ -0,0 +1,59 @@ +use core::ffi::*; + +use libffi::middle::Type; +use mlua::prelude::*; + +use super::super::c_type::{CType, CTypeCast, CTypeConvert}; +use num::cast::AsPrimitive; + +impl CTypeConvert for CType { + fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()> { + let value: c_double = match value { + LuaValue::Integer(t) => t.as_(), + LuaValue::Number(t) => t.as_(), + LuaValue::String(t) => t + .to_string_lossy() + .parse::() + .map_err(LuaError::external)?, + _ => { + return Err(LuaError::external(format!( + "Argument LuaValue expected a Integer, Number or String, got {}", + value.type_name() + ))) + } + }; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + } + fn ptr_into_luavalue(lua: &Lua, ptr: *mut ()) -> LuaResult { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + } +} + +impl CTypeCast for CType { + fn cast( + &self, + from_ctype: &LuaAnyUserData, + into_ctype: &LuaAnyUserData, + from: &LuaAnyUserData, + into: &LuaAnyUserData, + ) -> 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)?) + .ok_or_else(|| self.cast_failed_with(from_ctype, into_ctype)) + } +} + +pub fn get_export(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { + Ok(( + "double", + CType::::new_with_libffi_type(lua, Type::f64(), true, Some("double"))?, + )) +} diff --git a/crates/lune-std-ffi/src/c/types/c_float.rs b/crates/lune-std-ffi/src/c/types/c_float.rs new file mode 100644 index 00000000..c02fc80c --- /dev/null +++ b/crates/lune-std-ffi/src/c/types/c_float.rs @@ -0,0 +1,59 @@ +use core::ffi::*; + +use libffi::middle::Type; +use mlua::prelude::*; + +use super::super::c_type::{CType, CTypeCast, CTypeConvert}; +use num::cast::AsPrimitive; + +impl CTypeConvert for CType { + fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()> { + let value: c_float = match value { + LuaValue::Integer(t) => t.as_(), + LuaValue::Number(t) => t.as_(), + LuaValue::String(t) => t + .to_string_lossy() + .parse::() + .map_err(LuaError::external)?, + _ => { + return Err(LuaError::external(format!( + "Argument LuaValue expected a Integer, Number or String, got {}", + value.type_name() + ))) + } + }; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + } + fn ptr_into_luavalue(lua: &Lua, ptr: *mut ()) -> LuaResult { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + } +} + +impl CTypeCast for CType { + fn cast( + &self, + from_ctype: &LuaAnyUserData, + into_ctype: &LuaAnyUserData, + from: &LuaAnyUserData, + into: &LuaAnyUserData, + ) -> 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)?) + .ok_or_else(|| self.cast_failed_with(from_ctype, into_ctype)) + } +} + +pub fn get_export(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { + Ok(( + "float", + CType::::new_with_libffi_type(lua, Type::f32(), true, Some("float"))?, + )) +} diff --git a/crates/lune-std-ffi/src/c/types/c_int.rs b/crates/lune-std-ffi/src/c/types/c_int.rs index c11a8ebc..ac3551d8 100644 --- a/crates/lune-std-ffi/src/c/types/c_int.rs +++ b/crates/lune-std-ffi/src/c/types/c_int.rs @@ -2,20 +2,26 @@ use core::ffi::*; use libffi::middle::Type; use mlua::prelude::*; +use num::cast::AsPrimitive; -use super::super::c_type::{CType, CTypeConvert, CTypeNumCast}; +use super::super::c_type::{CType, CTypeCast, CTypeConvert}; impl CTypeConvert for CType { fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()> { - let value = match value { - LuaValue::Integer(t) => t, + let value: c_int = match value { + LuaValue::Integer(t) => t.as_(), + LuaValue::Number(t) => t.as_(), + LuaValue::String(t) => t + .to_string_lossy() + .parse::() + .map_err(LuaError::external)?, _ => { return Err(LuaError::external(format!( - "Integer expected, got {}", + "Argument LuaValue expected a Integer, Number or String, got {}", value.type_name() ))) } - } as c_int; + }; unsafe { *(ptr.cast::()) = value; } @@ -27,29 +33,26 @@ impl CTypeConvert for CType { } } -impl CType { +impl CType {} + +impl CTypeCast for CType { fn cast( &self, + from_ctype: &LuaAnyUserData, into_ctype: &LuaAnyUserData, from: &LuaAnyUserData, into: &LuaAnyUserData, ) -> LuaResult<()> { - Self::cast_userdata_if_type_match::(into_ctype, from, into)? - .or(Self::cast_userdata_if_type_match::( - into_ctype, from, into, - )?) - .or(Self::cast_userdata_if_type_match::( - into_ctype, from, into, - )?) - .or(Self::cast_userdata_if_type_match::( - into_ctype, from, into, - )?) - .ok_or_else(|| self.cast_failed_with(into_ctype)) + 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)) } } -impl CTypeNumCast for CType {} - pub fn get_export(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { Ok(( "int", diff --git a/crates/lune-std-ffi/src/c/types/c_long.rs b/crates/lune-std-ffi/src/c/types/c_long.rs new file mode 100644 index 00000000..60691c77 --- /dev/null +++ b/crates/lune-std-ffi/src/c/types/c_long.rs @@ -0,0 +1,59 @@ +use core::ffi::*; + +use libffi::middle::Type; +use mlua::prelude::*; + +use super::super::c_type::{CType, CTypeCast, CTypeConvert}; +use num::cast::AsPrimitive; + +impl CTypeConvert for CType { + fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()> { + let value: c_long = match value { + LuaValue::Integer(t) => t.as_(), + LuaValue::Number(t) => t.as_(), + LuaValue::String(t) => t + .to_string_lossy() + .parse::() + .map_err(LuaError::external)?, + _ => { + return Err(LuaError::external(format!( + "Argument LuaValue expected a Integer, Number or String, got {}", + value.type_name() + ))) + } + }; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + } + fn ptr_into_luavalue(lua: &Lua, ptr: *mut ()) -> LuaResult { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + } +} + +impl CTypeCast for CType { + fn cast( + &self, + from_ctype: &LuaAnyUserData, + into_ctype: &LuaAnyUserData, + from: &LuaAnyUserData, + into: &LuaAnyUserData, + ) -> 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)?) + .ok_or_else(|| self.cast_failed_with(from_ctype, into_ctype)) + } +} + +pub fn get_export(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { + Ok(( + "long", + CType::::new_with_libffi_type(lua, Type::c_long(), true, Some("long"))?, + )) +} diff --git a/crates/lune-std-ffi/src/c/types/mod.rs b/crates/lune-std-ffi/src/c/types/mod.rs index a543f974..af90e573 100644 --- a/crates/lune-std-ffi/src/c/types/mod.rs +++ b/crates/lune-std-ffi/src/c/types/mod.rs @@ -1,9 +1,18 @@ mod c_char; +mod c_double; +mod c_float; mod c_int; +mod c_long; use mlua::prelude::*; // export all default c-types pub fn create_all_types(lua: &Lua) -> LuaResult> { - Ok(vec![c_int::get_export(lua)?, c_char::get_export(lua)?]) + Ok(vec![ + c_char::get_export(lua)?, + c_double::get_export(lua)?, + c_float::get_export(lua)?, + c_int::get_export(lua)?, + c_long::get_export(lua)?, + ]) } diff --git a/crates/lune-std-ffi/src/ffi/ffi_box.rs b/crates/lune-std-ffi/src/ffi/ffi_box.rs index d25362dc..9eb892b8 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_box.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_box.rs @@ -39,18 +39,9 @@ impl FfiBox { // Todo: if too big, print as another format pub fn stringify(&self) -> String { - let mut buff: String = String::with_capacity(self.size() * 10 - 2); - for (pos, value) in self.0.iter().enumerate() { - for i in 0..8 { - if (value & (1 << i)) == 0 { - buff.push('0'); - } else { - buff.push('1'); - } - } - if pos < self.size() - 1 { - buff.push_str(", "); - } + let mut buff: String = String::with_capacity(self.size() * 2); + for value in &self.0 { + buff.push_str(format!("{:x}", value.to_be()).as_str()); } buff } @@ -78,7 +69,7 @@ impl FfiBox { bounds = bounds.offset(t); } - // Lua should not be able to deref a box that refers to a box managed by Lua. + // Lua should not be able to deref a box. // To deref a box space is to allow lua to read any space, // which has security issues and is ultimately dangerous. // Therefore, box:ref():deref() is not allowed. diff --git a/crates/lune-std-ffi/src/ffi/ffi_platform.rs b/crates/lune-std-ffi/src/ffi/ffi_platform.rs index c7371aaf..30600d21 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_platform.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_platform.rs @@ -1,22 +1,11 @@ use core::ffi::c_char; -use std::env::consts; use std::vec::Vec; pub const CHAR_IS_SIGNED: bool = c_char::MIN as u8 != u8::MIN; -pub const IS_LITTLE_ENDIAN: bool = cfg!(target_endian = "little"); pub fn get_platform_value() -> Vec<(&'static str, &'static str)> { - vec![ - // https://doc.rust-lang.org/std/env/consts/constant.ARCH.html - ("arch", consts::ARCH), - // https://doc.rust-lang.org/std/env/consts/constant.OS.html - ("os", consts::OS), - // https://doc.rust-lang.org/std/env/consts/constant.FAMILY.html - ("family", consts::FAMILY), - ("endian", if IS_LITTLE_ENDIAN { "little" } else { "big" }), - ( - "char_variant", - if CHAR_IS_SIGNED { "schar" } else { "uchar" }, - ), - ] + vec![( + "char_variant", + if CHAR_IS_SIGNED { "schar" } else { "uchar" }, + )] } diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs index 87ea3eaf..355cf3be 100644 --- a/crates/lune-std-ffi/src/lib.rs +++ b/crates/lune-std-ffi/src/lib.rs @@ -30,11 +30,11 @@ pub fn module(lua: &Lua) -> LuaResult { Ok(lib) })? .with_function("struct", |lua, types: LuaTable| { - let cstruct = CStruct::from_lua_table(lua, types)?; + let cstruct = CStruct::new_from_lua_table(lua, types)?; Ok(cstruct) })? .with_function("fn", |lua, (args, ret): (LuaTable, LuaAnyUserData)| { - let cfn = CFn::from_lua_table(lua, args, ret)?; + let cfn = CFn::new_from_lua_table(lua, args, ret)?; Ok(cfn) })?; From 3ccb0720fd8f806bb398ae726bd5f0ecd3374988 Mon Sep 17 00:00:00 2001 From: qwreey Date: Tue, 27 Aug 2024 13:24:17 +0000 Subject: [PATCH 09/79] Export ctypes and implement signedness (#243) --- .vscode/settings.json | 4 - crates/lune-std-ffi/readme.md | 129 -------------- crates/lune-std-ffi/src/c/c_struct.rs | 22 +-- crates/lune-std-ffi/src/c/c_type.rs | 141 +++++++--------- crates/lune-std-ffi/src/c/mod.rs | 19 ++- crates/lune-std-ffi/src/c/types/c_char.rs | 65 ------- crates/lune-std-ffi/src/c/types/c_double.rs | 59 ------- crates/lune-std-ffi/src/c/types/c_float.rs | 59 ------- crates/lune-std-ffi/src/c/types/c_int.rs | 66 -------- crates/lune-std-ffi/src/c/types/c_long.rs | 59 ------- crates/lune-std-ffi/src/c/types/f32.rs | 57 +++++++ crates/lune-std-ffi/src/c/types/f64.rs | 57 +++++++ crates/lune-std-ffi/src/c/types/i128.rs | 61 +++++++ crates/lune-std-ffi/src/c/types/i16.rs | 57 +++++++ crates/lune-std-ffi/src/c/types/i32.rs | 57 +++++++ crates/lune-std-ffi/src/c/types/i64.rs | 57 +++++++ crates/lune-std-ffi/src/c/types/i8.rs | 53 ++++++ crates/lune-std-ffi/src/c/types/isize.rs | 57 +++++++ crates/lune-std-ffi/src/c/types/mod.rs | 158 ++++++++++++++++-- crates/lune-std-ffi/src/c/types/u128.rs | 61 +++++++ crates/lune-std-ffi/src/c/types/u16.rs | 58 +++++++ crates/lune-std-ffi/src/c/types/u32.rs | 57 +++++++ crates/lune-std-ffi/src/c/types/u64.rs | 57 +++++++ crates/lune-std-ffi/src/c/types/u8.rs | 56 +++++++ crates/lune-std-ffi/src/c/types/usize.rs | 57 +++++++ .../lune-std-ffi/src/ffi/ffi_association.rs | 3 +- crates/lune-std-ffi/src/ffi/ffi_box.rs | 29 ++-- crates/lune-std-ffi/src/ffi/ffi_helper.rs | 20 +++ crates/lune-std-ffi/src/ffi/ffi_lib.rs | 18 +- .../lune-std-ffi/src/ffi/ffi_native/cast.rs | 24 +++ .../src/ffi/ffi_native/convert.rs | 52 ++++++ crates/lune-std-ffi/src/ffi/ffi_native/mod.rs | 5 + crates/lune-std-ffi/src/ffi/ffi_platform.rs | 11 -- .../ffi/{ffi_bounds.rs => ffi_ref/bounds.rs} | 48 ++++-- crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs | 71 ++++++++ .../src/ffi/{ffi_ref.rs => ffi_ref/mod.rs} | 100 ++++++++--- crates/lune-std-ffi/src/ffi/mod.rs | 15 +- crates/lune-std-ffi/src/lib.rs | 16 +- crates/lune-std-ffi/todo.md | 99 ----------- 39 files changed, 1359 insertions(+), 735 deletions(-) delete mode 100644 crates/lune-std-ffi/readme.md delete mode 100644 crates/lune-std-ffi/src/c/types/c_char.rs delete mode 100644 crates/lune-std-ffi/src/c/types/c_double.rs delete mode 100644 crates/lune-std-ffi/src/c/types/c_float.rs delete mode 100644 crates/lune-std-ffi/src/c/types/c_int.rs delete mode 100644 crates/lune-std-ffi/src/c/types/c_long.rs create mode 100644 crates/lune-std-ffi/src/c/types/f32.rs create mode 100644 crates/lune-std-ffi/src/c/types/f64.rs create mode 100644 crates/lune-std-ffi/src/c/types/i128.rs create mode 100644 crates/lune-std-ffi/src/c/types/i16.rs create mode 100644 crates/lune-std-ffi/src/c/types/i32.rs create mode 100644 crates/lune-std-ffi/src/c/types/i64.rs create mode 100644 crates/lune-std-ffi/src/c/types/i8.rs create mode 100644 crates/lune-std-ffi/src/c/types/isize.rs create mode 100644 crates/lune-std-ffi/src/c/types/u128.rs create mode 100644 crates/lune-std-ffi/src/c/types/u16.rs create mode 100644 crates/lune-std-ffi/src/c/types/u32.rs create mode 100644 crates/lune-std-ffi/src/c/types/u64.rs create mode 100644 crates/lune-std-ffi/src/c/types/u8.rs create mode 100644 crates/lune-std-ffi/src/c/types/usize.rs create mode 100644 crates/lune-std-ffi/src/ffi/ffi_native/cast.rs create mode 100644 crates/lune-std-ffi/src/ffi/ffi_native/convert.rs create mode 100644 crates/lune-std-ffi/src/ffi/ffi_native/mod.rs delete mode 100644 crates/lune-std-ffi/src/ffi/ffi_platform.rs rename crates/lune-std-ffi/src/ffi/{ffi_bounds.rs => ffi_ref/bounds.rs} (58%) create mode 100644 crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs rename crates/lune-std-ffi/src/ffi/{ffi_ref.rs => ffi_ref/mod.rs} (50%) delete mode 100644 crates/lune-std-ffi/todo.md diff --git a/.vscode/settings.json b/.vscode/settings.json index 39405698..95c90cf6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -23,9 +23,5 @@ }, "[rust]": { "editor.defaultFormatter": "rust-lang.rust-analyzer" - }, - "files.associations": { - "*.inc": "c", - "random": "c" } } diff --git a/crates/lune-std-ffi/readme.md b/crates/lune-std-ffi/readme.md deleted file mode 100644 index e61256bb..00000000 --- a/crates/lune-std-ffi/readme.md +++ /dev/null @@ -1,129 +0,0 @@ -TODO: rewrite docs - -# Raw - -Data received from external. You can move this data into a box, use it as a ref, or change it directly to a Lua value. -The raw data is not on Lua's heap. - -Raw:toRef() -Convert data into ref. it allocate new lua userdata - -Raw:toBox() -Convert data into box. it allocate new lua userdata - -Raw:intoBox() -Raw:intoRef() - -See type:fromRaw() - -# Box - -`ffi.box(size)` - -Create new userdata with sized by `size` argument. Box is untyped, and have no ABI information. You can write some data into box with `type` - -All operation with box will boundary checked. GC will free heap well. - -일반적으로 포인터를 넘겨주기 위해서 사용됩니다. 박스의 공간은 ref 할 수 있으며. 함수를 수행한 후 루아에서 읽어볼 수 있습니다. - -## :zero() -박스를 0 으로 채워넣습니다. 기본적으로 박스는 초기화될 때 0 으로 채워지기 때문에 박스를 다시 0 으로 초기화하고 싶을 경우에 사용하십시오. - -## :copy(targetbox,size,offset?=0,targetoffset?=0) -박스 안의 값을 다른 박스에 복사합니다. 바운더리가 확인되어지므로 안전합니다. - -## .size -이 박스의 크기입니다. - -## :ref(offset?=0) => ref -이 박스를 참조합니다. 참조가 살아있는 동안 박스는 수거되지 않습니다. 일반적으로 외부의 함수에 포인터를 넘겨주기 위해서 사용됩니다. - -## more stuffs (not planned at this time) - -ref=>buffer conversion, or bit/byte related? - -# Ref (Unsafe) - -바운더리를 처리하지 않는 포인터입니다. 외부에서 받은 포인터, 또는 박스로부터 만들어진 포인터입니다. -ref 는 바운더리를 검사하지 않으므로 안전하지 않습니다. - -## :offset(bytes) - -이 ref 와 상대적인 위치에 있는 ref 를 구합니다. - -## :writefromRef() -다른 ref 안의 값을 읽어와 이 ref 안에 씁니다. 아래와 비슷한 연산을 합니다 -```c -int a = 100,b; -``` - -## :writefromBox() -box 값을 읽어와서 쓰기 - -# Type - -`type` is abstract class that helps encoding data into `box` or decode data from `box` - -## :toBox(luavalue) -Convert lua value to box. box will sized with `type.size` - -## :fromBox(box,offset?=0) -Read data from box, and convert into lua value. -Boundary will checked - -## :intoBox(luavalue,box,offset?=0) -Convert lua value, and write into box -Boundary will checked - -## :fromRef(ref,offset?=0) -포인터가 가르키는 곳의 데이터를 읽어서 루아의 데이터로 변환합니다. - -## :intoRef(luavalue,ref,offset?=0) -포인터가 가르키는 곳에 데이터를 작성합니다. - -## :fromRaw(raw,offset?=0) - - -## :ptr() -> Ptr -Get pointer type - -## :arr(len) -> Arr -Get array type - -## .size - -Byte size of this type. you can initialize box with - -## :cast(box,type) TODO - -# Ptr -Pointer type of some type. - -Ptr is not data converter. It only works for type hint of `struct` or `fn` - -## .inner -Inner type - -## .size -Size of `usize` - -:ptr() -:arr() - -## Arr - -## Void - -`ffi.void` - -Zero sized type. - -## Fn -Prototype type of some function. converts lua function into native function pointer or native function pointer into lua function. - -`ffi.fn({ type }, type) -> fn` - -:toLua( ref ) -> luafunction -:toBox( luafunction ) -> ref - -> TODO: rust, and another ABI support diff --git a/crates/lune-std-ffi/src/c/c_struct.rs b/crates/lune-std-ffi/src/c/c_struct.rs index 168d7d20..16e2f8f3 100644 --- a/crates/lune-std-ffi/src/c/c_struct.rs +++ b/crates/lune-std-ffi/src/c/c_struct.rs @@ -113,16 +113,6 @@ impl CStruct { 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)); - - // Simply pass in the locked table used when first creating this object. - // By strongly referencing the table, the types inside do not disappear - // and the user can read the contents as needed. (good recycling!) - fields.add_field_function_get("inner", |lua, this: LuaAnyUserData| { - let table: LuaValue = get_association(lua, CSTRUCT_INNER, this)? - // It shouldn't happen. - .ok_or(LuaError::external("inner field not found"))?; - Ok(table) - }); } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { @@ -130,6 +120,18 @@ impl LuaUserData for CStruct { let offset = this.offset(index)?; Ok(offset) }); + // 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)? + .ok_or(LuaError::external("Field table not found"))? + { + let value: LuaValue = t.get(field + 1)?; + Ok(value) + } else { + Err(LuaError::external("Failed to read field table")) + } + }); methods.add_function("ptr", |lua, this: LuaAnyUserData| { let pointer = CPtr::from_lua_userdata(lua, &this)?; Ok(pointer) diff --git a/crates/lune-std-ffi/src/c/c_type.rs b/crates/lune-std-ffi/src/c/c_type.rs index 5300bead..17c61717 100644 --- a/crates/lune-std-ffi/src/c/c_type.rs +++ b/crates/lune-std-ffi/src/c/c_type.rs @@ -1,28 +1,19 @@ #![allow(clippy::cargo_common_metadata)] -use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; -use num::cast::AsPrimitive; use std::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; -use super::c_arr::CArr; -use super::c_helper::get_ensured_size; -use super::c_ptr::CPtr; -use crate::ffi::ffi_association::set_association; -use crate::ffi::ffi_helper::get_ptr_from_userdata; - -pub struct CType { - // for ffi_ptrarray_to_raw? - // libffi_cif: Cif, - libffi_type: Type, - size: usize, - name: Option<&'static str>, - signedness: bool, - _phantom: PhantomData, -} +use super::{ + association_names::CTYPE_STATIC, c_arr::CArr, c_helper::get_ensured_size, c_ptr::CPtr, +}; +use crate::ffi::{ + ffi_association::set_association, + ffi_native::{NativeCast, NativeConvert}, +}; // We can't get a CType through mlua, something like // .is::> will fail. @@ -35,28 +26,34 @@ pub struct CTypeStatic { pub name: Option<&'static str>, pub signedness: bool, } - impl CTypeStatic { - fn new(ctype: &CType) -> Self { + fn new(ctype: &CType, signedness: bool) -> Self { Self { libffi_type: ctype.libffi_type.clone(), size: ctype.size, name: ctype.name, - signedness: ctype.signedness, + signedness, } } } impl LuaUserData for CTypeStatic {} +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: CTypeConvert + CTypeCast, + Self: NativeConvert + CTypeCast + CTypeSignedness, { pub fn new_with_libffi_type<'lua>( lua: &'lua Lua, libffi_type: Type, - signedness: bool, name: Option<&'static str>, ) -> LuaResult> { // let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void()); @@ -67,10 +64,10 @@ where libffi_type, size, name, - signedness, _phantom: PhantomData, }; - let userdata_static = lua.create_any_userdata(CTypeStatic::new::(&ctype))?; + let userdata_static = + lua.create_any_userdata(CTypeStatic::new::(&ctype, ctype.get_signedness()))?; let userdata = lua.create_userdata(ctype)?; set_association(lua, CTYPE_STATIC, &userdata, &userdata_static)?; @@ -85,57 +82,13 @@ where } } } +impl NativeCast for CType {} -// Handle C data, provide type conversion between luavalue and c-type -pub trait CTypeConvert { - // Convert luavalue into data, then write into ptr - fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()>; - - // Read data from ptr, then convert into luavalue - fn ptr_into_luavalue(lua: &Lua, ptr: *mut ()) -> LuaResult; - - // Read data from userdata (such as box or ref) and convert it into luavalue - unsafe fn read_userdata<'lua>( - &self, - lua: &'lua Lua, - userdata: LuaAnyUserData<'lua>, - offset: Option, - ) -> LuaResult> { - let ptr = unsafe { get_ptr_from_userdata(&userdata, offset)? }; - let value = Self::ptr_into_luavalue(lua, ptr)?; - Ok(value) - } - - // Write data into userdata (such as box or ref) from luavalue - unsafe fn write_userdata<'lua>( - &self, - luavalue: LuaValue<'lua>, - userdata: LuaAnyUserData<'lua>, - offset: Option, - ) -> LuaResult<()> { - let ptr = unsafe { get_ptr_from_userdata(&userdata, offset)? }; - Self::luavalue_into_ptr(luavalue, ptr)?; - Ok(()) - } -} - -pub trait CTypeCast { - // 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::() }; - - unsafe { - *into_ptr = (*from_ptr).as_(); - } - - Ok(()) - } - +// Cast native data +pub trait CTypeCast +where + Self: NativeCast, +{ fn try_cast_num( &self, ctype: &LuaAnyUserData, @@ -154,7 +107,6 @@ pub trait CTypeCast { } } - #[allow(unused_variables)] fn cast( &self, from_ctype: &LuaAnyUserData, @@ -179,31 +131,52 @@ pub trait CTypeCast { } } +pub trait CTypeSignedness { + fn get_signedness(&self) -> bool { + true + } +} + impl LuaUserData for CType where T: 'static, - Self: CTypeConvert + CTypeCast, + Self: CTypeCast + CTypeSignedness + NativeCast + NativeConvert, { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { fields.add_field_method_get("size", |_, this| Ok(this.size)); fields.add_meta_field(LuaMetaMethod::Type, "CType"); - fields.add_field_method_get("signedness", |_, this| Ok(this.signedness)); + 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) }); - methods.add_method( + methods.add_function( "from", - |lua, ctype, (userdata, offset): (LuaAnyUserData, Option)| unsafe { - ctype.read_userdata(lua, userdata, offset) + |lua, + (ctype, userdata, offset): ( + LuaAnyUserData, + LuaAnyUserData, + Option, + )| unsafe { + ctype + .borrow::>()? + .read_userdata(&ctype, lua, &userdata, offset) }, ); - methods.add_method( + methods.add_function( "into", - |_, ctype, (value, userdata, offset): (LuaValue, LuaAnyUserData, Option)| unsafe { - ctype.write_userdata(value, userdata, offset) + |lua, + (ctype, value, userdata, offset): ( + LuaAnyUserData, + LuaValue, + LuaAnyUserData, + Option, + )| unsafe { + ctype + .borrow::>()? + .write_userdata(&ctype, lua, value, userdata, offset) }, ); methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| { diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index 35ba0638..7b510d78 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -1,14 +1,15 @@ -pub(super) mod c_arr; -pub(super) mod c_fn; -pub(super) mod c_helper; -pub(super) mod c_ptr; -pub(super) mod c_string; -pub(super) mod c_struct; -pub(super) mod c_type; -pub(super) mod types; - +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/c_char.rs b/crates/lune-std-ffi/src/c/types/c_char.rs deleted file mode 100644 index adaec6a9..00000000 --- a/crates/lune-std-ffi/src/c/types/c_char.rs +++ /dev/null @@ -1,65 +0,0 @@ -use core::ffi::*; - -use libffi::middle::Type; -use mlua::prelude::*; -use num::cast::AsPrimitive; - -use super::super::c_type::{CType, CTypeCast, CTypeConvert}; -use crate::ffi::ffi_platform::CHAR_IS_SIGNED; - -impl CTypeConvert for CType { - fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()> { - let value: c_char = match value { - LuaValue::Integer(t) => t.as_(), - LuaValue::String(t) => t.as_bytes().first().map_or(0, u8::to_owned).as_(), - _ => { - return Err(LuaError::external(format!( - "Argument LuaValue expected a Integer or String, got {}", - value.type_name() - ))) - } - }; - unsafe { - *(ptr.cast::()) = value; - } - Ok(()) - } - fn ptr_into_luavalue(lua: &Lua, ptr: *mut ()) -> LuaResult { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; - Ok(value) - } -} - -impl CTypeCast for CType { - fn cast( - &self, - from_ctype: &LuaAnyUserData, - into_ctype: &LuaAnyUserData, - from: &LuaAnyUserData, - into: &LuaAnyUserData, - ) -> 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)?) - .ok_or_else(|| self.cast_failed_with(from_ctype, into_ctype)) - } -} - -pub fn get_export(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { - Ok(( - "char", - CType::::new_with_libffi_type( - lua, - if CHAR_IS_SIGNED { - Type::c_schar() - } else { - Type::c_uchar() - }, - CHAR_IS_SIGNED, - Some("char"), - )?, - )) -} diff --git a/crates/lune-std-ffi/src/c/types/c_double.rs b/crates/lune-std-ffi/src/c/types/c_double.rs deleted file mode 100644 index 9f63f992..00000000 --- a/crates/lune-std-ffi/src/c/types/c_double.rs +++ /dev/null @@ -1,59 +0,0 @@ -use core::ffi::*; - -use libffi::middle::Type; -use mlua::prelude::*; - -use super::super::c_type::{CType, CTypeCast, CTypeConvert}; -use num::cast::AsPrimitive; - -impl CTypeConvert for CType { - fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()> { - let value: c_double = match value { - LuaValue::Integer(t) => t.as_(), - LuaValue::Number(t) => t.as_(), - LuaValue::String(t) => t - .to_string_lossy() - .parse::() - .map_err(LuaError::external)?, - _ => { - return Err(LuaError::external(format!( - "Argument LuaValue expected a Integer, Number or String, got {}", - value.type_name() - ))) - } - }; - unsafe { - *(ptr.cast::()) = value; - } - Ok(()) - } - fn ptr_into_luavalue(lua: &Lua, ptr: *mut ()) -> LuaResult { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; - Ok(value) - } -} - -impl CTypeCast for CType { - fn cast( - &self, - from_ctype: &LuaAnyUserData, - into_ctype: &LuaAnyUserData, - from: &LuaAnyUserData, - into: &LuaAnyUserData, - ) -> 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)?) - .ok_or_else(|| self.cast_failed_with(from_ctype, into_ctype)) - } -} - -pub fn get_export(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { - Ok(( - "double", - CType::::new_with_libffi_type(lua, Type::f64(), true, Some("double"))?, - )) -} diff --git a/crates/lune-std-ffi/src/c/types/c_float.rs b/crates/lune-std-ffi/src/c/types/c_float.rs deleted file mode 100644 index c02fc80c..00000000 --- a/crates/lune-std-ffi/src/c/types/c_float.rs +++ /dev/null @@ -1,59 +0,0 @@ -use core::ffi::*; - -use libffi::middle::Type; -use mlua::prelude::*; - -use super::super::c_type::{CType, CTypeCast, CTypeConvert}; -use num::cast::AsPrimitive; - -impl CTypeConvert for CType { - fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()> { - let value: c_float = match value { - LuaValue::Integer(t) => t.as_(), - LuaValue::Number(t) => t.as_(), - LuaValue::String(t) => t - .to_string_lossy() - .parse::() - .map_err(LuaError::external)?, - _ => { - return Err(LuaError::external(format!( - "Argument LuaValue expected a Integer, Number or String, got {}", - value.type_name() - ))) - } - }; - unsafe { - *(ptr.cast::()) = value; - } - Ok(()) - } - fn ptr_into_luavalue(lua: &Lua, ptr: *mut ()) -> LuaResult { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; - Ok(value) - } -} - -impl CTypeCast for CType { - fn cast( - &self, - from_ctype: &LuaAnyUserData, - into_ctype: &LuaAnyUserData, - from: &LuaAnyUserData, - into: &LuaAnyUserData, - ) -> 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)?) - .ok_or_else(|| self.cast_failed_with(from_ctype, into_ctype)) - } -} - -pub fn get_export(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { - Ok(( - "float", - CType::::new_with_libffi_type(lua, Type::f32(), true, Some("float"))?, - )) -} diff --git a/crates/lune-std-ffi/src/c/types/c_int.rs b/crates/lune-std-ffi/src/c/types/c_int.rs deleted file mode 100644 index ac3551d8..00000000 --- a/crates/lune-std-ffi/src/c/types/c_int.rs +++ /dev/null @@ -1,66 +0,0 @@ -use core::ffi::*; - -use libffi::middle::Type; -use mlua::prelude::*; -use num::cast::AsPrimitive; - -use super::super::c_type::{CType, CTypeCast, CTypeConvert}; - -impl CTypeConvert for CType { - fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()> { - let value: c_int = match value { - LuaValue::Integer(t) => t.as_(), - LuaValue::Number(t) => t.as_(), - LuaValue::String(t) => t - .to_string_lossy() - .parse::() - .map_err(LuaError::external)?, - _ => { - return Err(LuaError::external(format!( - "Argument LuaValue expected a Integer, Number or String, got {}", - value.type_name() - ))) - } - }; - unsafe { - *(ptr.cast::()) = value; - } - Ok(()) - } - fn ptr_into_luavalue(lua: &Lua, ptr: *mut ()) -> LuaResult { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; - Ok(value) - } -} - -impl CType {} - -impl CTypeCast for CType { - fn cast( - &self, - from_ctype: &LuaAnyUserData, - into_ctype: &LuaAnyUserData, - from: &LuaAnyUserData, - into: &LuaAnyUserData, - ) -> 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)?) - .ok_or_else(|| self.cast_failed_with(from_ctype, into_ctype)) - } -} - -pub fn get_export(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { - Ok(( - "int", - CType::::new_with_libffi_type( - lua, - Type::c_int(), - c_int::MIN.unsigned_abs() != 0, - Some("int"), - )?, - )) -} diff --git a/crates/lune-std-ffi/src/c/types/c_long.rs b/crates/lune-std-ffi/src/c/types/c_long.rs deleted file mode 100644 index 60691c77..00000000 --- a/crates/lune-std-ffi/src/c/types/c_long.rs +++ /dev/null @@ -1,59 +0,0 @@ -use core::ffi::*; - -use libffi::middle::Type; -use mlua::prelude::*; - -use super::super::c_type::{CType, CTypeCast, CTypeConvert}; -use num::cast::AsPrimitive; - -impl CTypeConvert for CType { - fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()> { - let value: c_long = match value { - LuaValue::Integer(t) => t.as_(), - LuaValue::Number(t) => t.as_(), - LuaValue::String(t) => t - .to_string_lossy() - .parse::() - .map_err(LuaError::external)?, - _ => { - return Err(LuaError::external(format!( - "Argument LuaValue expected a Integer, Number or String, got {}", - value.type_name() - ))) - } - }; - unsafe { - *(ptr.cast::()) = value; - } - Ok(()) - } - fn ptr_into_luavalue(lua: &Lua, ptr: *mut ()) -> LuaResult { - let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; - Ok(value) - } -} - -impl CTypeCast for CType { - fn cast( - &self, - from_ctype: &LuaAnyUserData, - into_ctype: &LuaAnyUserData, - from: &LuaAnyUserData, - into: &LuaAnyUserData, - ) -> 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)?) - .ok_or_else(|| self.cast_failed_with(from_ctype, into_ctype)) - } -} - -pub fn get_export(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { - Ok(( - "long", - CType::::new_with_libffi_type(lua, Type::c_long(), true, Some("long"))?, - )) -} diff --git a/crates/lune-std-ffi/src/c/types/f32.rs b/crates/lune-std-ffi/src/c/types/f32.rs new file mode 100644 index 00000000..79baa3e5 --- /dev/null +++ b/crates/lune-std-ffi/src/c/types/f32.rs @@ -0,0 +1,57 @@ +use libffi::middle::Type; +use mlua::prelude::*; +use num::cast::AsPrimitive; + +use super::super::c_type::{CType, CTypeSignedness}; +use crate::ffi::ffi_native::NativeConvert; + +impl CTypeSignedness for CType { + fn get_signedness(&self) -> bool { + true + } +} + +impl NativeConvert for CType { + fn luavalue_into_ptr<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + _lua: &'lua Lua, + value: LuaValue<'lua>, + ptr: *mut (), + ) -> LuaResult<()> { + let value: f32 = match value { + LuaValue::Integer(t) => t.as_(), + LuaValue::Number(t) => t.as_(), + LuaValue::String(t) => t + .to_string_lossy() + .parse::() + .map_err(LuaError::external)?, + _ => { + return Err(LuaError::external(format!( + "Argument LuaValue expected a Integer, Number or String, got {}", + value.type_name() + ))) + } + }; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + } + fn ptr_into_luavalue<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + lua: &'lua Lua, + ptr: *mut (), + ) -> LuaResult> { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + } +} + +pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { + Ok(( + "f32", + CType::::new_with_libffi_type(lua, Type::f32(), Some("f32"))?, + )) +} diff --git a/crates/lune-std-ffi/src/c/types/f64.rs b/crates/lune-std-ffi/src/c/types/f64.rs new file mode 100644 index 00000000..7dec899c --- /dev/null +++ b/crates/lune-std-ffi/src/c/types/f64.rs @@ -0,0 +1,57 @@ +use libffi::middle::Type; +use mlua::prelude::*; +use num::cast::AsPrimitive; + +use super::super::c_type::{CType, CTypeSignedness}; +use crate::ffi::ffi_native::NativeConvert; + +impl CTypeSignedness for CType { + fn get_signedness(&self) -> bool { + true + } +} + +impl NativeConvert for CType { + fn luavalue_into_ptr<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + _lua: &'lua Lua, + value: LuaValue<'lua>, + ptr: *mut (), + ) -> LuaResult<()> { + let value: f64 = match value { + LuaValue::Integer(t) => t.as_(), + LuaValue::Number(t) => t.as_(), + LuaValue::String(t) => t + .to_string_lossy() + .parse::() + .map_err(LuaError::external)?, + _ => { + return Err(LuaError::external(format!( + "Argument LuaValue expected a Integer, Number or String, got {}", + value.type_name() + ))) + } + }; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + } + fn ptr_into_luavalue<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + lua: &'lua Lua, + ptr: *mut (), + ) -> LuaResult> { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + } +} + +pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { + Ok(( + "f64", + CType::::new_with_libffi_type(lua, Type::f64(), Some("f64"))?, + )) +} diff --git a/crates/lune-std-ffi/src/c/types/i128.rs b/crates/lune-std-ffi/src/c/types/i128.rs new file mode 100644 index 00000000..8f75d9ca --- /dev/null +++ b/crates/lune-std-ffi/src/c/types/i128.rs @@ -0,0 +1,61 @@ +use libffi::middle::Type; +use mlua::prelude::*; +use num::cast::AsPrimitive; + +use super::super::c_type::{CType, CTypeSignedness}; +use crate::ffi::ffi_native::NativeConvert; + +impl CTypeSignedness for CType { + fn get_signedness(&self) -> bool { + true + } +} + +impl NativeConvert for CType { + fn luavalue_into_ptr<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + _lua: &'lua Lua, + value: LuaValue<'lua>, + ptr: *mut (), + ) -> LuaResult<()> { + let value: i128 = match value { + LuaValue::Integer(t) => t.as_(), + LuaValue::Number(t) => t.as_(), + LuaValue::String(t) => t + .to_string_lossy() + .parse::() + .map_err(LuaError::external)?, + _ => { + return Err(LuaError::external(format!( + "Argument LuaValue expected a Integer, Number or String, got {}", + value.type_name() + ))) + } + }; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + } + fn ptr_into_luavalue<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + lua: &'lua Lua, + ptr: *mut (), + ) -> LuaResult> { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + } +} + +pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { + Ok(( + "i128", + CType::::new_with_libffi_type( + lua, + Type::structure(vec![Type::u64(), Type::u64()]), + Some("i128"), + )?, + )) +} diff --git a/crates/lune-std-ffi/src/c/types/i16.rs b/crates/lune-std-ffi/src/c/types/i16.rs new file mode 100644 index 00000000..e9a33ccc --- /dev/null +++ b/crates/lune-std-ffi/src/c/types/i16.rs @@ -0,0 +1,57 @@ +use libffi::middle::Type; +use mlua::prelude::*; +use num::cast::AsPrimitive; + +use super::super::c_type::{CType, CTypeSignedness}; +use crate::ffi::ffi_native::NativeConvert; + +impl CTypeSignedness for CType { + fn get_signedness(&self) -> bool { + true + } +} + +impl NativeConvert for CType { + fn luavalue_into_ptr<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + _lua: &'lua Lua, + value: LuaValue<'lua>, + ptr: *mut (), + ) -> LuaResult<()> { + let value: i16 = match value { + LuaValue::Integer(t) => t.as_(), + LuaValue::Number(t) => t.as_(), + LuaValue::String(t) => t + .to_string_lossy() + .parse::() + .map_err(LuaError::external)?, + _ => { + return Err(LuaError::external(format!( + "Argument LuaValue expected a Integer, Number or String, got {}", + value.type_name() + ))) + } + }; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + } + fn ptr_into_luavalue<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + lua: &'lua Lua, + ptr: *mut (), + ) -> LuaResult> { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + } +} + +pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { + Ok(( + "i16", + CType::::new_with_libffi_type(lua, Type::i16(), Some("f32"))?, + )) +} diff --git a/crates/lune-std-ffi/src/c/types/i32.rs b/crates/lune-std-ffi/src/c/types/i32.rs new file mode 100644 index 00000000..6478370f --- /dev/null +++ b/crates/lune-std-ffi/src/c/types/i32.rs @@ -0,0 +1,57 @@ +use libffi::middle::Type; +use mlua::prelude::*; +use num::cast::AsPrimitive; + +use super::super::c_type::{CType, CTypeSignedness}; +use crate::ffi::ffi_native::NativeConvert; + +impl CTypeSignedness for CType { + fn get_signedness(&self) -> bool { + true + } +} + +impl NativeConvert for CType { + fn luavalue_into_ptr<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + _lua: &'lua Lua, + value: LuaValue<'lua>, + ptr: *mut (), + ) -> LuaResult<()> { + let value: i32 = match value { + LuaValue::Integer(t) => t.as_(), + LuaValue::Number(t) => t.as_(), + LuaValue::String(t) => t + .to_string_lossy() + .parse::() + .map_err(LuaError::external)?, + _ => { + return Err(LuaError::external(format!( + "Argument LuaValue expected a Integer, Number or String, got {}", + value.type_name() + ))) + } + }; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + } + fn ptr_into_luavalue<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + lua: &'lua Lua, + ptr: *mut (), + ) -> LuaResult> { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + } +} + +pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { + Ok(( + "i32", + CType::::new_with_libffi_type(lua, Type::i32(), Some("i32"))?, + )) +} diff --git a/crates/lune-std-ffi/src/c/types/i64.rs b/crates/lune-std-ffi/src/c/types/i64.rs new file mode 100644 index 00000000..ff1e2285 --- /dev/null +++ b/crates/lune-std-ffi/src/c/types/i64.rs @@ -0,0 +1,57 @@ +use libffi::middle::Type; +use mlua::prelude::*; +use num::cast::AsPrimitive; + +use super::super::c_type::{CType, CTypeSignedness}; +use crate::ffi::ffi_native::NativeConvert; + +impl CTypeSignedness for CType { + fn get_signedness(&self) -> bool { + true + } +} + +impl NativeConvert for CType { + fn luavalue_into_ptr<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + _lua: &'lua Lua, + value: LuaValue<'lua>, + ptr: *mut (), + ) -> LuaResult<()> { + let value: i64 = match value { + LuaValue::Integer(t) => t.as_(), + LuaValue::Number(t) => t.as_(), + LuaValue::String(t) => t + .to_string_lossy() + .parse::() + .map_err(LuaError::external)?, + _ => { + return Err(LuaError::external(format!( + "Argument LuaValue expected a Integer, Number or String, got {}", + value.type_name() + ))) + } + }; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + } + fn ptr_into_luavalue<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + lua: &'lua Lua, + ptr: *mut (), + ) -> LuaResult> { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + } +} + +pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { + Ok(( + "i64", + CType::::new_with_libffi_type(lua, Type::i64(), Some("i64"))?, + )) +} diff --git a/crates/lune-std-ffi/src/c/types/i8.rs b/crates/lune-std-ffi/src/c/types/i8.rs new file mode 100644 index 00000000..0c8cc287 --- /dev/null +++ b/crates/lune-std-ffi/src/c/types/i8.rs @@ -0,0 +1,53 @@ +use libffi::middle::Type; +use mlua::prelude::*; +use num::cast::AsPrimitive; + +use super::super::c_type::{CType, CTypeSignedness}; +use crate::ffi::ffi_native::NativeConvert; + +impl CTypeSignedness for CType { + fn get_signedness(&self) -> bool { + true + } +} + +impl NativeConvert for CType { + fn luavalue_into_ptr<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + _lua: &'lua Lua, + value: LuaValue<'lua>, + ptr: *mut (), + ) -> LuaResult<()> { + let value: i8 = match value { + LuaValue::Integer(t) => t.as_(), + LuaValue::String(t) => t.as_bytes().first().map_or(0, u8::to_owned).as_(), + _ => { + return Err(LuaError::external(format!( + "Argument LuaValue expected a Integer or String, got {}", + value.type_name() + ))) + } + }; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + } + fn ptr_into_luavalue<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + lua: &'lua Lua, + ptr: *mut (), + ) -> LuaResult> { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + } +} + +pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { + Ok(( + "i8", + CType::::new_with_libffi_type(lua, Type::i8(), Some("i8"))?, + )) +} diff --git a/crates/lune-std-ffi/src/c/types/isize.rs b/crates/lune-std-ffi/src/c/types/isize.rs new file mode 100644 index 00000000..634d7bf3 --- /dev/null +++ b/crates/lune-std-ffi/src/c/types/isize.rs @@ -0,0 +1,57 @@ +use libffi::middle::Type; +use mlua::prelude::*; +use num::cast::AsPrimitive; + +use super::super::c_type::{CType, CTypeSignedness}; +use crate::ffi::ffi_native::NativeConvert; + +impl CTypeSignedness for CType { + fn get_signedness(&self) -> bool { + true + } +} + +impl NativeConvert for CType { + fn luavalue_into_ptr<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + _lua: &'lua Lua, + value: LuaValue<'lua>, + ptr: *mut (), + ) -> LuaResult<()> { + let value: isize = match value { + LuaValue::Integer(t) => t.as_(), + LuaValue::Number(t) => t.as_(), + LuaValue::String(t) => t + .to_string_lossy() + .parse::() + .map_err(LuaError::external)?, + _ => { + return Err(LuaError::external(format!( + "Argument LuaValue expected a Integer, Number or String, got {}", + value.type_name() + ))) + } + }; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + } + fn ptr_into_luavalue<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + lua: &'lua Lua, + ptr: *mut (), + ) -> LuaResult> { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + } +} + +pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { + Ok(( + "isize", + CType::::new_with_libffi_type(lua, Type::isize(), Some("isize"))?, + )) +} diff --git a/crates/lune-std-ffi/src/c/types/mod.rs b/crates/lune-std-ffi/src/c/types/mod.rs index af90e573..a059967d 100644 --- a/crates/lune-std-ffi/src/c/types/mod.rs +++ b/crates/lune-std-ffi/src/c/types/mod.rs @@ -1,18 +1,156 @@ -mod c_char; -mod c_double; -mod c_float; -mod c_int; -mod c_long; +use core::ffi::*; +use std::any::TypeId; +use libffi::middle::Type; use mlua::prelude::*; +use num::cast::AsPrimitive; + +use super::c_type::CType; +use super::c_type::CTypeCast; + +pub mod f32; +pub mod f64; +pub mod i128; +pub mod i16; +pub mod i32; +pub mod i64; +pub mod i8; +pub mod isize; +pub mod u128; +pub mod u16; +pub mod u32; +pub mod u64; +pub mod u8; +pub mod usize; + +impl CTypeCast for CType +where + T: AsPrimitive + + AsPrimitive + + AsPrimitive + + AsPrimitive + + AsPrimitive + + AsPrimitive + + AsPrimitive + + AsPrimitive + + AsPrimitive + + AsPrimitive + + AsPrimitive + + AsPrimitive + + AsPrimitive + + AsPrimitive, +{ + fn cast( + &self, + from_ctype: &LuaAnyUserData, + into_ctype: &LuaAnyUserData, + from: &LuaAnyUserData, + into: &LuaAnyUserData, + ) -> 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)) + } +} + +// export all default c-types +pub fn create_all_c_types(lua: &Lua) -> LuaResult> { + Ok(vec![ + ( + "char", + CType::::new_with_libffi_type( + lua, + if TypeId::of::() == TypeId::of::() { + Type::c_uchar() + } else { + Type::c_schar() + }, + Some("longlong"), + )?, + ), + ( + "uchar", + CType::::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"), + )?, + ), + ( + "float", + CType::::new_with_libffi_type(lua, Type::f32(), Some("float"))?, + ), + ( + "double", + CType::::new_with_libffi_type(lua, Type::f64(), Some("double"))?, + ), + ]) +} // export all default c-types pub fn create_all_types(lua: &Lua) -> LuaResult> { Ok(vec![ - c_char::get_export(lua)?, - c_double::get_export(lua)?, - c_float::get_export(lua)?, - c_int::get_export(lua)?, - c_long::get_export(lua)?, + self::u8::create_type(lua)?, + self::u16::create_type(lua)?, + self::u32::create_type(lua)?, + self::u64::create_type(lua)?, + self::u128::create_type(lua)?, + self::i8::create_type(lua)?, + self::i16::create_type(lua)?, + self::i32::create_type(lua)?, + self::i64::create_type(lua)?, + self::i128::create_type(lua)?, + self::f64::create_type(lua)?, + self::f32::create_type(lua)?, + self::usize::create_type(lua)?, + self::isize::create_type(lua)?, ]) } diff --git a/crates/lune-std-ffi/src/c/types/u128.rs b/crates/lune-std-ffi/src/c/types/u128.rs new file mode 100644 index 00000000..80ff6215 --- /dev/null +++ b/crates/lune-std-ffi/src/c/types/u128.rs @@ -0,0 +1,61 @@ +use libffi::middle::Type; +use mlua::prelude::*; +use num::cast::AsPrimitive; + +use super::super::c_type::{CType, CTypeSignedness}; +use crate::ffi::ffi_native::NativeConvert; + +impl CTypeSignedness for CType { + fn get_signedness(&self) -> bool { + false + } +} + +impl NativeConvert for CType { + fn luavalue_into_ptr<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + _lua: &'lua Lua, + value: LuaValue<'lua>, + ptr: *mut (), + ) -> LuaResult<()> { + let value: u128 = match value { + LuaValue::Integer(t) => t.as_(), + LuaValue::Number(t) => t.as_(), + LuaValue::String(t) => t + .to_string_lossy() + .parse::() + .map_err(LuaError::external)?, + _ => { + return Err(LuaError::external(format!( + "Argument LuaValue expected a Integer, Number or String, got {}", + value.type_name() + ))) + } + }; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + } + fn ptr_into_luavalue<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + lua: &'lua Lua, + ptr: *mut (), + ) -> LuaResult> { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + } +} + +pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { + Ok(( + "u128", + CType::::new_with_libffi_type( + lua, + Type::structure(vec![Type::u64(), Type::u64()]), + Some("u128"), + )?, + )) +} diff --git a/crates/lune-std-ffi/src/c/types/u16.rs b/crates/lune-std-ffi/src/c/types/u16.rs new file mode 100644 index 00000000..b2a172b8 --- /dev/null +++ b/crates/lune-std-ffi/src/c/types/u16.rs @@ -0,0 +1,58 @@ +use libffi::middle::Type; +use mlua::prelude::*; +use num::cast::AsPrimitive; + +use super::super::c_type::{CType, CTypeSignedness}; +use crate::ffi::ffi_native::NativeConvert; + +impl CTypeSignedness for CType { + fn get_signedness(&self) -> bool { + false + } +} + +impl NativeConvert for CType { + // Convert luavalue into data, then write into ptr + fn luavalue_into_ptr<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + _lua: &'lua Lua, + value: LuaValue<'lua>, + ptr: *mut (), + ) -> LuaResult<()> { + let value: u16 = match value { + LuaValue::Integer(t) => t.as_(), + LuaValue::Number(t) => t.as_(), + LuaValue::String(t) => t + .to_string_lossy() + .parse::() + .map_err(LuaError::external)?, + _ => { + return Err(LuaError::external(format!( + "Argument LuaValue expected a Integer, Number or String, got {}", + value.type_name() + ))) + } + }; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + } + fn ptr_into_luavalue<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + lua: &'lua Lua, + ptr: *mut (), + ) -> LuaResult> { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + } +} + +pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { + Ok(( + "u16", + CType::::new_with_libffi_type(lua, Type::u16(), Some("u16"))?, + )) +} diff --git a/crates/lune-std-ffi/src/c/types/u32.rs b/crates/lune-std-ffi/src/c/types/u32.rs new file mode 100644 index 00000000..3f494c22 --- /dev/null +++ b/crates/lune-std-ffi/src/c/types/u32.rs @@ -0,0 +1,57 @@ +use libffi::middle::Type; +use mlua::prelude::*; +use num::cast::AsPrimitive; + +use super::super::c_type::{CType, CTypeSignedness}; +use crate::ffi::ffi_native::NativeConvert; + +impl CTypeSignedness for CType { + fn get_signedness(&self) -> bool { + false + } +} + +impl NativeConvert for CType { + fn luavalue_into_ptr<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + _lua: &'lua Lua, + value: LuaValue<'lua>, + ptr: *mut (), + ) -> LuaResult<()> { + let value: u32 = match value { + LuaValue::Integer(t) => t.as_(), + LuaValue::Number(t) => t.as_(), + LuaValue::String(t) => t + .to_string_lossy() + .parse::() + .map_err(LuaError::external)?, + _ => { + return Err(LuaError::external(format!( + "Argument LuaValue expected a Integer, Number or String, got {}", + value.type_name() + ))) + } + }; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + } + fn ptr_into_luavalue<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + lua: &'lua Lua, + ptr: *mut (), + ) -> LuaResult> { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + } +} + +pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { + Ok(( + "u32", + CType::::new_with_libffi_type(lua, Type::u32(), Some("u32"))?, + )) +} diff --git a/crates/lune-std-ffi/src/c/types/u64.rs b/crates/lune-std-ffi/src/c/types/u64.rs new file mode 100644 index 00000000..13cc41ae --- /dev/null +++ b/crates/lune-std-ffi/src/c/types/u64.rs @@ -0,0 +1,57 @@ +use libffi::middle::Type; +use mlua::prelude::*; +use num::cast::AsPrimitive; + +use super::super::c_type::{CType, CTypeSignedness}; +use crate::ffi::ffi_native::NativeConvert; + +impl CTypeSignedness for CType { + fn get_signedness(&self) -> bool { + false + } +} + +impl NativeConvert for CType { + fn luavalue_into_ptr<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + _lua: &'lua Lua, + value: LuaValue<'lua>, + ptr: *mut (), + ) -> LuaResult<()> { + let value: u64 = match value { + LuaValue::Integer(t) => t.as_(), + LuaValue::Number(t) => t.as_(), + LuaValue::String(t) => t + .to_string_lossy() + .parse::() + .map_err(LuaError::external)?, + _ => { + return Err(LuaError::external(format!( + "Argument LuaValue expected a Integer, Number or String, got {}", + value.type_name() + ))) + } + }; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + } + fn ptr_into_luavalue<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + lua: &'lua Lua, + ptr: *mut (), + ) -> LuaResult> { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + } +} + +pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { + Ok(( + "u64", + CType::::new_with_libffi_type(lua, Type::u64(), Some("u64"))?, + )) +} diff --git a/crates/lune-std-ffi/src/c/types/u8.rs b/crates/lune-std-ffi/src/c/types/u8.rs new file mode 100644 index 00000000..65c81d6d --- /dev/null +++ b/crates/lune-std-ffi/src/c/types/u8.rs @@ -0,0 +1,56 @@ +use libffi::middle::Type; +use mlua::prelude::*; +use num::cast::AsPrimitive; + +use super::super::c_type::{CType, CTypeSignedness}; +use crate::ffi::ffi_native::NativeConvert; + +impl CTypeSignedness for CType { + fn get_signedness(&self) -> bool { + false + } +} + +impl NativeConvert for CType { + // Convert luavalue into data, then write into ptr + fn luavalue_into_ptr<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + _lua: &'lua Lua, + value: LuaValue<'lua>, + ptr: *mut (), + ) -> LuaResult<()> { + let value: u8 = match value { + LuaValue::Integer(t) => t.as_(), + LuaValue::String(t) => t.as_bytes().first().map_or(0, u8::to_owned).as_(), + _ => { + return Err(LuaError::external(format!( + "Argument LuaValue expected a Integer or String, got {}", + value.type_name() + ))) + } + }; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + } + + // Read data from ptr, then convert into luavalue + fn ptr_into_luavalue<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + lua: &'lua Lua, + ptr: *mut (), + ) -> LuaResult> { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + } +} + +pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { + Ok(( + "u8", + CType::::new_with_libffi_type(lua, Type::u8(), Some("u8"))?, + )) +} diff --git a/crates/lune-std-ffi/src/c/types/usize.rs b/crates/lune-std-ffi/src/c/types/usize.rs new file mode 100644 index 00000000..8b959d65 --- /dev/null +++ b/crates/lune-std-ffi/src/c/types/usize.rs @@ -0,0 +1,57 @@ +use libffi::middle::Type; +use mlua::prelude::*; +use num::cast::AsPrimitive; + +use super::super::c_type::{CType, CTypeSignedness}; +use crate::ffi::ffi_native::NativeConvert; + +impl CTypeSignedness for CType { + fn get_signedness(&self) -> bool { + false + } +} + +impl NativeConvert for CType { + fn luavalue_into_ptr<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + _lua: &'lua Lua, + value: LuaValue<'lua>, + ptr: *mut (), + ) -> LuaResult<()> { + let value: usize = match value { + LuaValue::Integer(t) => t.as_(), + LuaValue::Number(t) => t.as_(), + LuaValue::String(t) => t + .to_string_lossy() + .parse::() + .map_err(LuaError::external)?, + _ => { + return Err(LuaError::external(format!( + "Argument LuaValue expected a Integer, Number or String, got {}", + value.type_name() + ))) + } + }; + unsafe { + *(ptr.cast::()) = value; + } + Ok(()) + } + fn ptr_into_luavalue<'lua>( + &self, + _this: &LuaAnyUserData<'lua>, + lua: &'lua Lua, + ptr: *mut (), + ) -> LuaResult> { + let value = unsafe { (*ptr.cast::()).into_lua(lua)? }; + Ok(value) + } +} + +pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { + Ok(( + "usize", + CType::::new_with_libffi_type(lua, Type::usize(), Some("usize"))?, + )) +} diff --git a/crates/lune-std-ffi/src/ffi/ffi_association.rs b/crates/lune-std-ffi/src/ffi/ffi_association.rs index be242de5..6990938a 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_association.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_association.rs @@ -1,5 +1,7 @@ #![allow(clippy::cargo_common_metadata)] +use mlua::prelude::*; + // This is a small library that helps you set the dependencies of data in Lua. // In FFI, there is often data that is dependent on other data. // However, if you use user_value to inform Lua of the dependency, @@ -22,7 +24,6 @@ // Since the outermost pointer holds the definition for the pointer // type inside it, only the outermost type will be removed on the first gc. // It doesn't matter much. But if there is a cleaner way, we should choose it -use mlua::prelude::*; // Forces 'associated' to persist as long as 'value' is alive. // 'value' can only hold one value. If you want to keep something else, diff --git a/crates/lune-std-ffi/src/ffi/ffi_box.rs b/crates/lune-std-ffi/src/ffi/ffi_box.rs index 9eb892b8..f31a8253 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_box.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_box.rs @@ -1,5 +1,22 @@ #![allow(clippy::cargo_common_metadata)] +use std::boxed::Box; +use std::sync::LazyLock; + +use mlua::prelude::*; + +use super::association_names::REF_INNER; +use super::ffi_association::set_association; +use super::ffi_ref::{FfiRef, FfiRefBounds, FfiRefFlag, FfiRefFlagList}; + +static BOX_REF_FLAGS: LazyLock = LazyLock::new(|| { + FfiRefFlagList::new(&[ + FfiRefFlag::Offsetable, + FfiRefFlag::Readable, + FfiRefFlag::Writable, + ]) +}); + // It is an untyped, sized memory area that Lua can manage. // This area is safe within Lua. Operations have their boundaries checked. // It is basically intended to implement passing a pointed space to the outside. @@ -9,15 +26,6 @@ // rather, it creates more heap space, so it should be used appropriately // where necessary. -use std::boxed::Box; - -use mlua::prelude::*; - -use super::association_names::REF_INNER; -use super::ffi_association::set_association; -use super::ffi_bounds::FfiRefBounds; -use super::ffi_ref::FfiRef; - pub struct FfiBox(Box<[u8]>); impl FfiBox { @@ -73,7 +81,8 @@ impl FfiBox { // To deref a box space is to allow lua to read any space, // which has security issues and is ultimately dangerous. // Therefore, box:ref():deref() is not allowed. - let luaref = lua.create_userdata(FfiRef::new(ptr.cast(), false, Some(bounds)))?; + let luaref = + lua.create_userdata(FfiRef::new(ptr.cast(), (*BOX_REF_FLAGS).clone(), bounds))?; // Makes box alive longer then ref set_association(lua, REF_INNER, &luaref, &this)?; diff --git a/crates/lune-std-ffi/src/ffi/ffi_helper.rs b/crates/lune-std-ffi/src/ffi/ffi_helper.rs index 00605e7f..26be508e 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_helper.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_helper.rs @@ -34,3 +34,23 @@ pub unsafe fn get_ptr_from_userdata( Ok(ptr) } + +#[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/ffi/ffi_lib.rs b/crates/lune-std-ffi/src/ffi/ffi_lib.rs index a4a657f6..6e393da3 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_lib.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_lib.rs @@ -1,10 +1,20 @@ use std::ffi::c_void; +use std::sync::LazyLock; use dlopen2::symbor::Library; use mlua::prelude::*; use super::ffi_association::set_association; -use super::ffi_ref::FfiRef; +use super::ffi_ref::{FfiRef, FfiRefFlag, FfiRefFlagList, UNSIZED_BOUNDS}; + +static LIB_REF_FLAGS: LazyLock = LazyLock::new(|| { + FfiRefFlagList::new(&[ + FfiRefFlag::Offsetable, + FfiRefFlag::Readable, + FfiRefFlag::Dereferenceable, + FfiRefFlag::Function, + ]) +}); pub struct FfiLib(Library); @@ -39,7 +49,11 @@ impl FfiLib { .map_err(|err| LuaError::external(format!("{err}")))? }; - let luasym = lua.create_userdata(FfiRef::new((*sym).cast(), true, None))?; + let luasym = lua.create_userdata(FfiRef::new( + (*sym).cast(), + (*LIB_REF_FLAGS).clone(), + UNSIZED_BOUNDS, + ))?; set_association(lua, SYM_INNER, &luasym, &this)?; diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/cast.rs b/crates/lune-std-ffi/src/ffi/ffi_native/cast.rs new file mode 100644 index 00000000..50bd6519 --- /dev/null +++ b/crates/lune-std-ffi/src/ffi/ffi_native/cast.rs @@ -0,0 +1,24 @@ +#![allow(clippy::cargo_common_metadata)] + +use mlua::prelude::*; +use num::cast::AsPrimitive; + +use super::super::ffi_helper::get_ptr_from_userdata; + +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::() }; + + 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 new file mode 100644 index 00000000..e3b5d195 --- /dev/null +++ b/crates/lune-std-ffi/src/ffi/ffi_native/convert.rs @@ -0,0 +1,52 @@ +#![allow(clippy::cargo_common_metadata)] + +use mlua::prelude::*; + +use super::super::ffi_helper::get_ptr_from_userdata; + +// 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>( + &self, + this: &LuaAnyUserData<'lua>, + lua: &'lua Lua, + value: LuaValue<'lua>, + ptr: *mut (), + ) -> LuaResult<()>; + + // Read data from ptr, then convert into luavalue + fn ptr_into_luavalue<'lua>( + &self, + this: &LuaAnyUserData<'lua>, + lua: &'lua Lua, + ptr: *mut (), + ) -> 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 new file mode 100644 index 00000000..16490b52 --- /dev/null +++ b/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs @@ -0,0 +1,5 @@ +mod cast; +mod convert; + +pub use self::cast::NativeCast; +pub use self::convert::NativeConvert; diff --git a/crates/lune-std-ffi/src/ffi/ffi_platform.rs b/crates/lune-std-ffi/src/ffi/ffi_platform.rs deleted file mode 100644 index 30600d21..00000000 --- a/crates/lune-std-ffi/src/ffi/ffi_platform.rs +++ /dev/null @@ -1,11 +0,0 @@ -use core::ffi::c_char; -use std::vec::Vec; - -pub const CHAR_IS_SIGNED: bool = c_char::MIN as u8 != u8::MIN; - -pub fn get_platform_value() -> Vec<(&'static str, &'static str)> { - vec![( - "char_variant", - if CHAR_IS_SIGNED { "schar" } else { "uchar" }, - )] -} diff --git a/crates/lune-std-ffi/src/ffi/ffi_bounds.rs b/crates/lune-std-ffi/src/ffi/ffi_ref/bounds.rs similarity index 58% rename from crates/lune-std-ffi/src/ffi/ffi_bounds.rs rename to crates/lune-std-ffi/src/ffi/ffi_ref/bounds.rs index 5c73bb32..89c7f218 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_bounds.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/bounds.rs @@ -1,24 +1,36 @@ // Memory range for ref or box data. For boundary checking pub struct FfiRefBounds { // Indicates how much data is above the pointer - pub(crate) high: usize, + pub(crate) above: usize, // Indicates how much data is below the pointer - pub(crate) low: usize, + pub(crate) below: usize, } +pub const UNSIZED_BOUNDS: FfiRefBounds = FfiRefBounds { + above: usize::MAX, + below: usize::MAX, +}; + impl FfiRefBounds { - pub fn new(high: usize, low: usize) -> Self { - Self { high, low } + pub fn new(above: usize, below: usize) -> Self { + Self { above, below } + } + + pub fn is_unsized(&self) -> bool { + self.above == usize::MAX && self.below == usize::MAX } // Check boundary pub fn check(&self, offset: isize) -> bool { + if self.is_unsized() { + return true; + } let sign = offset.signum(); let offset_abs = offset.unsigned_abs(); if sign == -1 { - self.high >= offset_abs + self.above >= offset_abs } else if sign == 1 { - self.low >= offset_abs + self.below >= offset_abs } else { // sign == 0 true @@ -27,13 +39,16 @@ impl FfiRefBounds { // Check boundary pub fn check_sized(&self, offset: isize, size: usize) -> bool { + if self.is_unsized() { + return true; + } let end = offset + (size as isize) - 1; let sign = end.signum(); let end_abs = end.unsigned_abs(); if sign == -1 { - self.high >= end_abs + self.above >= end_abs } else if sign == 1 { - self.low >= end_abs + self.below >= end_abs } else { // sign == 0 true @@ -47,21 +62,24 @@ impl FfiRefBounds { let offset_abs = offset.unsigned_abs(); let high: usize = if sign == -1 { - self.high - offset_abs + self.above - offset_abs } else if sign == 1 { - self.high + offset_abs + self.above + offset_abs } else { - self.high + self.above }; let low: usize = if sign == -1 { - self.low + offset_abs + self.below + offset_abs } else if sign == 1 { - self.low - offset_abs + self.below - offset_abs } else { - self.low + self.below }; - Self { high, low } + Self { + above: high, + below: low, + } } } diff --git a/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs b/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs new file mode 100644 index 00000000..faf969e1 --- /dev/null +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs @@ -0,0 +1,71 @@ +use super::super::ffi_helper::bit_mask::*; + +pub enum FfiRefFlag { + Dereferenceable, + Readable, + Writable, + Offsetable, + Function, +} +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, + } + } +} + +pub struct FfiRefFlagList(u8); +#[allow(unused)] +impl FfiRefFlagList { + pub fn zero() -> Self { + Self(0) + } + pub fn new(flags: &[FfiRefFlag]) -> Self { + let mut value = 0; + for i in flags { + value |= i.value(); + } + Self(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, U8_MASK1) + } + pub fn set_dereferenceable(&mut self, value: bool) { + self.set(value, U8_MASK1); + } + pub fn is_readable(&self) -> bool { + U8_TEST!(self.0, U8_MASK2) + } + pub fn set_readable(&mut self, value: bool) { + self.set(value, U8_MASK2); + } + pub fn is_writable(&self) -> bool { + U8_TEST!(self.0, U8_MASK3) + } + pub fn set_writable(&mut self, value: bool) { + self.set(value, U8_MASK2); + } + pub fn is_offsetable(&self) -> bool { + U8_TEST!(self.0, U8_MASK4) + } + pub fn set_offsetable(&mut self, value: bool) { + self.set(value, U8_MASK2); + } +} +impl Clone for FfiRefFlagList { + fn clone(&self) -> Self { + Self(self.0) + } +} diff --git a/crates/lune-std-ffi/src/ffi/ffi_ref.rs b/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs similarity index 50% rename from crates/lune-std-ffi/src/ffi/ffi_ref.rs rename to crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs index 8700e726..19aa6f46 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs @@ -4,7 +4,12 @@ use mlua::prelude::*; use super::association_names::REF_INNER; use super::ffi_association::{get_association, set_association}; -use super::ffi_bounds::FfiRefBounds; + +mod bounds; +mod flags; + +pub use self::bounds::{FfiRefBounds, UNSIZED_BOUNDS}; +pub use self::flags::{FfiRefFlag, FfiRefFlagList}; // 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 @@ -16,16 +21,16 @@ use super::ffi_bounds::FfiRefBounds; pub struct FfiRef { ptr: *mut (), - dereferenceable: bool, - range: Option, + flags: FfiRefFlagList, + boundary: FfiRefBounds, } impl FfiRef { - pub fn new(ptr: *mut (), dereferenceable: bool, range: Option) -> Self { + pub fn new(ptr: *mut (), flags: FfiRefFlagList, range: FfiRefBounds) -> Self { Self { ptr, - dereferenceable, - range, + flags, + boundary: range, } } @@ -35,14 +40,19 @@ impl FfiRef { this: LuaAnyUserData<'lua>, ) -> LuaResult> { let target = this.borrow::()?; + let mut flags = target.flags.clone(); + + // FIXME: + // We cannot dereference ref which created by lua, in lua + flags.set_dereferenceable(false); let luaref = lua.create_userdata(FfiRef::new( ptr::from_ref(&target.ptr) as *mut (), - true, - Some(FfiRefBounds { - low: 0, - high: size_of::(), - }), + flags, + FfiRefBounds { + below: 0, + above: size_of::(), + }, ))?; // If the ref holds a box, make sure the new ref also holds the box by holding ref @@ -55,26 +65,51 @@ impl FfiRef { self.ptr } - pub unsafe fn deref(&self) -> Self { - // FIXME - Self::new(*self.ptr.cast::<*mut ()>(), true, None) + pub unsafe fn deref(&self) -> LuaResult { + self.flags + .is_dereferenceable() + .then_some(()) + .ok_or(LuaError::external("This pointer is not dereferenceable."))?; + + self.boundary + .check_sized(0, size_of::()) + .then_some(()) + .ok_or(LuaError::external( + "Offset is out of bounds. Dereferencing pointer requires size of usize", + ))?; + + // FIXME flags + Ok(Self::new( + *self.ptr.cast::<*mut ()>(), + self.flags.clone(), + UNSIZED_BOUNDS, + )) + } + + pub fn is_nullptr(&self) -> bool { + self.ptr as usize == 0 } pub unsafe fn offset(&self, offset: isize) -> LuaResult { - if let Some(ref t) = self.range { - if !t.check(offset) { - return Err(LuaError::external(format!( - "Offset is out of bounds. high: {}, low: {}. offset got {}", - t.high, t.low, offset - ))); - } - } - let range = self.range.as_ref().map(|t| t.offset(offset)); + self.flags + .is_offsetable() + .then_some(()) + .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 + )) + })?; + + let boundary = self.boundary.offset(offset); Ok(Self::new( self.ptr.byte_offset(offset), - self.dereferenceable, - range, + self.flags.clone(), + boundary, )) } } @@ -84,7 +119,7 @@ impl LuaUserData for FfiRef { methods.add_function("deref", |lua, this: LuaAnyUserData| { let inner = get_association(lua, REF_INNER, &this)?; let ffiref = this.borrow::()?; - let result = lua.create_userdata(unsafe { ffiref.deref() })?; + let result = lua.create_userdata(unsafe { ffiref.deref()? })?; if let Some(t) = inner { // if let Some(u) = get_association(lua, regname, value) {} @@ -108,5 +143,18 @@ impl LuaUserData for FfiRef { let ffiref = FfiRef::luaref(lua, this)?; Ok(ffiref) }); + methods.add_method("isNullptr", |_, this, ()| Ok(this.is_nullptr())); } } + +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(), + // 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 + UNSIZED_BOUNDS, + )) +} diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index dd369051..c13f88a1 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -1,11 +1,10 @@ -pub(super) mod ffi_association; -pub(super) mod ffi_bounds; -pub(super) mod ffi_box; -pub(super) mod ffi_helper; -pub(super) mod ffi_lib; -pub(super) mod ffi_platform; -pub(super) mod ffi_raw; -pub(super) mod ffi_ref; +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; // Named registry table names mod association_names { diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs index 355cf3be..36549a95 100644 --- a/crates/lune-std-ffi/src/lib.rs +++ b/crates/lune-std-ffi/src/lib.rs @@ -3,14 +3,12 @@ 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::{c_fn::CFn, c_struct::CStruct, create_all_types}; -use crate::ffi::{ - ffi_association::get_table, ffi_box::FfiBox, ffi_lib::FfiLib, ffi_platform::get_platform_value, -}; - /** Creates the `ffi` standard library module. @@ -19,10 +17,10 @@ use crate::ffi::{ Errors when out of memory. */ pub fn module(lua: &Lua) -> LuaResult { - let ctypes = create_all_types(lua)?; let result = TableBuilder::new(lua)? - .with_values(ctypes)? - .with_values(get_platform_value())? + .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("dlopen", |_, name: String| { @@ -40,7 +38,7 @@ pub fn module(lua: &Lua) -> LuaResult { #[cfg(debug_assertions)] let result = result.with_function("debug_associate", |lua, str: String| { - get_table(lua, str.as_ref()) + crate::ffi::ffi_association::get_table(lua, str.as_ref()) })?; result.build_readonly() diff --git a/crates/lune-std-ffi/todo.md b/crates/lune-std-ffi/todo.md deleted file mode 100644 index fbd89994..00000000 --- a/crates/lune-std-ffi/todo.md +++ /dev/null @@ -1,99 +0,0 @@ -- last thing to do -- [ ] Add tests -- [ ] Add docs -- [ ] Typing - -pragma pack? - -# Raw - -- [ ] Raw:toRef() -- [ ] Raw:toBox() -- [ ] Raw:intoBox() -- [ ] Raw:intoRef() - -# Box - -- [x] ffi.box(size) -- [x] .size -- [x] :zero() -- [x] :ref(offset?=0) => ref -- [x] tostring - -- [~] :copy(box,size?=-1,offset?=0) - - working on it - -# Ref (Unsafe) - -- [ ] high, low Boundaries -- [ ] iter - -- [x] ref:deref() -> ref -- [x] ref:offset(bytes) -> ref -- [x] ref:ref() -> ref - -~~- [ ] ref:fromRef(size,offset?=0) ?? what is this~~ -~~- [ ] ref:fromBox(size,offset?=0) ?? what is this~~ - -# Struct - -- [x] :offset(index) -- [x] :ptr() -- [x] .inner[n] -- [!] .size -- [ ] # -- [x] tostring - -size, offset is strange. maybe related to cif state. - -# Type - -- [ ] :toBox(luavalue) - -Very stupid idea. -from(box|ref|raw, offset) is better idea i think. - -- [ ] :fromBox(box,offset?=0) -- [ ] :intoBox(luavalue,box,offset?=0) -- [ ] :fromRef(ref,offset?=0) -- [ ] :intoRef(luavalue,ref,offset?=0) -- [ ] :fromRaw(raw,offset?=0) - -- [ ] :castBox(box,type) TODO -- [ ] - -- [ ] :sum -- [ ] :mul -- [ ] :sub - -## subtype - -- [x] :ptr() -> Ptr -- [~] :arr(len) -> Arr -- [x] .size - -# Ptr - -- [x] .inner -- [x] .size -- [x] :ptr() -- [~] :arr() - -## Arr - -## Void - -`ffi.void` - -Zero sized type. - -## Fn - -Prototype type of some function. converts lua function into native function pointer or native function pointer into lua function. - -`ffi.fn({ type }, type) -> fn` - -:toLua( ref ) -> luafunction -:toBox( luafunction ) -> ref - -> TODO: rust, and another ABI support From b54ea519ba17a51fe92018f91a73144e46808334 Mon Sep 17 00:00:00 2001 From: qwreey Date: Wed, 28 Aug 2024 16:39:35 +0000 Subject: [PATCH 10/79] 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 | 161 +++++++++--- 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, 924 insertions(+), 490 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 063b93ad..e1deff79 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 7a4bce3d..d83ecf7d 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 23101803..6d0ac971 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 ced880b8..08d9d331 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 16e2f8f3..39df2261 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 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.size)); + 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 17c61717..6cc763a8 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, - LuaValue, LuaAnyUserData, + LuaValue, 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 00000000..e69de29b diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index 7b510d78..34c80445 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 79baa3e5..ffe72efd 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 7dec899c..6970c436 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 8f75d9ca..320f6737 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 e9a33ccc..d3b883f0 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 6478370f..b4108c4c 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 ff1e2285..c5539848 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 0c8cc287..367723eb 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 634d7bf3..f7a779a9 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 a059967d..5b8a700e 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 80ff6215..71e75760 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 b2a172b8..4debe03a 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 3f494c22..6e8e3d45 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 13cc41ae..34972c1d 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 65c81d6d..20ac295b 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 8b959d65..063db46c 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 6990938a..bf1a2cdf 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 f31a8253..7035ff45 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 26be508e..3288ed5f 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 50bd6519..31d7775d 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 e3b5d195..76007500 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 16490b52..e083fe55 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 00000000..a7d98dc6 --- /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 c32ca765..8348b3db 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 89c7f218..3e3bd004 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 faf969e1..12055c5f 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 19aa6f46..1c3cdcb3 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 c13f88a1..5f57be82 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 36549a95..18b6c245 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()) })?; From dd6a3861e541aa89b54a9a3ddbb15ea24a19f22e Mon Sep 17 00:00:00 2001 From: qwreey Date: Fri, 30 Aug 2024 04:04:24 +0000 Subject: [PATCH 11/79] Improve conversion performance by caching dyn handle on subtype (#243) --- crates/lune-std-ffi/src/c/c_arr.rs | 138 ++++++++++++-- crates/lune-std-ffi/src/c/c_helper.rs | 7 +- crates/lune-std-ffi/src/c/c_type.rs | 2 +- crates/lune-std-ffi/src/c/mod.rs | 2 +- crates/lune-std-ffi/src/c/types/mod.rs | 204 ++++++++++----------- crates/lune-std-ffi/src/ffi/ffi_box.rs | 10 +- crates/lune-std-ffi/src/ffi/ffi_func.rs | 0 crates/lune-std-ffi/src/ffi/ffi_helper.rs | 29 --- crates/lune-std-ffi/src/ffi/ffi_lib.rs | 9 +- crates/lune-std-ffi/src/ffi/ffi_raw.rs | 2 +- crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs | 16 +- crates/lune-std-ffi/src/ffi/mod.rs | 1 + 12 files changed, 244 insertions(+), 176 deletions(-) create mode 100644 crates/lune-std-ffi/src/ffi/ffi_func.rs delete mode 100644 crates/lune-std-ffi/src/ffi/ffi_helper.rs diff --git a/crates/lune-std-ffi/src/c/c_arr.rs b/crates/lune-std-ffi/src/c/c_arr.rs index e1deff79..9302a3db 100644 --- a/crates/lune-std-ffi/src/c/c_arr.rs +++ b/crates/lune-std-ffi/src/c/c_arr.rs @@ -1,10 +1,17 @@ +use std::cell::Ref; + use libffi::middle::Type; use mlua::prelude::*; -use super::association_names::CARR_INNER; -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}; +use super::{ + association_names::CARR_INNER, + c_helper::{get_conv, get_ensured_size, libffi_type_from_userdata, pretty_format_userdata}, + CPtr, +}; +use crate::ffi::{ + ffi_association::{get_association, set_association}, + FfiBox, GetNativeDataHandle, NativeConvert, NativeDataHandle, NativeSignedness, NativeSize, +}; // This is a series of some type. // It provides the final size and the offset of the index, @@ -18,24 +25,30 @@ use crate::ffi::ffi_association::{get_association, set_association}; // There is no problem even if you create a struct with n fields of a single type within the struct. Array adheres to the condition that there is no additional padding between each element. Padding to a struct is padding inside the struct. Simply think of the padding byte as a trailing unnamed field. pub struct CArr { - element_type: Type, + // element_type: Type, struct_type: Type, length: usize, field_size: usize, size: usize, + conv: *const dyn NativeConvert, } impl CArr { - pub fn new(element_type: Type, length: usize) -> LuaResult { - let struct_type = Type::structure(vec![element_type.clone(); length]); + pub fn new( + element_type: Type, + length: usize, + conv: *const dyn NativeConvert, + ) -> LuaResult { let field_size = get_ensured_size(element_type.as_raw_ptr())?; + let struct_type = Type::structure(vec![element_type.clone(); length]); Ok(Self { - element_type, + // element_type, struct_type, length, field_size, size: field_size * length, + conv, }) } @@ -45,16 +58,13 @@ impl CArr { length: usize, ) -> LuaResult> { let fields = libffi_type_from_userdata(lua, luatype)?; - let carr = lua.create_userdata(Self::new(fields, length)?)?; + let conv = unsafe { get_conv(luatype)? }; + let carr = lua.create_userdata(Self::new(fields, length, conv)?)?; 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 } @@ -63,9 +73,9 @@ impl CArr { &self.struct_type } - pub fn get_element_type(&self) -> &Type { - &self.element_type - } + // pub fn get_element_type(&self) -> &Type { + // &self.element_type + // } // Stringify cstruct for pretty printing something like: // @@ -89,6 +99,64 @@ impl CArr { } } +impl NativeSize for CArr { + fn get_size(&self) -> usize { + self.size + } +} +impl NativeSignedness for CArr { + fn get_signedness(&self) -> bool { + false + } +} +impl NativeConvert for CArr { + // 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 in 0..self.length { + let field_offset = (i * self.field_size) as isize; + let data: LuaValue = table.get(i + 1)?; + + self.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.length, 0)?; + for i in 0..self.length { + let field_offset = (i * self.field_size) as isize; + table.set( + i + 1, + self.conv.as_ref().unwrap().luavalue_from( + lua, + field_offset + offset, + data_handle, + )?, + )?; + } + Ok(LuaValue::Table(table)) + } +} + impl LuaUserData for CArr { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { fields.add_field_method_get("size", |_, this| Ok(this.get_size())); @@ -109,6 +177,44 @@ impl LuaUserData for CArr { 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")); + } + 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::new_from_lua_userdata(lua, &this)?; Ok(pointer) diff --git a/crates/lune-std-ffi/src/c/c_helper.rs b/crates/lune-std-ffi/src/c/c_helper.rs index 6d0ac971..d072bd43 100644 --- a/crates/lune-std-ffi/src/c/c_helper.rs +++ b/crates/lune-std-ffi/src/c/c_helper.rs @@ -6,10 +6,9 @@ use libffi::{low, middle::Type, raw}; use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; use mlua::prelude::*; -use super::association_names::CTYPE_STATIC; -use super::c_type::CTypeStatic; -use super::types::get_ctype_conv; -use super::{CArr, CPtr, CStruct}; +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}; // Get the NativeConvert handle from the type UserData diff --git a/crates/lune-std-ffi/src/c/c_type.rs b/crates/lune-std-ffi/src/c/c_type.rs index 6cc763a8..4ab4cd88 100644 --- a/crates/lune-std-ffi/src/c/c_type.rs +++ b/crates/lune-std-ffi/src/c/c_type.rs @@ -88,7 +88,7 @@ impl NativeSize for CType { } } -pub struct CType { +pub struct CType { // for ffi_ptrarray_to_raw? // libffi_cif: Cif, libffi_type: Type, diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index 34c80445..2d7d6184 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -12,7 +12,7 @@ pub use self::{ c_fn::CFn, c_ptr::CPtr, c_struct::CStruct, - c_type::{CType, CTypeCast}, + c_type::{CType, CTypeCast, CTypeStatic}, }; pub use types::create_all_c_types; diff --git a/crates/lune-std-ffi/src/c/types/mod.rs b/crates/lune-std-ffi/src/c/types/mod.rs index 5b8a700e..9863e75e 100644 --- a/crates/lune-std-ffi/src/c/types/mod.rs +++ b/crates/lune-std-ffi/src/c/types/mod.rs @@ -1,15 +1,14 @@ #![allow(clippy::inline_always)] use core::ffi::*; -use std::cell::Ref; -use std::{any::TypeId, ops::Deref}; +use std::{any::TypeId, cell::Ref}; use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; use super::{CType, CTypeCast}; -use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; +use crate::ffi::{NativeConvert, NativeDataHandle}; pub mod f32; pub mod f64; @@ -129,120 +128,107 @@ 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]>, +// macro_rules! define_ctype_size_from_userdata { +// ($t:ident, $f:ty, $( $c:ty ),*) => { +// 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 +// ) // } -// 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( +// 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, -// type_userdata: &LuaAnyUserData<'lua>, +// this: &LuaAnyUserData<'lua>, // offset: isize, // data_handle: &Ref, // value: LuaValue<'lua>, -// ) -> LuaResult<()> = || CType::::luavalue_into; +// ) -> 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 +// ) // } +// Use UB method, but safe. because we use ffi_association to ensure children alive +// Much faster then get NativeConvert handle everytime from lua table +// it's spam of table.get(), if ud.is::() { ud.borrow::()? ... } macro_rules! define_get_ctype_conv { ($userdata:ident, $f:ty, $( $c:ty ),*) => { if $userdata.is::>() { diff --git a/crates/lune-std-ffi/src/ffi/ffi_box.rs b/crates/lune-std-ffi/src/ffi/ffi_box.rs index 7035ff45..63c1f1e8 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_box.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_box.rs @@ -3,10 +3,12 @@ use std::sync::LazyLock; 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}; +use super::{ + association_names::REF_INNER, + ffi_association::set_association, + ffi_ref::{FfiRef, FfiRefBounds, FfiRefFlag, FfiRefFlagList}, + NativeDataHandle, +}; static BOX_REF_FLAGS: LazyLock = LazyLock::new(|| { FfiRefFlagList::new(&[ diff --git a/crates/lune-std-ffi/src/ffi/ffi_func.rs b/crates/lune-std-ffi/src/ffi/ffi_func.rs new file mode 100644 index 00000000..e69de29b diff --git a/crates/lune-std-ffi/src/ffi/ffi_helper.rs b/crates/lune-std-ffi/src/ffi/ffi_helper.rs deleted file mode 100644 index 3288ed5f..00000000 --- a/crates/lune-std-ffi/src/ffi/ffi_helper.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![allow(clippy::inline_always)] - -// 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/ffi/ffi_lib.rs b/crates/lune-std-ffi/src/ffi/ffi_lib.rs index 6e393da3..14d2cec2 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_lib.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_lib.rs @@ -4,8 +4,11 @@ use std::sync::LazyLock; use dlopen2::symbor::Library; use mlua::prelude::*; -use super::ffi_association::set_association; -use super::ffi_ref::{FfiRef, FfiRefFlag, FfiRefFlagList, UNSIZED_BOUNDS}; +use super::{ + association_names::SYM_INNER, + ffi_association::set_association, + ffi_ref::{FfiRef, FfiRefFlag, FfiRefFlagList, UNSIZED_BOUNDS}, +}; static LIB_REF_FLAGS: LazyLock = LazyLock::new(|| { FfiRefFlagList::new(&[ @@ -18,8 +21,6 @@ static LIB_REF_FLAGS: LazyLock = LazyLock::new(|| { pub struct FfiLib(Library); -const SYM_INNER: &str = "__syn_inner"; - // COMMENT HERE // For convenience, it would be nice to provide a way to get // symbols from a table with type and field names specified. diff --git a/crates/lune-std-ffi/src/ffi/ffi_raw.rs b/crates/lune-std-ffi/src/ffi/ffi_raw.rs index 8348b3db..2827ffc0 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_raw.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_raw.rs @@ -10,4 +10,4 @@ // relatively insecure operations, and help ensure that as little // data copy as possible occurs, while allowing you to do little restrictions. -pub struct FfiRaw(); +pub struct FfiRaw(*const ()); 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 1c3cdcb3..7971644f 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs @@ -2,15 +2,19 @@ use std::ptr; use mlua::prelude::*; -use super::association_names::REF_INNER; -use super::ffi_association::{get_association, set_association}; -use super::ffi_native::NativeDataHandle; +use super::{ + association_names::REF_INNER, + ffi_association::{get_association, set_association}, + NativeDataHandle, +}; mod bounds; mod flags; -pub use self::bounds::{FfiRefBounds, UNSIZED_BOUNDS}; -pub use self::flags::{FfiRefFlag, FfiRefFlagList}; +pub use self::{ + bounds::{FfiRefBounds, UNSIZED_BOUNDS}, + flags::{FfiRefFlag, FfiRefFlagList}, +}; // 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 @@ -18,8 +22,6 @@ pub use self::flags::{FfiRefFlag, FfiRefFlagList}; // If it references an area managed by Lua, // the box will remain as long as this reference is alive. -// Todo : how to impl ref == nullptr - pub struct FfiRef { ptr: *mut (), pub flags: FfiRefFlagList, diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index 5f57be82..3eb02f96 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -18,6 +18,7 @@ pub use self::{ // Named registry table names mod association_names { pub const REF_INNER: &str = "__ref_inner"; + pub const SYM_INNER: &str = "__syn_inner"; } // Converts ffi status into &str From 94d8d079c412311751748503bf37e61ac290948b Mon Sep 17 00:00:00 2001 From: qwreey Date: Mon, 2 Sep 2024 10:14:34 +0000 Subject: [PATCH 12/79] Add is_integer (#243) --- crates/lune-std-ffi/src/c/c_helper.rs | 2 +- crates/lune-std-ffi/src/ffi/ffi_box.rs | 28 +++++++++++-------- crates/lune-std-ffi/src/ffi/ffi_func.rs | 3 ++ crates/lune-std-ffi/src/ffi/ffi_lib.rs | 2 +- .../lune-std-ffi/src/ffi/ffi_native/call.rs | 19 +++++++++++++ crates/lune-std-ffi/src/ffi/ffi_native/mod.rs | 5 ++-- crates/lune-std-ffi/src/ffi/mod.rs | 6 ++++ crates/lune-std-ffi/src/lib.rs | 5 ++-- 8 files changed, 52 insertions(+), 18 deletions(-) create mode 100644 crates/lune-std-ffi/src/ffi/ffi_native/call.rs diff --git a/crates/lune-std-ffi/src/c/c_helper.rs b/crates/lune-std-ffi/src/c/c_helper.rs index d072bd43..3338c727 100644 --- a/crates/lune-std-ffi/src/c/c_helper.rs +++ b/crates/lune-std-ffi/src/c/c_helper.rs @@ -12,7 +12,7 @@ use super::{ 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) +// this is intended to avoid lookup userdata and lua table every time. (eg: struct) // userdata must live longer than the NativeConvert handle. // However, c_struct is a strong reference to each field, so this is not a problem. pub unsafe fn get_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn NativeConvert> { diff --git a/crates/lune-std-ffi/src/ffi/ffi_box.rs b/crates/lune-std-ffi/src/ffi/ffi_box.rs index 63c1f1e8..f7696666 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_box.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_box.rs @@ -1,5 +1,5 @@ use std::boxed::Box; -use std::sync::LazyLock; +use std::sync::OnceLock; use mlua::prelude::*; @@ -10,13 +10,18 @@ use super::{ NativeDataHandle, }; -static BOX_REF_FLAGS: LazyLock = LazyLock::new(|| { - FfiRefFlagList::new(&[ - FfiRefFlag::Offsetable, - FfiRefFlag::Readable, - FfiRefFlag::Writable, - ]) -}); +static BOX_REF_FLAGS: OnceLock = OnceLock::new(); +fn get_box_ref_flags() -> FfiRefFlagList { + BOX_REF_FLAGS + .get_or_init(|| { + FfiRefFlagList::new(&[ + FfiRefFlag::Offsetable, + FfiRefFlag::Readable, + FfiRefFlag::Writable, + ]) + }) + .to_owned() +} // It is an untyped, sized memory area that Lua can manage. // This area is safe within Lua. Operations have their boundaries checked. @@ -93,8 +98,7 @@ impl FfiBox { // To deref a box space is to allow lua to read any space, // which has security issues and is ultimately dangerous. // Therefore, box:ref():deref() is not allowed. - let luaref = - lua.create_userdata(FfiRef::new(ptr.cast(), (*BOX_REF_FLAGS).clone(), bounds))?; + let luaref = lua.create_userdata(FfiRef::new(ptr.cast(), get_box_ref_flags(), bounds))?; // Makes box alive longer then ref set_association(lua, REF_INNER, &luaref, &this)?; @@ -114,7 +118,7 @@ impl FfiBox { // Get raw ptr pub fn get_ptr(&self) -> *mut u8 { - self.data.as_ptr() as *mut u8 + self.data.as_ptr().cast_mut() } } @@ -134,7 +138,7 @@ impl NativeDataHandle for FfiBox { true } unsafe fn get_pointer(&self, offset: isize) -> *mut () { - self.get_ptr().byte_offset(offset) as *mut () + self.get_ptr().byte_offset(offset).cast::<()>() } } diff --git a/crates/lune-std-ffi/src/ffi/ffi_func.rs b/crates/lune-std-ffi/src/ffi/ffi_func.rs index e69de29b..2126bc52 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_func.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_func.rs @@ -0,0 +1,3 @@ +struct FfiFunc { + args: Vec, +} diff --git a/crates/lune-std-ffi/src/ffi/ffi_lib.rs b/crates/lune-std-ffi/src/ffi/ffi_lib.rs index 14d2cec2..6b5180a5 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_lib.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_lib.rs @@ -64,7 +64,7 @@ impl FfiLib { impl LuaUserData for FfiLib { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { - methods.add_function("dlsym", |lua, (this, name): (LuaAnyUserData, String)| { + methods.add_function("find", |lua, (this, name): (LuaAnyUserData, String)| { let luasym = FfiLib::get_sym(lua, this, name)?; Ok(luasym) }); diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/call.rs b/crates/lune-std-ffi/src/ffi/ffi_native/call.rs new file mode 100644 index 00000000..b551484a --- /dev/null +++ b/crates/lune-std-ffi/src/ffi/ffi_native/call.rs @@ -0,0 +1,19 @@ +use std::cell::Ref; + +use mlua::prelude::*; + +use super::NativeDataHandle; + +// 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/mod.rs b/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs index e083fe55..9ecfe3e8 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs @@ -1,3 +1,4 @@ +mod call; mod cast; mod convert; mod readwrite; @@ -13,6 +14,6 @@ pub trait NativeSignedness { } pub use self::{ - cast::native_num_cast, convert::NativeConvert, readwrite::GetNativeDataHandle, - readwrite::NativeDataHandle, + call::NativeCall, cast::native_num_cast, convert::NativeConvert, + readwrite::GetNativeDataHandle, readwrite::NativeDataHandle, }; diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index 3eb02f96..15263167 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -5,6 +5,8 @@ mod ffi_native; mod ffi_raw; mod ffi_ref; +use mlua::prelude::*; + pub use self::{ ffi_box::FfiBox, ffi_lib::FfiLib, @@ -48,3 +50,7 @@ pub mod bit_mask { pub(crate) use U8_TEST; } + +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 18b6c245..ad1aad06 100644 --- a/crates/lune-std-ffi/src/lib.rs +++ b/crates/lune-std-ffi/src/lib.rs @@ -8,7 +8,7 @@ mod ffi; use crate::{ c::{create_all_c_types, create_all_types, CFn, CStruct}, - ffi::{create_nullptr, FfiBox, FfiLib}, + ffi::{create_nullptr, is_integer, FfiBox, FfiLib}, }; /** @@ -25,7 +25,7 @@ pub fn module(lua: &Lua) -> LuaResult { .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("dlopen", |_, name: String| { + .with_function("open", |_, name: String| { let lib = FfiLib::new(name)?; Ok(lib) })? @@ -33,6 +33,7 @@ pub fn module(lua: &Lua) -> LuaResult { let cstruct = CStruct::new_from_lua_table(lua, types)?; Ok(cstruct) })? + .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) From e23aaef8a7d2d27bf97893da522551731e33daaf Mon Sep 17 00:00:00 2001 From: qwreey Date: Mon, 2 Sep 2024 15:11:13 +0000 Subject: [PATCH 13/79] Improve ffiref (#243) --- crates/lune-std-ffi/src/c/c_arr.rs | 11 +--- crates/lune-std-ffi/src/c/c_fn.rs | 34 +++++++---- crates/lune-std-ffi/src/c/c_struct.rs | 10 ++-- crates/lune-std-ffi/src/c/c_type.rs | 4 +- crates/lune-std-ffi/src/c/c_void.rs | 1 + crates/lune-std-ffi/src/ffi/ffi_box.rs | 60 ++++++++++++------- crates/lune-std-ffi/src/ffi/ffi_func.rs | 3 - crates/lune-std-ffi/src/ffi/ffi_lib.rs | 24 +++----- .../src/ffi/ffi_native/readwrite.rs | 5 +- crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs | 17 ++++-- crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs | 35 +++++++++-- 11 files changed, 129 insertions(+), 75 deletions(-) delete mode 100644 crates/lune-std-ffi/src/ffi/ffi_func.rs diff --git a/crates/lune-std-ffi/src/c/c_arr.rs b/crates/lune-std-ffi/src/c/c_arr.rs index 9302a3db..33625a82 100644 --- a/crates/lune-std-ffi/src/c/c_arr.rs +++ b/crates/lune-std-ffi/src/c/c_arr.rs @@ -10,7 +10,7 @@ use super::{ }; use crate::ffi::{ ffi_association::{get_association, set_association}, - FfiBox, GetNativeDataHandle, NativeConvert, NativeDataHandle, NativeSignedness, NativeSize, + FfiBox, GetNativeDataHandle, NativeConvert, NativeDataHandle, NativeSize, }; // This is a series of some type. @@ -104,11 +104,6 @@ impl NativeSize for CArr { self.size } } -impl NativeSignedness for CArr { - fn get_signedness(&self) -> bool { - false - } -} impl NativeConvert for CArr { // FIXME: FfiBox, FfiRef support required unsafe fn luavalue_into<'lua>( @@ -192,7 +187,7 @@ impl LuaUserData for CArr { 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()) { + if !data_handle.check_readable(offset, this.get_size()) { return Err(LuaError::external("Unreadable data handle")); } @@ -208,7 +203,7 @@ impl LuaUserData for CArr { if !data_handle.check_boundary(offset, this.size) { return Err(LuaError::external("Out of bounds")); } - if !data_handle.checek_writable(&userdata, offset, this.size) { + if !data_handle.checek_writable(offset, this.size) { return Err(LuaError::external("Unwritable data handle")); } diff --git a/crates/lune-std-ffi/src/c/c_fn.rs b/crates/lune-std-ffi/src/c/c_fn.rs index d83ecf7d..c1877a6b 100644 --- a/crates/lune-std-ffi/src/c/c_fn.rs +++ b/crates/lune-std-ffi/src/c/c_fn.rs @@ -1,7 +1,10 @@ use libffi::middle::{Cif, Type}; use mlua::prelude::*; -use super::c_helper::{libffi_type_from_userdata, libffi_type_list_from_table}; +use super::c_helper::{ + get_conv, get_conv_list_from_table, libffi_type_from_userdata, libffi_type_list_from_table, +}; +use crate::ffi::NativeConvert; // cfn is a type declaration for a function. // Basically, when calling an external function, this type declaration @@ -21,24 +24,35 @@ use super::c_helper::{libffi_type_from_userdata, libffi_type_list_from_table}; pub struct CFn { libffi_cif: Cif, - args: Vec, - ret: Type, + args_conv: Vec<*const dyn NativeConvert>, + ret_conv: *const dyn NativeConvert, } impl CFn { - pub fn new(args: Vec, ret: Type) -> Self { - let libffi_cif = Cif::new(args.clone(), ret.clone()); + pub fn new( + args: Vec, + ret: Type, + args_conv: Vec<*const dyn NativeConvert>, + ret_conv: *const dyn NativeConvert, + ) -> Self { + let libffi_cif: Cif = Cif::new(args.clone(), ret.clone()); Self { libffi_cif, - args, - ret, + args_conv, + ret_conv, } } pub fn new_from_lua_table(lua: &Lua, args: LuaTable, ret: LuaAnyUserData) -> LuaResult { - let args = libffi_type_list_from_table(lua, &args)?; - let ret = libffi_type_from_userdata(lua, &ret)?; - Ok(Self::new(args, ret)) + let args_type = 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)? }, + )) } } diff --git a/crates/lune-std-ffi/src/c/c_struct.rs b/crates/lune-std-ffi/src/c/c_struct.rs index 39df2261..16a399b6 100644 --- a/crates/lune-std-ffi/src/c/c_struct.rs +++ b/crates/lune-std-ffi/src/c/c_struct.rs @@ -50,6 +50,7 @@ impl CStruct { // 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 }; Ok(Self { @@ -91,7 +92,8 @@ impl CStruct { } // size of - result.push_str(format!("size = {} ", userdata.borrow::()?.size).as_str()); + result + .push_str(format!("size = {} ", userdata.borrow::()?.get_size()).as_str()); Ok(result) } else { Err(LuaError::external("failed to get inner type table.")) @@ -206,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(&userdata, offset, this.get_size()) { + if !data_handle.check_readable(offset, this.get_size()) { return Err(LuaError::external("Unreadable data handle")); } @@ -219,10 +221,10 @@ impl LuaUserData for CStruct { let offset = offset.unwrap_or(0); let data_handle = &userdata.get_data_handle()?; - if !data_handle.check_boundary(offset, this.size) { + if !data_handle.check_boundary(offset, this.get_size()) { return Err(LuaError::external("Out of bounds")); } - if !data_handle.checek_writable(&userdata, offset, this.size) { + if !data_handle.checek_writable(offset, this.get_size()) { 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 4ab4cd88..7ad121d9 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(&userdata, offset, ctype.get_size()) { + if !data_handle.check_readable(offset, ctype.get_size()) { 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(&userdata, offset, ctype.get_size()) { + if !data_handle.checek_writable(offset, ctype.get_size()) { return Err(LuaError::external("Unwritable data handle")); } diff --git a/crates/lune-std-ffi/src/c/c_void.rs b/crates/lune-std-ffi/src/c/c_void.rs index e69de29b..b1e6fcbb 100644 --- a/crates/lune-std-ffi/src/c/c_void.rs +++ b/crates/lune-std-ffi/src/c/c_void.rs @@ -0,0 +1 @@ +use core::ffi::c_void; diff --git a/crates/lune-std-ffi/src/ffi/ffi_box.rs b/crates/lune-std-ffi/src/ffi/ffi_box.rs index f7696666..9229b8d3 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_box.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_box.rs @@ -1,27 +1,17 @@ use std::boxed::Box; -use std::sync::OnceLock; use mlua::prelude::*; use super::{ association_names::REF_INNER, ffi_association::set_association, - ffi_ref::{FfiRef, FfiRefBounds, FfiRefFlag, FfiRefFlagList}, + ffi_ref::{FfiRef, FfiRefBounds, FfiRefFlag, FfiRefFlagList, UNSIZED_BOUNDS}, NativeDataHandle, }; -static BOX_REF_FLAGS: OnceLock = OnceLock::new(); -fn get_box_ref_flags() -> FfiRefFlagList { - BOX_REF_FLAGS - .get_or_init(|| { - FfiRefFlagList::new(&[ - FfiRefFlag::Offsetable, - FfiRefFlag::Readable, - FfiRefFlag::Writable, - ]) - }) - .to_owned() -} +const BOX_REF_FLAGS: FfiRefFlagList = FfiRefFlagList::new( + FfiRefFlag::Offsetable.value() | FfiRefFlag::Readable.value() | FfiRefFlag::Writable.value(), +); // It is an untyped, sized memory area that Lua can manage. // This area is safe within Lua. Operations have their boundaries checked. @@ -35,6 +25,7 @@ fn get_box_ref_flags() -> FfiRefFlagList { struct RefData { address: usize, offset: usize, + lua_inner_id: i32, } pub struct FfiBox { @@ -77,7 +68,7 @@ impl FfiBox { this: LuaAnyUserData<'lua>, offset: Option, ) -> LuaResult> { - let mut target = this.borrow_mut::()?; + let target = this.borrow::()?; let mut bounds = FfiRefBounds::new(0, target.size()); let mut ptr = target.get_ptr(); @@ -98,7 +89,7 @@ impl FfiBox { // To deref a box space is to allow lua to read any space, // which has security issues and is ultimately dangerous. // Therefore, box:ref():deref() is not allowed. - let luaref = lua.create_userdata(FfiRef::new(ptr.cast(), get_box_ref_flags(), bounds))?; + let luaref = lua.create_userdata(FfiRef::new(ptr.cast(), BOX_REF_FLAGS, bounds))?; // Makes box alive longer then ref set_association(lua, REF_INNER, &luaref, &this)?; @@ -106,6 +97,27 @@ impl FfiBox { Ok(luaref) } + // Make FfiRef from box, without any safe features + pub fn luaref_unsafe<'lua>( + lua: &'lua Lua, + this: LuaAnyUserData<'lua>, + offset: Option, + ) -> LuaResult> { + let target = this.borrow::()?; + let mut ptr = target.get_ptr(); + + // Calculate offset + if let Some(t) = offset { + ptr = unsafe { target.get_ptr().byte_offset(t) }; + } + + lua.create_userdata(FfiRef::new( + ptr.cast(), + FfiRefFlagList::all(), + UNSIZED_BOUNDS, + )) + } + // Fill every field with 0 pub fn zero(&mut self) { self.data.fill(0u8); @@ -130,13 +142,16 @@ impl NativeDataHandle for FfiBox { self.size() > ((offset as usize) + size) } // FIXME - fn checek_writable(&self, userdata: &LuaAnyUserData, offset: isize, size: usize) -> bool { + fn checek_writable(&self, offset: isize, size: usize) -> bool { true } // FIXME - fn check_readable(&self, userdata: &LuaAnyUserData, offset: isize, size: usize) -> bool { + fn check_readable(&self, offset: isize, size: usize) -> bool { true } + fn mark_ref(&self, userdata: &LuaAnyUserData, offset: isize, ptr: usize) -> LuaResult<()> { + Ok(()) + } unsafe fn get_pointer(&self, offset: isize) -> *mut () { self.get_ptr().byte_offset(offset).cast::<()>() } @@ -155,8 +170,13 @@ impl LuaUserData for FfiBox { methods.add_function( "ref", |lua, (this, offset): (LuaAnyUserData, Option)| { - let luaref = FfiBox::luaref(lua, this, offset)?; - Ok(luaref) + FfiBox::luaref(lua, this, offset) + }, + ); + methods.add_function( + "unsafeRef", + |lua, (this, offset): (LuaAnyUserData, Option)| { + FfiBox::luaref_unsafe(lua, this, offset) }, ); methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| Ok(this.stringify())); diff --git a/crates/lune-std-ffi/src/ffi/ffi_func.rs b/crates/lune-std-ffi/src/ffi/ffi_func.rs deleted file mode 100644 index 2126bc52..00000000 --- a/crates/lune-std-ffi/src/ffi/ffi_func.rs +++ /dev/null @@ -1,3 +0,0 @@ -struct FfiFunc { - args: Vec, -} diff --git a/crates/lune-std-ffi/src/ffi/ffi_lib.rs b/crates/lune-std-ffi/src/ffi/ffi_lib.rs index 6b5180a5..4d924621 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_lib.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_lib.rs @@ -1,5 +1,4 @@ -use std::ffi::c_void; -use std::sync::LazyLock; +use core::ffi::c_void; use dlopen2::symbor::Library; use mlua::prelude::*; @@ -10,14 +9,12 @@ use super::{ ffi_ref::{FfiRef, FfiRefFlag, FfiRefFlagList, UNSIZED_BOUNDS}, }; -static LIB_REF_FLAGS: LazyLock = LazyLock::new(|| { - FfiRefFlagList::new(&[ - FfiRefFlag::Offsetable, - FfiRefFlag::Readable, - FfiRefFlag::Dereferenceable, - FfiRefFlag::Function, - ]) -}); +const LIB_REF_FLAGS: FfiRefFlagList = FfiRefFlagList::new( + FfiRefFlag::Offsetable.value() + | FfiRefFlag::Readable.value() + | FfiRefFlag::Dereferenceable.value() + | FfiRefFlag::Function.value(), +); pub struct FfiLib(Library); @@ -50,11 +47,8 @@ impl FfiLib { .map_err(|err| LuaError::external(format!("{err}")))? }; - let luasym = lua.create_userdata(FfiRef::new( - (*sym).cast(), - (*LIB_REF_FLAGS).clone(), - UNSIZED_BOUNDS, - ))?; + let luasym = + lua.create_userdata(FfiRef::new((*sym).cast(), LIB_REF_FLAGS, UNSIZED_BOUNDS))?; set_association(lua, SYM_INNER, &luasym, &this)?; diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/readwrite.rs b/crates/lune-std-ffi/src/ffi/ffi_native/readwrite.rs index a7d98dc6..2f96eaa5 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/readwrite.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/readwrite.rs @@ -7,8 +7,9 @@ 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; + fn check_readable(&self, offset: isize, size: usize) -> bool; + fn checek_writable(&self, offset: isize, size: usize) -> bool; + fn mark_ref(&self, userdata: &LuaAnyUserData, offset: isize, ptr: usize) -> LuaResult<()>; unsafe fn get_pointer(&self, offset: isize) -> *mut (); } 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 12055c5f..114f67c3 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs @@ -25,12 +25,17 @@ impl FfiRefFlagList { pub fn zero() -> Self { Self(0) } - pub fn new(flags: &[FfiRefFlag]) -> Self { - let mut value = 0; - for i in flags { - value |= i.value(); - } - Self(value) + 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 { 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 7971644f..4412828f 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs @@ -26,6 +26,8 @@ pub struct FfiRef { ptr: *mut (), pub flags: FfiRefFlagList, pub boundary: FfiRefBounds, + // Save lua ffibox pointer + pub inner: Option<*const dyn NativeDataHandle>, } impl FfiRef { @@ -34,6 +36,7 @@ impl FfiRef { ptr, flags, boundary: range, + inner: None, } } @@ -125,12 +128,34 @@ 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() + fn checek_writable(&self, offset: isize, size: usize) -> bool { + // If unreadable ref + if !self.flags.is_writable() { + return false; + } + + // If ref have inner luabox + if let Some(inner) = self.inner { + return unsafe { inner.as_ref().unwrap().checek_writable(offset, size) }; + } + + true + } + fn check_readable(&self, offset: isize, size: usize) -> bool { + // If unreadable ref + if !self.flags.is_readable() { + return false; + } + + // If ref have inner luabox + if let Some(inner) = self.inner { + return unsafe { inner.as_ref().unwrap().check_readable(offset, size) }; + } + + true } - // TODO: if ref points box , check box too - fn check_readable(&self, userdata: &LuaAnyUserData, offset: isize, size: usize) -> bool { - self.flags.is_readable() + fn mark_ref(&self, userdata: &LuaAnyUserData, offset: isize, ptr: usize) -> LuaResult<()> { + Ok(()) } unsafe fn get_pointer(&self, offset: isize) -> *mut () { self.get_ptr().byte_offset(offset) From c656a486c4b0e33ce0c23ce7395eaef178e7e1ad Mon Sep 17 00:00:00 2001 From: qwreey Date: Fri, 6 Sep 2024 07:30:45 +0000 Subject: [PATCH 14/79] Add tests for ffi (#243) --- crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs | 2 +- crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs | 10 +++--- tests/ffi/box-recursion-gc.luau | 20 ++++++++++++ tests/ffi/cast.luau | 0 tests/ffi/external.luau | 0 tests/ffi/from-boundary.luau | 0 tests/ffi/into-boundary.luau | 0 tests/ffi/isInteger.luau | 10 ++++++ tests/ffi/ptr.luau | 33 -------------------- tests/ffi/ref-hold-box.luau | 15 +++++++++ tests/ffi/struct.luau | 2 -- tests/ffi/types/arr.luau | 0 tests/ffi/types/fn.luau | 0 tests/ffi/types/ptr.luau | 32 +++++++++++++++++++ tests/ffi/types/struct.luau | 12 +++++++ 15 files changed, 94 insertions(+), 42 deletions(-) create mode 100644 tests/ffi/box-recursion-gc.luau create mode 100644 tests/ffi/cast.luau create mode 100644 tests/ffi/external.luau create mode 100644 tests/ffi/from-boundary.luau create mode 100644 tests/ffi/into-boundary.luau create mode 100644 tests/ffi/isInteger.luau delete mode 100644 tests/ffi/ptr.luau create mode 100644 tests/ffi/ref-hold-box.luau delete mode 100644 tests/ffi/struct.luau create mode 100644 tests/ffi/types/arr.luau create mode 100644 tests/ffi/types/fn.luau create mode 100644 tests/ffi/types/ptr.luau create mode 100644 tests/ffi/types/struct.luau 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 114f67c3..b6a2ca7f 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs @@ -22,7 +22,7 @@ impl FfiRefFlag { pub struct FfiRefFlagList(u8); #[allow(unused)] impl FfiRefFlagList { - pub fn zero() -> Self { + pub const fn zero() -> Self { Self(0) } pub const fn new(flags: u8) -> Self { 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 4412828f..ccd5589f 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs @@ -16,6 +16,9 @@ pub use self::{ flags::{FfiRefFlag, FfiRefFlagList}, }; +// Box:ref():ref() should not be able to modify, Only for external +const BOX_REF_REF_FLAGS: FfiRefFlagList = FfiRefFlagList::zero(); + // A referenced space. It is possible to read and write through types. // This operation is not safe. This may cause a memory error in Lua // if use it incorrectly. @@ -46,15 +49,10 @@ impl FfiRef { this: LuaAnyUserData<'lua>, ) -> LuaResult> { let target = this.borrow::()?; - let mut flags = target.flags.clone(); - - // FIXME: - // We cannot dereference ref which created by lua, in lua - flags.set_dereferenceable(false); let luaref = lua.create_userdata(FfiRef::new( ptr::from_ref(&target.ptr) as *mut (), - flags, + BOX_REF_REF_FLAGS, FfiRefBounds { below: 0, above: size_of::(), diff --git a/tests/ffi/box-recursion-gc.luau b/tests/ffi/box-recursion-gc.luau new file mode 100644 index 00000000..d86d0453 --- /dev/null +++ b/tests/ffi/box-recursion-gc.luau @@ -0,0 +1,20 @@ +--!nocheck +--!nolint + +local ffi = require("@lune/ffi") + +local box = ffi.box(ffi.u8:ptr().size) +local ref = box:ref() +ffi.u8:ptr():into(box, ref) + +local wt = setmetatable({}, { __mode = "v" }) + +wt[1] = box +wt[2] = ref + +box = nil +ref = nil + +collectgarbage("collect") + +assert(wt[1] == nil and wt[2] == nil, "Box - ref recursion GC test failed") diff --git a/tests/ffi/cast.luau b/tests/ffi/cast.luau new file mode 100644 index 00000000..e69de29b diff --git a/tests/ffi/external.luau b/tests/ffi/external.luau new file mode 100644 index 00000000..e69de29b diff --git a/tests/ffi/from-boundary.luau b/tests/ffi/from-boundary.luau new file mode 100644 index 00000000..e69de29b diff --git a/tests/ffi/into-boundary.luau b/tests/ffi/into-boundary.luau new file mode 100644 index 00000000..e69de29b diff --git a/tests/ffi/isInteger.luau b/tests/ffi/isInteger.luau new file mode 100644 index 00000000..1084b8f0 --- /dev/null +++ b/tests/ffi/isInteger.luau @@ -0,0 +1,10 @@ +--!nocheck +--!nolint + +local ffi = require("@lune/ffi") + +local int = 0b1 +local float = 0.5 + +assert(ffi.isInteger(int) == true, "ffi.isInteger(int) == true failed") +assert(ffi.isInteger(float) == false, "ffi.isInteger(float) == false failed") diff --git a/tests/ffi/ptr.luau b/tests/ffi/ptr.luau deleted file mode 100644 index c62eadf3..00000000 --- a/tests/ffi/ptr.luau +++ /dev/null @@ -1,33 +0,0 @@ - -local ffi = require("@lune/ffi") - --- ptr size test -assert( - ffi.i32:ptr().size == ffi.i64:ptr().size, - "All of Ptr.size must be same.\n".. - "ffi.i32:ptr().size == ffi.i64:ptr().size failed" -) - --- inner test -local i32ptr = ffi.i32:ptr() -assert( - rawequal(ffi.i32, i32ptr.inner), - "Ptr.inner must be same with their parent\n".. - "raweq ffi.i32 == ffi.i32:ptr().inner failed" -) -assert( - rawequal(i32ptr, i32ptr:ptr().inner), - "Ptr.inner must be same with their parent\n".. - "raweq i32ptr == i32ptr:ptr().inner failed" -) -assert( - rawequal(i32ptr, i32ptr:ptr().inner:ptr().inner:ptr().inner), - "Ptr.inner must be same with their parent\n".. - "raweq i32ptr == i32ptr:ptr().inner:ptr().inner:ptr().inner failed" -) - --- deep ptr test -local ok,err = pcall(function() - i32ptr:ptr():ptr():ptr():ptr():ptr():ptr():ptr() -end) -assert(ok,`Deep ptr test failed.\n{err}`) diff --git a/tests/ffi/ref-hold-box.luau b/tests/ffi/ref-hold-box.luau new file mode 100644 index 00000000..f6f1490e --- /dev/null +++ b/tests/ffi/ref-hold-box.luau @@ -0,0 +1,15 @@ +--!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") diff --git a/tests/ffi/struct.luau b/tests/ffi/struct.luau deleted file mode 100644 index e1c1f8df..00000000 --- a/tests/ffi/struct.luau +++ /dev/null @@ -1,2 +0,0 @@ - -local ffi = require("@lune/ffi") diff --git a/tests/ffi/types/arr.luau b/tests/ffi/types/arr.luau new file mode 100644 index 00000000..e69de29b diff --git a/tests/ffi/types/fn.luau b/tests/ffi/types/fn.luau new file mode 100644 index 00000000..e69de29b diff --git a/tests/ffi/types/ptr.luau b/tests/ffi/types/ptr.luau new file mode 100644 index 00000000..cdbc2fe7 --- /dev/null +++ b/tests/ffi/types/ptr.luau @@ -0,0 +1,32 @@ +--!nocheck +--!nolint + +local ffi = require("@lune/ffi") + +-- ptr size test +assert( + ffi.i32:ptr().size == ffi.i64:ptr().size, + "All of Ptr.size must be same.\n" .. "ffi.i32:ptr().size == ffi.i64:ptr().size failed" +) + +-- inner test +local i32ptr = ffi.i32:ptr() +assert( + rawequal(ffi.i32, i32ptr.inner), + "Ptr.inner must be same with their parent\n" .. "raweq ffi.i32 == ffi.i32:ptr().inner failed" +) +assert( + rawequal(i32ptr, i32ptr:ptr().inner), + "Ptr.inner must be same with their parent\n" .. "raweq i32ptr == i32ptr:ptr().inner failed" +) +assert( + rawequal(i32ptr, i32ptr:ptr().inner:ptr().inner:ptr().inner), + "Ptr.inner must be same with their parent\n" + .. "raweq i32ptr == i32ptr:ptr().inner:ptr().inner:ptr().inner failed" +) + +-- deep ptr test +local ok, err = pcall(function() + i32ptr:ptr():ptr():ptr():ptr():ptr():ptr():ptr() +end) +assert(ok, `Deep ptr test failed.\n{err}`) diff --git a/tests/ffi/types/struct.luau b/tests/ffi/types/struct.luau new file mode 100644 index 00000000..a955e718 --- /dev/null +++ b/tests/ffi/types/struct.luau @@ -0,0 +1,12 @@ +--!nocheck +--!nolint + +local ffi = require("@lune/ffi") + +local i32ptr = ffi.i32:ptr() +local struct = ffi.struct({ i32ptr, ffi.i32 }) + +assert(rawequal(struct:field(0), i32ptr), "Struct get field failed") +assert(rawequal(struct:field(1), ffi.i32), "Struct get field failed") + +-- offset(2) should fail From 11bf0b6896959ab35c646988867e3244ca550745 Mon Sep 17 00:00:00 2001 From: qwreey Date: Fri, 6 Sep 2024 11:06:21 +0000 Subject: [PATCH 15/79] Remove unused codes and strange safety features (#243) --- crates/lune-std-ffi/src/c/c_arr.rs | 11 +- crates/lune-std-ffi/src/c/c_struct.rs | 6 +- crates/lune-std-ffi/src/c/c_type.rs | 12 +- crates/lune-std-ffi/src/c/types/f32.rs | 6 +- crates/lune-std-ffi/src/c/types/f64.rs | 6 +- crates/lune-std-ffi/src/c/types/i128.rs | 6 +- crates/lune-std-ffi/src/c/types/i16.rs | 6 +- crates/lune-std-ffi/src/c/types/i32.rs | 6 +- crates/lune-std-ffi/src/c/types/i64.rs | 6 +- crates/lune-std-ffi/src/c/types/i8.rs | 6 +- crates/lune-std-ffi/src/c/types/isize.rs | 6 +- crates/lune-std-ffi/src/c/types/mod.rs | 108 +-------------- crates/lune-std-ffi/src/c/types/u128.rs | 6 +- crates/lune-std-ffi/src/c/types/u16.rs | 6 +- crates/lune-std-ffi/src/c/types/u32.rs | 6 +- crates/lune-std-ffi/src/c/types/u64.rs | 6 +- crates/lune-std-ffi/src/c/types/u8.rs | 6 +- crates/lune-std-ffi/src/c/types/usize.rs | 6 +- crates/lune-std-ffi/src/ffi/ffi_box/flag.rs | 15 +++ .../src/ffi/{ffi_box.rs => ffi_box/mod.rs} | 127 ++++++++---------- .../lune-std-ffi/src/ffi/ffi_native/call.rs | 4 +- .../lune-std-ffi/src/ffi/ffi_native/cast.rs | 6 +- .../src/ffi/ffi_native/convert.rs | 6 +- .../ffi/ffi_native/{readwrite.rs => data.rs} | 17 +-- crates/lune-std-ffi/src/ffi/ffi_native/mod.rs | 6 +- crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs | 34 +++-- crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs | 46 +------ crates/lune-std-ffi/src/ffi/mod.rs | 21 ++- 28 files changed, 191 insertions(+), 312 deletions(-) create mode 100644 crates/lune-std-ffi/src/ffi/ffi_box/flag.rs rename crates/lune-std-ffi/src/ffi/{ffi_box.rs => ffi_box/mod.rs} (60%) rename crates/lune-std-ffi/src/ffi/ffi_native/{readwrite.rs => data.rs} (60%) diff --git a/crates/lune-std-ffi/src/c/c_arr.rs b/crates/lune-std-ffi/src/c/c_arr.rs index 33625a82..fc7ddf8e 100644 --- a/crates/lune-std-ffi/src/c/c_arr.rs +++ b/crates/lune-std-ffi/src/c/c_arr.rs @@ -10,7 +10,7 @@ use super::{ }; use crate::ffi::{ ffi_association::{get_association, set_association}, - FfiBox, GetNativeDataHandle, NativeConvert, NativeDataHandle, NativeSize, + FfiBox, GetNativeData, NativeConvert, NativeData, NativeSize, }; // This is a series of some type. @@ -110,7 +110,7 @@ impl NativeConvert for CArr { &self, lua: &'lua Lua, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let LuaValue::Table(ref table) = value else { @@ -134,7 +134,7 @@ impl NativeConvert for CArr { &self, lua: &'lua Lua, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { let table = lua.create_table_with_capacity(self.length, 0)?; for i in 0..self.length { @@ -187,9 +187,6 @@ impl LuaUserData for CArr { 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()) { - return Err(LuaError::external("Unreadable data handle")); - } unsafe { this.luavalue_from(lua, offset, data_handle) } }, @@ -203,7 +200,7 @@ impl LuaUserData for CArr { if !data_handle.check_boundary(offset, this.size) { return Err(LuaError::external("Out of bounds")); } - if !data_handle.checek_writable(offset, this.size) { + if !data_handle.is_writable() { return Err(LuaError::external("Unwritable data handle")); } diff --git a/crates/lune-std-ffi/src/c/c_struct.rs b/crates/lune-std-ffi/src/c/c_struct.rs index 16a399b6..ff51b44e 100644 --- a/crates/lune-std-ffi/src/c/c_struct.rs +++ b/crates/lune-std-ffi/src/c/c_struct.rs @@ -10,7 +10,7 @@ use super::{ }; use crate::ffi::{ ffi_association::{get_association, set_association}, - FfiBox, GetNativeDataHandle, NativeConvert, NativeDataHandle, NativeSignedness, NativeSize, + FfiBox, GetNativeData, NativeConvert, NativeData, NativeSignedness, NativeSize, FFI_STATUS_NAMES, }; @@ -135,7 +135,7 @@ impl NativeConvert for CStruct { &self, lua: &'lua Lua, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let LuaValue::Table(ref table) = value else { @@ -156,7 +156,7 @@ impl NativeConvert for CStruct { &self, lua: &'lua Lua, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { let table = lua.create_table_with_capacity(self.conv.len(), 0)?; for (i, conv) in self.conv.iter().enumerate() { diff --git a/crates/lune-std-ffi/src/c/c_type.rs b/crates/lune-std-ffi/src/c/c_type.rs index 7ad121d9..bf1ff458 100644 --- a/crates/lune-std-ffi/src/c/c_type.rs +++ b/crates/lune-std-ffi/src/c/c_type.rs @@ -9,8 +9,8 @@ use num::cast::AsPrimitive; use super::{association_names::CTYPE_STATIC, c_helper::get_ensured_size, CArr, CPtr}; use crate::ffi::{ - ffi_association::set_association, native_num_cast, FfiBox, GetNativeDataHandle, NativeConvert, - NativeDataHandle, NativeSignedness, NativeSize, + ffi_association::set_association, native_num_cast, FfiBox, GetNativeData, NativeConvert, + NativeData, NativeSignedness, NativeSize, }; // We can't get a CType through mlua, something like @@ -42,8 +42,8 @@ pub trait CTypeCast { fn try_cast_num( &self, ctype: &LuaAnyUserData, - from: &Ref, - into: &Ref, + from: &Ref, + into: &Ref, ) -> LuaResult> where T: AsPrimitive, @@ -62,8 +62,8 @@ pub trait CTypeCast { &self, from_ctype: &LuaAnyUserData, into_ctype: &LuaAnyUserData, - _from: &Ref, - _into: &Ref, + _from: &Ref, + _into: &Ref, ) -> LuaResult<()> { Err(Self::cast_failed_with(self, from_ctype, into_ctype)) } diff --git a/crates/lune-std-ffi/src/c/types/f32.rs b/crates/lune-std-ffi/src/c/types/f32.rs index ffe72efd..8f6556f9 100644 --- a/crates/lune-std-ffi/src/c/types/f32.rs +++ b/crates/lune-std-ffi/src/c/types/f32.rs @@ -5,7 +5,7 @@ use mlua::prelude::*; use num::cast::AsPrimitive; use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; +use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; impl NativeSignedness for CType { fn get_signedness(&self) -> bool { @@ -19,7 +19,7 @@ impl NativeConvert for CType { _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: f32 = match value { @@ -46,7 +46,7 @@ impl NativeConvert for CType { lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { 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 6970c436..fd989f2d 100644 --- a/crates/lune-std-ffi/src/c/types/f64.rs +++ b/crates/lune-std-ffi/src/c/types/f64.rs @@ -5,7 +5,7 @@ use mlua::prelude::*; use num::cast::AsPrimitive; use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; +use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; impl NativeSignedness for CType { fn get_signedness(&self) -> bool { @@ -19,7 +19,7 @@ impl NativeConvert for CType { _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: f64 = match value { @@ -46,7 +46,7 @@ impl NativeConvert for CType { lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { 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 320f6737..156c40a3 100644 --- a/crates/lune-std-ffi/src/c/types/i128.rs +++ b/crates/lune-std-ffi/src/c/types/i128.rs @@ -5,7 +5,7 @@ use mlua::prelude::*; use num::cast::AsPrimitive; use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; +use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; impl NativeSignedness for CType { fn get_signedness(&self) -> bool { @@ -19,7 +19,7 @@ impl NativeConvert for CType { _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: i128 = match value { @@ -46,7 +46,7 @@ impl NativeConvert for CType { lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { 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 d3b883f0..5198b4ed 100644 --- a/crates/lune-std-ffi/src/c/types/i16.rs +++ b/crates/lune-std-ffi/src/c/types/i16.rs @@ -5,7 +5,7 @@ use mlua::prelude::*; use num::cast::AsPrimitive; use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; +use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; impl NativeSignedness for CType { fn get_signedness(&self) -> bool { @@ -19,7 +19,7 @@ impl NativeConvert for CType { _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: i16 = match value { @@ -46,7 +46,7 @@ impl NativeConvert for CType { lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; Ok(value) diff --git a/crates/lune-std-ffi/src/c/types/i32.rs b/crates/lune-std-ffi/src/c/types/i32.rs index b4108c4c..8a3b7a59 100644 --- a/crates/lune-std-ffi/src/c/types/i32.rs +++ b/crates/lune-std-ffi/src/c/types/i32.rs @@ -5,7 +5,7 @@ use mlua::prelude::*; use num::cast::AsPrimitive; use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; +use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; impl NativeSignedness for CType { fn get_signedness(&self) -> bool { @@ -19,7 +19,7 @@ impl NativeConvert for CType { _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: i32 = match value { @@ -46,7 +46,7 @@ impl NativeConvert for CType { lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { 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 c5539848..f34cbab6 100644 --- a/crates/lune-std-ffi/src/c/types/i64.rs +++ b/crates/lune-std-ffi/src/c/types/i64.rs @@ -5,7 +5,7 @@ use mlua::prelude::*; use num::cast::AsPrimitive; use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; +use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; impl NativeSignedness for CType { fn get_signedness(&self) -> bool { @@ -19,7 +19,7 @@ impl NativeConvert for CType { _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: i64 = match value { @@ -46,7 +46,7 @@ impl NativeConvert for CType { lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { 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 367723eb..859a394a 100644 --- a/crates/lune-std-ffi/src/c/types/i8.rs +++ b/crates/lune-std-ffi/src/c/types/i8.rs @@ -5,7 +5,7 @@ use mlua::prelude::*; use num::cast::AsPrimitive; use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; +use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; impl NativeSignedness for CType { fn get_signedness(&self) -> bool { @@ -19,7 +19,7 @@ impl NativeConvert for CType { _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: i8 = match value { @@ -42,7 +42,7 @@ impl NativeConvert for CType { lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { 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 f7a779a9..e98b3fb9 100644 --- a/crates/lune-std-ffi/src/c/types/isize.rs +++ b/crates/lune-std-ffi/src/c/types/isize.rs @@ -5,7 +5,7 @@ use mlua::prelude::*; use num::cast::AsPrimitive; use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; +use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; impl NativeSignedness for CType { fn get_signedness(&self) -> bool { @@ -19,7 +19,7 @@ impl NativeConvert for CType { _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: isize = match value { @@ -46,7 +46,7 @@ impl NativeConvert for CType { lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { 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 9863e75e..3beb647f 100644 --- a/crates/lune-std-ffi/src/c/types/mod.rs +++ b/crates/lune-std-ffi/src/c/types/mod.rs @@ -8,7 +8,7 @@ use mlua::prelude::*; use num::cast::AsPrimitive; use super::{CType, CTypeCast}; -use crate::ffi::{NativeConvert, NativeDataHandle}; +use crate::ffi::{NativeConvert, NativeData}; pub mod f32; pub mod f64; @@ -54,8 +54,8 @@ where &self, from_ctype: &LuaAnyUserData, into_ctype: &LuaAnyUserData, - from: &Ref, - into: &Ref, + from: &Ref, + into: &Ref, ) -> LuaResult<()> { cast_nums!( T, self, into_ctype, from_ctype, from, into, u8, u16, u32, u64, u128, i8, i16, i128, @@ -128,106 +128,8 @@ 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 -// ) -// } - -// Use UB method, but safe. because we use ffi_association to ensure children alive -// Much faster then get NativeConvert handle everytime from lua table +// Use UB method, but safe. because we use ffi_association to ensure children keep alive +// Much faster then get NativeConvert handle every time from lua table // it's spam of table.get(), if ud.is::() { ud.borrow::()? ... } macro_rules! define_get_ctype_conv { ($userdata:ident, $f:ty, $( $c:ty ),*) => { diff --git a/crates/lune-std-ffi/src/c/types/u128.rs b/crates/lune-std-ffi/src/c/types/u128.rs index 71e75760..8effc688 100644 --- a/crates/lune-std-ffi/src/c/types/u128.rs +++ b/crates/lune-std-ffi/src/c/types/u128.rs @@ -5,7 +5,7 @@ use mlua::prelude::*; use num::cast::AsPrimitive; use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; +use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; impl NativeSignedness for CType { fn get_signedness(&self) -> bool { @@ -19,7 +19,7 @@ impl NativeConvert for CType { _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: u128 = match value { @@ -46,7 +46,7 @@ impl NativeConvert for CType { lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { 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 4debe03a..fb84ece5 100644 --- a/crates/lune-std-ffi/src/c/types/u16.rs +++ b/crates/lune-std-ffi/src/c/types/u16.rs @@ -5,7 +5,7 @@ use mlua::prelude::*; use num::cast::AsPrimitive; use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; +use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; impl NativeSignedness for CType { fn get_signedness(&self) -> bool { @@ -20,7 +20,7 @@ impl NativeConvert for CType { _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: u16 = match value { @@ -47,7 +47,7 @@ impl NativeConvert for CType { lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { 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 6e8e3d45..21a4dad9 100644 --- a/crates/lune-std-ffi/src/c/types/u32.rs +++ b/crates/lune-std-ffi/src/c/types/u32.rs @@ -5,7 +5,7 @@ use mlua::prelude::*; use num::cast::AsPrimitive; use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; +use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; impl NativeSignedness for CType { fn get_signedness(&self) -> bool { @@ -19,7 +19,7 @@ impl NativeConvert for CType { _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: u32 = match value { @@ -46,7 +46,7 @@ impl NativeConvert for CType { lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { 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 34972c1d..7aac4c44 100644 --- a/crates/lune-std-ffi/src/c/types/u64.rs +++ b/crates/lune-std-ffi/src/c/types/u64.rs @@ -5,7 +5,7 @@ use mlua::prelude::*; use num::cast::AsPrimitive; use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; +use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; impl NativeSignedness for CType { fn get_signedness(&self) -> bool { @@ -19,7 +19,7 @@ impl NativeConvert for CType { _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: u64 = match value { @@ -46,7 +46,7 @@ impl NativeConvert for CType { lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { 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 20ac295b..b3cda2ad 100644 --- a/crates/lune-std-ffi/src/c/types/u8.rs +++ b/crates/lune-std-ffi/src/c/types/u8.rs @@ -5,7 +5,7 @@ use mlua::prelude::*; use num::cast::AsPrimitive; use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; +use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; impl NativeSignedness for CType { fn get_signedness(&self) -> bool { @@ -20,7 +20,7 @@ impl NativeConvert for CType { _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: u8 = match value { @@ -45,7 +45,7 @@ impl NativeConvert for CType { lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { 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 063db46c..b5ddfbb9 100644 --- a/crates/lune-std-ffi/src/c/types/usize.rs +++ b/crates/lune-std-ffi/src/c/types/usize.rs @@ -5,7 +5,7 @@ use mlua::prelude::*; use num::cast::AsPrimitive; use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness}; +use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; impl NativeSignedness for CType { fn get_signedness(&self) -> bool { @@ -19,7 +19,7 @@ impl NativeConvert for CType { _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: usize = match value { @@ -46,7 +46,7 @@ impl NativeConvert for CType { lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; Ok(value) diff --git a/crates/lune-std-ffi/src/ffi/ffi_box/flag.rs b/crates/lune-std-ffi/src/ffi/ffi_box/flag.rs new file mode 100644 index 00000000..34e712f5 --- /dev/null +++ b/crates/lune-std-ffi/src/ffi/ffi_box/flag.rs @@ -0,0 +1,15 @@ +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.rs b/crates/lune-std-ffi/src/ffi/ffi_box/mod.rs similarity index 60% rename from crates/lune-std-ffi/src/ffi/ffi_box.rs rename to crates/lune-std-ffi/src/ffi/ffi_box/mod.rs index 9229b8d3..6e61eeca 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_box.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_box/mod.rs @@ -1,17 +1,28 @@ -use std::boxed::Box; +use std::{alloc, alloc::Layout, boxed::Box, mem::ManuallyDrop, ptr}; use mlua::prelude::*; use super::{ association_names::REF_INNER, + bit_mask::*, ffi_association::set_association, - ffi_ref::{FfiRef, FfiRefBounds, FfiRefFlag, FfiRefFlagList, UNSIZED_BOUNDS}, - NativeDataHandle, + ffi_ref::{FfiRef, FfiRefBounds, FfiRefFlag, FfiRefFlagList}, + NativeData, }; +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(), +); // It is an untyped, sized memory area that Lua can manage. // This area is safe within Lua. Operations have their boundaries checked. @@ -22,46 +33,48 @@ const BOX_REF_FLAGS: FfiRefFlagList = FfiRefFlagList::new( // rather, it creates more heap space, so it should be used appropriately // where necessary. -struct RefData { - address: usize, - offset: usize, - lua_inner_id: i32, -} - pub struct FfiBox { - data: Box<[u8]>, - refs: Vec, + flags: u8, + data: ManuallyDrop>, } +const FFI_BOX_PRINT_MAX_LENGTH: usize = 1024; + impl FfiBox { // For efficiency, it is initialized non-zeroed. pub fn new(size: usize) -> Self { - // Create new vector to allocate heap memory. sized with 'size' - let mut vec_heap = Vec::::with_capacity(size); - - // It is safe to have a length equal to the capacity - #[allow(clippy::uninit_vec)] - unsafe { - vec_heap.set_len(size); - } + let slice = unsafe { + Box::from_raw(ptr::slice_from_raw_parts_mut( + alloc::alloc(Layout::array::(size).unwrap()), + size, + )) + }; Self { - data: vec_heap.into_boxed_slice(), - refs: vec![], + flags: 0, + data: ManuallyDrop::new(slice), } } // pub fn copy(&self, target: &mut FfiBox) {} - // Todo: if too big, print as another format pub fn stringify(&self) -> String { + if self.size() > FFI_BOX_PRINT_MAX_LENGTH * 2 { + // FIXME + // Todo: if too big, print as another format + return String::from("exceed"); + } let mut buff: String = String::with_capacity(self.size() * 2); - for value in &self.data { + for value in self.data.iter() { buff.push_str(format!("{:x}", value.to_be()).as_str()); } buff } + pub fn leak(&mut self) { + self.flags = u8_set(self.flags, FfiBoxFlag::Leaked.value(), true); + } + // Make FfiRef from box, with boundary checking pub fn luaref<'lua>( lua: &'lua Lua, @@ -70,7 +83,7 @@ impl FfiBox { ) -> LuaResult> { let target = this.borrow::()?; let mut bounds = FfiRefBounds::new(0, target.size()); - let mut ptr = target.get_ptr(); + let mut ptr = unsafe { target.get_pointer(0) }; // Calculate offset if let Some(t) = offset { @@ -81,14 +94,10 @@ impl FfiBox { t ))); } - ptr = unsafe { target.get_ptr().byte_offset(t) }; + ptr = unsafe { target.get_pointer(t) }; bounds = bounds.offset(t); } - // Lua should not be able to deref a box. - // To deref a box space is to allow lua to read any space, - // which has security issues and is ultimately dangerous. - // Therefore, box:ref():deref() is not allowed. let luaref = lua.create_userdata(FfiRef::new(ptr.cast(), BOX_REF_FLAGS, bounds))?; // Makes box alive longer then ref @@ -97,63 +106,42 @@ impl FfiBox { Ok(luaref) } - // Make FfiRef from box, without any safe features - pub fn luaref_unsafe<'lua>( - lua: &'lua Lua, - this: LuaAnyUserData<'lua>, - offset: Option, - ) -> LuaResult> { - let target = this.borrow::()?; - let mut ptr = target.get_ptr(); - - // Calculate offset - if let Some(t) = offset { - ptr = unsafe { target.get_ptr().byte_offset(t) }; - } - - lua.create_userdata(FfiRef::new( - ptr.cast(), - FfiRefFlagList::all(), - UNSIZED_BOUNDS, - )) + pub unsafe fn drop(&mut self) { + ManuallyDrop::drop(&mut self.data); } // Fill every field with 0 pub fn zero(&mut self) { - self.data.fill(0u8); + self.data.fill(0); } // Get size of box pub fn size(&self) -> usize { self.data.len() } +} - // Get raw ptr - pub fn get_ptr(&self) -> *mut u8 { - self.data.as_ptr().cast_mut() +impl Drop for FfiBox { + fn drop(&mut self) { + if u8_test_not(self.flags, FfiBoxFlag::Leaked.value()) { + unsafe { self.drop() }; + } } } -impl NativeDataHandle for FfiBox { +impl NativeData 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, offset: isize, size: usize) -> bool { - true - } - // FIXME - fn check_readable(&self, offset: isize, size: usize) -> bool { - true - } - fn mark_ref(&self, userdata: &LuaAnyUserData, offset: isize, ptr: usize) -> LuaResult<()> { - Ok(()) - } unsafe fn get_pointer(&self, offset: isize) -> *mut () { - self.get_ptr().byte_offset(offset).cast::<()>() + self.data + .as_ptr() + .byte_offset(offset) + .cast_mut() + .cast::<()>() } } @@ -167,16 +155,17 @@ impl LuaUserData for FfiBox { this.borrow_mut::()?.zero(); Ok(this) }); - methods.add_function( - "ref", + methods.add_function_mut( + "leak", |lua, (this, offset): (LuaAnyUserData, Option)| { + this.borrow_mut::()?.leak(); FfiBox::luaref(lua, this, offset) }, ); methods.add_function( - "unsafeRef", + "ref", |lua, (this, offset): (LuaAnyUserData, Option)| { - FfiBox::luaref_unsafe(lua, this, offset) + FfiBox::luaref(lua, this, offset) }, ); methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| Ok(this.stringify())); diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/call.rs b/crates/lune-std-ffi/src/ffi/ffi_native/call.rs index b551484a..164bfbc0 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/call.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/call.rs @@ -2,7 +2,7 @@ use std::cell::Ref; use mlua::prelude::*; -use super::NativeDataHandle; +use super::NativeData; // Handle native data, provide type conversion between luavalue and native types pub trait NativeCall { @@ -11,7 +11,7 @@ pub trait NativeCall { &self, lua: &Lua, arg: LuaMultiValue, - ret: &Ref, + ret: &Ref, ) -> LuaResult<()>; // Call lua closure 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 31d7775d..14fbdad4 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/cast.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/cast.rs @@ -5,14 +5,14 @@ use std::cell::Ref; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::NativeDataHandle; +use super::NativeData; // Cast T as U #[inline(always)] pub fn native_num_cast( - from: &Ref, - into: &Ref, + from: &Ref, + into: &Ref, ) -> LuaResult<()> where T: AsPrimitive, 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 76007500..073b0802 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/convert.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/convert.rs @@ -4,7 +4,7 @@ use std::cell::Ref; use mlua::prelude::*; -use super::NativeDataHandle; +use super::NativeData; // Handle native data, provide type conversion between luavalue and native types pub trait NativeConvert { @@ -14,7 +14,7 @@ pub trait NativeConvert { lua: &'lua Lua, // type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()>; @@ -24,6 +24,6 @@ pub trait NativeConvert { lua: &'lua Lua, // type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult>; } diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/readwrite.rs b/crates/lune-std-ffi/src/ffi/ffi_native/data.rs similarity index 60% rename from crates/lune-std-ffi/src/ffi/ffi_native/readwrite.rs rename to crates/lune-std-ffi/src/ffi/ffi_native/data.rs index 2f96eaa5..471eb506 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/readwrite.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/data.rs @@ -5,28 +5,25 @@ use mlua::prelude::*; use super::super::{FfiBox, FfiRef}; -pub trait NativeDataHandle { +pub trait NativeData { fn check_boundary(&self, offset: isize, size: usize) -> bool; - fn check_readable(&self, offset: isize, size: usize) -> bool; - fn checek_writable(&self, offset: isize, size: usize) -> bool; - fn mark_ref(&self, userdata: &LuaAnyUserData, offset: isize, ptr: usize) -> LuaResult<()>; unsafe fn get_pointer(&self, offset: isize) -> *mut (); } -pub trait GetNativeDataHandle { - fn get_data_handle(&self) -> LuaResult>; +pub trait GetNativeData { + 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> { +impl GetNativeData for LuaAnyUserData<'_> { + fn get_data_handle(&self) -> LuaResult> { if self.is::() { - Ok(self.borrow::()? as Ref) + Ok(self.borrow::()? as Ref) } else if self.is::() { - Ok(self.borrow::()? as Ref) + Ok(self.borrow::()? as Ref) // } else if self.is::() { // Ok(self.borrow::()? as Ref) } else { 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 9ecfe3e8..af7ac725 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,7 @@ mod call; mod cast; mod convert; -mod readwrite; +mod data; pub trait NativeSize { fn get_size(&self) -> usize; @@ -14,6 +14,6 @@ pub trait NativeSignedness { } pub use self::{ - call::NativeCall, cast::native_num_cast, convert::NativeConvert, - readwrite::GetNativeDataHandle, readwrite::NativeDataHandle, + call::NativeCall, cast::native_num_cast, convert::NativeConvert, data::GetNativeData, + data::NativeData, }; 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 b6a2ca7f..b1dbfdee 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs @@ -1,11 +1,12 @@ use super::super::bit_mask::*; pub enum FfiRefFlag { - Dereferenceable, - Readable, - Writable, - Offsetable, - Function, + // Dereferenceable, + // Readable, + // Writable, + // Offsetable, + // Function, + // Mutable, } impl FfiRefFlag { pub const fn value(&self) -> u8 { @@ -15,6 +16,7 @@ impl FfiRefFlag { Self::Writable => U8_MASK3, Self::Offsetable => U8_MASK4, Self::Function => U8_MASK5, + Self::Mutable => U8_MASK6, } } } @@ -45,28 +47,34 @@ impl FfiRefFlagList { } } pub fn is_dereferenceable(&self) -> bool { - U8_TEST!(self.0, U8_MASK1) + U8_TEST!(self.0, FfiRefFlag::Dereferenceable.value()) } pub fn set_dereferenceable(&mut self, value: bool) { - self.set(value, U8_MASK1); + self.set(value, FfiRefFlag::Dereferenceable.value()); } pub fn is_readable(&self) -> bool { - U8_TEST!(self.0, U8_MASK2) + U8_TEST!(self.0, FfiRefFlag::Readable.value()) } pub fn set_readable(&mut self, value: bool) { - self.set(value, U8_MASK2); + self.set(value, FfiRefFlag::Readable.value()); } pub fn is_writable(&self) -> bool { - U8_TEST!(self.0, U8_MASK3) + U8_TEST!(self.0, FfiRefFlag::Writable.value()) } pub fn set_writable(&mut self, value: bool) { - self.set(value, U8_MASK2); + self.set(value, FfiRefFlag::Writable.value()); } pub fn is_offsetable(&self) -> bool { - U8_TEST!(self.0, U8_MASK4) + U8_TEST!(self.0, FfiRefFlag::Offsetable.value()) } pub fn set_offsetable(&mut self, value: bool) { - self.set(value, U8_MASK2); + 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 { 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 ccd5589f..d65178f7 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs @@ -5,7 +5,7 @@ use mlua::prelude::*; use super::{ association_names::REF_INNER, ffi_association::{get_association, set_association}, - NativeDataHandle, + NativeData, }; mod bounds; @@ -29,17 +29,14 @@ pub struct FfiRef { ptr: *mut (), pub flags: FfiRefFlagList, pub boundary: FfiRefBounds, - // Save lua ffibox pointer - pub inner: Option<*const dyn NativeDataHandle>, } impl FfiRef { - pub fn new(ptr: *mut (), flags: FfiRefFlagList, range: FfiRefBounds) -> Self { + pub fn new(ptr: *mut (), flags: FfiRefFlagList, boundary: FfiRefBounds) -> Self { Self { ptr, flags, - boundary: range, - inner: None, + boundary, } } @@ -65,10 +62,6 @@ impl FfiRef { Ok(luaref) } - pub fn get_ptr(&self) -> *mut () { - self.ptr - } - pub unsafe fn deref(&self) -> LuaResult { self.flags .is_dereferenceable() @@ -122,41 +115,12 @@ impl FfiRef { } } -impl NativeDataHandle for FfiRef { +impl NativeData for FfiRef { fn check_boundary(&self, offset: isize, size: usize) -> bool { self.boundary.check_sized(offset, size) } - fn checek_writable(&self, offset: isize, size: usize) -> bool { - // If unreadable ref - if !self.flags.is_writable() { - return false; - } - - // If ref have inner luabox - if let Some(inner) = self.inner { - return unsafe { inner.as_ref().unwrap().checek_writable(offset, size) }; - } - - true - } - fn check_readable(&self, offset: isize, size: usize) -> bool { - // If unreadable ref - if !self.flags.is_readable() { - return false; - } - - // If ref have inner luabox - if let Some(inner) = self.inner { - return unsafe { inner.as_ref().unwrap().check_readable(offset, size) }; - } - - true - } - fn mark_ref(&self, userdata: &LuaAnyUserData, offset: isize, ptr: usize) -> LuaResult<()> { - Ok(()) - } unsafe fn get_pointer(&self, offset: isize) -> *mut () { - self.get_ptr().byte_offset(offset) + self.ptr.byte_offset(offset) } } diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index 15263167..97687e0f 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -11,8 +11,7 @@ pub use self::{ ffi_box::FfiBox, ffi_lib::FfiLib, ffi_native::{ - native_num_cast, GetNativeDataHandle, NativeConvert, NativeDataHandle, NativeSignedness, - NativeSize, + native_num_cast, GetNativeData, NativeConvert, NativeData, NativeSignedness, NativeSize, }, ffi_ref::{create_nullptr, FfiRef}, }; @@ -42,13 +41,21 @@ pub mod bit_mask { pub const U8_MASK7: u8 = 64; pub const U8_MASK8: u8 = 128; - macro_rules! U8_TEST { - ($val:expr, $mask:ident) => { - ($val & $mask != 0) - }; + pub fn u8_test(bits: u8, mask: u8) -> bool { + bits & mask != 0 } - pub(crate) use U8_TEST; + pub fn u8_test_not(bits: u8, mask: u8) -> bool { + bits & mask == 0 + } + + pub fn u8_set(bits: u8, mask: u8, val: bool) -> u8 { + if val { + bits | mask + } else { + bits & !mask + } + } } pub fn is_integer(num: LuaValue) -> bool { From 4d0fd9d80a6c9839e2c42d0f231f6e18b3fc85bd Mon Sep 17 00:00:00 2001 From: qwreey Date: Sat, 12 Oct 2024 15:20:49 +0000 Subject: [PATCH 16/79] Implement callable and closure (#243) --- crates/lune-std-ffi/src/c/c_fn.rs | 50 +++++--- crates/lune-std-ffi/src/c/c_helper.rs | 15 ++- crates/lune-std-ffi/src/c/c_struct.rs | 4 +- crates/lune-std-ffi/src/c/c_type.rs | 4 +- crates/lune-std-ffi/src/ffi/ffi_box/flag.rs | 2 - crates/lune-std-ffi/src/ffi/ffi_box/mod.rs | 20 ++-- crates/lune-std-ffi/src/ffi/ffi_callable.rs | 109 ++++++++++++++++++ crates/lune-std-ffi/src/ffi/ffi_closure.rs | 106 +++++++++++++++++ crates/lune-std-ffi/src/ffi/ffi_lib.rs | 12 +- crates/lune-std-ffi/src/ffi/ffi_native/arg.rs | 15 +++ .../lune-std-ffi/src/ffi/ffi_native/call.rs | 19 --- .../src/ffi/ffi_native/convert.rs | 9 +- .../lune-std-ffi/src/ffi/ffi_native/data.rs | 2 + crates/lune-std-ffi/src/ffi/ffi_native/mod.rs | 8 +- .../lune-std-ffi/src/ffi/ffi_native/result.rs | 11 ++ crates/lune-std-ffi/src/ffi/ffi_raw.rs | 11 +- crates/lune-std-ffi/src/ffi/ffi_ref/bounds.rs | 11 ++ crates/lune-std-ffi/src/ffi/ffi_ref/flag.rs | 24 ++++ crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs | 84 -------------- crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs | 37 ++++-- crates/lune-std-ffi/src/ffi/mod.rs | 15 ++- crates/lune-std-ffi/src/lib.rs | 16 +-- 22 files changed, 399 insertions(+), 185 deletions(-) create mode 100644 crates/lune-std-ffi/src/ffi/ffi_callable.rs create mode 100644 crates/lune-std-ffi/src/ffi/ffi_closure.rs create mode 100644 crates/lune-std-ffi/src/ffi/ffi_native/arg.rs delete mode 100644 crates/lune-std-ffi/src/ffi/ffi_native/call.rs create mode 100644 crates/lune-std-ffi/src/ffi/ffi_native/result.rs create mode 100644 crates/lune-std-ffi/src/ffi/ffi_ref/flag.rs delete mode 100644 crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs 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)] From 7ce5be248f13a15e383d286015fbd0518db89340 Mon Sep 17 00:00:00 2001 From: qwreey Date: Mon, 14 Oct 2024 03:15:16 +0000 Subject: [PATCH 17/79] Add uninit ref and Implement Callable (#243) --- crates/lune-std-ffi/src/c/c_fn.rs | 75 ++++++++++++---- crates/lune-std-ffi/src/c/mod.rs | 4 + crates/lune-std-ffi/src/ffi/ffi_callable.rs | 88 +++++-------------- crates/lune-std-ffi/src/ffi/ffi_native/arg.rs | 2 +- crates/lune-std-ffi/src/ffi/ffi_native/mod.rs | 12 ++- .../lune-std-ffi/src/ffi/ffi_native/result.rs | 12 +-- crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs | 30 +++++-- crates/lune-std-ffi/src/ffi/mod.rs | 3 +- 8 files changed, 126 insertions(+), 100 deletions(-) diff --git a/crates/lune-std-ffi/src/c/c_fn.rs b/crates/lune-std-ffi/src/c/c_fn.rs index dd6e2fcb..d6cfbbf1 100644 --- a/crates/lune-std-ffi/src/c/c_fn.rs +++ b/crates/lune-std-ffi/src/c/c_fn.rs @@ -1,13 +1,20 @@ +use std::ptr; + 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 super::{ + association_names::{CALLABLE_CFN, CALLABLE_REF, CFN_ARGS, CFN_RESULT}, + c_helper::{ + get_conv, get_conv_list_from_table, libffi_type_from_userdata, libffi_type_list_from_table, + }, }; +use crate::ffi::bit_mask::u8_test_not; use crate::ffi::{ - FfiClosure, NativeArgInfo, NativeArgType, NativeConvert, NativeResultInfo, NativeResultType, + ffi_association::set_association, FfiClosure, NativeArgInfo, NativeConvert, NativeResultInfo, }; +use crate::ffi::{FfiCallable, FfiRef, FfiRefFlag, NativeData}; // cfn is a type declaration for a function. // Basically, when calling an external function, this type declaration @@ -47,31 +54,67 @@ impl CFn { } } - pub fn new_from_lua_table(lua: &Lua, args: LuaTable, ret: LuaAnyUserData) -> LuaResult { + pub fn new_from_lua_table<'lua>( + lua: &'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)?; - let len = args.raw_len(); - let mut arg_info_list = Vec::::with_capacity(len); - + let mut arg_info_list = Vec::::with_capacity(args.raw_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() + let result_info = NativeResultInfo { + conv: unsafe { get_conv(&ret)? }, + }; + + let cfn = + lua.create_userdata(Self::new(args_types, ret_type, arg_info_list, result_info))?; - Ok(Self::new(args_types, ret_type, unsafe {}, unsafe { - get_conv(&ret)? - })) + // Create association to hold argument and result type + set_association(lua, CFN_ARGS, &cfn, args)?; + set_association(lua, CFN_ARGS, &cfn, ret)?; + + Ok(cfn) } } impl LuaUserData for CFn { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { - methods.add_method("closure", |lua, this, func: LuaFunction| { - lua.create_userdata(FfiClosure::new(this.cif, userdata)) - }) + // methods.add_method("closure", |lua, this, func: LuaFunction| { + // lua.create_userdata(FfiClosure::new(this.cif, userdata)) + // }) + methods.add_function( + "func", + |lua, (cfn, function_ref): (LuaAnyUserData, LuaAnyUserData)| { + let this = cfn.borrow::()?; + + if !function_ref.is::() { + return Err(LuaError::external("")); + } + + let ffi_ref = function_ref.borrow::()?; + if u8_test_not(ffi_ref.flags, FfiRefFlag::Function.value()) { + return Err(LuaError::external("")); + } + + let callable = lua.create_userdata(unsafe { + FfiCallable::new( + this.cif, + ptr::from_ref(&this.arg_info_list), + ptr::from_ref(&this.result_info), + ffi_ref.get_pointer(0), + ) + })?; + + set_association(lua, CALLABLE_CFN, &callable, cfn.clone())?; + set_association(lua, CALLABLE_REF, &callable, function_ref.clone())?; + + Ok(callable) + }, + ); } } diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index 2d7d6184..151ed73f 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -24,4 +24,8 @@ mod association_names { pub const CARR_INNER: &str = "__carr_inner"; pub const CSTRUCT_INNER: &str = "__cstruct_inner"; pub const CTYPE_STATIC: &str = "__ctype_static"; + pub const CFN_RESULT: &str = "__cfn_result"; + pub const CFN_ARGS: &str = "__cfn_args"; + pub const CALLABLE_REF: &str = "__callable_ref"; + pub const CALLABLE_CFN: &str = "__callable_cfn"; } diff --git a/crates/lune-std-ffi/src/ffi/ffi_callable.rs b/crates/lune-std-ffi/src/ffi/ffi_callable.rs index b9752e8c..abf94d25 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_callable.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_callable.rs @@ -10,62 +10,34 @@ use libffi::{ }; 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; +use super::{GetNativeData, NativeArgInfo, NativeData, NativeResultInfo}; pub struct FfiCallable { cif: *mut ffi_cif, - arg_type_list: Vec, - result_size: usize, + arg_info: *const Vec, + result_info: *const NativeResultInfo, code: CodePtr, + + // Caching for better performance + result_size: usize, } 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 { + arg_info: *const Vec, + result_info: *const NativeResultInfo, + function_pointer: *const (), + ) -> Self { + let result_size = (*(*result_info).conv).get_size(); + Self { cif, - arg_type_list, + arg_info, + result_info, + code: CodePtr::from_ptr(function_pointer.cast::()), + result_size, - code: CodePtr::from_ptr(function_ref.get_pointer(0).cast::()), - }) + } } pub unsafe fn call(&self, result: &Ref, args: LuaMultiValue) -> LuaResult<()> { @@ -74,20 +46,6 @@ impl FfiCallable { .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 { @@ -95,15 +53,15 @@ impl LuaUserData for FfiCallable { methods.add_method( "call", |_lua, this: &FfiCallable, mut args: LuaMultiValue| { - let LuaValue::UserData(result) = args.pop_front().ok_or_else(|| { + let result_userdata = args.pop_front().ok_or_else(|| { LuaError::external("first argument must be result data handle") - })? - else { + })?; + let LuaValue::UserData(result) = result_userdata else { return Err(LuaError::external("")); }; - let call_result = unsafe { this.call(&result.get_data_handle()?, args) }; - call_result + // FIXME: clone + unsafe { this.call(&result.clone().get_data_handle()?, args) } }, - ) + ); } } diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/arg.rs b/crates/lune-std-ffi/src/ffi/ffi_native/arg.rs index c324f2dd..108495de 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/arg.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/arg.rs @@ -11,5 +11,5 @@ pub enum NativeArgType { pub struct NativeArgInfo { pub conv: *const dyn NativeConvert, - pub kind: NativeArgType, + // pub kind: NativeArgType, } 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 c835deb0..a089a8b9 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs @@ -15,7 +15,13 @@ pub trait NativeSignedness { } pub use self::{ - arg::FfiArgRefOption, arg::NativeArgInfo, arg::NativeArgType, cast::native_num_cast, - convert::NativeConvert, data::GetNativeData, data::NativeData, result::NativeResultInfo, - result::NativeResultType, + 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 index b25995fb..0a34f52f 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/result.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/result.rs @@ -1,11 +1,11 @@ use super::NativeConvert; -pub enum NativeResultType { - FfiBox, - FfiRef, -} +// pub enum NativeResultType { +// FfiBox, +// FfiRef, +// } pub struct NativeResultInfo { - conv: *const dyn NativeConvert, - kind: NativeResultType, + pub conv: *const dyn NativeConvert, + // kind: NativeResultType, } 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 d0a54042..c107b736 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs @@ -1,10 +1,10 @@ -use std::ptr; +use std::{mem::ManuallyDrop, ptr}; use mlua::prelude::*; use super::{ association_names::REF_INNER, - bit_mask::u8_test, + bit_mask::{u8_test, u8_test_not}, ffi_association::{get_association, set_association}, NativeData, }; @@ -19,6 +19,12 @@ pub use self::{ // Box:ref():ref() should not be able to modify, Only for external const BOX_REF_REF_FLAGS: u8 = 0; +const UNINIT_REF_FLAGS: u8 = FfiRefFlag::Uninit.value() + | FfiRefFlag::Writable.value() + | FfiRefFlag::Readable.value() + | FfiRefFlag::Dereferenceable.value() + | FfiRefFlag::Offsetable.value() + | FfiRefFlag::Function.value(); // A referenced space. It is possible to read and write through types. // This operation is not safe. This may cause a memory error in Lua @@ -27,7 +33,7 @@ const BOX_REF_REF_FLAGS: u8 = 0; // the box will remain as long as this reference is alive. pub struct FfiRef { - ptr: *mut (), + ptr: ManuallyDrop>, pub flags: u8, pub boundary: FfiRefBounds, } @@ -35,7 +41,7 @@ pub struct FfiRef { impl FfiRef { pub fn new(ptr: *mut (), flags: u8, boundary: FfiRefBounds) -> Self { Self { - ptr, + ptr: ManuallyDrop::new(Box::new(ptr)), flags, boundary, } @@ -43,8 +49,8 @@ impl FfiRef { pub fn new_uninit() -> Self { Self { - ptr: ptr::null_mut(), - flags: FfiRefFlag::Uninit.value(), + ptr: ManuallyDrop::new(Box::new(ptr::null_mut())), + flags: UNINIT_REF_FLAGS, boundary: UNSIZED_BOUNDS, } } @@ -92,7 +98,9 @@ impl FfiRef { } pub fn is_nullptr(&self) -> bool { - self.ptr as usize == 0 + // * ManuallyDrop wrapper + // * Box wrapper + (**self.ptr) as usize == 0 } pub unsafe fn offset(&self, offset: isize) -> LuaResult { @@ -122,6 +130,14 @@ impl FfiRef { } } +impl Drop for FfiRef { + fn drop(&mut self) { + if u8_test_not(self.flags, FfiRefFlag::Leaked.value()) { + unsafe { ManuallyDrop::drop(&mut self.ptr) }; + } + } +} + impl NativeData for FfiRef { fn check_boundary(&self, offset: isize, size: usize) -> bool { self.boundary.check_sized(offset, size) diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index 4196bcee..f186e99a 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -16,8 +16,7 @@ pub use self::{ ffi_lib::FfiLib, ffi_native::{ native_num_cast, FfiArgRefOption, GetNativeData, NativeArgInfo, NativeArgType, - NativeConvert, NativeData, NativeResultInfo, NativeResultType, NativeSignedness, - NativeSize, + NativeConvert, NativeData, NativeResultInfo, NativeSignedness, NativeSize, }, ffi_raw::FfiRaw, ffi_ref::{create_nullptr, FfiRef, FfiRefFlag}, From 46dd185c6fd49ae014e0bb06b9eb09a049e9ef1d Mon Sep 17 00:00:00 2001 From: qwreey Date: Mon, 14 Oct 2024 09:37:21 +0000 Subject: [PATCH 18/79] Implement call (#243) --- .gitignore | 5 ++ crates/lune-std-ffi/src/c/c_arr.rs | 3 +- crates/lune-std-ffi/src/c/c_fn.rs | 54 ++++++------- crates/lune-std-ffi/src/c/c_helper.rs | 75 +++++++------------ crates/lune-std-ffi/src/c/c_string.rs | 2 + crates/lune-std-ffi/src/c/c_type.rs | 5 +- crates/lune-std-ffi/src/c/types/mod.rs | 17 ++++- crates/lune-std-ffi/src/ffi/ffi_box/mod.rs | 2 +- crates/lune-std-ffi/src/ffi/ffi_callable.rs | 55 ++++++++++---- crates/lune-std-ffi/src/ffi/ffi_lib.rs | 16 ++-- crates/lune-std-ffi/src/ffi/ffi_native/arg.rs | 1 + .../src/ffi/ffi_native/convert.rs | 7 +- crates/lune-std-ffi/src/ffi/ffi_native/mod.rs | 2 - .../lune-std-ffi/src/ffi/ffi_native/result.rs | 1 + crates/lune-std-ffi/src/ffi/ffi_ref/bounds.rs | 2 - crates/lune-std-ffi/src/ffi/mod.rs | 5 +- crates/lune-std-ffi/src/lib.rs | 1 + crates/lune-std-ffi/src/libffi_helper.rs | 29 +++++++ tests/ffi/external_math/init.luau | 42 +++++++++++ tests/ffi/external_math/lib.c | 7 ++ tests/ffi/external_struct/init.luau | 30 ++++++++ tests/ffi/external_struct/lib.c | 14 ++++ tests/ffi/utility/compile.luau | 9 +++ 23 files changed, 271 insertions(+), 113 deletions(-) create mode 100644 crates/lune-std-ffi/src/libffi_helper.rs create mode 100644 tests/ffi/external_math/init.luau create mode 100644 tests/ffi/external_math/lib.c create mode 100644 tests/ffi/external_struct/init.luau create mode 100644 tests/ffi/external_struct/lib.c create mode 100644 tests/ffi/utility/compile.luau diff --git a/.gitignore b/.gitignore index 6f7b83e6..ba748c2d 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,11 @@ luneDocs.json luneTypes.d.luau # Files generated by runtime or build scripts + scripts/brick_color.rs scripts/font_enum_map.rs scripts/physical_properties_enum_map.rs + +# Files generated by tests + +/tests/ffi/**/*.so diff --git a/crates/lune-std-ffi/src/c/c_arr.rs b/crates/lune-std-ffi/src/c/c_arr.rs index fc7ddf8e..6aa9caa6 100644 --- a/crates/lune-std-ffi/src/c/c_arr.rs +++ b/crates/lune-std-ffi/src/c/c_arr.rs @@ -5,13 +5,14 @@ use mlua::prelude::*; use super::{ association_names::CARR_INNER, - c_helper::{get_conv, get_ensured_size, libffi_type_from_userdata, pretty_format_userdata}, + c_helper::{get_conv, libffi_type_from_userdata, pretty_format_userdata}, CPtr, }; use crate::ffi::{ ffi_association::{get_association, set_association}, FfiBox, GetNativeData, NativeConvert, NativeData, NativeSize, }; +use crate::libffi_helper::get_ensured_size; // This is a series of some type. // It provides the final size and the offset of the index, diff --git a/crates/lune-std-ffi/src/c/c_fn.rs b/crates/lune-std-ffi/src/c/c_fn.rs index d6cfbbf1..ef1bc0dc 100644 --- a/crates/lune-std-ffi/src/c/c_fn.rs +++ b/crates/lune-std-ffi/src/c/c_fn.rs @@ -1,20 +1,17 @@ use std::ptr; -use libffi::low::ffi_cif; 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, get_conv_list_from_table, libffi_type_from_userdata, libffi_type_list_from_table, - }, + c_helper::{get_conv, libffi_type_from_userdata, libffi_type_list_from_table}, }; -use crate::ffi::bit_mask::u8_test_not; use crate::ffi::{ - ffi_association::set_association, FfiClosure, NativeArgInfo, NativeConvert, NativeResultInfo, + bit_mask::u8_test_not, ffi_association::set_association, FfiCallable, FfiRef, FfiRefFlag, + NativeArgInfo, NativeData, NativeResultInfo, }; -use crate::ffi::{FfiCallable, FfiRef, FfiRefFlag, NativeData}; // cfn is a type declaration for a function. // Basically, when calling an external function, this type declaration @@ -33,7 +30,7 @@ use crate::ffi::{FfiCallable, FfiRef, FfiRefFlag, NativeData}; // moved to a Lua function or vice versa. pub struct CFn { - cif: *mut ffi_cif, + cif: Cif, arg_info_list: Vec, result_info: NativeResultInfo, } @@ -46,37 +43,44 @@ impl CFn { ret: Type, arg_info_list: Vec, result_info: NativeResultInfo, - ) -> Self { - Self { - cif: Cif::new(args.clone(), ret.clone()).as_raw_ptr(), + ) -> LuaResult { + // let cif = ; + + Ok(Self { + cif: Cif::new(args.clone(), ret.clone()), arg_info_list, result_info, - } + }) } pub fn new_from_lua_table<'lua>( lua: &'lua Lua, - args: LuaTable, + arg_table: LuaTable, ret: LuaAnyUserData, ) -> LuaResult> { - let args_types = libffi_type_list_from_table(lua, &args)?; + let args_types = libffi_type_list_from_table(lua, &arg_table)?; let ret_type = libffi_type_from_userdata(lua, &ret)?; - let mut arg_info_list = Vec::::with_capacity(args.raw_len()); - for conv in unsafe { get_conv_list_from_table(&args)? } { - arg_info_list.push(NativeArgInfo { conv }) + 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)?)?; + arg_info_list.push(NativeArgInfo { + conv: unsafe { get_conv(&userdata)? }, + size: get_size(&userdata)?, + }); } - let result_info = NativeResultInfo { conv: unsafe { get_conv(&ret)? }, + size: get_size(&ret)?, }; let cfn = - lua.create_userdata(Self::new(args_types, ret_type, arg_info_list, result_info))?; + lua.create_userdata(Self::new(args_types, ret_type, arg_info_list, result_info)?)?; // Create association to hold argument and result type - set_association(lua, CFN_ARGS, &cfn, args)?; - set_association(lua, CFN_ARGS, &cfn, ret)?; + set_association(lua, CFN_ARGS, &cfn, arg_table)?; + set_association(lua, CFN_RESULT, &cfn, ret)?; Ok(cfn) } @@ -88,22 +92,22 @@ impl LuaUserData for CFn { // lua.create_userdata(FfiClosure::new(this.cif, userdata)) // }) methods.add_function( - "func", + "caller", |lua, (cfn, function_ref): (LuaAnyUserData, LuaAnyUserData)| { let this = cfn.borrow::()?; if !function_ref.is::() { - return Err(LuaError::external("")); + return Err(LuaError::external("argument 0 must be ffiref")); } let ffi_ref = function_ref.borrow::()?; if u8_test_not(ffi_ref.flags, FfiRefFlag::Function.value()) { - return Err(LuaError::external("")); + return Err(LuaError::external("not a function ref")); } let callable = lua.create_userdata(unsafe { FfiCallable::new( - this.cif, + this.cif.as_raw_ptr(), ptr::from_ref(&this.arg_info_list), ptr::from_ref(&this.result_info), ffi_ref.get_pointer(0), diff --git a/crates/lune-std-ffi/src/c/c_helper.rs b/crates/lune-std-ffi/src/c/c_helper.rs index f4a2e186..b7c8478b 100644 --- a/crates/lune-std-ffi/src/c/c_helper.rs +++ b/crates/lune-std-ffi/src/c/c_helper.rs @@ -1,17 +1,26 @@ #![allow(clippy::inline_always)] -use std::ptr::{self, null_mut}; - -use libffi::{low, middle::Type, raw}; +use libffi::middle::Type; use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; 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, NativeSignedness, NativeSize, FFI_STATUS_NAMES, + association_names::CTYPE_STATIC, + types::{get_ctype_conv, get_ctype_size}, + CArr, CPtr, CStruct, CTypeStatic, }; +use crate::ffi::{ffi_association::get_association, NativeConvert, NativeSize}; + +pub fn get_userdata(value: LuaValue) -> LuaResult { + if let LuaValue::UserData(field_type) = value { + Ok(field_type) + } else { + Err(LuaError::external(format!( + "Unexpected field. CStruct, CType or CArr is required for element but got {}", + pretty_format_value(&value, &ValueFormatConfig::new()) + ))) + } +} // Get the NativeConvert handle from the type UserData // this is intended to avoid lookup userdata and lua table every time. (eg: struct) @@ -33,30 +42,21 @@ pub unsafe fn get_conv_list_from_table( 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()) - ))); - } + conv_list.push(get_conv(&get_userdata(value)?)?); } 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) -// } -// } +pub fn get_size(this: &LuaAnyUserData) -> LuaResult { + if this.is::() { + Ok(this.borrow::()?.get_size()) + } else if this.is::() { + Ok(this.borrow::()?.get_size()) + } else { + get_ctype_size(this) + } +} // get Vec from table(array) of c-type userdata pub fn libffi_type_list_from_table(lua: &Lua, table: &LuaTable) -> LuaResult> { @@ -162,26 +162,3 @@ pub fn pretty_format_userdata(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult )) } } - -// Ensure sizeof c-type (raw::libffi_type) -// See: http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html -pub fn get_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult { - let mut cif = low::ffi_cif::default(); - let result = unsafe { - raw::ffi_prep_cif( - ptr::from_mut(&mut cif), - raw::ffi_abi_FFI_DEFAULT_ABI, - 0, - ffi_type, - null_mut(), - ) - }; - - if result != raw::ffi_status_FFI_OK { - return Err(LuaError::external(format!( - "ffi_get_struct_offsets failed. expected result {}, got {}", - FFI_STATUS_NAMES[0], FFI_STATUS_NAMES[result as usize] - ))); - } - unsafe { Ok((*ffi_type).size) } -} diff --git a/crates/lune-std-ffi/src/c/c_string.rs b/crates/lune-std-ffi/src/c/c_string.rs index cf79b487..9c3d777b 100644 --- a/crates/lune-std-ffi/src/c/c_string.rs +++ b/crates/lune-std-ffi/src/c/c_string.rs @@ -4,3 +4,5 @@ // but separated it for clarity. // This also allows operations such as ffi.string:intoBox(). // (Write a string to an already existing box) + +// FIXME: use buffer instead? diff --git a/crates/lune-std-ffi/src/c/c_type.rs b/crates/lune-std-ffi/src/c/c_type.rs index 98ab565c..3738f04e 100644 --- a/crates/lune-std-ffi/src/c/c_type.rs +++ b/crates/lune-std-ffi/src/c/c_type.rs @@ -7,11 +7,12 @@ use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::{association_names::CTYPE_STATIC, c_helper::get_ensured_size, CArr, CPtr}; +use super::{association_names::CTYPE_STATIC, CArr, CPtr}; use crate::ffi::{ ffi_association::set_association, native_num_cast, FfiBox, GetNativeData, NativeConvert, NativeData, NativeSignedness, NativeSize, }; +use crate::libffi_helper::get_ensured_size; // We can't get a CType through mlua, something like // .is::> will fail. @@ -106,11 +107,9 @@ where libffi_type: Type, name: Option<&'static str>, ) -> LuaResult> { - // let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void()); let size = get_ensured_size(libffi_type.as_raw_ptr())?; let ctype = Self { - // libffi_cif: libffi_cfi, libffi_type, size, name, diff --git a/crates/lune-std-ffi/src/c/types/mod.rs b/crates/lune-std-ffi/src/c/types/mod.rs index 3beb647f..7e116e46 100644 --- a/crates/lune-std-ffi/src/c/types/mod.rs +++ b/crates/lune-std-ffi/src/c/types/mod.rs @@ -8,7 +8,7 @@ use mlua::prelude::*; use num::cast::AsPrimitive; use super::{CType, CTypeCast}; -use crate::ffi::{NativeConvert, NativeData}; +use crate::ffi::{NativeConvert, NativeData, NativeSize}; pub mod f32; pub mod f64; @@ -145,3 +145,18 @@ macro_rules! define_get_ctype_conv { 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) } + +macro_rules! define_get_ctype_size { + ($userdata:ident, $f:ty, $( $c:ty ),*) => { + if $userdata.is::>() { + Ok($userdata.borrow::>()?.get_size()) + }$( else if $userdata.is::>() { + Ok($userdata.borrow::>()?.get_size()) + })* else { + Err(LuaError::external("Unexpected type")) + } + }; +} +pub fn get_ctype_size(userdata: &LuaAnyUserData) -> LuaResult { + define_get_ctype_size!(userdata, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64) +} 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 9832455f..18815c5e 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_box/mod.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_box/mod.rs @@ -128,7 +128,7 @@ impl NativeData for FfiBox { if offset < 0 { return false; } - self.size() > ((offset as usize) + size) + self.size() - (offset as usize) >= size } unsafe fn get_pointer(&self, offset: isize) -> *mut () { self.data diff --git a/crates/lune-std-ffi/src/ffi/ffi_callable.rs b/crates/lune-std-ffi/src/ffi/ffi_callable.rs index abf94d25..829b0a2d 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_callable.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_callable.rs @@ -1,12 +1,9 @@ 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, + raw::ffi_call, }; use mlua::prelude::*; @@ -14,37 +11,64 @@ use super::{GetNativeData, NativeArgInfo, NativeData, NativeResultInfo}; pub struct FfiCallable { cif: *mut ffi_cif, - arg_info: *const Vec, + arg_info_list: *const Vec, result_info: *const NativeResultInfo, code: CodePtr, - - // Caching for better performance - result_size: usize, } impl FfiCallable { pub unsafe fn new( cif: *mut ffi_cif, - arg_info: *const Vec, + arg_info_list: *const Vec, result_info: *const NativeResultInfo, function_pointer: *const (), ) -> Self { - let result_size = (*(*result_info).conv).get_size(); Self { cif, - arg_info, + arg_info_list, result_info, code: CodePtr::from_ptr(function_pointer.cast::()), - - result_size, } } pub unsafe fn call(&self, result: &Ref, args: LuaMultiValue) -> LuaResult<()> { result - .check_boundary(0, self.result_size) + .check_boundary(0, self.result_info.as_ref().unwrap().size) .then_some(()) - .ok_or_else(|| LuaError::external("result boundary check failed")) + .ok_or_else(|| LuaError::external("result boundary check failed"))?; + + // cache Vec => unable to create async call but no allocation + let arg_info_list = self.arg_info_list.as_ref().unwrap(); + let mut arg_list = Vec::<*mut c_void>::with_capacity(arg_info_list.len()); + + for index in 0..arg_info_list.len() { + let arg_info = arg_info_list.get(index).unwrap(); + let arg = args + .get(index) + .ok_or_else(|| LuaError::external(format!("argument {index} required")))?; + let arg_pointer = if let LuaValue::UserData(userdata) = arg { + let data_handle = userdata.get_data_handle()?; + data_handle + .check_boundary(0, arg_info.size) + .then_some(()) + .ok_or_else(|| { + LuaError::external(format!("argument {index} boundary check failed")) + })?; + data_handle.get_pointer(0) + } else { + return Err(LuaError::external("unimpl")); + }; + arg_list.push(arg_pointer.cast::()); + } + + ffi_call( + self.cif, + Some(*self.code.as_safe_fun()), + result.get_pointer(0).cast::(), + arg_list.as_mut_ptr(), + ); + + Ok(()) } } @@ -63,5 +87,6 @@ impl LuaUserData for FfiCallable { unsafe { this.call(&result.clone().get_data_handle()?, args) } }, ); + // ref, leak ..? } } diff --git a/crates/lune-std-ffi/src/ffi/ffi_lib.rs b/crates/lune-std-ffi/src/ffi/ffi_lib.rs index 8bc0524d..87d81bd2 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_lib.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_lib.rs @@ -1,6 +1,6 @@ use core::ffi::c_void; -use dlopen2::symbor::Library; +use dlopen2::raw::Library; use mlua::prelude::*; use super::{ @@ -41,12 +41,17 @@ impl FfiLib { let lib = this.borrow::()?; let sym = unsafe { lib.0 - .symbol::<*mut c_void>(name.as_str()) + .symbol::<*const c_void>(name.as_str()) .map_err(|err| LuaError::external(format!("{err}")))? }; + let ptr = sym.cast::<()>().cast_mut(); - let luasym = - lua.create_userdata(FfiRef::new((*sym).cast(), LIB_REF_FLAGS, UNSIZED_BOUNDS))?; + // unsafe { + // let f = transmute::<*mut (), unsafe extern "C" fn(i32, i32) -> i32>(ptr); + // dbg!(f(1, 2)); + // } + + let luasym = lua.create_userdata(FfiRef::new(ptr, LIB_REF_FLAGS, UNSIZED_BOUNDS))?; set_association(lua, SYM_INNER, &luasym, &this)?; @@ -57,8 +62,7 @@ impl FfiLib { impl LuaUserData for FfiLib { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { methods.add_function("find", |lua, (this, name): (LuaAnyUserData, String)| { - let luasym = FfiLib::get_sym(lua, this, name)?; - Ok(luasym) + FfiLib::get_sym(lua, this, name) }); } } diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/arg.rs b/crates/lune-std-ffi/src/ffi/ffi_native/arg.rs index 108495de..9eb06a09 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/arg.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/arg.rs @@ -11,5 +11,6 @@ pub enum NativeArgType { pub struct NativeArgInfo { pub conv: *const dyn NativeConvert, + pub size: usize, // pub kind: NativeArgType, } 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 2629a8a3..4d493e13 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/convert.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/convert.rs @@ -4,13 +4,10 @@ use std::cell::Ref; use mlua::prelude::*; -use super::{NativeData, NativeSize}; +use super::NativeData; // Handle native data, provide type conversion between luavalue and native types -pub trait NativeConvert -where - Self: NativeSize, -{ +pub trait NativeConvert { // Convert luavalue into data, then write into ptr unsafe fn luavalue_into<'lua>( &self, 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 a089a8b9..4ac89ba8 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs @@ -15,9 +15,7 @@ pub trait NativeSignedness { } pub use self::{ - arg::FfiArgRefOption, arg::NativeArgInfo, - arg::NativeArgType, cast::native_num_cast, convert::NativeConvert, data::GetNativeData, diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/result.rs b/crates/lune-std-ffi/src/ffi/ffi_native/result.rs index 0a34f52f..588aae71 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/result.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/result.rs @@ -7,5 +7,6 @@ use super::NativeConvert; pub struct NativeResultInfo { pub conv: *const dyn NativeConvert, + pub size: usize, // kind: NativeResultType, } 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 1df4b2bc..9fd85665 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/bounds.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/bounds.rs @@ -1,5 +1,3 @@ -use std::clone; - // Memory range for ref or box data. For boundary checking pub struct FfiRefBounds { // Indicates how much data is above the pointer diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index f186e99a..50dd8f89 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -15,10 +15,9 @@ pub use self::{ ffi_closure::FfiClosure, ffi_lib::FfiLib, ffi_native::{ - native_num_cast, FfiArgRefOption, GetNativeData, NativeArgInfo, NativeArgType, - NativeConvert, NativeData, NativeResultInfo, NativeSignedness, NativeSize, + native_num_cast, GetNativeData, NativeArgInfo, NativeConvert, NativeData, NativeResultInfo, + NativeSignedness, NativeSize, }, - ffi_raw::FfiRaw, ffi_ref::{create_nullptr, FfiRef, FfiRefFlag}, }; diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs index 9df4bd7a..72bbbdbc 100644 --- a/crates/lune-std-ffi/src/lib.rs +++ b/crates/lune-std-ffi/src/lib.rs @@ -6,6 +6,7 @@ use mlua::prelude::*; mod c; mod ffi; +mod libffi_helper; use crate::{ c::{create_all_c_types, create_all_types, CFn, CStruct}, diff --git a/crates/lune-std-ffi/src/libffi_helper.rs b/crates/lune-std-ffi/src/libffi_helper.rs new file mode 100644 index 00000000..37feaa79 --- /dev/null +++ b/crates/lune-std-ffi/src/libffi_helper.rs @@ -0,0 +1,29 @@ +use std::ptr::{self, null_mut}; + +use libffi::{low, raw}; +use mlua::prelude::*; + +use crate::ffi::FFI_STATUS_NAMES; + +// Ensure sizeof c-type (raw::libffi_type) +// See: http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html +pub fn get_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult { + let mut cif = low::ffi_cif::default(); + let result = unsafe { + raw::ffi_prep_cif( + ptr::from_mut(&mut cif), + raw::ffi_abi_FFI_DEFAULT_ABI, + 0, + ffi_type, + null_mut(), + ) + }; + + if result != raw::ffi_status_FFI_OK { + return Err(LuaError::external(format!( + "ffi_prep_cif failed. expected result {}, got {}", + FFI_STATUS_NAMES[0], FFI_STATUS_NAMES[result as usize] + ))); + } + unsafe { Ok((*ffi_type).size) } +} diff --git a/tests/ffi/external_math/init.luau b/tests/ffi/external_math/init.luau new file mode 100644 index 00000000..3b76871c --- /dev/null +++ b/tests/ffi/external_math/init.luau @@ -0,0 +1,42 @@ +local ffi = require("@lune/ffi") + +local testdir = "./tests/ffi/external_math" + +local compile = require("../utility/compile") +compile(`{testdir}/lib.c`, `{testdir}/lib.so`) + +local lib = ffi.open(`{testdir}/lib.so`) + +local function test_add_int() + local add_int = ffi.fn({ ffi.int, ffi.int }, ffi.int) + + local add_int_caller = add_int:caller(lib:find("add_int")) + + local resultBox = ffi.box(ffi.int.size) + local arg1 = ffi.int:box(100) + local arg2 = ffi.int:box(200) + + add_int_caller:call(resultBox, arg1, arg2) + local result = ffi.int:from(resultBox) + + assert(result == 300, `add_int failed. result expected 300, got {result}`) +end + +test_add_int() + +local function test_mul_int() + local mul_int = ffi.fn({ ffi.int, ffi.int }, ffi.int) + + local mul_int_caller = mul_int:caller(lib:find("mul_int")) + + local resultBox = ffi.box(ffi.int.size) + local arg1 = ffi.int:box(100) + local arg2 = ffi.int:box(200) + + mul_int_caller:call(resultBox, arg1, arg2) + local result = ffi.int:from(resultBox) + + assert(result == 20000, `mul_int failed. result expected 20000, got {result}`) +end + +test_mul_int() diff --git a/tests/ffi/external_math/lib.c b/tests/ffi/external_math/lib.c new file mode 100644 index 00000000..b5182308 --- /dev/null +++ b/tests/ffi/external_math/lib.c @@ -0,0 +1,7 @@ +int add_int(int a, int b) { + return a + b; +} + +int mul_int(int a, int b) { + return a * b; +} diff --git a/tests/ffi/external_struct/init.luau b/tests/ffi/external_struct/init.luau new file mode 100644 index 00000000..d07cf420 --- /dev/null +++ b/tests/ffi/external_struct/init.luau @@ -0,0 +1,30 @@ +local ffi = require("@lune/ffi") + +local testdir = "./tests/ffi/external_struct" + +local compile = require("../utility/compile") +compile(`{testdir}/lib.c`, `{testdir}/lib.so`) + +local lib = ffi.open(`{testdir}/lib.so`) + +local function test_AB() + local ArgStruct = ffi.struct({ ffi.int, ffi.int:ptr() }) + local ResultStruct = ffi.struct({ ffi.int, ffi.int }) + + local AB = ffi.fn({ ArgStruct }, ResultStruct) + + local AB_caller = AB:caller(lib:find("AB")) + + local resultBox = ffi.box(ffi.int.size) + local a = ffi.int:box(100) + local b = ffi.int:box(200) + local arg = ArgStruct:box({ a, b:leak() }) + + AB_caller:call(resultBox, arg) + local result = ResultStruct:from(resultBox) + + assert(result[0] == 300, `AB failed. result expected 300, got {result}`) + assert(result[1] == 20000, `AB failed. result expected 300, got {result}`) +end + +test_AB() diff --git a/tests/ffi/external_struct/lib.c b/tests/ffi/external_struct/lib.c new file mode 100644 index 00000000..a9e076b9 --- /dev/null +++ b/tests/ffi/external_struct/lib.c @@ -0,0 +1,14 @@ +typedef struct { + int a; + int* b; +} ArgStruct; + +typedef struct { + int sum; + int mul; +} ResultStruct; + +ResultStruct AB(ArgStruct t) { + ResultStruct result = { t.a+*t.b, t.a**t.b }; + return result; +} diff --git a/tests/ffi/utility/compile.luau b/tests/ffi/utility/compile.luau new file mode 100644 index 00000000..0b67f4c4 --- /dev/null +++ b/tests/ffi/utility/compile.luau @@ -0,0 +1,9 @@ +local process = require("@lune/process") +local function compile(file, out) + local gcc = process.spawn("gcc", { "-shared", "-o", out, "-fPIC", file }) + if not gcc.ok then + error("Failed to execute gcc command\n" .. gcc.stdout .. gcc.stderr) + end +end + +return compile From 7d4e4a24b2b5ac4068cd2a67b6ea89bdaaa41b12 Mon Sep 17 00:00:00 2001 From: qwreey Date: Wed, 16 Oct 2024 03:12:36 +0000 Subject: [PATCH 19/79] Refactor type-define macro rules (#243) --- crates/lune-std-ffi/src/c/c_arr.rs | 8 +- crates/lune-std-ffi/src/c/c_helper.rs | 2 +- crates/lune-std-ffi/src/c/c_type.rs | 25 +-- crates/lune-std-ffi/src/c/mod.rs | 3 +- crates/lune-std-ffi/src/c/types/f32.rs | 8 - crates/lune-std-ffi/src/c/types/f64.rs | 8 - crates/lune-std-ffi/src/c/types/i128.rs | 12 -- crates/lune-std-ffi/src/c/types/i16.rs | 8 - crates/lune-std-ffi/src/c/types/i32.rs | 8 - crates/lune-std-ffi/src/c/types/i64.rs | 8 - crates/lune-std-ffi/src/c/types/i8.rs | 8 - crates/lune-std-ffi/src/c/types/isize.rs | 8 - crates/lune-std-ffi/src/c/types/mod.rs | 186 +++++++++------------ crates/lune-std-ffi/src/c/types/u128.rs | 12 -- crates/lune-std-ffi/src/c/types/u16.rs | 8 - crates/lune-std-ffi/src/c/types/u32.rs | 8 - crates/lune-std-ffi/src/c/types/u64.rs | 8 - crates/lune-std-ffi/src/c/types/u8.rs | 8 - crates/lune-std-ffi/src/c/types/usize.rs | 8 - crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs | 2 + crates/lune-std-ffi/src/lib.rs | 18 +- crates/lune-std-ffi/src/libffi_helper.rs | 2 +- 22 files changed, 104 insertions(+), 262 deletions(-) diff --git a/crates/lune-std-ffi/src/c/c_arr.rs b/crates/lune-std-ffi/src/c/c_arr.rs index 6aa9caa6..0f22de27 100644 --- a/crates/lune-std-ffi/src/c/c_arr.rs +++ b/crates/lune-std-ffi/src/c/c_arr.rs @@ -14,17 +14,17 @@ use crate::ffi::{ }; 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. // However, multidimensional arrays are not impossible to implement -// because they are a series of transcribed one-dimensional arrays. +// because they are a series of transcribed one-dimensional arrays. (flatten) +// We can simply provide array type with struct. // See: https://stackoverflow.com/a/43525176 -// Padding after each field inside the struct is set to next field can follow the alignment. -// There is no problem even if you create a struct with n fields of a single type within the struct. Array adheres to the condition that there is no additional padding between each element. Padding to a struct is padding inside the struct. Simply think of the padding byte as a trailing unnamed field. - pub struct CArr { // element_type: Type, struct_type: Type, diff --git a/crates/lune-std-ffi/src/c/c_helper.rs b/crates/lune-std-ffi/src/c/c_helper.rs index b7c8478b..a843ae5e 100644 --- a/crates/lune-std-ffi/src/c/c_helper.rs +++ b/crates/lune-std-ffi/src/c/c_helper.rs @@ -30,7 +30,7 @@ pub unsafe fn get_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn Native if userdata.is::() { Ok(userdata.to_pointer().cast::() as *const dyn NativeConvert) } else { - unsafe { get_ctype_conv(userdata) } + get_ctype_conv(userdata) } } diff --git a/crates/lune-std-ffi/src/c/c_type.rs b/crates/lune-std-ffi/src/c/c_type.rs index 3738f04e..1b6dcf17 100644 --- a/crates/lune-std-ffi/src/c/c_type.rs +++ b/crates/lune-std-ffi/src/c/c_type.rs @@ -5,12 +5,11 @@ 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, CArr, CPtr}; use crate::ffi::{ - ffi_association::set_association, native_num_cast, FfiBox, GetNativeData, NativeConvert, - NativeData, NativeSignedness, NativeSize, + ffi_association::set_association, FfiBox, GetNativeData, NativeConvert, NativeData, + NativeSignedness, NativeSize, }; use crate::libffi_helper::get_ensured_size; @@ -39,25 +38,6 @@ 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, @@ -66,6 +46,7 @@ pub trait CTypeCast { _from: &Ref, _into: &Ref, ) -> LuaResult<()> { + // Show error if have no cast implement Err(Self::cast_failed_with(self, from_ctype, into_ctype)) } diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index 151ed73f..e1a577af 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -15,8 +15,7 @@ pub use self::{ c_type::{CType, CTypeCast, CTypeStatic}, }; -pub use types::create_all_c_types; -pub use types::create_all_types; +pub use types::export_ctypes; // Named registry table names mod association_names { diff --git a/crates/lune-std-ffi/src/c/types/f32.rs b/crates/lune-std-ffi/src/c/types/f32.rs index 8f6556f9..64d54e6e 100644 --- a/crates/lune-std-ffi/src/c/types/f32.rs +++ b/crates/lune-std-ffi/src/c/types/f32.rs @@ -1,6 +1,5 @@ use std::cell::Ref; -use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; @@ -52,10 +51,3 @@ impl NativeConvert for CType { Ok(value) } } - -pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { - Ok(( - "f32", - CType::::new_with_libffi_type(lua, Type::f32(), Some("f32"))?, - )) -} diff --git a/crates/lune-std-ffi/src/c/types/f64.rs b/crates/lune-std-ffi/src/c/types/f64.rs index fd989f2d..448d0080 100644 --- a/crates/lune-std-ffi/src/c/types/f64.rs +++ b/crates/lune-std-ffi/src/c/types/f64.rs @@ -1,6 +1,5 @@ use std::cell::Ref; -use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; @@ -52,10 +51,3 @@ impl NativeConvert for CType { Ok(value) } } - -pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { - Ok(( - "f64", - CType::::new_with_libffi_type(lua, Type::f64(), Some("f64"))?, - )) -} diff --git a/crates/lune-std-ffi/src/c/types/i128.rs b/crates/lune-std-ffi/src/c/types/i128.rs index 156c40a3..0f161621 100644 --- a/crates/lune-std-ffi/src/c/types/i128.rs +++ b/crates/lune-std-ffi/src/c/types/i128.rs @@ -1,6 +1,5 @@ use std::cell::Ref; -use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; @@ -52,14 +51,3 @@ impl NativeConvert for CType { Ok(value) } } - -pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { - Ok(( - "i128", - CType::::new_with_libffi_type( - lua, - Type::structure(vec![Type::u64(), Type::u64()]), - Some("i128"), - )?, - )) -} diff --git a/crates/lune-std-ffi/src/c/types/i16.rs b/crates/lune-std-ffi/src/c/types/i16.rs index 5198b4ed..0ced536e 100644 --- a/crates/lune-std-ffi/src/c/types/i16.rs +++ b/crates/lune-std-ffi/src/c/types/i16.rs @@ -1,6 +1,5 @@ use std::cell::Ref; -use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; @@ -52,10 +51,3 @@ impl NativeConvert for CType { Ok(value) } } - -pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { - Ok(( - "i16", - 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 8a3b7a59..5ebfd05c 100644 --- a/crates/lune-std-ffi/src/c/types/i32.rs +++ b/crates/lune-std-ffi/src/c/types/i32.rs @@ -1,6 +1,5 @@ use std::cell::Ref; -use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; @@ -52,10 +51,3 @@ impl NativeConvert for CType { Ok(value) } } - -pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { - Ok(( - "i32", - CType::::new_with_libffi_type(lua, Type::i32(), Some("i32"))?, - )) -} diff --git a/crates/lune-std-ffi/src/c/types/i64.rs b/crates/lune-std-ffi/src/c/types/i64.rs index f34cbab6..82a34ee5 100644 --- a/crates/lune-std-ffi/src/c/types/i64.rs +++ b/crates/lune-std-ffi/src/c/types/i64.rs @@ -1,6 +1,5 @@ use std::cell::Ref; -use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; @@ -52,10 +51,3 @@ impl NativeConvert for CType { Ok(value) } } - -pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { - Ok(( - "i64", - CType::::new_with_libffi_type(lua, Type::i64(), Some("i64"))?, - )) -} diff --git a/crates/lune-std-ffi/src/c/types/i8.rs b/crates/lune-std-ffi/src/c/types/i8.rs index 859a394a..e5b8c858 100644 --- a/crates/lune-std-ffi/src/c/types/i8.rs +++ b/crates/lune-std-ffi/src/c/types/i8.rs @@ -1,6 +1,5 @@ use std::cell::Ref; -use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; @@ -48,10 +47,3 @@ impl NativeConvert for CType { Ok(value) } } - -pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { - Ok(( - "i8", - CType::::new_with_libffi_type(lua, Type::i8(), Some("i8"))?, - )) -} diff --git a/crates/lune-std-ffi/src/c/types/isize.rs b/crates/lune-std-ffi/src/c/types/isize.rs index e98b3fb9..cf40db28 100644 --- a/crates/lune-std-ffi/src/c/types/isize.rs +++ b/crates/lune-std-ffi/src/c/types/isize.rs @@ -1,6 +1,5 @@ use std::cell::Ref; -use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; @@ -52,10 +51,3 @@ impl NativeConvert for CType { Ok(value) } } - -pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { - Ok(( - "isize", - CType::::new_with_libffi_type(lua, Type::isize(), Some("isize"))?, - )) -} diff --git a/crates/lune-std-ffi/src/c/types/mod.rs b/crates/lune-std-ffi/src/c/types/mod.rs index 7e116e46..f054142d 100644 --- a/crates/lune-std-ffi/src/c/types/mod.rs +++ b/crates/lune-std-ffi/src/c/types/mod.rs @@ -8,7 +8,7 @@ use mlua::prelude::*; use num::cast::AsPrimitive; use super::{CType, CTypeCast}; -use crate::ffi::{NativeConvert, NativeData, NativeSize}; +use crate::ffi::{native_num_cast, NativeConvert, NativeData, NativeSize}; pub mod f32; pub mod f64; @@ -25,14 +25,83 @@ 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)) +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))?, + ),)*]) }; } + +// create CType userdata and export +pub fn export_ctypes(lua: &Lua) -> LuaResult> { + create_ctypes!( + lua, + // Export Compile-time known c-types + ("char", c_char, { + if TypeId::of::() == TypeId::of::() { + Type::c_uchar() + } else { + Type::c_schar() + } + }), + ("uchar", c_uchar, Type::c_uchar()), + ("schar", c_schar, Type::c_schar()), + ("short", c_short, Type::c_short()), + ("ushort", c_ushort, Type::c_ushort()), + ("int", c_int, Type::c_int()), + ("uint", c_uint, Type::c_uint()), + ("long", c_long, Type::c_long()), + ("ulong", c_ulong, Type::c_ulong()), + ("longlong", c_longlong, Type::c_longlong()), + ("ulonglong", c_ulonglong, Type::c_ulonglong()), + // TODO: c_float and c_double sometime can be half and single, + // TODO: but libffi-rs doesn't support it. need work-around or drop support + ("float", f32, Type::f32()), + ("double", f64, Type::f64()), + // Export Source-time known c-types (fixed) + ("u8", u8, Type::u8()), + ("u16", u16, Type::u16()), + ("u32", u32, Type::u32()), + ("u64", u64, Type::u64()), + ("u128", u128, Type::c_longlong()), + ("i8", i8, Type::i8()), + ("i16", i16, Type::i16()), + ("i32", i32, Type::i32()), + ("i64", i64, Type::i64()), + ("i128", i128, Type::c_ulonglong()), + ("f64", f64, Type::f64()), + ("f32", f32, Type::f32()), + ("usize", usize, Type::usize()), + ("isize", isize, Type::isize()), + ) +} + +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")) + } + }; + (@get_size $userdata:ident, $( $rust_type:ty )*) => { + $( if $userdata.is::>() { + Ok($userdata.borrow::>()?.get_size()) + } else )* { + Err(LuaError::external("Unexpected type")) + } + }; + (@cast_num $from_rust_type:ident, $self:ident, $from_ctype:ident, $into_ctype:ident, $from:ident, $into:ident, $($into_rust_type:ty)*) => { + $( if $into_ctype.is::>() { + native_num_cast::<$from_rust_type, $into_rust_type>($from, $into) + } else )* { + Err($self.cast_failed_with($from_ctype, $into_ctype)) + } + }; +} + impl CTypeCast for CType where T: AsPrimitive @@ -57,106 +126,17 @@ where from: &Ref, into: &Ref, ) -> LuaResult<()> { - cast_nums!( - T, self, into_ctype, from_ctype, from, into, u8, u16, u32, u64, u128, i8, i16, i128, - f32, f64, usize, isize + define!( + @cast_num T, self, into_ctype, from_ctype, from, into, + u8 u16 u32 u64 u128 i8 i16 i32 i64 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![ - ( - "char", - CType::::new_with_libffi_type( - lua, - if TypeId::of::() == TypeId::of::() { - Type::c_uchar() - } else { - Type::c_schar() - }, - Some("char"), - )?, - ), - ( - "float", - CType::::new_with_libffi_type(lua, Type::f32(), Some("float"))?, - ), - ( - "double", - CType::::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), - ]) -} - -// export all default c-types -pub fn create_all_types(lua: &Lua) -> LuaResult> { - Ok(vec![ - self::u8::create_type(lua)?, - self::u16::create_type(lua)?, - self::u32::create_type(lua)?, - self::u64::create_type(lua)?, - self::u128::create_type(lua)?, - self::i8::create_type(lua)?, - self::i16::create_type(lua)?, - self::i32::create_type(lua)?, - self::i64::create_type(lua)?, - self::i128::create_type(lua)?, - self::f64::create_type(lua)?, - self::f32::create_type(lua)?, - self::usize::create_type(lua)?, - self::isize::create_type(lua)?, - ]) -} - -// Use UB method, but safe. because we use ffi_association to ensure children keep alive -// Much faster then get NativeConvert handle every time from lua table -// it's spam of table.get(), if ud.is::() { ud.borrow::()? ... } -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) -} - -macro_rules! define_get_ctype_size { - ($userdata:ident, $f:ty, $( $c:ty ),*) => { - if $userdata.is::>() { - Ok($userdata.borrow::>()?.get_size()) - }$( else if $userdata.is::>() { - Ok($userdata.borrow::>()?.get_size()) - })* else { - Err(LuaError::external("Unexpected type")) - } - }; +// To prevent drop NativeConvert, we must use ffi_association to ensure children keep alive +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 fn get_ctype_size(userdata: &LuaAnyUserData) -> LuaResult { - define_get_ctype_size!(userdata, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64) + define!(@get_size userdata, u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize) } diff --git a/crates/lune-std-ffi/src/c/types/u128.rs b/crates/lune-std-ffi/src/c/types/u128.rs index 8effc688..7ed99d6a 100644 --- a/crates/lune-std-ffi/src/c/types/u128.rs +++ b/crates/lune-std-ffi/src/c/types/u128.rs @@ -1,6 +1,5 @@ use std::cell::Ref; -use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; @@ -52,14 +51,3 @@ impl NativeConvert for CType { Ok(value) } } - -pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { - Ok(( - "u128", - CType::::new_with_libffi_type( - lua, - Type::structure(vec![Type::u64(), Type::u64()]), - Some("u128"), - )?, - )) -} diff --git a/crates/lune-std-ffi/src/c/types/u16.rs b/crates/lune-std-ffi/src/c/types/u16.rs index fb84ece5..d30d1ba7 100644 --- a/crates/lune-std-ffi/src/c/types/u16.rs +++ b/crates/lune-std-ffi/src/c/types/u16.rs @@ -1,6 +1,5 @@ use std::cell::Ref; -use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; @@ -53,10 +52,3 @@ impl NativeConvert for CType { Ok(value) } } - -pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { - Ok(( - "u16", - CType::::new_with_libffi_type(lua, Type::u16(), Some("u16"))?, - )) -} diff --git a/crates/lune-std-ffi/src/c/types/u32.rs b/crates/lune-std-ffi/src/c/types/u32.rs index 21a4dad9..54545f84 100644 --- a/crates/lune-std-ffi/src/c/types/u32.rs +++ b/crates/lune-std-ffi/src/c/types/u32.rs @@ -1,6 +1,5 @@ use std::cell::Ref; -use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; @@ -52,10 +51,3 @@ impl NativeConvert for CType { Ok(value) } } - -pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { - Ok(( - "u32", - CType::::new_with_libffi_type(lua, Type::u32(), Some("u32"))?, - )) -} diff --git a/crates/lune-std-ffi/src/c/types/u64.rs b/crates/lune-std-ffi/src/c/types/u64.rs index 7aac4c44..cfde9793 100644 --- a/crates/lune-std-ffi/src/c/types/u64.rs +++ b/crates/lune-std-ffi/src/c/types/u64.rs @@ -1,6 +1,5 @@ use std::cell::Ref; -use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; @@ -52,10 +51,3 @@ impl NativeConvert for CType { Ok(value) } } - -pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { - Ok(( - "u64", - CType::::new_with_libffi_type(lua, Type::u64(), Some("u64"))?, - )) -} diff --git a/crates/lune-std-ffi/src/c/types/u8.rs b/crates/lune-std-ffi/src/c/types/u8.rs index b3cda2ad..7aa185af 100644 --- a/crates/lune-std-ffi/src/c/types/u8.rs +++ b/crates/lune-std-ffi/src/c/types/u8.rs @@ -1,6 +1,5 @@ use std::cell::Ref; -use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; @@ -51,10 +50,3 @@ impl NativeConvert for CType { Ok(value) } } - -pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { - Ok(( - "u8", - CType::::new_with_libffi_type(lua, Type::u8(), Some("u8"))?, - )) -} diff --git a/crates/lune-std-ffi/src/c/types/usize.rs b/crates/lune-std-ffi/src/c/types/usize.rs index b5ddfbb9..a6523b65 100644 --- a/crates/lune-std-ffi/src/c/types/usize.rs +++ b/crates/lune-std-ffi/src/c/types/usize.rs @@ -1,6 +1,5 @@ use std::cell::Ref; -use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; @@ -52,10 +51,3 @@ impl NativeConvert for CType { Ok(value) } } - -pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> { - Ok(( - "usize", - CType::::new_with_libffi_type(lua, Type::usize(), Some("usize"))?, - )) -} 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 c107b736..001f8c8c 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs @@ -155,6 +155,7 @@ impl NativeData for FfiRef { impl LuaUserData for FfiRef { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + // FIXME: methods.add_function("deref", |lua, this: LuaAnyUserData| { let inner = get_association(lua, REF_INNER, &this)?; let ffiref = this.borrow::()?; @@ -178,6 +179,7 @@ impl LuaUserData for FfiRef { Ok(userdata) }); + // FIXME: methods.add_function("ref", |lua, this: LuaAnyUserData| { let ffiref = FfiRef::luaref(lua, this)?; Ok(ffiref) diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs index 72bbbdbc..d2f593a8 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::{create_all_c_types, create_all_types, CFn, CStruct}, + c::{export_ctypes, CFn, CStruct}, ffi::{create_nullptr, is_integer, FfiBox, FfiLib}, }; @@ -22,19 +22,19 @@ use crate::{ */ pub fn module(lua: &Lua) -> LuaResult { let result = TableBuilder::new(lua)? - .with_values(create_all_types(lua)?)? - .with_values(create_all_c_types(lua)?)? - .with_value("nullptr", create_nullptr(lua)?)? + .with_values(export_ctypes(lua)?)? + .with_value("nullRef", create_nullptr(lua)?)? .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| { + .with_function("structInfo", |lua, types: LuaTable| { CStruct::new_from_lua_table(lua, types) })? - .with_function("ref", |_lua, ()| Ok(FfiRef::new_uninit()))? + .with_function("uninitRef", |_lua, ()| Ok(FfiRef::new_uninit()))? .with_function("isInteger", |_lua, num: LuaValue| Ok(is_integer(num)))? - .with_function("fn", |lua, (args, ret): (LuaTable, LuaAnyUserData)| { - CFn::new_from_lua_table(lua, args, ret) - })?; + .with_function( + "funcInfo", + |lua, (args, ret): (LuaTable, LuaAnyUserData)| CFn::new_from_lua_table(lua, args, ret), + )?; #[cfg(debug_assertions)] let result = result.with_function("debug_associate", |lua, str: String| { diff --git a/crates/lune-std-ffi/src/libffi_helper.rs b/crates/lune-std-ffi/src/libffi_helper.rs index 37feaa79..10c56043 100644 --- a/crates/lune-std-ffi/src/libffi_helper.rs +++ b/crates/lune-std-ffi/src/libffi_helper.rs @@ -5,7 +5,7 @@ use mlua::prelude::*; use crate::ffi::FFI_STATUS_NAMES; -// Ensure sizeof c-type (raw::libffi_type) +// Get ensured size of c-type (raw::libffi_type) // See: http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html pub fn get_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult { let mut cif = low::ffi_cif::default(); From f094f2b74a1a35bee5809be3de9c1865d5809a2f Mon Sep 17 00:00:00 2001 From: qwreey Date: Wed, 16 Oct 2024 06:35:09 +0000 Subject: [PATCH 20/79] Remove static ctype reduce duplicated code (#243) --- crates/lune-std-ffi/src/c/c_helper.rs | 3 +- crates/lune-std-ffi/src/c/c_type.rs | 34 +--------- crates/lune-std-ffi/src/c/mod.rs | 3 +- crates/lune-std-ffi/src/c/types/mod.rs | 91 ++++++++++++++++++-------- 4 files changed, 66 insertions(+), 65 deletions(-) diff --git a/crates/lune-std-ffi/src/c/c_helper.rs b/crates/lune-std-ffi/src/c/c_helper.rs index a843ae5e..2db73610 100644 --- a/crates/lune-std-ffi/src/c/c_helper.rs +++ b/crates/lune-std-ffi/src/c/c_helper.rs @@ -5,9 +5,8 @@ use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; use mlua::prelude::*; use super::{ - association_names::CTYPE_STATIC, types::{get_ctype_conv, get_ctype_size}, - CArr, CPtr, CStruct, CTypeStatic, + CArr, CPtr, CStruct, }; use crate::ffi::{ffi_association::get_association, NativeConvert, NativeSize}; diff --git a/crates/lune-std-ffi/src/c/c_type.rs b/crates/lune-std-ffi/src/c/c_type.rs index 1b6dcf17..67cfdda1 100644 --- a/crates/lune-std-ffi/src/c/c_type.rs +++ b/crates/lune-std-ffi/src/c/c_type.rs @@ -6,36 +6,10 @@ use libffi::middle::Type; use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; use mlua::prelude::*; -use super::{association_names::CTYPE_STATIC, CArr, CPtr}; -use crate::ffi::{ - ffi_association::set_association, FfiBox, GetNativeData, NativeConvert, NativeData, - NativeSignedness, NativeSize, -}; +use super::{CArr, CPtr}; +use crate::ffi::{FfiBox, GetNativeData, NativeConvert, NativeData, NativeSignedness, NativeSize}; use crate::libffi_helper::get_ensured_size; -// We can't get a CType through mlua, something like -// .is::> will fail. -// So we need data that has a static type. -// each CType userdata instance stores an instance of CTypeStatic. -#[allow(unused)] -pub struct CTypeStatic { - pub libffi_type: Type, - pub size: usize, - pub name: Option<&'static str>, - pub signedness: bool, -} -impl CTypeStatic { - fn new(ctype: &CType, signedness: bool) -> Self { - Self { - libffi_type: ctype.libffi_type.clone(), - size: ctype.size, - name: ctype.name, - signedness, - } - } -} -impl LuaUserData for CTypeStatic {} - // Cast native data pub trait CTypeCast { #[inline(always)] @@ -96,12 +70,8 @@ where name, _phantom: PhantomData, }; - let userdata_static = - lua.create_any_userdata(CTypeStatic::new::(&ctype, ctype.get_signedness()))?; let userdata = lua.create_userdata(ctype)?; - set_association(lua, CTYPE_STATIC, &userdata, &userdata_static)?; - Ok(userdata) } diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index e1a577af..e99b9c95 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -12,7 +12,7 @@ pub use self::{ c_fn::CFn, c_ptr::CPtr, c_struct::CStruct, - c_type::{CType, CTypeCast, CTypeStatic}, + c_type::{CType, CTypeCast}, }; pub use types::export_ctypes; @@ -22,7 +22,6 @@ mod association_names { pub const CPTR_INNER: &str = "__cptr_inner"; pub const CARR_INNER: &str = "__carr_inner"; pub const CSTRUCT_INNER: &str = "__cstruct_inner"; - pub const CTYPE_STATIC: &str = "__ctype_static"; pub const CFN_RESULT: &str = "__cfn_result"; pub const CFN_ARGS: &str = "__cfn_args"; pub const CALLABLE_REF: &str = "__callable_ref"; diff --git a/crates/lune-std-ffi/src/c/types/mod.rs b/crates/lune-std-ffi/src/c/types/mod.rs index f054142d..87df5174 100644 --- a/crates/lune-std-ffi/src/c/types/mod.rs +++ b/crates/lune-std-ffi/src/c/types/mod.rs @@ -25,6 +25,7 @@ pub mod u64; pub mod u8; pub mod usize; +// create CType userdata and export macro_rules! create_ctypes { ($lua:ident, $(( $name:expr, $rust_type:ty, $libffi_type:expr ),)* ) => { Ok(vec![$(( @@ -33,8 +34,6 @@ macro_rules! create_ctypes { ),)*]) }; } - -// create CType userdata and export pub fn export_ctypes(lua: &Lua) -> LuaResult> { create_ctypes!( lua, @@ -56,10 +55,6 @@ pub fn export_ctypes(lua: &Lua) -> LuaResult ("ulong", c_ulong, Type::c_ulong()), ("longlong", c_longlong, Type::c_longlong()), ("ulonglong", c_ulonglong, Type::c_ulonglong()), - // TODO: c_float and c_double sometime can be half and single, - // TODO: but libffi-rs doesn't support it. need work-around or drop support - ("float", f32, Type::f32()), - ("double", f64, Type::f64()), // Export Source-time known c-types (fixed) ("u8", u8, Type::u8()), ("u16", u16, Type::u16()), @@ -75,25 +70,16 @@ pub fn export_ctypes(lua: &Lua) -> LuaResult ("f32", f32, Type::f32()), ("usize", usize, Type::usize()), ("isize", isize, Type::isize()), + // TODO: c_float and c_double sometime can be half and single, + // TODO: but libffi-rs doesn't support it. need work-around or drop support + ("float", f32, Type::f32()), + ("double", f64, Type::f64()), ) } -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")) - } - }; - (@get_size $userdata:ident, $( $rust_type:ty )*) => { - $( if $userdata.is::>() { - Ok($userdata.borrow::>()?.get_size()) - } else )* { - Err(LuaError::external("Unexpected type")) - } - }; - (@cast_num $from_rust_type:ident, $self:ident, $from_ctype:ident, $into_ctype:ident, $from:ident, $into:ident, $($into_rust_type:ty)*) => { +// Implement type-casting for numeric ctypes +macro_rules! define_cast_num { + ($from_rust_type:ident, $self:ident, $from_ctype:ident, $into_ctype:ident, $from:ident, $into:ident, $($into_rust_type:ty)*) => { $( if $into_ctype.is::>() { native_num_cast::<$from_rust_type, $into_rust_type>($from, $into) } else )* { @@ -101,10 +87,9 @@ macro_rules! define { } }; } - -impl CTypeCast for CType +impl CTypeCast for CType where - T: AsPrimitive + From: AsPrimitive + AsPrimitive + AsPrimitive + AsPrimitive @@ -126,17 +111,65 @@ where from: &Ref, into: &Ref, ) -> LuaResult<()> { - define!( - @cast_num T, self, into_ctype, from_ctype, from, into, + define_cast_num!( + From, self, into_ctype, from_ctype, from, into, 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")) + } + }; +} 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) + define_get_conv!(userdata, u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize) +} + +// Get size of ctype (not includes struct, arr, ... only CType<*>) +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) + define_get_size!(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 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) } From 95258e1b514f71b7bce793d627272bda68163659 Mon Sep 17 00:00:00 2001 From: qwreey Date: Wed, 16 Oct 2024 07:57:25 +0000 Subject: [PATCH 21/79] 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 | 211 ++++++++++++------ 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 | 108 +++------ 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, 509 insertions(+), 486 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 0f22de27..9ecefb3f 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 ef1bc0dc..68d8e49e 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 2db73610..cb03f62b 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,13 +135,38 @@ 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 libffi_type from any c-type userdata +pub fn get_middle_type(userdata: &LuaAnyUserData) -> LuaResult { + if userdata.is::() { + 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()) + } else if userdata.is::() { + Ok(CPtr::get_type()) + } else { + Err(LuaError::external(format!( + "Unexpected field. CStruct, CType, CString or CArr is required for element but got {}", + pretty_format_value( + // Since the data is in the Lua location, + // there is no problem with the clone. + &LuaValue::UserData(userdata.to_owned()), + &ValueFormatConfig::new() + ) + ))) } } // get Vec from table(array) of c-type userdata -pub fn libffi_type_list_from_table(lua: &Lua, table: &LuaTable) -> LuaResult> { +pub fn get_middle_type_list(table: &LuaTable) -> LuaResult> { let len: usize = table.raw_len(); let mut fields = Vec::with_capacity(len); @@ -66,7 +174,7 @@ pub fn libffi_type_list_from_table(lua: &Lua, table: &LuaTable) -> LuaResult LuaResult 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()) - } else if userdata.is::() { - Ok(userdata.borrow::()?.get_type().to_owned()) - } else if userdata.is::() { - Ok(CPtr::get_type()) - } else { - Err(LuaError::external(format!( - "Unexpected field. CStruct, CType, CString or CArr is required for element but got {}", - pretty_format_value( - // Since the data is in the Lua location, - // there is no problem with the clone. - &LuaValue::UserData(userdata.to_owned()), - &ValueFormatConfig::new() - ) - ))) - } -} - // 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 08d9d331..99375b43 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 f34a98ec..92e02173 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 67cfdda1..55c8c0b3 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()))?; - - 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); - - 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")); - } - - 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) - }); + // 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_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 e99b9c95..75635f72 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 87df5174..8c8840a3 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 bf1a2cdf..be15a658 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 87d81bd2..b0712579 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 luasym = lua.create_userdata(FfiRef::new(ptr, LIB_REF_FLAGS, UNSIZED_BOUNDS))?; + let ffi_ref = + lua.create_userdata(FfiRef::new(sym.cast_mut(), LIB_REF_FLAGS, UNSIZED_BOUNDS))?; - set_association(lua, SYM_INNER, &luasym, &this)?; + set_association(lua, SYM_INNER, &ffi_ref, &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 8e986774..00000000 --- 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 50dd8f89..ef4ae648 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 d2f593a8..661f0735 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 00000000..3686c9ea --- /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 00000000..7e92e32c --- /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 f6f1490e..00000000 --- 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") From f27bed578f4faaa19eb28ffcb29ae74a2f651519 Mon Sep 17 00:00:00 2001 From: Erica Marigold Date: Wed, 16 Oct 2024 12:34:59 +0100 Subject: [PATCH 22/79] chore(types): updated ffi types --- types/ffi.luau | 189 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 125 insertions(+), 64 deletions(-) diff --git a/types/ffi.luau b/types/ffi.luau index fb452081..c25ab4cc 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -1,79 +1,140 @@ ---[=[ - @interface Box - @within FFI +export type CType = { + size: number, + signedness: boolean, - Box is an untyped, sized memory area that Lua can manage. - This area is safe within Lua. Operations have their boundaries checked. + ptr: (self: CType) -> CPtr, + box: (self: CType, val: K) -> Box, + from: (self: CType, ud: any, offset: number?) -> K, + into: (self: CType, ud: any, value: K, offset: number?) -> (), + arr: (self: CType, len: number) -> CArr, + -- FIXME: intoType is of type `CTypes`, but that leads to recursive types + cast: (self: CType, intoType: any, from: F, into: I) -> () +} & { ["__phantom"]: T } - You can passing box as raw arguments or as pointer to outside. - It also helps you handle data that Lua cannot handle. or you can reuse box to save cost from convertsion. - Depending on the type, operations such as sum, mul, and mod may be implemented. See Types +export type CPtr = { + size: number, + inner: T?, +} + +export type CArr = { + size: number, + length: number, + inner: {T}?, - ```lua - ffi.box(size) - ``` - This is a dictionary that will contain the following values: + offset: (self: CArr, offset: number) -> number, + ptr: (self: CArr) -> CPtr, + box: (self: CArr, table: { K }) -> Box, + from: (self: CArr, ud: any, offset: number?) -> { K }, + into: (self: CArr, ud: any, value: { K }, offset: number?) -> (), +} - * `readOnly` - If the target path is read-only or not -]=] +-- Numeric types -- +export type u8 = CType<"u8"> +export type u16 = CType<"u16"> +export type u32 = CType<"u32"> +export type u64 = CType<"u64"> +export type u128 = CType<"u128"> +export type i8 = CType<"i8"> +export type i16 = CType<"i16"> +export type i32 = CType<"i32"> +export type i64 = CType<"i64"> +export type i128 = CType<"i128"> +export type f32 = CType<"f32"> +export type f64 = CType<"f64"> +export type usize = CType<"usize"> +export type isize = CType<"isize"> -export type Box = { - size: number, - ref: (self: Box)->Ref, +-- C types -- +export type char = CType<"char"> +export type float = CType<"float"> +export type double = CType<"double"> +export type uchar = CType<"uchar"> +export type schar = CType<"schar"> +export type short = CType<"short"> +export type ushort = CType<"ushort"> +export type int = CType<"int"> +export type uint = CType<"uint"> +export type long = CType<"long"> +export type ulong = CType<"ulong"> +export type longlong = CType<"longlong"> +export type ulonglong = CType<"ulonglong"> +export type CFn = { + caller: () -> Callable } -export type BoxConstructor = (size: number)->Box -export type Type = {} +export type CTypes = + | u8 + | u16 + | u32 + | u64 + | u128 + | i8 + | i16 + | i32 + | i64 + | i128 + | f32 + | f64 + | usize + | isize + | char + | float + | double + | uchar + | schar + | short + | ushort + | int + | uint + | long + | ulong + | longlong + | ulonglong ----! FIXME: better typing for PointerSize -export type PointerSize = number -- typeof(5) | typeof(8) +export type Ref = { + deref: (self: Ref) -> Ref, + offset: (self: Ref, offset: number) -> Ref, + ref: (self: Ref) -> Ref, + isNullptr: (self: Ref) -> boolean, +} -export type Arr = { - inner: T, +export type Box = { size: number, - ptr: (self: Arr) -> any, + + zero: (self: Box) -> Box, + leak: (self: Box, offset: number?) -> Ref, + ref: (self: Box, offset: number?) -> Ref, } ---[=[ - @interface Ptr - @within FFI - -]=] ----! FIXME: due to recursive type limition. hardcoded 6 depth. better idea? -export type Ptr = { - inner: T, - size: PointerSize, - ptr: (self: Ptr)->PtrPtr>, - arr: (self: Ptr, size: number) -> Arr>, -} -export type PtrPtr = { - inner: T, - size: PointerSize, - ptr: (self: PtrPtr)->PtrPtrPtr>, - arr: (self: PtrPtr, size: number) -> Arr>, +export type Library = { + find: (sym: string) -> Ref, } -export type PtrPtrPtr = { - inner: T, - size: PointerSize, - ptr: (self: PtrPtrPtr)->PtrPtrPtrPtr>, - arr: (self: PtrPtrPtr, size: number) -> Arr>, -} -export type PtrPtrPtrPtr = { - inner: T, - size: PointerSize, - ptr: (self: PtrPtrPtrPtr)->PtrPtrPtrPtrPtr>, - arr: (self: PtrPtrPtrPtr, size: number) -> Arr>, -} -export type PtrPtrPtrPtrPtr = { - inner: T, - size: PointerSize, - ptr: (self: PtrPtrPtrPtrPtr)->PtrPtrPtrPtrPtrPtr>, - arr: (self: PtrPtrPtrPtrPtr, size: number) -> Arr>, -} -export type PtrPtrPtrPtrPtrPtr = { - inner: T, - size: PointerSize, - ptr: (self: PtrPtrPtrPtrPtrPtr)->any, -- Yes. At this point. more type is useless. - arr: (self: PtrPtrPtrPtrPtrPtr, size: number) -> Arr>, + +export type Callable = { + call: (...any) -> (), } +local ffi = {} + +ffi.u8 = {} :: u8 +ffi.nullptr = {} :: Ref + +function ffi.box(size: number): Box + return nil :: any +end + +function ffi.open(path: string): Library + return nil :: any +end + +function ffi.ref(): Ref + return nil :: any +end + +function ffi.isInteger(val: T): boolean + return nil :: any +end + +function ffi.fn(args: { any }, ret: CPtr): CFn + return nil :: any +end From b03b485e29cfc443a8e2f0401429ef0f62bf3910 Mon Sep 17 00:00:00 2001 From: Erica Marigold Date: Wed, 16 Oct 2024 12:53:16 +0100 Subject: [PATCH 23/79] chore(types): fix `CType:cast` to be properly typed --- types/ffi.luau | 99 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 39 deletions(-) diff --git a/types/ffi.luau b/types/ffi.luau index c25ab4cc..ecb40fdf 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -1,16 +1,34 @@ -export type CType = { +local CType = {} +-- NOTE: T is a unique identifier for the `CType` and R is the closest Lua type. +export type CType = typeof(CType) & { size: number, signedness: boolean, - - ptr: (self: CType) -> CPtr, - box: (self: CType, val: K) -> Box, - from: (self: CType, ud: any, offset: number?) -> K, - into: (self: CType, ud: any, value: K, offset: number?) -> (), - arr: (self: CType, len: number) -> CArr, - -- FIXME: intoType is of type `CTypes`, but that leads to recursive types - cast: (self: CType, intoType: any, from: F, into: I) -> () } & { ["__phantom"]: T } +function CType.ptr(self: CType): CPtr + return nil :: any +end + +function CType.box(self: CType, val: R): Box + return nil :: any +end + +function CType.from(self: CType, ud: CTypes, offset: number?): R + return nil :: any +end + +function CType.into(self: CType, ud: CTypes, value: R, offset: number?) + return nil :: any +end + +function CType.arr(self: CType, len: number): CArr + return nil :: any +end + +function CType.cast(self: CType, intoType: CTypes, from: F, into: I) + return nil :: any +end + export type CPtr = { size: number, inner: T?, @@ -28,36 +46,39 @@ export type CArr = { into: (self: CArr, ud: any, value: { K }, offset: number?) -> (), } --- Numeric types -- -export type u8 = CType<"u8"> -export type u16 = CType<"u16"> -export type u32 = CType<"u32"> -export type u64 = CType<"u64"> -export type u128 = CType<"u128"> -export type i8 = CType<"i8"> -export type i16 = CType<"i16"> -export type i32 = CType<"i32"> -export type i64 = CType<"i64"> -export type i128 = CType<"i128"> -export type f32 = CType<"f32"> -export type f64 = CType<"f64"> -export type usize = CType<"usize"> -export type isize = CType<"isize"> - --- C types -- -export type char = CType<"char"> -export type float = CType<"float"> -export type double = CType<"double"> -export type uchar = CType<"uchar"> -export type schar = CType<"schar"> -export type short = CType<"short"> -export type ushort = CType<"ushort"> -export type int = CType<"int"> -export type uint = CType<"uint"> -export type long = CType<"long"> -export type ulong = CType<"ulong"> -export type longlong = CType<"longlong"> -export type ulonglong = CType<"ulonglong"> +type NumCType = CType + +-- Fixed size Rust-style types -- +export type u8 = NumCType<"u8"> +export type u16 = NumCType<"u16"> +export type u32 = NumCType<"u32"> +export type u64 = NumCType<"u64"> +export type u128 = NumCType<"u128"> +export type i8 = NumCType<"i8"> +export type i16 = NumCType<"i16"> +export type i32 = NumCType<"i32"> +export type i64 = NumCType<"i64"> +export type i128 = NumCType<"i128"> +export type f32 = NumCType<"f32"> +export type f64 = NumCType<"f64"> +export type usize = NumCType<"usize"> +export type isize = NumCType<"isize"> + +-- Variable C-style types -- +export type char = NumCType<"char"> +export type float = NumCType<"float"> +export type double = NumCType<"double"> +export type uchar = NumCType<"uchar"> +export type schar = NumCType<"schar"> +export type short = NumCType<"short"> +export type ushort = NumCType<"ushort"> +export type int = NumCType<"int"> +export type uint = NumCType<"uint"> +export type long = NumCType<"long"> +export type ulong = NumCType<"ulong"> +export type longlong = NumCType<"longlong"> +export type ulonglong = NumCType<"ulonglong"> + export type CFn = { caller: () -> Callable } From d27fba81475ce94137823e35fa77450d9e9ab502 Mon Sep 17 00:00:00 2001 From: Erica Marigold Date: Wed, 16 Oct 2024 12:56:57 +0100 Subject: [PATCH 24/79] chore(types): remove unnecessary generic usage --- types/ffi.luau | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/types/ffi.luau b/types/ffi.luau index ecb40fdf..541aff4c 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -40,10 +40,10 @@ export type CArr = { inner: {T}?, offset: (self: CArr, offset: number) -> number, - ptr: (self: CArr) -> CPtr, - box: (self: CArr, table: { K }) -> Box, - from: (self: CArr, ud: any, offset: number?) -> { K }, - into: (self: CArr, ud: any, value: { K }, offset: number?) -> (), + ptr: (self: CArr) -> CPtr<{T}>, + box: (self: CArr, table: { T }) -> Box, + from: (self: CArr, ud: CTypes, offset: number?) -> { T }, + into: (self: CArr, ud: CTypes, value: { T }, offset: number?) -> (), } type NumCType = CType @@ -64,7 +64,7 @@ export type f64 = NumCType<"f64"> export type usize = NumCType<"usize"> export type isize = NumCType<"isize"> --- Variable C-style types -- +-- Variable size C-style types -- export type char = NumCType<"char"> export type float = NumCType<"float"> export type double = NumCType<"double"> From 991ae5a9f1554905d4dea44c401c8ee2beaaea82 Mon Sep 17 00:00:00 2001 From: Erica Marigold Date: Wed, 16 Oct 2024 19:08:29 +0100 Subject: [PATCH 25/79] chore(types): fix incorrect function signatures * Fixes incorrect function signatures for callables. * Now correctly returns the main module. --- types/ffi.luau | 187 ++++++++++++++++++++++++++----------------------- 1 file changed, 101 insertions(+), 86 deletions(-) diff --git a/types/ffi.luau b/types/ffi.luau index 541aff4c..f43f8d75 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -1,49 +1,34 @@ -local CType = {} -- NOTE: T is a unique identifier for the `CType` and R is the closest Lua type. -export type CType = typeof(CType) & { - size: number, - signedness: boolean, +export type CType = { + size: number, + signedness: boolean, + + ptr: (self: CType) -> CPtr, + box: (self: CType, val: R) -> Box, + -- FIXME: recursive types; ud should be CTypes + from: (self: CType, ud: any, offset: number?) -> R, + into: (self: CType, ud: any, value: R, offset: number?) -> (), + arr: (self: CType, len: number) -> CArr, + -- FIXME: recursive types; intoType should be CTypes + cast: (self: CType, intoType: any, from: F, into: I) -> (), } & { ["__phantom"]: T } -function CType.ptr(self: CType): CPtr - return nil :: any -end - -function CType.box(self: CType, val: R): Box - return nil :: any -end - -function CType.from(self: CType, ud: CTypes, offset: number?): R - return nil :: any -end - -function CType.into(self: CType, ud: CTypes, value: R, offset: number?) - return nil :: any -end - -function CType.arr(self: CType, len: number): CArr - return nil :: any -end - -function CType.cast(self: CType, intoType: CTypes, from: F, into: I) - return nil :: any -end - export type CPtr = { - size: number, - inner: T?, + size: number, + inner: T?, } export type CArr = { - size: number, - length: number, - inner: {T}?, - - offset: (self: CArr, offset: number) -> number, - ptr: (self: CArr) -> CPtr<{T}>, - box: (self: CArr, table: { T }) -> Box, - from: (self: CArr, ud: CTypes, offset: number?) -> { T }, - into: (self: CArr, ud: CTypes, value: { T }, offset: number?) -> (), + size: number, + length: number, + inner: { T }?, + + offset: (self: CArr, offset: number) -> number, + ptr: (self: CArr) -> CPtr<{ T }>, + box: (self: CArr, table: { T }) -> Box, + -- FIXME: recursive types; ud should be CTypes + from: (self: CArr, ud: any, offset: number?) -> { T }, + into: (self: CArr, ud: any, value: { T }, offset: number?) -> (), } type NumCType = CType @@ -80,82 +65,112 @@ export type longlong = NumCType<"longlong"> export type ulonglong = NumCType<"ulonglong"> export type CFn = { - caller: () -> Callable + caller: (self: CFn, fnPtr: Ref) -> Callable, } -export type CTypes = - | u8 - | u16 - | u32 - | u64 - | u128 - | i8 - | i16 - | i32 - | i64 - | i128 - | f32 - | f64 - | usize - | isize - | char - | float - | double - | uchar - | schar - | short - | ushort - | int - | uint - | long - | ulong - | longlong - | ulonglong +export type CTypes = + u8 + | u16 + | u32 + | u64 + | u128 + | i8 + | i16 + | i32 + | i64 + | i128 + | f32 + | f64 + | usize + | isize + | char + | float + | double + | uchar + | schar + | short + | ushort + | int + | uint + | long + | ulong + | longlong + | ulonglong export type Ref = { - deref: (self: Ref) -> Ref, - offset: (self: Ref, offset: number) -> Ref, - ref: (self: Ref) -> Ref, - isNullptr: (self: Ref) -> boolean, + deref: (self: Ref) -> Ref, + offset: (self: Ref, offset: number) -> Ref, + ref: (self: Ref) -> Ref, + isNullptr: (self: Ref) -> boolean, } export type Box = { - size: number, - - zero: (self: Box) -> Box, - leak: (self: Box, offset: number?) -> Ref, - ref: (self: Box, offset: number?) -> Ref, + size: number, + + zero: (self: Box) -> Box, + leak: (self: Box, offset: number?) -> Ref, + ref: (self: Box, offset: number?) -> Ref, } export type Library = { - find: (sym: string) -> Ref, + find: (self: Library, sym: string) -> Ref, } export type Callable = { - call: (...any) -> (), + call: (self: Callable, retPtr: Ref, ...Box) -> (), } local ffi = {} -ffi.u8 = {} :: u8 +ffi.u8 = (nil :: unknown) :: u8 +ffi.u16 = {} :: u16 +ffi.u32 = {} :: u32 +ffi.u64 = {} :: u64 +ffi.u128 = {} :: u128 +ffi.i8 = {} :: i8 +ffi.i16 = {} :: i16 +ffi.i32 = {} :: i32 +ffi.i64 = {} :: i64 +ffi.i128 = {} :: i128 +ffi.f32 = {} :: f32 +ffi.f64 = {} :: f64 +ffi.usize = {} :: usize +ffi.isize = {} :: isize + +ffi.char = {} :: char +ffi.float = {} :: float +ffi.double = {} :: double +ffi.uchar = {} :: uchar +ffi.schar = {} :: schar +ffi.short = {} :: short +ffi.ushort = {} :: ushort +ffi.int = {} :: int +ffi.uint = {} :: uint +ffi.long = {} :: long +ffi.ulong = {} :: ulong +ffi.longlong = {} :: longlong +ffi.ulonglong = {} :: ulonglong + ffi.nullptr = {} :: Ref function ffi.box(size: number): Box - return nil :: any + return nil :: any end function ffi.open(path: string): Library - return nil :: any + return nil :: any end function ffi.ref(): Ref - return nil :: any + return nil :: any end function ffi.isInteger(val: T): boolean - return nil :: any + return nil :: any end -function ffi.fn(args: { any }, ret: CPtr): CFn - return nil :: any +function ffi.fn(args: { CTypes }, ret: CTypes): CFn + return nil :: any end + +return ffi From 133abb5477102f7f2b5c0ed3cb89888329bd34e3 Mon Sep 17 00:00:00 2001 From: Erica Marigold Date: Wed, 16 Oct 2024 19:09:35 +0100 Subject: [PATCH 26/79] chore(types): add accidently removed leading pipe to `CTypes` --- types/ffi.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/ffi.luau b/types/ffi.luau index f43f8d75..ddcc5e96 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -69,7 +69,7 @@ export type CFn = { } export type CTypes = - u8 + | u8 | u16 | u32 | u64 From ba074d9a283112ed0e224bbf078e6b4241504160 Mon Sep 17 00:00:00 2001 From: qwreey Date: Wed, 16 Oct 2024 23:37:56 +0000 Subject: [PATCH 27/79] Reducing and organizing duplicated codes (#243) --- crates/lune-std-ffi/src/c/c_arr.rs | 2 +- crates/lune-std-ffi/src/c/c_func.rs | 2 +- crates/lune-std-ffi/src/c/c_helper.rs | 4 ++ crates/lune-std-ffi/src/c/c_ptr.rs | 46 ++++++++++++++----- crates/lune-std-ffi/src/c/c_struct.rs | 10 ++-- crates/lune-std-ffi/src/c/c_type.rs | 1 - crates/lune-std-ffi/src/c/types/f32.rs | 6 ++- crates/lune-std-ffi/src/c/types/f64.rs | 6 ++- crates/lune-std-ffi/src/c/types/i128.rs | 4 +- crates/lune-std-ffi/src/c/types/i16.rs | 4 +- crates/lune-std-ffi/src/c/types/i32.rs | 4 +- crates/lune-std-ffi/src/c/types/i64.rs | 4 +- crates/lune-std-ffi/src/c/types/i8.rs | 4 +- crates/lune-std-ffi/src/c/types/isize.rs | 4 +- crates/lune-std-ffi/src/c/types/u128.rs | 4 +- crates/lune-std-ffi/src/c/types/u16.rs | 4 +- crates/lune-std-ffi/src/c/types/u32.rs | 4 +- crates/lune-std-ffi/src/c/types/u64.rs | 4 +- crates/lune-std-ffi/src/c/types/u8.rs | 5 +- crates/lune-std-ffi/src/c/types/usize.rs | 4 +- crates/lune-std-ffi/src/ffi/ffi_box/mod.rs | 12 ++--- crates/lune-std-ffi/src/ffi/ffi_callable.rs | 6 ++- .../lune-std-ffi/src/ffi/ffi_native/cast.rs | 4 +- .../lune-std-ffi/src/ffi/ffi_native/data.rs | 2 +- crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs | 28 +++++------ crates/lune-std-ffi/src/lib.rs | 2 +- crates/lune-std-ffi/src/libffi_helper.rs | 2 + 27 files changed, 108 insertions(+), 74 deletions(-) diff --git a/crates/lune-std-ffi/src/c/c_arr.rs b/crates/lune-std-ffi/src/c/c_arr.rs index 9ecefb3f..7cd7bba4 100644 --- a/crates/lune-std-ffi/src/c/c_arr.rs +++ b/crates/lune-std-ffi/src/c/c_arr.rs @@ -145,7 +145,7 @@ impl LuaUserData for CArr { fields.add_field_function_get("inner", |lua, this: LuaAnyUserData| { let inner: LuaValue = get_association(lua, CARR_INNER, this)? // It shouldn't happen. - .ok_or(LuaError::external("inner field not found"))?; + .ok_or_else(|| LuaError::external("inner field not found"))?; Ok(inner) }); } diff --git a/crates/lune-std-ffi/src/c/c_func.rs b/crates/lune-std-ffi/src/c/c_func.rs index 68d8e49e..ff7952bc 100644 --- a/crates/lune-std-ffi/src/c/c_func.rs +++ b/crates/lune-std-ffi/src/c/c_func.rs @@ -158,7 +158,7 @@ impl LuaUserData for CFunc { this.cif.as_raw_ptr(), ptr::from_ref(&this.arg_info_list), ptr::from_ref(&this.result_info), - ffi_ref.get_pointer(0), + ffi_ref.get_pointer(), ) })?; diff --git a/crates/lune-std-ffi/src/c/c_helper.rs b/crates/lune-std-ffi/src/c/c_helper.rs index cb03f62b..68882df8 100644 --- a/crates/lune-std-ffi/src/c/c_helper.rs +++ b/crates/lune-std-ffi/src/c/c_helper.rs @@ -48,6 +48,9 @@ pub mod method_provider { 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) } }, @@ -65,6 +68,7 @@ pub mod method_provider { let offset = offset.unwrap_or(0); let data_handle = &userdata.get_data_handle()?; + // use or functions if !data_handle.check_boundary(offset, this.get_size()) { return Err(LuaError::external("Out of bounds")); } diff --git a/crates/lune-std-ffi/src/c/c_ptr.rs b/crates/lune-std-ffi/src/c/c_ptr.rs index 99375b43..840aa0fc 100644 --- a/crates/lune-std-ffi/src/c/c_ptr.rs +++ b/crates/lune-std-ffi/src/c/c_ptr.rs @@ -4,12 +4,17 @@ use libffi::middle::Type; use mlua::prelude::*; 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, +use crate::{ + ffi::{ + ffi_association::{get_association, set_association}, + FfiRef, NativeConvert, NativeData, NativeSignedness, NativeSize, + }, + libffi_helper::SIEE_OF_POINTER, }; -pub struct CPtr(); +pub struct CPtr { + inner_size: usize, +} impl NativeSignedness for CPtr { fn get_signedness(&self) -> bool { @@ -18,7 +23,7 @@ impl NativeSignedness for CPtr { } impl NativeSize for CPtr { fn get_size(&self) -> usize { - size_of::<*mut ()>() + SIEE_OF_POINTER } } impl NativeConvert for CPtr { @@ -26,11 +31,28 @@ impl NativeConvert for CPtr { unsafe fn luavalue_into<'lua>( &self, _lua: &'lua Lua, - _offset: isize, - _data_handle: &Ref, - _value: LuaValue<'lua>, + offset: isize, + data_handle: &Ref, + value: LuaValue<'lua>, ) -> LuaResult<()> { - Err(LuaError::external("Conversion of pointer is not allowed")) + if let LuaValue::UserData(value_userdata) = value { + if value_userdata.is::() { + let value_ref = value_userdata.borrow::()?; + value_ref + .check_boundary(0, self.inner_size) + .then_some(()) + .ok_or_else(|| LuaError::external("boundary check failed"))?; + *data_handle + .get_pointer() + .byte_offset(offset) + .cast::<*mut ()>() = value_ref.get_pointer(); + Ok(()) + } else { + Err(LuaError::external("Ptr:into only allows FfiRef")) + } + } else { + Err(LuaError::external("Conversion of pointer is not allowed")) + } } // Read data from ptr, then convert into luavalue @@ -51,7 +73,9 @@ impl CPtr { lua: &'lua Lua, inner: &LuaAnyUserData, ) -> LuaResult> { - let value = lua.create_userdata(Self())?; + let value = lua.create_userdata(Self { + inner_size: c_helper::get_size(inner)?, + })?; set_association(lua, CPTR_INNER, &value, inner)?; @@ -83,7 +107,7 @@ impl LuaUserData for CPtr { fields.add_field_method_get("size", |_, _| Ok(size_of::())); fields.add_field_function_get("inner", |lua, this| { let inner = get_association(lua, CPTR_INNER, this)? - .ok_or(LuaError::external("inner type not found"))?; + .ok_or_else(|| LuaError::external("inner type not found"))?; Ok(inner) }); } diff --git a/crates/lune-std-ffi/src/c/c_struct.rs b/crates/lune-std-ffi/src/c/c_struct.rs index 92e02173..4ecbbd37 100644 --- a/crates/lune-std-ffi/src/c/c_struct.rs +++ b/crates/lune-std-ffi/src/c/c_struct.rs @@ -3,7 +3,7 @@ use std::{cell::Ref, vec::Vec}; use libffi::{low, middle::Type, raw}; use mlua::prelude::*; -use super::{association_names::CSTRUCT_INNER, c_helper, method_provider, CArr, CPtr}; +use super::{association_names::CSTRUCT_INNER, c_helper, method_provider}; use crate::ffi::{ ffi_association::{get_association, set_association}, NativeConvert, NativeData, NativeSignedness, NativeSize, FFI_STATUS_NAMES, @@ -56,7 +56,7 @@ impl CStruct { // Create new CStruct UserData with LuaTable. // Lock and hold table for .inner ref - pub fn new_from_table<'lua>( + pub fn from_table<'lua>( lua: &'lua Lua, table: LuaTable<'lua>, ) -> LuaResult> { @@ -74,7 +74,7 @@ impl CStruct { // pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { if let LuaValue::Table(fields) = get_association(lua, CSTRUCT_INNER, userdata)? - .ok_or(LuaError::external("Field table not found"))? + .ok_or_else(|| LuaError::external("Field table not found"))? { let mut result = String::from(" "); for i in 0..fields.raw_len() { @@ -97,7 +97,7 @@ impl CStruct { let offset = self .inner_offset_list .get(index) - .ok_or(LuaError::external("Out of index"))? + .ok_or_else(|| LuaError::external("Out of index"))? .to_owned(); Ok(offset) } @@ -185,7 +185,7 @@ impl LuaUserData for CStruct { // 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(fields) = get_association(lua, CSTRUCT_INNER, this)? - .ok_or(LuaError::external("Field table not found"))? + .ok_or_else(|| LuaError::external("Field table not found"))? { let value: LuaValue = fields.raw_get(field + 1)?; Ok(value) diff --git a/crates/lune-std-ffi/src/c/c_type.rs b/crates/lune-std-ffi/src/c/c_type.rs index 55c8c0b3..a907c68c 100644 --- a/crates/lune-std-ffi/src/c/c_type.rs +++ b/crates/lune-std-ffi/src/c/c_type.rs @@ -6,7 +6,6 @@ use libffi::middle::Type; use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; use mlua::prelude::*; -use super::{CArr, CPtr}; use crate::{ c::method_provider, ffi::{GetNativeData, NativeConvert, NativeData, NativeSignedness, NativeSize}, diff --git a/crates/lune-std-ffi/src/c/types/f32.rs b/crates/lune-std-ffi/src/c/types/f32.rs index 64d54e6e..8dc86459 100644 --- a/crates/lune-std-ffi/src/c/types/f32.rs +++ b/crates/lune-std-ffi/src/c/types/f32.rs @@ -36,7 +36,7 @@ impl NativeConvert for CType { } }; unsafe { - *(data_handle.get_pointer(offset).cast::()) = value; + *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -47,7 +47,9 @@ impl NativeConvert for CType { offset: isize, data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; + let value = unsafe { + (*data_handle.get_pointer().byte_offset(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 448d0080..16c3a209 100644 --- a/crates/lune-std-ffi/src/c/types/f64.rs +++ b/crates/lune-std-ffi/src/c/types/f64.rs @@ -36,7 +36,7 @@ impl NativeConvert for CType { } }; unsafe { - *(data_handle.get_pointer(offset).cast::()) = value; + *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -47,7 +47,9 @@ impl NativeConvert for CType { offset: isize, data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; + let value = unsafe { + (*data_handle.get_pointer().byte_offset(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 0f161621..d4784e82 100644 --- a/crates/lune-std-ffi/src/c/types/i128.rs +++ b/crates/lune-std-ffi/src/c/types/i128.rs @@ -36,7 +36,7 @@ impl NativeConvert for CType { } }; unsafe { - *(data_handle.get_pointer(offset).cast::()) = value; + *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -47,7 +47,7 @@ impl NativeConvert for CType { offset: isize, data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer().byte_offset(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 0ced536e..47e33917 100644 --- a/crates/lune-std-ffi/src/c/types/i16.rs +++ b/crates/lune-std-ffi/src/c/types/i16.rs @@ -36,7 +36,7 @@ impl NativeConvert for CType { } }; unsafe { - *(data_handle.get_pointer(offset).cast::()) = value; + *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -47,7 +47,7 @@ impl NativeConvert for CType { offset: isize, data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; Ok(value) } } diff --git a/crates/lune-std-ffi/src/c/types/i32.rs b/crates/lune-std-ffi/src/c/types/i32.rs index 5ebfd05c..088f948f 100644 --- a/crates/lune-std-ffi/src/c/types/i32.rs +++ b/crates/lune-std-ffi/src/c/types/i32.rs @@ -36,7 +36,7 @@ impl NativeConvert for CType { } }; unsafe { - *(data_handle.get_pointer(offset).cast::()) = value; + *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -47,7 +47,7 @@ impl NativeConvert for CType { offset: isize, data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer().byte_offset(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 82a34ee5..4ea87c6f 100644 --- a/crates/lune-std-ffi/src/c/types/i64.rs +++ b/crates/lune-std-ffi/src/c/types/i64.rs @@ -36,7 +36,7 @@ impl NativeConvert for CType { } }; unsafe { - *(data_handle.get_pointer(offset).cast::()) = value; + *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -47,7 +47,7 @@ impl NativeConvert for CType { offset: isize, data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer().byte_offset(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 e5b8c858..083f1fcb 100644 --- a/crates/lune-std-ffi/src/c/types/i8.rs +++ b/crates/lune-std-ffi/src/c/types/i8.rs @@ -32,7 +32,7 @@ impl NativeConvert for CType { } }; unsafe { - *(data_handle.get_pointer(offset).cast::()) = value; + *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -43,7 +43,7 @@ impl NativeConvert for CType { offset: isize, data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer().byte_offset(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 cf40db28..261d217c 100644 --- a/crates/lune-std-ffi/src/c/types/isize.rs +++ b/crates/lune-std-ffi/src/c/types/isize.rs @@ -36,7 +36,7 @@ impl NativeConvert for CType { } }; unsafe { - *(data_handle.get_pointer(offset).cast::()) = value; + *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -47,7 +47,7 @@ impl NativeConvert for CType { offset: isize, data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; Ok(value) } } diff --git a/crates/lune-std-ffi/src/c/types/u128.rs b/crates/lune-std-ffi/src/c/types/u128.rs index 7ed99d6a..f68d91f6 100644 --- a/crates/lune-std-ffi/src/c/types/u128.rs +++ b/crates/lune-std-ffi/src/c/types/u128.rs @@ -36,7 +36,7 @@ impl NativeConvert for CType { } }; unsafe { - *(data_handle.get_pointer(offset).cast::()) = value; + *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -47,7 +47,7 @@ impl NativeConvert for CType { offset: isize, data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer().byte_offset(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 d30d1ba7..b29d4dac 100644 --- a/crates/lune-std-ffi/src/c/types/u16.rs +++ b/crates/lune-std-ffi/src/c/types/u16.rs @@ -37,7 +37,7 @@ impl NativeConvert for CType { } }; unsafe { - *(data_handle.get_pointer(offset).cast::()) = value; + *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -48,7 +48,7 @@ impl NativeConvert for CType { offset: isize, data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer().byte_offset(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 54545f84..798f586b 100644 --- a/crates/lune-std-ffi/src/c/types/u32.rs +++ b/crates/lune-std-ffi/src/c/types/u32.rs @@ -36,7 +36,7 @@ impl NativeConvert for CType { } }; unsafe { - *(data_handle.get_pointer(offset).cast::()) = value; + *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -47,7 +47,7 @@ impl NativeConvert for CType { offset: isize, data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer().byte_offset(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 cfde9793..757ece74 100644 --- a/crates/lune-std-ffi/src/c/types/u64.rs +++ b/crates/lune-std-ffi/src/c/types/u64.rs @@ -36,7 +36,7 @@ impl NativeConvert for CType { } }; unsafe { - *(data_handle.get_pointer(offset).cast::()) = value; + *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -47,7 +47,7 @@ impl NativeConvert for CType { offset: isize, data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer().byte_offset(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 7aa185af..273e8763 100644 --- a/crates/lune-std-ffi/src/c/types/u8.rs +++ b/crates/lune-std-ffi/src/c/types/u8.rs @@ -33,7 +33,7 @@ impl NativeConvert for CType { } }; unsafe { - *(data_handle.get_pointer(offset).cast::()) = value; + *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -46,7 +46,8 @@ impl NativeConvert for CType { offset: isize, data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; + let value = + unsafe { (*data_handle.get_pointer().byte_offset(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 a6523b65..0dc7afc5 100644 --- a/crates/lune-std-ffi/src/c/types/usize.rs +++ b/crates/lune-std-ffi/src/c/types/usize.rs @@ -36,7 +36,7 @@ impl NativeConvert for CType { } }; unsafe { - *(data_handle.get_pointer(offset).cast::()) = value; + *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -47,7 +47,7 @@ impl NativeConvert for CType { offset: isize, data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer(offset).cast::()).into_lua(lua)? }; + let value = unsafe { (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; Ok(value) } } 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 18815c5e..b10b5e3f 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_box/mod.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_box/mod.rs @@ -77,7 +77,7 @@ impl FfiBox { ) -> LuaResult> { let target = this.borrow::()?; let mut bounds = FfiRefBounds::new(0, target.size()); - let mut ptr = unsafe { target.get_pointer(0) }; + let mut ptr = unsafe { target.get_pointer() }; // Calculate offset if let Some(t) = offset { @@ -88,7 +88,7 @@ impl FfiBox { t ))); } - ptr = unsafe { target.get_pointer(t) }; + ptr = unsafe { ptr.byte_offset(t) }; bounds = bounds.offset(t); } @@ -130,12 +130,8 @@ impl NativeData for FfiBox { } self.size() - (offset as usize) >= size } - unsafe fn get_pointer(&self, offset: isize) -> *mut () { - self.data - .as_ptr() - .byte_offset(offset) - .cast_mut() - .cast::<()>() + unsafe fn get_pointer(&self) -> *mut () { + self.data.as_ptr().cast_mut().cast::<()>() } fn is_readable(&self) -> bool { true diff --git a/crates/lune-std-ffi/src/ffi/ffi_callable.rs b/crates/lune-std-ffi/src/ffi/ffi_callable.rs index 829b0a2d..b5e4c1da 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_callable.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_callable.rs @@ -31,6 +31,8 @@ impl FfiCallable { } } + // TODO? async call: if have no lua closure in arguments, fficallble can be called with async way + pub unsafe fn call(&self, result: &Ref, args: LuaMultiValue) -> LuaResult<()> { result .check_boundary(0, self.result_info.as_ref().unwrap().size) @@ -54,7 +56,7 @@ impl FfiCallable { .ok_or_else(|| { LuaError::external(format!("argument {index} boundary check failed")) })?; - data_handle.get_pointer(0) + data_handle.get_pointer() } else { return Err(LuaError::external("unimpl")); }; @@ -64,7 +66,7 @@ impl FfiCallable { ffi_call( self.cif, Some(*self.code.as_safe_fun()), - result.get_pointer(0).cast::(), + result.get_pointer().cast::(), arg_list.as_mut_ptr(), ); 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 14fbdad4..b0915f85 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/cast.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/cast.rs @@ -18,8 +18,8 @@ where T: AsPrimitive, U: 'static + Copy, { - let from_ptr = unsafe { from.get_pointer(0).cast::() }; - let into_ptr = unsafe { into.get_pointer(0).cast::() }; + let from_ptr = unsafe { from.get_pointer().cast::() }; + let into_ptr = unsafe { into.get_pointer().cast::() }; unsafe { *into_ptr = (*from_ptr).as_(); 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 513ab937..eaa32c6b 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/data.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/data.rs @@ -7,7 +7,7 @@ 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 (); + unsafe fn get_pointer(&self) -> *mut (); fn is_writable(&self) -> bool; fn is_readable(&self) -> bool; } 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 001f8c8c..9b23d5bb 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs @@ -19,12 +19,12 @@ pub use self::{ // Box:ref():ref() should not be able to modify, Only for external const BOX_REF_REF_FLAGS: u8 = 0; -const UNINIT_REF_FLAGS: u8 = FfiRefFlag::Uninit.value() - | FfiRefFlag::Writable.value() - | FfiRefFlag::Readable.value() - | FfiRefFlag::Dereferenceable.value() - | FfiRefFlag::Offsetable.value() - | FfiRefFlag::Function.value(); +const UNINIT_REF_FLAGS: u8 = FfiRefFlag::Uninit.value(); +// | FfiRefFlag::Writable.value() +// | FfiRefFlag::Readable.value() +// | FfiRefFlag::Dereferenceable.value() +// | FfiRefFlag::Offsetable.value() +// | FfiRefFlag::Function.value(); // A referenced space. It is possible to read and write through types. // This operation is not safe. This may cause a memory error in Lua @@ -80,14 +80,16 @@ impl FfiRef { pub unsafe fn deref(&self) -> LuaResult { u8_test(self.flags, FfiRefFlag::Dereferenceable.value()) .then_some(()) - .ok_or(LuaError::external("This pointer is not dereferenceable."))?; + .ok_or_else(|| LuaError::external("This pointer is not dereferenceable."))?; self.boundary .check_sized(0, size_of::()) .then_some(()) - .ok_or(LuaError::external( - "Offset is out of bounds. Dereferencing pointer requires size of usize", - ))?; + .ok_or_else(|| { + LuaError::external( + "Offset is out of bounds. Dereferencing pointer requires size of usize", + ) + })?; // FIXME flags Ok(Self::new( @@ -106,7 +108,7 @@ impl FfiRef { pub unsafe fn offset(&self, offset: isize) -> LuaResult { u8_test(self.flags, FfiRefFlag::Offsetable.value()) .then_some(()) - .ok_or(LuaError::external("This pointer is not offsetable."))?; + .ok_or_else(|| LuaError::external("This pointer is not offsetable."))?; // Check boundary, if exceed, return error self.boundary @@ -142,8 +144,8 @@ impl NativeData for FfiRef { fn check_boundary(&self, offset: isize, size: usize) -> bool { self.boundary.check_sized(offset, size) } - unsafe fn get_pointer(&self, offset: isize) -> *mut () { - self.ptr.byte_offset(offset) + unsafe fn get_pointer(&self) -> *mut () { + **self.ptr } fn is_readable(&self) -> bool { u8_test(self.flags, FfiRefFlag::Readable.value()) diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs index 661f0735..59648f13 100644 --- a/crates/lune-std-ffi/src/lib.rs +++ b/crates/lune-std-ffi/src/lib.rs @@ -27,7 +27,7 @@ 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_table(lua, types) + CStruct::from_table(lua, types) })? .with_function("uninitRef", |_lua, ()| Ok(FfiRef::new_uninit()))? .with_function("isInteger", |_lua, num: LuaValue| Ok(is_integer(num)))? diff --git a/crates/lune-std-ffi/src/libffi_helper.rs b/crates/lune-std-ffi/src/libffi_helper.rs index 10c56043..41b9f6ea 100644 --- a/crates/lune-std-ffi/src/libffi_helper.rs +++ b/crates/lune-std-ffi/src/libffi_helper.rs @@ -27,3 +27,5 @@ pub fn get_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult { } unsafe { Ok((*ffi_type).size) } } + +pub const SIEE_OF_POINTER: usize = size_of::<*mut ()>(); From 58add58244b5009b729194ddfe23ff5f5dda3040 Mon Sep 17 00:00:00 2001 From: qwreey Date: Thu, 17 Oct 2024 01:37:24 +0000 Subject: [PATCH 28/79] Renaming methods (#243) --- crates/lune-std-ffi/src/c/c_arr.rs | 6 +++--- crates/lune-std-ffi/src/c/c_func.rs | 4 ++-- crates/lune-std-ffi/src/c/c_helper.rs | 16 ++++++++-------- crates/lune-std-ffi/src/c/c_ptr.rs | 4 ++-- crates/lune-std-ffi/src/c/c_struct.rs | 8 ++++---- crates/lune-std-ffi/src/c/c_type.rs | 8 ++++---- crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs | 2 +- crates/lune-std-ffi/src/lib.rs | 2 +- 8 files changed, 25 insertions(+), 25 deletions(-) diff --git a/crates/lune-std-ffi/src/c/c_arr.rs b/crates/lune-std-ffi/src/c/c_arr.rs index 7cd7bba4..c4bbfc6c 100644 --- a/crates/lune-std-ffi/src/c/c_arr.rs +++ b/crates/lune-std-ffi/src/c/c_arr.rs @@ -152,15 +152,15 @@ impl LuaUserData for CArr { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { // Subtype - method_provider::provide_ptr(methods); + method_provider::provide_ptr_info(methods); // ToString method_provider::provide_to_string(methods); // Realize method_provider::provide_box(methods); - method_provider::provide_from(methods); - method_provider::provide_into(methods); + method_provider::provide_from_data(methods); + method_provider::provide_into_data(methods); methods.add_method("offset", |_, this, offset: isize| { if this.length > (offset as usize) && offset >= 0 { diff --git a/crates/lune-std-ffi/src/c/c_func.rs b/crates/lune-std-ffi/src/c/c_func.rs index ff7952bc..b323e3ea 100644 --- a/crates/lune-std-ffi/src/c/c_func.rs +++ b/crates/lune-std-ffi/src/c/c_func.rs @@ -129,8 +129,8 @@ impl CFunc { 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); + method_provider::provide_ptr_info(methods); + method_provider::provide_arr_info(methods); // ToString method_provider::provide_to_string(methods); diff --git a/crates/lune-std-ffi/src/c/c_helper.rs b/crates/lune-std-ffi/src/c/c_helper.rs index 68882df8..fcede756 100644 --- a/crates/lune-std-ffi/src/c/c_helper.rs +++ b/crates/lune-std-ffi/src/c/c_helper.rs @@ -16,31 +16,31 @@ pub mod method_provider { }); } - pub fn provide_ptr<'lua, Target, M>(methods: &mut M) + pub fn provide_ptr_info<'lua, Target, M>(methods: &mut M) where M: LuaUserDataMethods<'lua, Target>, { - methods.add_function("ptr", |lua, this: LuaAnyUserData| { + methods.add_function("ptrInfo", |lua, this: LuaAnyUserData| { CPtr::from_userdata(lua, &this) }); } - pub fn provide_arr<'lua, Target, M>(methods: &mut M) + pub fn provide_arr_info<'lua, Target, M>(methods: &mut M) where M: LuaUserDataMethods<'lua, Target>, { - methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| { + methods.add_function("arrInfo", |lua, (this, length): (LuaAnyUserData, usize)| { CArr::from_userdata(lua, &this, length) }); } - pub fn provide_from<'lua, Target, M>(methods: &mut M) + pub fn provide_from_data<'lua, Target, M>(methods: &mut M) where Target: NativeSize + NativeConvert, M: LuaUserDataMethods<'lua, Target>, { methods.add_method( - "from", + "fromData", |lua, this, (userdata, offset): (LuaAnyUserData, Option)| { let offset = offset.unwrap_or(0); @@ -57,13 +57,13 @@ pub mod method_provider { ); } - pub fn provide_into<'lua, Target, M>(methods: &mut M) + pub fn provide_into_data<'lua, Target, M>(methods: &mut M) where Target: NativeSize + NativeConvert, M: LuaUserDataMethods<'lua, Target>, { methods.add_method( - "into", + "intoData", |lua, this, (userdata, value, offset): (LuaAnyUserData, LuaValue, Option)| { let offset = offset.unwrap_or(0); diff --git a/crates/lune-std-ffi/src/c/c_ptr.rs b/crates/lune-std-ffi/src/c/c_ptr.rs index 840aa0fc..c56e83b6 100644 --- a/crates/lune-std-ffi/src/c/c_ptr.rs +++ b/crates/lune-std-ffi/src/c/c_ptr.rs @@ -114,8 +114,8 @@ impl LuaUserData for CPtr { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { // Subtype - method_provider::provide_ptr(methods); - method_provider::provide_arr(methods); + method_provider::provide_ptr_info(methods); + method_provider::provide_arr_info(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 4ecbbd37..b0042e94 100644 --- a/crates/lune-std-ffi/src/c/c_struct.rs +++ b/crates/lune-std-ffi/src/c/c_struct.rs @@ -166,16 +166,16 @@ impl LuaUserData for CStruct { } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { // Subtype - method_provider::provide_ptr(methods); - method_provider::provide_arr(methods); + method_provider::provide_ptr_info(methods); + method_provider::provide_arr_info(methods); // ToString method_provider::provide_to_string(methods); // Realize method_provider::provide_box(methods); - method_provider::provide_from(methods); - method_provider::provide_into(methods); + method_provider::provide_from_data(methods); + method_provider::provide_into_data(methods); methods.add_method("offset", |_, this, index: usize| { let offset = this.offset(index)?; diff --git a/crates/lune-std-ffi/src/c/c_type.rs b/crates/lune-std-ffi/src/c/c_type.rs index a907c68c..c90f1958 100644 --- a/crates/lune-std-ffi/src/c/c_type.rs +++ b/crates/lune-std-ffi/src/c/c_type.rs @@ -98,16 +98,16 @@ where fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { // Subtype - method_provider::provide_ptr(methods); - method_provider::provide_arr(methods); + method_provider::provide_ptr_info(methods); + method_provider::provide_arr_info(methods); // ToString method_provider::provide_to_string(methods); // Realize method_provider::provide_box(methods); - method_provider::provide_from(methods); - method_provider::provide_into(methods); + method_provider::provide_from_data(methods); + method_provider::provide_into_data(methods); methods.add_function( "cast", 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 9b23d5bb..3534e98f 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs @@ -186,7 +186,7 @@ impl LuaUserData for FfiRef { let ffiref = FfiRef::luaref(lua, this)?; Ok(ffiref) }); - methods.add_method("isNullptr", |_, this, ()| Ok(this.is_nullptr())); + methods.add_method("isNull", |_, this, ()| Ok(this.is_nullptr())); } } diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs index 59648f13..c2fb8441 100644 --- a/crates/lune-std-ffi/src/lib.rs +++ b/crates/lune-std-ffi/src/lib.rs @@ -23,7 +23,7 @@ use crate::{ pub fn module(lua: &Lua) -> LuaResult { let result = TableBuilder::new(lua)? .with_values(export_ctypes(lua)?)? - .with_value("nullRef", create_nullptr(lua)?)? + .with_function("nullRef", |lua, ()| create_nullptr(lua))? .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| { From da30dfb3f05cd24b2ba2c1518b0ece6c25f0dd37 Mon Sep 17 00:00:00 2001 From: qwreey Date: Thu, 17 Oct 2024 10:16:43 +0000 Subject: [PATCH 29/79] Refactor and documenting code structure (#243) --- Cargo.lock | 2 +- crates/lune-std-ffi/README.md | 79 +++++++++++++ .../src/c/{c_arr.rs => arr_info.rs} | 49 ++++----- crates/lune-std-ffi/src/c/c_string.rs | 8 -- .../src/c/{c_func.rs => fn_info.rs} | 74 ++++++------- .../src/c/{c_helper.rs => helper.rs} | 104 +++++++++--------- crates/lune-std-ffi/src/c/mod.rs | 27 +++-- .../src/c/{c_ptr.rs => ptr_info.rs} | 43 ++++---- .../src/c/{c_struct.rs => struct_info.rs} | 67 +++++------ .../src/c/{c_type.rs => type_info.rs} | 22 ++-- crates/lune-std-ffi/src/c/types/f32.rs | 18 +-- crates/lune-std-ffi/src/c/types/f64.rs | 18 +-- crates/lune-std-ffi/src/c/types/i128.rs | 22 ++-- crates/lune-std-ffi/src/c/types/i16.rs | 22 ++-- crates/lune-std-ffi/src/c/types/i32.rs | 22 ++-- crates/lune-std-ffi/src/c/types/i64.rs | 22 ++-- crates/lune-std-ffi/src/c/types/i8.rs | 21 ++-- crates/lune-std-ffi/src/c/types/isize.rs | 31 ++++-- crates/lune-std-ffi/src/c/types/mod.rs | 44 ++++---- crates/lune-std-ffi/src/c/types/u128.rs | 22 ++-- crates/lune-std-ffi/src/c/types/u16.rs | 22 ++-- crates/lune-std-ffi/src/c/types/u32.rs | 22 ++-- crates/lune-std-ffi/src/c/types/u64.rs | 22 ++-- crates/lune-std-ffi/src/c/types/u8.rs | 18 +-- crates/lune-std-ffi/src/c/types/usize.rs | 31 ++++-- .../src/c/{c_void.rs => void_info.rs} | 0 .../{ffi/ffi_box => data/box_data}/flag.rs | 6 +- .../src/{ffi/ffi_box => data/box_data}/mod.rs | 43 ++++---- .../ffi_callable.rs => data/callable_data.rs} | 20 ++-- .../ffi_closure.rs => data/closure_data.rs} | 25 +++-- .../src/{ffi/ffi_lib.rs => data/lib_data.rs} | 26 ++--- crates/lune-std-ffi/src/data/mod.rs | 53 +++++++++ .../{ffi/ffi_ref => data/ref_data}/bounds.rs | 8 +- .../{ffi/ffi_ref => data/ref_data}/flag.rs | 6 +- .../src/{ffi/ffi_ref => data/ref_data}/mod.rs | 64 ++++++----- .../src/ffi/{ffi_native => }/arg.rs | 8 +- .../{ffi_association.rs => association.rs} | 13 +-- crates/lune-std-ffi/src/ffi/bit_mask.rs | 29 +++++ crates/lune-std-ffi/src/ffi/cast.rs | 22 ++++ .../lune-std-ffi/src/ffi/ffi_native/cast.rs | 29 ----- .../src/ffi/ffi_native/convert.rs | 27 ----- .../lune-std-ffi/src/ffi/ffi_native/data.rs | 40 ------- crates/lune-std-ffi/src/ffi/ffi_native/mod.rs | 25 ----- .../src/{ => ffi}/libffi_helper.rs | 10 +- crates/lune-std-ffi/src/ffi/mod.rs | 98 +++++++---------- .../src/ffi/{ffi_native => }/result.rs | 6 +- crates/lune-std-ffi/src/lib.rs | 27 +++-- types/ffi.luau | 87 +++++++++------ 48 files changed, 803 insertions(+), 701 deletions(-) create mode 100644 crates/lune-std-ffi/README.md rename crates/lune-std-ffi/src/c/{c_arr.rs => arr_info.rs} (78%) delete mode 100644 crates/lune-std-ffi/src/c/c_string.rs rename crates/lune-std-ffi/src/c/{c_func.rs => fn_info.rs} (66%) rename crates/lune-std-ffi/src/c/{c_helper.rs => helper.rs} (68%) rename crates/lune-std-ffi/src/c/{c_ptr.rs => ptr_info.rs} (73%) rename crates/lune-std-ffi/src/c/{c_struct.rs => struct_info.rs} (76%) rename crates/lune-std-ffi/src/c/{c_type.rs => type_info.rs} (86%) rename crates/lune-std-ffi/src/c/{c_void.rs => void_info.rs} (100%) rename crates/lune-std-ffi/src/{ffi/ffi_box => data/box_data}/flag.rs (64%) rename crates/lune-std-ffi/src/{ffi/ffi_box => data/box_data}/mod.rs (79%) rename crates/lune-std-ffi/src/{ffi/ffi_callable.rs => data/callable_data.rs} (84%) rename crates/lune-std-ffi/src/{ffi/ffi_closure.rs => data/closure_data.rs} (78%) rename crates/lune-std-ffi/src/{ffi/ffi_lib.rs => data/lib_data.rs} (60%) create mode 100644 crates/lune-std-ffi/src/data/mod.rs rename crates/lune-std-ffi/src/{ffi/ffi_ref => data/ref_data}/bounds.rs (94%) rename crates/lune-std-ffi/src/{ffi/ffi_ref => data/ref_data}/flag.rs (86%) rename crates/lune-std-ffi/src/{ffi/ffi_ref => data/ref_data}/mod.rs (74%) rename crates/lune-std-ffi/src/ffi/{ffi_native => }/arg.rs (55%) rename crates/lune-std-ffi/src/ffi/{ffi_association.rs => association.rs} (91%) create mode 100644 crates/lune-std-ffi/src/ffi/bit_mask.rs create mode 100644 crates/lune-std-ffi/src/ffi/cast.rs delete mode 100644 crates/lune-std-ffi/src/ffi/ffi_native/cast.rs delete mode 100644 crates/lune-std-ffi/src/ffi/ffi_native/convert.rs delete mode 100644 crates/lune-std-ffi/src/ffi/ffi_native/data.rs delete mode 100644 crates/lune-std-ffi/src/ffi/ffi_native/mod.rs rename crates/lune-std-ffi/src/{ => ffi}/libffi_helper.rs (81%) rename crates/lune-std-ffi/src/ffi/{ffi_native => }/result.rs (55%) diff --git a/Cargo.lock b/Cargo.lock index 89ee282b..de492abe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -807,7 +807,7 @@ checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.79", ] [[package]] diff --git a/crates/lune-std-ffi/README.md b/crates/lune-std-ffi/README.md new file mode 100644 index 00000000..1b8c6ca3 --- /dev/null +++ b/crates/lune-std-ffi/README.md @@ -0,0 +1,79 @@ +# `lune-std-ffi` + +## Code structure + +### /c + +Define C-ABI type information and provide conversion and casting + +- [**Struct ` CArrInfo`:**](./src/c/struct_info.rs) Represents C Array type +- [**Struct ` CPtrInfo`:**](./src/c/ptr_info.rs) Represents C Pointer type +- [**Struct ` CFnInfo`:**](./src/c/fn_info.rs) Represents C Function signature + provide CallableData and ClosureData creation +- [**Struct ` CStructInfo`:**](./src/c/struct_info.rs) Represents C Struct type +- [**Struct ` CTypeInfo`:**](./src/c/type_info.rs) Represents C type, extended in `/c/types` + +#### /c/types + +Export fixed-size source time known types and non-fixed compile time known types +Implememt type-casting for all CTypes + +**Mod `ctype_helper`:** + +- **Function `get_conv`:** + get _FfiConvert_ from some ctype userdata, used for struct and array conversion +- **Function `get_size`:** + get size from some ctype userdata, used for call return and arguments boundary checking +- **Function `get_name`:** + get type name from some ctype userdata, used for pretty-print +- **Function `get_middle_type`:** + get **`libffi::middle::Type`:** from some ctype userdata +- **Function `is_ctype`:** check userdata is ctype + +--- + +### /data + +**Structs:** Provide memory userdata + +- [**Struct `BoxData`:**](./src/data/box_data/mod.rs) A heap allocated memory with user definable lifetime +- [**Struct `LibData`:**](./src/data/lib_data.rs) A dynamic opened library +- [**Struct `RefData`:**](./src/data/ref_data/mod.rs) A reference that can be used for receiving return data from external function or pass pointer arguments + +**Structs:** Provide function(pointer) userdata + +- [**Struct `CallableData`:**](./src/data/callable_data.rs) A callable function, which can be created from function pointer +- [**Struct `ClosureData`:**](./src/data/closure_data.rs) A closure pointer, which can be created from lua function and can be used for callback + +--- + +### /ffi + +**Traits:** Provide ABI shared common type information trait + +- **Trait `FfiSize`** +- **Trait `FfiSignedness`** +- **Trait `FfiConvert`:** Provide read LuaValue from FfiData or write LuaValue into FfiData + +**Trait `FfiData`:** Provide common data handle, including methods below + +- **Method `check_boundary`:** check boundary with offset and size +- **Method `get_pointer`:** returns raw pointer `*mut ()` +- **Method `is_writable`** +- **Method `is_readable`** + +> Note: `GetFfiData` trait in `data/mod.rs` provides `AnyUserData.get_data_handle() -> FfiData` method + +**Mods:** Provide common helper functions + +- **`association.rs`:** GC utility, used for inner, ret and arg type holding in subtype +- **`bit_mask.rs`:** u8 bitfield helper +- **`cast.rs`:** library + - **Function `num_cast(from: FfiData, from: FfiData)`:** + Cast number type value inno another number type +- **`libffi_helper.rs`:** + - **Const `FFI_STATUS_NAMES`:** Used for ffi_status stringify + - **Function `get_ensured_size`:** Returns ensured ffi_type size + - **Const `SIEE_OF_POINTER`:** Platform specific pointer size (Compile time known) + +## TODO diff --git a/crates/lune-std-ffi/src/c/c_arr.rs b/crates/lune-std-ffi/src/c/arr_info.rs similarity index 78% rename from crates/lune-std-ffi/src/c/c_arr.rs rename to crates/lune-std-ffi/src/c/arr_info.rs index c4bbfc6c..088fe340 100644 --- a/crates/lune-std-ffi/src/c/c_arr.rs +++ b/crates/lune-std-ffi/src/c/arr_info.rs @@ -3,12 +3,11 @@ use std::cell::Ref; use libffi::middle::Type; use mlua::prelude::*; -use super::{association_names::CARR_INNER, c_helper, method_provider}; -use crate::ffi::{ - ffi_association::{get_association, set_association}, - NativeConvert, NativeData, NativeSize, +use super::{association_names::CARR_INNER, helper, method_provider}; +use crate::{ + data::{FfiConvert, FfiData, FfiSize}, + ffi::{association, libffi_helper::get_ensured_size}, }; -use crate::libffi_helper::get_ensured_size; // This is a series of some type. // It provides the final size and the offset of the index, @@ -19,19 +18,19 @@ use crate::libffi_helper::get_ensured_size; // We can simply provide array type with struct. // See: https://stackoverflow.com/a/43525176 -pub struct CArr { +pub struct CArrInfo { struct_type: Type, length: usize, size: usize, inner_size: usize, - inner_conv: *const dyn NativeConvert, + inner_conv: *const dyn FfiConvert, } -impl CArr { +impl CArrInfo { pub fn new( element_type: Type, length: usize, - inner_conv: *const dyn NativeConvert, + inner_conv: *const dyn FfiConvert, ) -> LuaResult { let inner_size = get_ensured_size(element_type.as_raw_ptr())?; let struct_type = Type::structure(vec![element_type.clone(); length]); @@ -51,11 +50,11 @@ impl CArr { type_userdata: &LuaAnyUserData<'lua>, length: usize, ) -> LuaResult> { - let fields = c_helper::get_middle_type(type_userdata)?; - let conv = unsafe { c_helper::get_conv(type_userdata)? }; + let fields = helper::get_middle_type(type_userdata)?; + let conv = unsafe { helper::get_conv(type_userdata)? }; let carr = lua.create_userdata(Self::new(fields, length, conv)?)?; - set_association(lua, CARR_INNER, &carr, type_userdata)?; + association::set(lua, CARR_INNER, &carr, type_userdata)?; Ok(carr) } @@ -70,13 +69,13 @@ impl CArr { // Stringify for pretty printing like: // pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { - let this = userdata.borrow::()?; + let this = userdata.borrow::()?; if let Some(LuaValue::UserData(inner_userdata)) = - get_association(lua, CARR_INNER, userdata)? + association::get(lua, CARR_INNER, userdata)? { Ok(format!( " {}, length = {} ", - c_helper::pretty_format(lua, &inner_userdata)?, + helper::pretty_format(lua, &inner_userdata)?, this.length, )) } else { @@ -85,18 +84,18 @@ impl CArr { } } -impl NativeSize for CArr { +impl FfiSize for CArrInfo { fn get_size(&self) -> usize { self.size } } -impl NativeConvert for CArr { +impl FfiConvert for CArrInfo { // FIXME: FfiBox, FfiRef support required - unsafe fn luavalue_into<'lua>( + unsafe fn value_into_data<'lua>( &self, lua: &'lua Lua, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let LuaValue::Table(ref table) = value else { @@ -106,7 +105,7 @@ impl NativeConvert for CArr { let field_offset = (i * self.inner_size) as isize; let data: LuaValue = table.get(i + 1)?; - self.inner_conv.as_ref().unwrap().luavalue_into( + self.inner_conv.as_ref().unwrap().value_into_data( lua, field_offset + offset, data_handle, @@ -116,18 +115,18 @@ impl NativeConvert for CArr { Ok(()) } - unsafe fn luavalue_from<'lua>( + unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { let table = lua.create_table_with_capacity(self.length, 0)?; for i in 0..self.length { let field_offset = (i * self.inner_size) as isize; table.set( i + 1, - self.inner_conv.as_ref().unwrap().luavalue_from( + self.inner_conv.as_ref().unwrap().value_from_data( lua, field_offset + offset, data_handle, @@ -138,12 +137,12 @@ impl NativeConvert for CArr { } } -impl LuaUserData for CArr { +impl LuaUserData for CArrInfo { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { fields.add_field_method_get("size", |_, this| Ok(this.get_size())); fields.add_field_method_get("length", |_, this| Ok(this.get_length())); fields.add_field_function_get("inner", |lua, this: LuaAnyUserData| { - let inner: LuaValue = get_association(lua, CARR_INNER, this)? + let inner: LuaValue = association::get(lua, CARR_INNER, this)? // It shouldn't happen. .ok_or_else(|| LuaError::external("inner field not found"))?; Ok(inner) diff --git a/crates/lune-std-ffi/src/c/c_string.rs b/crates/lune-std-ffi/src/c/c_string.rs deleted file mode 100644 index 9c3d777b..00000000 --- a/crates/lune-std-ffi/src/c/c_string.rs +++ /dev/null @@ -1,8 +0,0 @@ -// This is a string type that can be given to an external function. -// To be exact, it converts the Lua string into a c_char array and puts it in the box. -// For this part, initially, i wanted to allow box("lua string"), -// but separated it for clarity. -// This also allows operations such as ffi.string:intoBox(). -// (Write a string to an already existing box) - -// FIXME: use buffer instead? diff --git a/crates/lune-std-ffi/src/c/c_func.rs b/crates/lune-std-ffi/src/c/fn_info.rs similarity index 66% rename from crates/lune-std-ffi/src/c/c_func.rs rename to crates/lune-std-ffi/src/c/fn_info.rs index b323e3ea..b2942a4f 100644 --- a/crates/lune-std-ffi/src/c/c_func.rs +++ b/crates/lune-std-ffi/src/c/fn_info.rs @@ -5,13 +5,11 @@ use mlua::prelude::*; use super::{ association_names::{CALLABLE_CFN, CALLABLE_REF, CFN_ARGS, CFN_RESULT}, - c_helper, method_provider, + helper, method_provider, }; -use crate::ffi::{ - bit_mask::u8_test_not, - ffi_association::{get_association, set_association}, - FfiCallable, FfiRef, FfiRefFlag, NativeArgInfo, NativeData, NativeResultInfo, NativeSignedness, - NativeSize, +use crate::{ + data::{CallableData, RefData, RefDataFlag}, + ffi::{association, bit_mask::*, FfiArgInfo, FfiData, FfiResultInfo, FfiSignedness, FfiSize}, }; // cfn is a type declaration for a function. @@ -30,29 +28,29 @@ 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 CFunc { +pub struct CFnInfo { cif: Cif, - arg_info_list: Vec, - result_info: NativeResultInfo, + arg_info_list: Vec, + result_info: FfiResultInfo, } -impl NativeSignedness for CFunc { +impl FfiSignedness for CFnInfo { fn get_signedness(&self) -> bool { false } } -impl NativeSize for CFunc { +impl FfiSize for CFnInfo { fn get_size(&self) -> usize { size_of::<*mut ()>() } } -impl CFunc { +impl CFnInfo { pub fn new( args: Vec, ret: Type, - arg_info_list: Vec, - result_info: NativeResultInfo, + arg_info_list: Vec, + result_info: FfiResultInfo, ) -> LuaResult { // let cif = ; @@ -68,29 +66,29 @@ impl CFunc { arg_table: LuaTable, ret: LuaAnyUserData, ) -> LuaResult> { - let args_types = c_helper::get_middle_type_list(&arg_table)?; - let ret_type = c_helper::get_middle_type(&ret)?; + let args_types = helper::get_middle_type_list(&arg_table)?; + let ret_type = helper::get_middle_type(&ret)?; let arg_len = arg_table.raw_len(); - let mut arg_info_list = Vec::::with_capacity(arg_len); + let mut arg_info_list = Vec::::with_capacity(arg_len); for index in 0..arg_len { - let userdata = c_helper::get_userdata(arg_table.raw_get(index + 1)?)?; - arg_info_list.push(NativeArgInfo { - conv: unsafe { c_helper::get_conv(&userdata)? }, - size: c_helper::get_size(&userdata)?, + let userdata = helper::get_userdata(arg_table.raw_get(index + 1)?)?; + arg_info_list.push(FfiArgInfo { + conv: unsafe { helper::get_conv(&userdata)? }, + size: helper::get_size(&userdata)?, }); } - let result_info = NativeResultInfo { - conv: unsafe { c_helper::get_conv(&ret)? }, - size: c_helper::get_size(&ret)?, + let result_info = FfiResultInfo { + conv: unsafe { helper::get_conv(&ret)? }, + size: helper::get_size(&ret)?, }; let cfn = lua.create_userdata(Self::new(args_types, ret_type, arg_info_list, result_info)?)?; // Create association to hold argument and result type - set_association(lua, CFN_ARGS, &cfn, arg_table)?; - set_association(lua, CFN_RESULT, &cfn, ret)?; + association::set(lua, CFN_ARGS, &cfn, arg_table)?; + association::set(lua, CFN_RESULT, &cfn, ret)?; Ok(cfn) } @@ -100,13 +98,13 @@ impl CFunc { 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)?, + association::get(lua, CFN_ARGS, userdata)?, + association::get(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)?; + let pretty_formatted = helper::pretty_format(lua, &arg_userdata)?; result.push_str( (if len == arg_index { pretty_formatted @@ -117,7 +115,7 @@ impl CFunc { ); } result.push_str( - format!(") -> {} ", c_helper::pretty_format(lua, &result_userdata)?,).as_str(), + format!(") -> {} ", helper::pretty_format(lua, &result_userdata)?,).as_str(), ); Ok(result) } else { @@ -126,7 +124,7 @@ impl CFunc { } } -impl LuaUserData for CFunc { +impl LuaUserData for CFnInfo { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { // Subtype method_provider::provide_ptr_info(methods); @@ -142,19 +140,19 @@ impl LuaUserData for CFunc { methods.add_function( "callable", |lua, (cfn, function_ref): (LuaAnyUserData, LuaAnyUserData)| { - let this = cfn.borrow::()?; + let this = cfn.borrow::()?; - if !function_ref.is::() { + if !function_ref.is::() { return Err(LuaError::external("argument 0 must be ffiref")); } - let ffi_ref = function_ref.borrow::()?; - if u8_test_not(ffi_ref.flags, FfiRefFlag::Function.value()) { + let ffi_ref = function_ref.borrow::()?; + if u8_test_not(ffi_ref.flags, RefDataFlag::Function.value()) { return Err(LuaError::external("not a function ref")); } let callable = lua.create_userdata(unsafe { - FfiCallable::new( + CallableData::new( this.cif.as_raw_ptr(), ptr::from_ref(&this.arg_info_list), ptr::from_ref(&this.result_info), @@ -162,8 +160,8 @@ impl LuaUserData for CFunc { ) })?; - set_association(lua, CALLABLE_CFN, &callable, cfn.clone())?; - set_association(lua, CALLABLE_REF, &callable, function_ref.clone())?; + association::set(lua, CALLABLE_CFN, &callable, cfn.clone())?; + association::set(lua, CALLABLE_REF, &callable, function_ref.clone())?; Ok(callable) }, diff --git a/crates/lune-std-ffi/src/c/c_helper.rs b/crates/lune-std-ffi/src/c/helper.rs similarity index 68% rename from crates/lune-std-ffi/src/c/c_helper.rs rename to crates/lune-std-ffi/src/c/helper.rs index fcede756..7f7b5ae1 100644 --- a/crates/lune-std-ffi/src/c/c_helper.rs +++ b/crates/lune-std-ffi/src/c/helper.rs @@ -2,8 +2,8 @@ use libffi::middle::Type; use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; use mlua::prelude::*; -use super::{c_type_helper, CArr, CFunc, CPtr, CStruct}; -use crate::ffi::{FfiBox, GetNativeData, NativeConvert, NativeSize}; +use super::{ctype_helper, CArrInfo, CFnInfo, CPtrInfo, CStructInfo}; +use crate::data::{BoxData, FfiConvert, FfiSize, GetFfiData}; pub mod method_provider { use super::*; @@ -20,8 +20,8 @@ pub mod method_provider { where M: LuaUserDataMethods<'lua, Target>, { - methods.add_function("ptrInfo", |lua, this: LuaAnyUserData| { - CPtr::from_userdata(lua, &this) + methods.add_function("pointerInfo", |lua, this: LuaAnyUserData| { + CPtrInfo::from_userdata(lua, &this) }); } @@ -29,14 +29,14 @@ pub mod method_provider { where M: LuaUserDataMethods<'lua, Target>, { - methods.add_function("arrInfo", |lua, (this, length): (LuaAnyUserData, usize)| { - CArr::from_userdata(lua, &this, length) + methods.add_function("ArrInfo", |lua, (this, length): (LuaAnyUserData, usize)| { + CArrInfo::from_userdata(lua, &this, length) }); } pub fn provide_from_data<'lua, Target, M>(methods: &mut M) where - Target: NativeSize + NativeConvert, + Target: FfiSize + FfiConvert, M: LuaUserDataMethods<'lua, Target>, { methods.add_method( @@ -52,14 +52,14 @@ pub mod method_provider { return Err(LuaError::external("Unreadable data handle")); } - unsafe { this.luavalue_from(lua, offset, data_handle) } + unsafe { this.value_from_data(lua, offset, data_handle) } }, ); } pub fn provide_into_data<'lua, Target, M>(methods: &mut M) where - Target: NativeSize + NativeConvert, + Target: FfiSize + FfiConvert, M: LuaUserDataMethods<'lua, Target>, { methods.add_method( @@ -76,19 +76,19 @@ pub mod method_provider { return Err(LuaError::external("Unwritable data handle")); } - unsafe { this.luavalue_into(lua, offset, data_handle, value) } + unsafe { this.value_into_data(lua, offset, data_handle, value) } }, ); } pub fn provide_box<'lua, Target, M>(methods: &mut M) where - Target: NativeSize + NativeConvert, + Target: FfiSize + FfiConvert, 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)? }; + let result = lua.create_userdata(BoxData::new(this.get_size()))?; + unsafe { this.value_into_data(lua, 0, &result.get_data_handle()?, table)? }; Ok(result) }); } @@ -109,22 +109,22 @@ pub fn get_userdata(value: LuaValue) -> LuaResult { // this is intended to avoid lookup userdata and lua table every time. (eg: struct) // userdata must live longer than the NativeConvert handle. // However, c_struct is a strong reference to each field, so this is not a problem. -pub unsafe fn get_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn 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) +pub unsafe fn get_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn FfiConvert> { + if userdata.is::() { + Ok(userdata.to_pointer().cast::() as *const dyn FfiConvert) + } else if userdata.is::() { + Ok(userdata.to_pointer().cast::() as *const dyn FfiConvert) + } else if userdata.is::() { + Ok(userdata.to_pointer().cast::() as *const dyn FfiConvert) } else { - c_type_helper::get_conv(userdata) + ctype_helper::get_conv(userdata) // TODO: struct and more } } -pub unsafe fn get_conv_list(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); + let mut conv_list = Vec::<*const dyn FfiConvert>::with_capacity(len); for i in 0..len { let value: LuaValue = table.raw_get(i + 1)?; @@ -135,27 +135,27 @@ pub unsafe fn get_conv_list(table: &LuaTable) -> LuaResult LuaResult { - if this.is::() { - Ok(this.borrow::()?.get_size()) - } else if this.is::() { - Ok(this.borrow::()?.get_size()) - } else if this.is::() { - Ok(this.borrow::()?.get_size()) + if this.is::() { + Ok(this.borrow::()?.get_size()) + } else if this.is::() { + Ok(this.borrow::()?.get_size()) + } else if this.is::() { + Ok(this.borrow::()?.get_size()) } else { - c_type_helper::get_size(this) + ctype_helper::get_size(this) } } // get libffi_type from any c-type userdata pub fn get_middle_type(userdata: &LuaAnyUserData) -> LuaResult { - if userdata.is::() { - Ok(userdata.borrow::()?.get_type()) - } else if let Some(middle_type) = c_type_helper::get_middle_type(userdata)? { + if userdata.is::() { + Ok(userdata.borrow::()?.get_type()) + } else if let Some(middle_type) = ctype_helper::get_middle_type(userdata)? { Ok(middle_type) - } else if userdata.is::() { - Ok(userdata.borrow::()?.get_type()) - } else if userdata.is::() { - Ok(CPtr::get_type()) + } else if userdata.is::() { + Ok(userdata.borrow::()?.get_type()) + } else if userdata.is::() { + Ok(CPtrInfo::get_type()) } else { Err(LuaError::external(format!( "Unexpected field. CStruct, CType, CString or CArr is required for element but got {}", @@ -192,15 +192,15 @@ pub fn get_middle_type_list(table: &LuaTable) -> LuaResult> { // stringify any c-type userdata (for recursive) pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { - if userdata.is::() { - CStruct::stringify(lua, userdata) - } else if userdata.is::() { - CArr::stringify(lua, userdata) - } else if userdata.is::() { - CPtr::stringify(lua, userdata) - } else if userdata.is::() { - CFunc::stringify(lua, userdata) - } else if let Some(name) = c_type_helper::get_name(userdata)? { + if userdata.is::() { + CStructInfo::stringify(lua, userdata) + } else if userdata.is::() { + CArrInfo::stringify(lua, userdata) + } else if userdata.is::() { + CPtrInfo::stringify(lua, userdata) + } else if userdata.is::() { + CFnInfo::stringify(lua, userdata) + } else if let Some(name) = ctype_helper::get_name(userdata)? { Ok(String::from(name)) } else { Ok(String::from("unknown")) @@ -209,15 +209,15 @@ pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { // get name tag for any c-type userdata pub fn get_tag_name(userdata: &LuaAnyUserData) -> LuaResult { - Ok(if userdata.is::() { + Ok(if userdata.is::() { String::from("CStruct") - } else if userdata.is::() { + } else if userdata.is::() { String::from("CArr") - } else if userdata.is::() { + } else if userdata.is::() { String::from("CPtr") - } else if userdata.is::() { + } else if userdata.is::() { String::from("CFunc") - } else if c_type_helper::is_ctype(userdata) { + } else if ctype_helper::is_ctype(userdata) { String::from("CType") } else { String::from("Unknown") @@ -226,7 +226,7 @@ pub fn get_tag_name(userdata: &LuaAnyUserData) -> LuaResult { // emulate 'print' for ctype userdata, but ctype is simplified pub fn pretty_format(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { - if c_type_helper::is_ctype(userdata) { + if ctype_helper::is_ctype(userdata) { stringify(lua, userdata) } else { Ok(format!( diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index 75635f72..075c8869 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -1,20 +1,19 @@ -mod c_arr; -mod c_func; -pub mod c_helper; -mod c_ptr; -mod c_string; -mod c_struct; -mod c_type; +mod arr_info; +mod fn_info; +pub mod helper; +mod ptr_info; +mod struct_info; +mod type_info; mod types; pub use self::{ - c_arr::CArr, - c_func::CFunc, - c_helper::method_provider, - c_ptr::CPtr, - c_struct::CStruct, - c_type::{CType, CTypeCast}, - types::{c_type_helper, export_ctypes}, + arr_info::CArrInfo, + fn_info::CFnInfo, + helper::method_provider, + ptr_info::CPtrInfo, + struct_info::CStructInfo, + type_info::{CTypeCast, CTypeInfo}, + types::{ctype_helper, export_ctypes}, }; // Named registry table names diff --git a/crates/lune-std-ffi/src/c/c_ptr.rs b/crates/lune-std-ffi/src/c/ptr_info.rs similarity index 73% rename from crates/lune-std-ffi/src/c/c_ptr.rs rename to crates/lune-std-ffi/src/c/ptr_info.rs index c56e83b6..4383da8c 100644 --- a/crates/lune-std-ffi/src/c/c_ptr.rs +++ b/crates/lune-std-ffi/src/c/ptr_info.rs @@ -3,41 +3,38 @@ use std::cell::Ref; use libffi::middle::Type; use mlua::prelude::*; -use super::{association_names::CPTR_INNER, c_helper, c_type_helper, method_provider}; +use super::{association_names::CPTR_INNER, ctype_helper, helper, method_provider}; use crate::{ - ffi::{ - ffi_association::{get_association, set_association}, - FfiRef, NativeConvert, NativeData, NativeSignedness, NativeSize, - }, - libffi_helper::SIEE_OF_POINTER, + data::{FfiConvert, FfiData, FfiSignedness, FfiSize, RefData}, + ffi::{association, libffi_helper::SIEE_OF_POINTER}, }; -pub struct CPtr { +pub struct CPtrInfo { inner_size: usize, } -impl NativeSignedness for CPtr { +impl FfiSignedness for CPtrInfo { fn get_signedness(&self) -> bool { false } } -impl NativeSize for CPtr { +impl FfiSize for CPtrInfo { fn get_size(&self) -> usize { SIEE_OF_POINTER } } -impl NativeConvert for CPtr { +impl FfiConvert for CPtrInfo { // Convert luavalue into data, then write into ptr - unsafe fn luavalue_into<'lua>( + unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { if let LuaValue::UserData(value_userdata) = value { - if value_userdata.is::() { - let value_ref = value_userdata.borrow::()?; + if value_userdata.is::() { + let value_ref = value_userdata.borrow::()?; value_ref .check_boundary(0, self.inner_size) .then_some(()) @@ -56,17 +53,17 @@ impl NativeConvert for CPtr { } // Read data from ptr, then convert into luavalue - unsafe fn luavalue_from<'lua>( + unsafe fn value_from_data<'lua>( &self, _lua: &'lua Lua, _offset: isize, - _data_handle: &Ref, + _data_handle: &Ref, ) -> LuaResult> { Err(LuaError::external("Conversion of pointer is not allowed")) } } -impl CPtr { +impl CPtrInfo { // Create pointer type with '.inner' field // inner can be CArr, CType or CStruct pub fn from_userdata<'lua>( @@ -74,10 +71,10 @@ impl CPtr { inner: &LuaAnyUserData, ) -> LuaResult> { let value = lua.create_userdata(Self { - inner_size: c_helper::get_size(inner)?, + inner_size: helper::get_size(inner)?, })?; - set_association(lua, CPTR_INNER, &value, inner)?; + association::set(lua, CPTR_INNER, &value, inner)?; Ok(value) } @@ -85,8 +82,8 @@ impl CPtr { // Stringify CPtr with inner ctype pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { 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) { + let pretty_formatted = helper::pretty_format(lua, &inner_userdata)?; + Ok(if ctype_helper::is_ctype(&inner_userdata) { pretty_formatted } else { format!(" {pretty_formatted} ") @@ -102,11 +99,11 @@ impl CPtr { } } -impl LuaUserData for CPtr { +impl LuaUserData for CPtrInfo { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { fields.add_field_method_get("size", |_, _| Ok(size_of::())); fields.add_field_function_get("inner", |lua, this| { - let inner = get_association(lua, CPTR_INNER, this)? + let inner = association::get(lua, CPTR_INNER, this)? .ok_or_else(|| LuaError::external("inner type not found"))?; Ok(inner) }); diff --git a/crates/lune-std-ffi/src/c/c_struct.rs b/crates/lune-std-ffi/src/c/struct_info.rs similarity index 76% rename from crates/lune-std-ffi/src/c/c_struct.rs rename to crates/lune-std-ffi/src/c/struct_info.rs index b0042e94..dd3d55fe 100644 --- a/crates/lune-std-ffi/src/c/c_struct.rs +++ b/crates/lune-std-ffi/src/c/struct_info.rs @@ -3,24 +3,21 @@ use std::{cell::Ref, vec::Vec}; use libffi::{low, middle::Type, raw}; use mlua::prelude::*; -use super::{association_names::CSTRUCT_INNER, c_helper, method_provider}; -use crate::ffi::{ - ffi_association::{get_association, set_association}, - NativeConvert, NativeData, NativeSignedness, NativeSize, FFI_STATUS_NAMES, +use super::{association_names::CSTRUCT_INNER, helper, method_provider}; +use crate::{ + data::{FfiConvert, FfiData, FfiSignedness, FfiSize}, + ffi::{association, libffi_helper::FFI_STATUS_NAMES}, }; -pub struct CStruct { +pub struct CStructInfo { middle_type: Type, size: usize, inner_offset_list: Vec, - inner_conv_list: Vec<*const dyn NativeConvert>, + inner_conv_list: Vec<*const dyn FfiConvert>, } -impl CStruct { - pub fn new( - fields: Vec, - inner_conv_list: Vec<*const dyn NativeConvert>, - ) -> LuaResult { +impl CStructInfo { + pub fn new(fields: Vec, inner_conv_list: Vec<*const dyn FfiConvert>) -> LuaResult { let len = fields.len(); let mut inner_offset_list = Vec::::with_capacity(len); let middle_type = Type::structure(fields); @@ -60,32 +57,33 @@ impl CStruct { lua: &'lua Lua, table: LuaTable<'lua>, ) -> LuaResult> { - let cstruct = lua.create_userdata(Self::new( - c_helper::get_middle_type_list(&table)?, - unsafe { c_helper::get_conv_list(&table)? }, - )?)?; + let cstruct = lua + .create_userdata(Self::new(helper::get_middle_type_list(&table)?, unsafe { + helper::get_conv_list(&table)? + })?)?; table.set_readonly(true); - set_association(lua, CSTRUCT_INNER, &cstruct, table)?; + association::set(lua, CSTRUCT_INNER, &cstruct, table)?; Ok(cstruct) } // 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)? + if let LuaValue::Table(fields) = association::get(lua, CSTRUCT_INNER, userdata)? .ok_or_else(|| LuaError::external("Field table not found"))? { let mut result = String::from(" "); for i in 0..fields.raw_len() { let child: LuaAnyUserData = fields.raw_get(i + 1)?; - let pretty_formatted = c_helper::pretty_format(lua, &child)?; + let pretty_formatted = helper::pretty_format(lua, &child)?; result.push_str(format!("{pretty_formatted}, ").as_str()); } // size of - result - .push_str(format!("size = {} ", userdata.borrow::()?.get_size()).as_str()); + result.push_str( + format!("size = {} ", userdata.borrow::()?.get_size()).as_str(), + ); Ok(result) } else { Err(LuaError::external("failed to get inner type table.")) @@ -107,23 +105,23 @@ impl CStruct { } } -impl NativeSize for CStruct { +impl FfiSize for CStructInfo { fn get_size(&self) -> usize { self.size } } -impl NativeSignedness for CStruct { +impl FfiSignedness for CStructInfo { fn get_signedness(&self) -> bool { false } } -impl NativeConvert for CStruct { +impl FfiConvert for CStructInfo { // FIXME: FfiBox, FfiRef support required - unsafe fn luavalue_into<'lua>( + unsafe fn value_into_data<'lua>( &self, lua: &'lua Lua, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let LuaValue::Table(ref table) = value else { @@ -133,18 +131,21 @@ impl NativeConvert for CStruct { 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)?; + conv.as_ref().unwrap().value_into_data( + lua, + field_offset + offset, + data_handle, + data, + )?; } Ok(()) } - unsafe fn luavalue_from<'lua>( + unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { let table = lua.create_table_with_capacity(self.inner_conv_list.len(), 0)?; for (i, conv) in self.inner_conv_list.iter().enumerate() { @@ -153,14 +154,14 @@ impl NativeConvert for CStruct { i + 1, conv.as_ref() .unwrap() - .luavalue_from(lua, field_offset + offset, data_handle)?, + .value_from_data(lua, field_offset + offset, data_handle)?, )?; } Ok(LuaValue::Table(table)) } } -impl LuaUserData for CStruct { +impl LuaUserData for CStructInfo { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { fields.add_field_method_get("size", |_, this| Ok(this.get_size())); } @@ -184,7 +185,7 @@ 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(fields) = get_association(lua, CSTRUCT_INNER, this)? + if let LuaValue::Table(fields) = association::get(lua, CSTRUCT_INNER, this)? .ok_or_else(|| LuaError::external("Field table not found"))? { let value: LuaValue = fields.raw_get(field + 1)?; diff --git a/crates/lune-std-ffi/src/c/c_type.rs b/crates/lune-std-ffi/src/c/type_info.rs similarity index 86% rename from crates/lune-std-ffi/src/c/c_type.rs rename to crates/lune-std-ffi/src/c/type_info.rs index c90f1958..dd459e85 100644 --- a/crates/lune-std-ffi/src/c/c_type.rs +++ b/crates/lune-std-ffi/src/c/type_info.rs @@ -6,10 +6,10 @@ use libffi::middle::Type; use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; use mlua::prelude::*; +use super::method_provider; use crate::{ - c::method_provider, - ffi::{GetNativeData, NativeConvert, NativeData, NativeSignedness, NativeSize}, - libffi_helper::get_ensured_size, + data::{FfiConvert, FfiData, FfiSignedness, FfiSize, GetFfiData}, + ffi::libffi_helper::get_ensured_size, }; // Cast native data @@ -19,8 +19,8 @@ pub trait CTypeCast { &self, from_ctype: &LuaAnyUserData, into_ctype: &LuaAnyUserData, - _from: &Ref, - _into: &Ref, + _from: &Ref, + _into: &Ref, ) -> LuaResult<()> { // Show error if have no cast implement Err(Self::cast_failed_with(self, from_ctype, into_ctype)) @@ -40,23 +40,23 @@ pub trait CTypeCast { } } -pub struct CType { +pub struct CTypeInfo { middle_type: Type, size: usize, name: &'static str, _phantom: PhantomData, } -impl NativeSize for CType { +impl FfiSize for CTypeInfo { fn get_size(&self) -> usize { self.size } } -impl CType +impl CTypeInfo where T: 'static, - Self: CTypeCast + NativeSignedness + NativeConvert + NativeSize, + Self: CTypeCast + FfiSignedness + FfiConvert + FfiSize, { pub fn new_with_libffi_type<'lua>( lua: &'lua Lua, @@ -85,10 +85,10 @@ where } } -impl LuaUserData for CType +impl LuaUserData for CTypeInfo where T: 'static, - Self: CTypeCast + NativeSignedness + NativeConvert + NativeSize, + Self: CTypeCast + FfiSignedness + FfiConvert + FfiSize, { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { fields.add_field_method_get("size", |_, this| Ok(this.get_size())); diff --git a/crates/lune-std-ffi/src/c/types/f32.rs b/crates/lune-std-ffi/src/c/types/f32.rs index 8dc86459..f397433a 100644 --- a/crates/lune-std-ffi/src/c/types/f32.rs +++ b/crates/lune-std-ffi/src/c/types/f32.rs @@ -3,22 +3,24 @@ use std::cell::Ref; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; +use crate::{ + c::type_info::CTypeInfo, + data::{FfiConvert, FfiData, FfiSignedness}, +}; -impl NativeSignedness for CType { +impl FfiSignedness for CTypeInfo { fn get_signedness(&self) -> bool { true } } -impl NativeConvert for CType { - unsafe fn luavalue_into<'lua>( +impl FfiConvert for CTypeInfo { + unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: f32 = match value { @@ -40,12 +42,12 @@ impl NativeConvert for CType { } Ok(()) } - unsafe fn luavalue_from<'lua>( + unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { let value = unsafe { (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? diff --git a/crates/lune-std-ffi/src/c/types/f64.rs b/crates/lune-std-ffi/src/c/types/f64.rs index 16c3a209..1055c5c9 100644 --- a/crates/lune-std-ffi/src/c/types/f64.rs +++ b/crates/lune-std-ffi/src/c/types/f64.rs @@ -3,22 +3,24 @@ use std::cell::Ref; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; +use crate::{ + c::type_info::CTypeInfo, + data::{FfiConvert, FfiData, FfiSignedness}, +}; -impl NativeSignedness for CType { +impl FfiSignedness for CTypeInfo { fn get_signedness(&self) -> bool { true } } -impl NativeConvert for CType { - unsafe fn luavalue_into<'lua>( +impl FfiConvert for CTypeInfo { + unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: f64 = match value { @@ -40,12 +42,12 @@ impl NativeConvert for CType { } Ok(()) } - unsafe fn luavalue_from<'lua>( + unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { let value = unsafe { (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? diff --git a/crates/lune-std-ffi/src/c/types/i128.rs b/crates/lune-std-ffi/src/c/types/i128.rs index d4784e82..6a0b55c0 100644 --- a/crates/lune-std-ffi/src/c/types/i128.rs +++ b/crates/lune-std-ffi/src/c/types/i128.rs @@ -3,22 +3,24 @@ use std::cell::Ref; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; +use crate::{ + c::type_info::CTypeInfo, + data::{FfiConvert, FfiData, FfiSignedness}, +}; -impl NativeSignedness for CType { +impl FfiSignedness for CTypeInfo { fn get_signedness(&self) -> bool { true } } -impl NativeConvert for CType { - unsafe fn luavalue_into<'lua>( +impl FfiConvert for CTypeInfo { + unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: i128 = match value { @@ -40,14 +42,16 @@ impl NativeConvert for CType { } Ok(()) } - unsafe fn luavalue_from<'lua>( + unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; + let value = unsafe { + (*data_handle.get_pointer().byte_offset(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 47e33917..a6c29486 100644 --- a/crates/lune-std-ffi/src/c/types/i16.rs +++ b/crates/lune-std-ffi/src/c/types/i16.rs @@ -3,22 +3,24 @@ use std::cell::Ref; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; +use crate::{ + c::type_info::CTypeInfo, + data::{FfiConvert, FfiData, FfiSignedness}, +}; -impl NativeSignedness for CType { +impl FfiSignedness for CTypeInfo { fn get_signedness(&self) -> bool { true } } -impl NativeConvert for CType { - unsafe fn luavalue_into<'lua>( +impl FfiConvert for CTypeInfo { + unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: i16 = match value { @@ -40,14 +42,16 @@ impl NativeConvert for CType { } Ok(()) } - unsafe fn luavalue_from<'lua>( + unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; + let value = unsafe { + (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? + }; Ok(value) } } diff --git a/crates/lune-std-ffi/src/c/types/i32.rs b/crates/lune-std-ffi/src/c/types/i32.rs index 088f948f..8afd129c 100644 --- a/crates/lune-std-ffi/src/c/types/i32.rs +++ b/crates/lune-std-ffi/src/c/types/i32.rs @@ -3,22 +3,24 @@ use std::cell::Ref; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; +use crate::{ + c::type_info::CTypeInfo, + data::{FfiConvert, FfiData, FfiSignedness}, +}; -impl NativeSignedness for CType { +impl FfiSignedness for CTypeInfo { fn get_signedness(&self) -> bool { true } } -impl NativeConvert for CType { - unsafe fn luavalue_into<'lua>( +impl FfiConvert for CTypeInfo { + unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: i32 = match value { @@ -40,14 +42,16 @@ impl NativeConvert for CType { } Ok(()) } - unsafe fn luavalue_from<'lua>( + unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; + let value = unsafe { + (*data_handle.get_pointer().byte_offset(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 4ea87c6f..f4f914fd 100644 --- a/crates/lune-std-ffi/src/c/types/i64.rs +++ b/crates/lune-std-ffi/src/c/types/i64.rs @@ -3,22 +3,24 @@ use std::cell::Ref; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; +use crate::{ + c::type_info::CTypeInfo, + data::{FfiConvert, FfiData, FfiSignedness}, +}; -impl NativeSignedness for CType { +impl FfiSignedness for CTypeInfo { fn get_signedness(&self) -> bool { true } } -impl NativeConvert for CType { - unsafe fn luavalue_into<'lua>( +impl FfiConvert for CTypeInfo { + unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: i64 = match value { @@ -40,14 +42,16 @@ impl NativeConvert for CType { } Ok(()) } - unsafe fn luavalue_from<'lua>( + unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; + let value = unsafe { + (*data_handle.get_pointer().byte_offset(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 083f1fcb..53ec8533 100644 --- a/crates/lune-std-ffi/src/c/types/i8.rs +++ b/crates/lune-std-ffi/src/c/types/i8.rs @@ -3,22 +3,24 @@ use std::cell::Ref; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; +use crate::{ + c::type_info::CTypeInfo, + data::{FfiConvert, FfiData, FfiSignedness}, +}; -impl NativeSignedness for CType { +impl FfiSignedness for CTypeInfo { fn get_signedness(&self) -> bool { true } } -impl NativeConvert for CType { - unsafe fn luavalue_into<'lua>( +impl FfiConvert for CTypeInfo { + unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: i8 = match value { @@ -36,14 +38,15 @@ impl NativeConvert for CType { } Ok(()) } - unsafe fn luavalue_from<'lua>( + unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; + let value = + unsafe { (*data_handle.get_pointer().byte_offset(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 261d217c..ccd54059 100644 --- a/crates/lune-std-ffi/src/c/types/isize.rs +++ b/crates/lune-std-ffi/src/c/types/isize.rs @@ -3,22 +3,24 @@ use std::cell::Ref; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; +use crate::{ + c::type_info::CTypeInfo, + data::{FfiConvert, FfiData, FfiSignedness}, +}; -impl NativeSignedness for CType { +impl FfiSignedness for CTypeInfo { fn get_signedness(&self) -> bool { true } } -impl NativeConvert for CType { - unsafe fn luavalue_into<'lua>( +impl FfiConvert for CTypeInfo { + unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: isize = match value { @@ -36,18 +38,27 @@ impl NativeConvert for CType { } }; unsafe { - *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; + *(data_handle + .get_pointer() + .byte_offset(offset) + .cast::()) = value; } Ok(()) } - unsafe fn luavalue_from<'lua>( + unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; + let value = unsafe { + (*data_handle + .get_pointer() + .byte_offset(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 8c8840a3..0e0387e6 100644 --- a/crates/lune-std-ffi/src/c/types/mod.rs +++ b/crates/lune-std-ffi/src/c/types/mod.rs @@ -7,8 +7,8 @@ use libffi::middle::Type; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::{CType, CTypeCast}; -use crate::ffi::{native_num_cast, NativeConvert, NativeData, NativeSize}; +use super::{CTypeCast, CTypeInfo}; +use crate::data::{num_cast, FfiConvert, FfiData, FfiSize}; pub mod f32; pub mod f64; @@ -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, $name)?, + CTypeInfo::<$rust_type>::new_with_libffi_type($lua, $libffi_type, $name)?, ),)*]) }; } @@ -80,14 +80,14 @@ pub fn export_ctypes(lua: &Lua) -> LuaResult // Implement type-casting for numeric ctypes macro_rules! define_cast_num { ($from_rust_type:ident, $self:ident, $from_ctype:ident, $into_ctype:ident, $from:ident, $into:ident, $($into_rust_type:ty)*) => { - $( if $into_ctype.is::>() { - native_num_cast::<$from_rust_type, $into_rust_type>($from, $into) + $( if $into_ctype.is::>() { + num_cast::<$from_rust_type, $into_rust_type>($from, $into) } else )* { Err($self.cast_failed_with($from_ctype, $into_ctype)) } }; } -impl CTypeCast for CType +impl CTypeCast for CTypeInfo where From: AsPrimitive + AsPrimitive @@ -106,41 +106,41 @@ where { fn cast( &self, - from_ctype: &LuaAnyUserData, - into_ctype: &LuaAnyUserData, - from: &Ref, - into: &Ref, + from_info: &LuaAnyUserData, + into_info: &LuaAnyUserData, + from: &Ref, + into: &Ref, ) -> LuaResult<()> { define_cast_num!( - From, self, into_ctype, from_ctype, from, into, + From, self, into_info, from_info, from, into, u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize ) } } -pub mod c_type_helper { +pub mod ctype_helper { use super::*; // 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) + $( if $userdata.is::>() { + Ok($userdata.to_pointer().cast::>() as *const dyn FfiConvert) } else )* { Err(LuaError::external("Unexpected type")) } }; } #[inline] - pub fn get_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn NativeConvert> { + pub fn get_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn FfiConvert> { define_get_conv!(userdata, u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize) } // Get size of ctype (not includes struct, arr, ... only CType<*>) macro_rules! define_get_size { ($userdata:ident, $( $rust_type:ty )*) => { - $( if $userdata.is::>() { - Ok($userdata.borrow::>()?.get_size()) + $( if $userdata.is::>() { + Ok($userdata.borrow::>()?.get_size()) } else )* { Err(LuaError::external("Unexpected type")) } @@ -154,8 +154,8 @@ pub mod c_type_helper { // Get name of ctype macro_rules! define_get_name { ($userdata:ident, $( $rust_type:ty )*) => { - $( if $userdata.is::>() { - Ok(Some($userdata.borrow::>()?.get_name())) + $( if $userdata.is::>() { + Ok(Some($userdata.borrow::>()?.get_name())) } else )* { Ok(None) } @@ -169,8 +169,8 @@ pub mod c_type_helper { // 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())) + $( if $userdata.is::>() { + Ok(Some($userdata.borrow::>()?.get_type())) } else )* { Ok(None) } @@ -183,7 +183,7 @@ pub mod c_type_helper { macro_rules! define_is_ctype { ($userdata:ident, $( $rust_type:ty )*) => { - $( if $userdata.is::>() { + $( if $userdata.is::>() { true } else )* { false diff --git a/crates/lune-std-ffi/src/c/types/u128.rs b/crates/lune-std-ffi/src/c/types/u128.rs index f68d91f6..34af1e59 100644 --- a/crates/lune-std-ffi/src/c/types/u128.rs +++ b/crates/lune-std-ffi/src/c/types/u128.rs @@ -3,22 +3,24 @@ use std::cell::Ref; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; +use crate::{ + c::type_info::CTypeInfo, + data::{FfiConvert, FfiData, FfiSignedness}, +}; -impl NativeSignedness for CType { +impl FfiSignedness for CTypeInfo { fn get_signedness(&self) -> bool { false } } -impl NativeConvert for CType { - unsafe fn luavalue_into<'lua>( +impl FfiConvert for CTypeInfo { + unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: u128 = match value { @@ -40,14 +42,16 @@ impl NativeConvert for CType { } Ok(()) } - unsafe fn luavalue_from<'lua>( + unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; + let value = unsafe { + (*data_handle.get_pointer().byte_offset(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 b29d4dac..b3428347 100644 --- a/crates/lune-std-ffi/src/c/types/u16.rs +++ b/crates/lune-std-ffi/src/c/types/u16.rs @@ -3,23 +3,25 @@ use std::cell::Ref; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; +use crate::{ + c::type_info::CTypeInfo, + data::{FfiConvert, FfiData, FfiSignedness}, +}; -impl NativeSignedness for CType { +impl FfiSignedness for CTypeInfo { fn get_signedness(&self) -> bool { false } } -impl NativeConvert for CType { +impl FfiConvert for CTypeInfo { // Convert luavalue into data, then write into ptr - unsafe fn luavalue_into<'lua>( + unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: u16 = match value { @@ -41,14 +43,16 @@ impl NativeConvert for CType { } Ok(()) } - unsafe fn luavalue_from<'lua>( + unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; + let value = unsafe { + (*data_handle.get_pointer().byte_offset(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 798f586b..09d9a07b 100644 --- a/crates/lune-std-ffi/src/c/types/u32.rs +++ b/crates/lune-std-ffi/src/c/types/u32.rs @@ -3,22 +3,24 @@ use std::cell::Ref; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; +use crate::{ + c::type_info::CTypeInfo, + data::{FfiConvert, FfiData, FfiSignedness}, +}; -impl NativeSignedness for CType { +impl FfiSignedness for CTypeInfo { fn get_signedness(&self) -> bool { false } } -impl NativeConvert for CType { - unsafe fn luavalue_into<'lua>( +impl FfiConvert for CTypeInfo { + unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: u32 = match value { @@ -40,14 +42,16 @@ impl NativeConvert for CType { } Ok(()) } - unsafe fn luavalue_from<'lua>( + unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; + let value = unsafe { + (*data_handle.get_pointer().byte_offset(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 757ece74..beb1ba4e 100644 --- a/crates/lune-std-ffi/src/c/types/u64.rs +++ b/crates/lune-std-ffi/src/c/types/u64.rs @@ -3,22 +3,24 @@ use std::cell::Ref; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; +use crate::{ + c::type_info::CTypeInfo, + data::{FfiConvert, FfiData, FfiSignedness}, +}; -impl NativeSignedness for CType { +impl FfiSignedness for CTypeInfo { fn get_signedness(&self) -> bool { false } } -impl NativeConvert for CType { - unsafe fn luavalue_into<'lua>( +impl FfiConvert for CTypeInfo { + unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: u64 = match value { @@ -40,14 +42,16 @@ impl NativeConvert for CType { } Ok(()) } - unsafe fn luavalue_from<'lua>( + unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; + let value = unsafe { + (*data_handle.get_pointer().byte_offset(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 273e8763..a7d9ad31 100644 --- a/crates/lune-std-ffi/src/c/types/u8.rs +++ b/crates/lune-std-ffi/src/c/types/u8.rs @@ -3,23 +3,25 @@ use std::cell::Ref; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; +use crate::{ + c::type_info::CTypeInfo, + data::{FfiConvert, FfiData, FfiSignedness}, +}; -impl NativeSignedness for CType { +impl FfiSignedness for CTypeInfo { fn get_signedness(&self) -> bool { false } } -impl NativeConvert for CType { +impl FfiConvert for CTypeInfo { // Convert luavalue into data, then write into ptr - unsafe fn luavalue_into<'lua>( + unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: u8 = match value { @@ -39,12 +41,12 @@ impl NativeConvert for CType { } // Read data from ptr, then convert into luavalue - unsafe fn luavalue_from<'lua>( + unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { let value = unsafe { (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; diff --git a/crates/lune-std-ffi/src/c/types/usize.rs b/crates/lune-std-ffi/src/c/types/usize.rs index 0dc7afc5..0fa44424 100644 --- a/crates/lune-std-ffi/src/c/types/usize.rs +++ b/crates/lune-std-ffi/src/c/types/usize.rs @@ -3,22 +3,24 @@ use std::cell::Ref; use mlua::prelude::*; use num::cast::AsPrimitive; -use super::super::c_type::CType; -use crate::ffi::{NativeConvert, NativeData, NativeSignedness}; +use crate::{ + c::type_info::CTypeInfo, + data::{FfiConvert, FfiData, FfiSignedness}, +}; -impl NativeSignedness for CType { +impl FfiSignedness for CTypeInfo { fn get_signedness(&self) -> bool { false } } -impl NativeConvert for CType { - unsafe fn luavalue_into<'lua>( +impl FfiConvert for CTypeInfo { + unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { let value: usize = match value { @@ -36,18 +38,27 @@ impl NativeConvert for CType { } }; unsafe { - *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; + *(data_handle + .get_pointer() + .byte_offset(offset) + .cast::()) = value; } Ok(()) } - unsafe fn luavalue_from<'lua>( + unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, - data_handle: &Ref, + data_handle: &Ref, ) -> LuaResult> { - let value = unsafe { (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; + let value = unsafe { + (*data_handle + .get_pointer() + .byte_offset(offset) + .cast::()) + .into_lua(lua)? + }; Ok(value) } } diff --git a/crates/lune-std-ffi/src/c/c_void.rs b/crates/lune-std-ffi/src/c/void_info.rs similarity index 100% rename from crates/lune-std-ffi/src/c/c_void.rs rename to crates/lune-std-ffi/src/c/void_info.rs diff --git a/crates/lune-std-ffi/src/ffi/ffi_box/flag.rs b/crates/lune-std-ffi/src/data/box_data/flag.rs similarity index 64% rename from crates/lune-std-ffi/src/ffi/ffi_box/flag.rs rename to crates/lune-std-ffi/src/data/box_data/flag.rs index dfb4757d..f54a1b5f 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_box/flag.rs +++ b/crates/lune-std-ffi/src/data/box_data/flag.rs @@ -1,10 +1,10 @@ -use super::super::bit_mask::*; +use crate::ffi::bit_mask::*; -pub enum FfiBoxFlag { +pub enum BoxDataFlag { Leaked, } -impl FfiBoxFlag { +impl BoxDataFlag { pub const fn value(&self) -> u8 { match self { Self::Leaked => U8_MASK2, diff --git a/crates/lune-std-ffi/src/ffi/ffi_box/mod.rs b/crates/lune-std-ffi/src/data/box_data/mod.rs similarity index 79% rename from crates/lune-std-ffi/src/ffi/ffi_box/mod.rs rename to crates/lune-std-ffi/src/data/box_data/mod.rs index b10b5e3f..ea5b1f43 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_box/mod.rs +++ b/crates/lune-std-ffi/src/data/box_data/mod.rs @@ -2,21 +2,18 @@ use std::{alloc, alloc::Layout, boxed::Box, mem::ManuallyDrop, ptr}; use mlua::prelude::*; -use super::{ - association_names::REF_INNER, - bit_mask::*, - ffi_association::set_association, - ffi_ref::{FfiRef, FfiRefBounds, FfiRefFlag}, - NativeData, +use crate::{ + data::{association_names::REF_INNER, RefData, RefDataBounds, RefDataFlag}, + ffi::{association, bit_mask::*, FfiData}, }; mod flag; -pub use self::flag::FfiBoxFlag; +pub use self::flag::BoxDataFlag; // Ref which created by lua should not be dereferenceable, const BOX_REF_FLAGS: u8 = - FfiRefFlag::Readable.value() | FfiRefFlag::Writable.value() | FfiRefFlag::Offsetable.value(); + RefDataFlag::Readable.value() | RefDataFlag::Writable.value() | RefDataFlag::Offsetable.value(); // It is an untyped, sized memory area that Lua can manage. // This area is safe within Lua. Operations have their boundaries checked. @@ -27,14 +24,14 @@ const BOX_REF_FLAGS: u8 = // rather, it creates more heap space, so it should be used appropriately // where necessary. -pub struct FfiBox { +pub struct BoxData { flags: u8, data: ManuallyDrop>, } const FFI_BOX_PRINT_MAX_LENGTH: usize = 1024; -impl FfiBox { +impl BoxData { // For efficiency, it is initialized non-zeroed. pub fn new(size: usize) -> Self { let slice = unsafe { @@ -66,7 +63,7 @@ impl FfiBox { } pub fn leak(&mut self) { - self.flags = u8_set(self.flags, FfiBoxFlag::Leaked.value(), true); + self.flags = u8_set(self.flags, BoxDataFlag::Leaked.value(), true); } // Make FfiRef from box, with boundary checking @@ -75,8 +72,8 @@ impl FfiBox { this: LuaAnyUserData<'lua>, offset: Option, ) -> LuaResult> { - let target = this.borrow::()?; - let mut bounds = FfiRefBounds::new(0, target.size()); + let target = this.borrow::()?; + let mut bounds = RefDataBounds::new(0, target.size()); let mut ptr = unsafe { target.get_pointer() }; // Calculate offset @@ -92,10 +89,10 @@ impl FfiBox { bounds = bounds.offset(t); } - let luaref = lua.create_userdata(FfiRef::new(ptr.cast(), BOX_REF_FLAGS, bounds))?; + let luaref = lua.create_userdata(RefData::new(ptr.cast(), BOX_REF_FLAGS, bounds))?; // Makes box alive longer then ref - set_association(lua, REF_INNER, &luaref, &this)?; + association::set(lua, REF_INNER, &luaref, &this)?; Ok(luaref) } @@ -115,15 +112,15 @@ impl FfiBox { } } -impl Drop for FfiBox { +impl Drop for BoxData { fn drop(&mut self) { - if u8_test_not(self.flags, FfiBoxFlag::Leaked.value()) { + if u8_test_not(self.flags, BoxDataFlag::Leaked.value()) { unsafe { self.drop() }; } } } -impl NativeData for FfiBox { +impl FfiData for BoxData { fn check_boundary(&self, offset: isize, size: usize) -> bool { if offset < 0 { return false; @@ -141,27 +138,27 @@ impl NativeData for FfiBox { } } -impl LuaUserData for FfiBox { +impl LuaUserData for BoxData { 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| { - this.borrow_mut::()?.zero(); + this.borrow_mut::()?.zero(); Ok(this) }); methods.add_function_mut( "leak", |lua, (this, offset): (LuaAnyUserData, Option)| { - this.borrow_mut::()?.leak(); - FfiBox::luaref(lua, this, offset) + this.borrow_mut::()?.leak(); + BoxData::luaref(lua, this, offset) }, ); methods.add_function( "ref", |lua, (this, offset): (LuaAnyUserData, Option)| { - FfiBox::luaref(lua, this, offset) + BoxData::luaref(lua, this, offset) }, ); methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| Ok(this.stringify())); diff --git a/crates/lune-std-ffi/src/ffi/ffi_callable.rs b/crates/lune-std-ffi/src/data/callable_data.rs similarity index 84% rename from crates/lune-std-ffi/src/ffi/ffi_callable.rs rename to crates/lune-std-ffi/src/data/callable_data.rs index b5e4c1da..ca8f65c5 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_callable.rs +++ b/crates/lune-std-ffi/src/data/callable_data.rs @@ -7,20 +7,20 @@ use libffi::{ }; use mlua::prelude::*; -use super::{GetNativeData, NativeArgInfo, NativeData, NativeResultInfo}; +use super::{FfiArgInfo, FfiData, FfiResultInfo, GetFfiData}; -pub struct FfiCallable { +pub struct CallableData { cif: *mut ffi_cif, - arg_info_list: *const Vec, - result_info: *const NativeResultInfo, + arg_info_list: *const Vec, + result_info: *const FfiResultInfo, code: CodePtr, } -impl FfiCallable { +impl CallableData { pub unsafe fn new( cif: *mut ffi_cif, - arg_info_list: *const Vec, - result_info: *const NativeResultInfo, + arg_info_list: *const Vec, + result_info: *const FfiResultInfo, function_pointer: *const (), ) -> Self { Self { @@ -33,7 +33,7 @@ impl FfiCallable { // TODO? async call: if have no lua closure in arguments, fficallble can be called with async way - pub unsafe fn call(&self, result: &Ref, args: LuaMultiValue) -> LuaResult<()> { + pub unsafe fn call(&self, result: &Ref, args: LuaMultiValue) -> LuaResult<()> { result .check_boundary(0, self.result_info.as_ref().unwrap().size) .then_some(()) @@ -74,11 +74,11 @@ impl FfiCallable { } } -impl LuaUserData for FfiCallable { +impl LuaUserData for CallableData { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { methods.add_method( "call", - |_lua, this: &FfiCallable, mut args: LuaMultiValue| { + |_lua, this: &CallableData, mut args: LuaMultiValue| { let result_userdata = args.pop_front().ok_or_else(|| { LuaError::external("first argument must be result data handle") })?; diff --git a/crates/lune-std-ffi/src/ffi/ffi_closure.rs b/crates/lune-std-ffi/src/data/closure_data.rs similarity index 78% rename from crates/lune-std-ffi/src/ffi/ffi_closure.rs rename to crates/lune-std-ffi/src/data/closure_data.rs index 7afca469..8175be33 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_closure.rs +++ b/crates/lune-std-ffi/src/data/closure_data.rs @@ -8,17 +8,18 @@ use libffi::{ use mlua::prelude::*; use super::{ - ffi_ref::{FfiRefBounds, FfiRefFlag}, - FfiRef, FFI_STATUS_NAMES, + ref_data::{RefDataBounds, RefDataFlag}, + RefData, }; +use crate::ffi::libffi_helper::FFI_STATUS_NAMES; -pub struct FfiClosure<'a> { +pub struct ClosureData<'a> { closure: *mut ffi_closure, code: CodePtr, userdata: CallbackUserdata<'a>, } -impl<'a> Drop for FfiClosure<'a> { +impl<'a> Drop for ClosureData<'a> { fn drop(&mut self) { unsafe { closure_free(self.closure); @@ -35,7 +36,7 @@ pub struct CallbackUserdata<'a> { pub result_size: usize, } -const RESULT_REF_FLAGS: u8 = FfiRefFlag::Leaked.value() | FfiRefFlag::Writable.value(); +const RESULT_REF_FLAGS: u8 = RefDataFlag::Leaked.value() | RefDataFlag::Writable.value(); unsafe extern "C" fn callback( cif: *mut ffi_cif, @@ -51,10 +52,10 @@ unsafe extern "C" fn callback( args.push(LuaValue::UserData( (*userdata) .lua - .create_userdata(FfiRef::new( + .create_userdata(RefData::new( result_pointer.cast::<()>(), RESULT_REF_FLAGS, - FfiRefBounds::new(0, (*userdata).result_size), + RefDataBounds::new(0, (*userdata).result_size), )) .unwrap(), )); @@ -64,10 +65,10 @@ unsafe extern "C" fn callback( args.push(LuaValue::UserData( (*userdata) .lua - .create_userdata(FfiRef::new( + .create_userdata(RefData::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()), + RefDataBounds::new(0, (*userdata).arg_ref_size.get(i).unwrap().to_owned()), )) .unwrap(), )); @@ -76,11 +77,11 @@ unsafe extern "C" fn callback( (*userdata).func.call::<_, ()>(args).unwrap(); } -impl<'a> FfiClosure<'a> { +impl<'a> ClosureData<'a> { pub unsafe fn new( cif: *mut ffi_cif, userdata: CallbackUserdata<'a>, - ) -> LuaResult> { + ) -> LuaResult> { let (closure, code) = closure_alloc(); let prep_result = ffi_prep_closure_loc( closure, @@ -96,7 +97,7 @@ impl<'a> FfiClosure<'a> { FFI_STATUS_NAMES[0], FFI_STATUS_NAMES[prep_result as usize] ))) } else { - Ok(FfiClosure { + Ok(ClosureData { closure, code, userdata, diff --git a/crates/lune-std-ffi/src/ffi/ffi_lib.rs b/crates/lune-std-ffi/src/data/lib_data.rs similarity index 60% rename from crates/lune-std-ffi/src/ffi/ffi_lib.rs rename to crates/lune-std-ffi/src/data/lib_data.rs index b0712579..211dbda6 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_lib.rs +++ b/crates/lune-std-ffi/src/data/lib_data.rs @@ -2,19 +2,19 @@ use dlopen2::raw::Library; use mlua::prelude::*; use super::{ + association, association_names::SYM_INNER, - ffi_association::set_association, - ffi_ref::{FfiRef, FfiRefFlag, UNSIZED_BOUNDS}, + ref_data::{RefData, RefDataFlag, UNSIZED_BOUNDS}, }; -const LIB_REF_FLAGS: u8 = FfiRefFlag::Offsetable.value() - | FfiRefFlag::Readable.value() - | FfiRefFlag::Dereferenceable.value() - | FfiRefFlag::Function.value(); +const LIB_REF_FLAGS: u8 = RefDataFlag::Offsetable.value() + | RefDataFlag::Readable.value() + | RefDataFlag::Dereferenceable.value() + | RefDataFlag::Function.value(); -pub struct FfiLib(Library); +pub struct LibData(Library); -impl FfiLib { +impl LibData { pub fn new(libname: String) -> LuaResult { match Library::open(libname) { Ok(t) => Ok(Self(t)), @@ -27,7 +27,7 @@ impl FfiLib { this: LuaAnyUserData<'lua>, name: String, ) -> LuaResult> { - let lib = this.borrow::()?; + let lib = this.borrow::()?; let sym = unsafe { lib.0 .symbol::<*const ()>(name.as_str()) @@ -35,18 +35,18 @@ impl FfiLib { }; let ffi_ref = - lua.create_userdata(FfiRef::new(sym.cast_mut(), LIB_REF_FLAGS, UNSIZED_BOUNDS))?; + lua.create_userdata(RefData::new(sym.cast_mut(), LIB_REF_FLAGS, UNSIZED_BOUNDS))?; - set_association(lua, SYM_INNER, &ffi_ref, &this)?; + association::set(lua, SYM_INNER, &ffi_ref, &this)?; Ok(ffi_ref) } } -impl LuaUserData for FfiLib { +impl LuaUserData for LibData { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { methods.add_function("find", |lua, (this, name): (LuaAnyUserData, String)| { - FfiLib::get_sym(lua, this, name) + LibData::get_sym(lua, this, name) }); } } diff --git a/crates/lune-std-ffi/src/data/mod.rs b/crates/lune-std-ffi/src/data/mod.rs new file mode 100644 index 00000000..6b5de23e --- /dev/null +++ b/crates/lune-std-ffi/src/data/mod.rs @@ -0,0 +1,53 @@ +use std::cell::Ref; + +use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; +use mlua::prelude::*; + +mod box_data; +mod callable_data; +mod closure_data; +mod lib_data; +mod ref_data; + +pub use crate::{ + data::{ + box_data::BoxData, + callable_data::CallableData, + closure_data::ClosureData, + lib_data::LibData, + ref_data::{create_nullptr, RefData, RefDataBounds, RefDataFlag}, + }, + ffi::{ + association, num_cast, FfiArgInfo, FfiConvert, FfiData, FfiResultInfo, FfiSignedness, + FfiSize, + }, +}; + +// Named registry table names +mod association_names { + pub const REF_INNER: &str = "__ref_inner"; + pub const SYM_INNER: &str = "__syn_inner"; +} + +pub trait GetFfiData { + fn get_data_handle(&self) -> LuaResult>; +} + +impl GetFfiData 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_ref/bounds.rs b/crates/lune-std-ffi/src/data/ref_data/bounds.rs similarity index 94% rename from crates/lune-std-ffi/src/ffi/ffi_ref/bounds.rs rename to crates/lune-std-ffi/src/data/ref_data/bounds.rs index 9fd85665..cfa16998 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/bounds.rs +++ b/crates/lune-std-ffi/src/data/ref_data/bounds.rs @@ -1,17 +1,17 @@ // Memory range for ref or box data. For boundary checking -pub struct FfiRefBounds { +pub struct RefDataBounds { // Indicates how much data is above the pointer pub(crate) above: usize, // Indicates how much data is below the pointer pub(crate) below: usize, } -pub const UNSIZED_BOUNDS: FfiRefBounds = FfiRefBounds { +pub const UNSIZED_BOUNDS: RefDataBounds = RefDataBounds { above: usize::MAX, below: usize::MAX, }; -impl FfiRefBounds { +impl RefDataBounds { pub fn new(above: usize, below: usize) -> Self { Self { above, below } } @@ -88,7 +88,7 @@ impl FfiRefBounds { } } -impl Clone for FfiRefBounds { +impl Clone for RefDataBounds { fn clone(&self) -> Self { Self { above: self.above, diff --git a/crates/lune-std-ffi/src/ffi/ffi_ref/flag.rs b/crates/lune-std-ffi/src/data/ref_data/flag.rs similarity index 86% rename from crates/lune-std-ffi/src/ffi/ffi_ref/flag.rs rename to crates/lune-std-ffi/src/data/ref_data/flag.rs index 5dd4ec12..3cf3b11d 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/flag.rs +++ b/crates/lune-std-ffi/src/data/ref_data/flag.rs @@ -1,6 +1,6 @@ -use super::super::bit_mask::*; +use crate::ffi::bit_mask::*; -pub enum FfiRefFlag { +pub enum RefDataFlag { Leaked, Dereferenceable, Readable, @@ -9,7 +9,7 @@ pub enum FfiRefFlag { Function, Uninit, } -impl FfiRefFlag { +impl RefDataFlag { pub const fn value(&self) -> u8 { match self { Self::Leaked => U8_MASK1, diff --git a/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs b/crates/lune-std-ffi/src/data/ref_data/mod.rs similarity index 74% rename from crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs rename to crates/lune-std-ffi/src/data/ref_data/mod.rs index 3534e98f..4659cef2 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs +++ b/crates/lune-std-ffi/src/data/ref_data/mod.rs @@ -2,24 +2,22 @@ use std::{mem::ManuallyDrop, ptr}; use mlua::prelude::*; -use super::{ - association_names::REF_INNER, - bit_mask::{u8_test, u8_test_not}, - ffi_association::{get_association, set_association}, - NativeData, +use crate::{ + data::association_names::REF_INNER, + ffi::{association, bit_mask::*, FfiData}, }; mod bounds; mod flag; pub use self::{ - bounds::{FfiRefBounds, UNSIZED_BOUNDS}, - flag::FfiRefFlag, + bounds::{RefDataBounds, UNSIZED_BOUNDS}, + flag::RefDataFlag, }; // Box:ref():ref() should not be able to modify, Only for external const BOX_REF_REF_FLAGS: u8 = 0; -const UNINIT_REF_FLAGS: u8 = FfiRefFlag::Uninit.value(); +const UNINIT_REF_FLAGS: u8 = RefDataFlag::Uninit.value(); // | FfiRefFlag::Writable.value() // | FfiRefFlag::Readable.value() // | FfiRefFlag::Dereferenceable.value() @@ -32,14 +30,14 @@ const UNINIT_REF_FLAGS: u8 = FfiRefFlag::Uninit.value(); // If it references an area managed by Lua, // the box will remain as long as this reference is alive. -pub struct FfiRef { +pub struct RefData { ptr: ManuallyDrop>, pub flags: u8, - pub boundary: FfiRefBounds, + pub boundary: RefDataBounds, } -impl FfiRef { - pub fn new(ptr: *mut (), flags: u8, boundary: FfiRefBounds) -> Self { +impl RefData { + pub fn new(ptr: *mut (), flags: u8, boundary: RefDataBounds) -> Self { Self { ptr: ManuallyDrop::new(Box::new(ptr)), flags, @@ -60,25 +58,25 @@ impl FfiRef { lua: &'lua Lua, this: LuaAnyUserData<'lua>, ) -> LuaResult> { - let target = this.borrow::()?; + let target = this.borrow::()?; - let luaref = lua.create_userdata(FfiRef::new( + let luaref = lua.create_userdata(RefData::new( ptr::from_ref(&target.ptr) as *mut (), BOX_REF_REF_FLAGS, - FfiRefBounds { + RefDataBounds { below: 0, above: size_of::(), }, ))?; // If the ref holds a box, make sure the new ref also holds the box by holding ref - set_association(lua, REF_INNER, &luaref, &this)?; + association::set(lua, REF_INNER, &luaref, &this)?; Ok(luaref) } pub unsafe fn deref(&self) -> LuaResult { - u8_test(self.flags, FfiRefFlag::Dereferenceable.value()) + u8_test(self.flags, RefDataFlag::Dereferenceable.value()) .then_some(()) .ok_or_else(|| LuaError::external("This pointer is not dereferenceable."))?; @@ -106,7 +104,7 @@ impl FfiRef { } pub unsafe fn offset(&self, offset: isize) -> LuaResult { - u8_test(self.flags, FfiRefFlag::Offsetable.value()) + u8_test(self.flags, RefDataFlag::Offsetable.value()) .then_some(()) .ok_or_else(|| LuaError::external("This pointer is not offsetable."))?; @@ -132,15 +130,15 @@ impl FfiRef { } } -impl Drop for FfiRef { +impl Drop for RefData { fn drop(&mut self) { - if u8_test_not(self.flags, FfiRefFlag::Leaked.value()) { + if u8_test_not(self.flags, RefDataFlag::Leaked.value()) { unsafe { ManuallyDrop::drop(&mut self.ptr) }; } } } -impl NativeData for FfiRef { +impl FfiData for RefData { fn check_boundary(&self, offset: isize, size: usize) -> bool { self.boundary.check_sized(offset, size) } @@ -148,42 +146,42 @@ impl NativeData for FfiRef { **self.ptr } fn is_readable(&self) -> bool { - u8_test(self.flags, FfiRefFlag::Readable.value()) + u8_test(self.flags, RefDataFlag::Readable.value()) } fn is_writable(&self) -> bool { - u8_test(self.flags, FfiRefFlag::Writable.value()) + u8_test(self.flags, RefDataFlag::Writable.value()) } } -impl LuaUserData for FfiRef { +impl LuaUserData for RefData { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { // FIXME: methods.add_function("deref", |lua, this: LuaAnyUserData| { - let inner = get_association(lua, REF_INNER, &this)?; - let ffiref = this.borrow::()?; + let inner = association::get(lua, REF_INNER, &this)?; + let ffiref = this.borrow::()?; let result = lua.create_userdata(unsafe { ffiref.deref()? })?; if let Some(t) = inner { - // if let Some(u) = get_association(lua, regname, value) {} - set_association(lua, REF_INNER, &result, &t)?; + // if let Some(u) = association::get(lua, regname, value) {} + association::set(lua, REF_INNER, &result, &t)?; } Ok(result) }); methods.add_function("offset", |lua, (this, offset): (LuaAnyUserData, isize)| { - let ffiref = unsafe { this.borrow::()?.offset(offset)? }; + let ffiref = unsafe { this.borrow::()?.offset(offset)? }; let userdata = lua.create_userdata(ffiref)?; // If the ref holds a box, make sure the new ref also holds the box - if let Some(t) = get_association(lua, REF_INNER, &this)? { - set_association(lua, REF_INNER, &userdata, t)?; + if let Some(t) = association::get(lua, REF_INNER, &this)? { + association::set(lua, REF_INNER, &userdata, t)?; } Ok(userdata) }); // FIXME: methods.add_function("ref", |lua, this: LuaAnyUserData| { - let ffiref = FfiRef::luaref(lua, this)?; + let ffiref = RefData::luaref(lua, this)?; Ok(ffiref) }); methods.add_method("isNull", |_, this, ()| Ok(this.is_nullptr())); @@ -192,7 +190,7 @@ impl LuaUserData for FfiRef { pub fn create_nullptr(lua: &Lua) -> LuaResult { // https://en.cppreference.com/w/cpp/types/nullptr_t - lua.create_userdata(FfiRef::new( + lua.create_userdata(RefData::new( ptr::null_mut::<()>().cast(), 0, // usize::MAX means that nullptr is can be 'any' pointer type diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/arg.rs b/crates/lune-std-ffi/src/ffi/arg.rs similarity index 55% rename from crates/lune-std-ffi/src/ffi/ffi_native/arg.rs rename to crates/lune-std-ffi/src/ffi/arg.rs index 9eb06a09..9d895fe5 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/arg.rs +++ b/crates/lune-std-ffi/src/ffi/arg.rs @@ -1,16 +1,16 @@ -use super::NativeConvert; +use super::FfiConvert; pub struct FfiArgRefOption { pub flag: u8, } -pub enum NativeArgType { +pub enum FfiArgType { FfiBox, FfiRef(FfiArgRefOption), } -pub struct NativeArgInfo { - pub conv: *const dyn NativeConvert, +pub struct FfiArgInfo { + pub conv: *const dyn FfiConvert, pub size: usize, // pub kind: NativeArgType, } diff --git a/crates/lune-std-ffi/src/ffi/ffi_association.rs b/crates/lune-std-ffi/src/ffi/association.rs similarity index 91% rename from crates/lune-std-ffi/src/ffi/ffi_association.rs rename to crates/lune-std-ffi/src/ffi/association.rs index be15a658..b5c6265f 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_association.rs +++ b/crates/lune-std-ffi/src/ffi/association.rs @@ -29,12 +29,7 @@ use mlua::prelude::*; // You can delete the relationship by changing 'associated' to nil #[inline] -pub fn set_association<'lua, T, U>( - lua: &'lua Lua, - regname: &str, - value: T, - associated: U, -) -> LuaResult<()> +pub fn set<'lua, T, U>(lua: &'lua Lua, regname: &str, value: T, associated: U) -> LuaResult<()> where T: IntoLua<'lua>, U: IntoLua<'lua>, @@ -61,11 +56,7 @@ where // If there is no table in registry, it returns None. // If there is no value in table, it returns LuaNil. #[inline] -pub fn get_association<'lua, T>( - lua: &'lua Lua, - regname: &str, - value: T, -) -> LuaResult>> +pub fn get<'lua, T>(lua: &'lua Lua, regname: &str, value: T) -> LuaResult>> where T: IntoLua<'lua>, { diff --git a/crates/lune-std-ffi/src/ffi/bit_mask.rs b/crates/lune-std-ffi/src/ffi/bit_mask.rs new file mode 100644 index 00000000..db88474b --- /dev/null +++ b/crates/lune-std-ffi/src/ffi/bit_mask.rs @@ -0,0 +1,29 @@ +#![allow(unused)] + +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; + +#[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 + } else { + bits & !mask + } +} diff --git a/crates/lune-std-ffi/src/ffi/cast.rs b/crates/lune-std-ffi/src/ffi/cast.rs new file mode 100644 index 00000000..76fd18e1 --- /dev/null +++ b/crates/lune-std-ffi/src/ffi/cast.rs @@ -0,0 +1,22 @@ +use std::cell::Ref; + +use mlua::prelude::*; +use num::cast::AsPrimitive; + +use super::FfiData; + +#[inline] +pub fn num_cast(from: &Ref, into: &Ref) -> LuaResult<()> +where + From: AsPrimitive, + Into: 'static + Copy, +{ + let from_ptr = unsafe { from.get_pointer().cast::() }; + let into_ptr = unsafe { into.get_pointer().cast::() }; + + unsafe { + *into_ptr = (*from_ptr).as_(); + } + + Ok(()) +} diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/cast.rs b/crates/lune-std-ffi/src/ffi/ffi_native/cast.rs deleted file mode 100644 index b0915f85..00000000 --- a/crates/lune-std-ffi/src/ffi/ffi_native/cast.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![allow(clippy::inline_always)] - -use std::cell::Ref; - -use mlua::prelude::*; -use num::cast::AsPrimitive; - -use super::NativeData; - -// Cast T as U - -#[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().cast::() }; - let into_ptr = unsafe { into.get_pointer().cast::() }; - - 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 deleted file mode 100644 index 4d493e13..00000000 --- a/crates/lune-std-ffi/src/ffi/ffi_native/convert.rs +++ /dev/null @@ -1,27 +0,0 @@ -#![allow(clippy::inline_always)] - -use std::cell::Ref; - -use mlua::prelude::*; - -use super::NativeData; - -// Handle native data, provide type conversion between luavalue and native types -pub trait NativeConvert { - // 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<()>; - - // Read data from ptr, then convert into luavalue - unsafe fn luavalue_from<'lua>( - &self, - lua: &'lua 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 deleted file mode 100644 index eaa32c6b..00000000 --- a/crates/lune-std-ffi/src/ffi/ffi_native/data.rs +++ /dev/null @@ -1,40 +0,0 @@ -use std::cell::Ref; - -use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; -use mlua::prelude::*; - -use super::super::{FfiBox, FfiRef}; - -pub trait NativeData { - fn check_boundary(&self, offset: isize, size: usize) -> bool; - unsafe fn get_pointer(&self) -> *mut (); - fn is_writable(&self) -> bool; - fn is_readable(&self) -> bool; -} - -pub trait GetNativeData { - 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 GetNativeData 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_native/mod.rs b/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs deleted file mode 100644 index 4ac89ba8..00000000 --- a/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -mod arg; -mod cast; -mod convert; -mod data; -mod result; - -pub trait NativeSize { - fn get_size(&self) -> usize; -} - -pub trait NativeSignedness { - fn get_signedness(&self) -> bool { - false - } -} - -pub use self::{ - arg::NativeArgInfo, - cast::native_num_cast, - convert::NativeConvert, - data::GetNativeData, - data::NativeData, - result::NativeResultInfo, - // result::NativeResultType, -}; diff --git a/crates/lune-std-ffi/src/libffi_helper.rs b/crates/lune-std-ffi/src/ffi/libffi_helper.rs similarity index 81% rename from crates/lune-std-ffi/src/libffi_helper.rs rename to crates/lune-std-ffi/src/ffi/libffi_helper.rs index 41b9f6ea..2c0d1e06 100644 --- a/crates/lune-std-ffi/src/libffi_helper.rs +++ b/crates/lune-std-ffi/src/ffi/libffi_helper.rs @@ -3,8 +3,6 @@ use std::ptr::{self, null_mut}; use libffi::{low, raw}; use mlua::prelude::*; -use crate::ffi::FFI_STATUS_NAMES; - // Get ensured size of c-type (raw::libffi_type) // See: http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html pub fn get_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult { @@ -29,3 +27,11 @@ pub fn get_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult { } pub const SIEE_OF_POINTER: usize = size_of::<*mut ()>(); + +// 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", +]; diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index ef4ae648..c1a68223 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -1,71 +1,49 @@ -pub mod ffi_association; -mod ffi_box; -mod ffi_callable; -mod ffi_closure; -mod ffi_lib; -mod ffi_native; -mod ffi_ref; +use std::cell::Ref; use mlua::prelude::*; -pub use self::{ - ffi_box::FfiBox, - ffi_callable::FfiCallable, - ffi_closure::FfiClosure, - ffi_lib::FfiLib, - ffi_native::{ - native_num_cast, GetNativeData, NativeArgInfo, NativeConvert, NativeData, NativeResultInfo, - NativeSignedness, NativeSize, - }, - ffi_ref::{create_nullptr, FfiRef, FfiRefFlag}, -}; +mod arg; +pub mod association; +pub mod bit_mask; +mod cast; +pub mod libffi_helper; +mod result; -// Named registry table names -mod association_names { - pub const REF_INNER: &str = "__ref_inner"; - pub const SYM_INNER: &str = "__syn_inner"; +pub trait FfiSize { + fn get_size(&self) -> usize; } -// 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; - - #[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 +pub trait FfiSignedness { + fn get_signedness(&self) -> bool { + false } +} - #[inline] - pub fn u8_set(bits: u8, mask: u8, val: bool) -> u8 { - if val { - bits | mask - } else { - bits & !mask - } - } +// Provide type conversion between luavalue and ffidata types +pub trait FfiConvert { + // Write LuaValue into FfiData + unsafe fn value_into_data<'lua>( + &self, + lua: &'lua Lua, + offset: isize, + data_handle: &Ref, + value: LuaValue<'lua>, + ) -> LuaResult<()>; + + // Read LuaValue from FfiData + unsafe fn value_from_data<'lua>( + &self, + lua: &'lua Lua, + offset: isize, + data_handle: &Ref, + ) -> LuaResult>; } -#[inline] -pub fn is_integer(num: LuaValue) -> bool { - num.is_integer() +pub trait FfiData { + fn check_boundary(&self, offset: isize, size: usize) -> bool; + unsafe fn get_pointer(&self) -> *mut (); + fn is_writable(&self) -> bool; + fn is_readable(&self) -> bool; } + +pub use self::{arg::FfiArgInfo, cast::num_cast, result::FfiResultInfo}; diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/result.rs b/crates/lune-std-ffi/src/ffi/result.rs similarity index 55% rename from crates/lune-std-ffi/src/ffi/ffi_native/result.rs rename to crates/lune-std-ffi/src/ffi/result.rs index 588aae71..06bd8088 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/result.rs +++ b/crates/lune-std-ffi/src/ffi/result.rs @@ -1,12 +1,12 @@ -use super::NativeConvert; +use super::FfiConvert; // pub enum NativeResultType { // FfiBox, // FfiRef, // } -pub struct NativeResultInfo { - pub conv: *const dyn NativeConvert, +pub struct FfiResultInfo { + pub conv: *const dyn FfiConvert, pub size: usize, // kind: NativeResultType, } diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs index c2fb8441..18b96481 100644 --- a/crates/lune-std-ffi/src/lib.rs +++ b/crates/lune-std-ffi/src/lib.rs @@ -1,16 +1,16 @@ #![allow(clippy::cargo_common_metadata)] -use ffi::FfiRef; +use data::RefData; use lune_utils::TableBuilder; use mlua::prelude::*; mod c; +mod data; mod ffi; -mod libffi_helper; use crate::{ - c::{export_ctypes, CFunc, CStruct}, - ffi::{create_nullptr, is_integer, FfiBox, FfiLib}, + c::{export_ctypes, CFnInfo, CStructInfo}, + data::{create_nullptr, BoxData, LibData}, }; /** @@ -24,22 +24,21 @@ pub fn module(lua: &Lua) -> LuaResult { let result = TableBuilder::new(lua)? .with_values(export_ctypes(lua)?)? .with_function("nullRef", |lua, ()| create_nullptr(lua))? - .with_function("box", |_lua, size: usize| Ok(FfiBox::new(size)))? - .with_function("open", |_lua, name: String| FfiLib::new(name))? + .with_function("box", |_lua, size: usize| Ok(BoxData::new(size)))? + .with_function("open", |_lua, name: String| LibData::new(name))? .with_function("structInfo", |lua, types: LuaTable| { - CStruct::from_table(lua, types) + CStructInfo::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)| CFunc::new_from_table(lua, args, ret), - )?; + .with_function("uninitRef", |_lua, ()| Ok(RefData::new_uninit()))? + .with_function("isInteger", |_lua, num: LuaValue| Ok(num.is_integer()))? + .with_function("fnInfo", |lua, (args, ret): (LuaTable, LuaAnyUserData)| { + CFnInfo::new_from_table(lua, args, ret) + })?; #[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()) + ffi::association::get_table(lua, str.as_ref()) })?; result.build_readonly() diff --git a/types/ffi.luau b/types/ffi.luau index ddcc5e96..9db46478 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -1,37 +1,57 @@ -- NOTE: T is a unique identifier for the `CType` and R is the closest Lua type. -export type CType = { +export type CTypeInfo = { size: number, signedness: boolean, - ptr: (self: CType) -> CPtr, - box: (self: CType, val: R) -> Box, - -- FIXME: recursive types; ud should be CTypes - from: (self: CType, ud: any, offset: number?) -> R, - into: (self: CType, ud: any, value: R, offset: number?) -> (), - arr: (self: CType, len: number) -> CArr, - -- FIXME: recursive types; intoType should be CTypes - cast: (self: CType, intoType: any, from: F, into: I) -> (), + -- subtype + ptrInfo: (self: CTypeInfo) -> CPtrInfo>, + arrInfo: (self: CTypeInfo, len: number) -> CArrInfo, R>, + + -- realize + box: (self: CTypeInfo, val: R) -> Box, + fromData: (self: CTypeInfo, data: (Ref|Box), offset: number?) -> R, + intoData: (self: CTypeInfo, data: (Ref|Box), value: R, offset: number?) -> (), + + -- FIXME: recursive types; 'intoType' should be CTypes + cast: (self: CTypeInfo, intoType: any, fromData: (Ref|Box), intoData: (Ref|Box)) -> (), } & { ["__phantom"]: T } -export type CPtr = { +export type CPtrInfo = { size: number, - inner: T?, + inner: T, + + -- subtype + -- FIXME: recursive types; 'any' should be CPtrInfo + arrInfo: (self: CPtrInfo, len: number) -> any, + ptrInfo: (self: CPtrInfo) -> any, } -export type CArr = { +export type CArrInfo = { size: number, length: number, - inner: { T }?, - - offset: (self: CArr, offset: number) -> number, - ptr: (self: CArr) -> CPtr<{ T }>, - box: (self: CArr, table: { T }) -> Box, - -- FIXME: recursive types; ud should be CTypes - from: (self: CArr, ud: any, offset: number?) -> { T }, - into: (self: CArr, ud: any, value: { T }, offset: number?) -> (), + inner: T, + + -- subtype + ptrInfo: (self: CArrInfo) -> CPtrInfo, + + -- realize + box: (self: CArrInfo, table: { T }) -> Box, + fromData: (self: CArrInfo, data: (Ref|Box), offset: number?) -> { T }, + intoData: (self: CArrInfo, data: (Ref|Box), value: { T }, offset: number?) -> (), + + offset: (self: CArrInfo, offset: number) -> number, +} + +export type CFuncInfo = { + callable: (self: CFuncInfo, functionRef: Ref) -> Callable, } -type NumCType = CType +export type CStructInfo = { + arrInfo: (self: CStructInfo, len: number) -> CArrInfo, + ptrInfo: (self: CStructInfo) -> CPtrInfo, +} + +type NumCType = CTypeInfo -- Fixed size Rust-style types -- export type u8 = NumCType<"u8"> @@ -64,10 +84,6 @@ export type ulong = NumCType<"ulong"> export type longlong = NumCType<"longlong"> export type ulonglong = NumCType<"ulonglong"> -export type CFn = { - caller: (self: CFn, fnPtr: Ref) -> Callable, -} - export type CTypes = | u8 | u16 @@ -96,12 +112,15 @@ export type CTypes = | ulong | longlong | ulonglong + | CArrInfo + | CPtrInfo + | CFuncInfo export type Ref = { deref: (self: Ref) -> Ref, offset: (self: Ref, offset: number) -> Ref, ref: (self: Ref) -> Ref, - isNullptr: (self: Ref) -> boolean, + isNull: (self: Ref) -> boolean, } export type Box = { @@ -112,12 +131,12 @@ export type Box = { ref: (self: Box, offset: number?) -> Ref, } -export type Library = { - find: (self: Library, sym: string) -> Ref, +export type Lib = { + find: (self: Lib, sym: string) -> Ref, } export type Callable = { - call: (self: Callable, retPtr: Ref, ...Box) -> (), + call: (self: Callable, result: Ref, ...(Ref | Box))->(); } local ffi = {} @@ -151,17 +170,19 @@ ffi.ulong = {} :: ulong ffi.longlong = {} :: longlong ffi.ulonglong = {} :: ulonglong -ffi.nullptr = {} :: Ref +function ffi.nullRef(): Ref + return nil :: any +end function ffi.box(size: number): Box return nil :: any end -function ffi.open(path: string): Library +function ffi.open(name: string): Lib return nil :: any end -function ffi.ref(): Ref +function ffi.uninitRef(): Ref return nil :: any end @@ -169,7 +190,7 @@ function ffi.isInteger(val: T): boolean return nil :: any end -function ffi.fn(args: { CTypes }, ret: CTypes): CFn +function ffi.funcInfo(args: { CTypes }, ret: CTypes): CFuncInfo return nil :: any end From e19d9748e56f80c443d546cc4405ceb8a2c22843 Mon Sep 17 00:00:00 2001 From: qwreey Date: Thu, 17 Oct 2024 16:24:13 +0000 Subject: [PATCH 30/79] Implement ClosureData (#243) --- crates/lune-std-ffi/README.md | 23 ++- crates/lune-std-ffi/src/c/arr_info.rs | 5 +- crates/lune-std-ffi/src/c/fn_info.rs | 146 ++++++++++++------ crates/lune-std-ffi/src/c/helper.rs | 5 +- crates/lune-std-ffi/src/c/mod.rs | 2 + crates/lune-std-ffi/src/c/ptr_info.rs | 8 +- crates/lune-std-ffi/src/c/struct_info.rs | 5 +- crates/lune-std-ffi/src/c/type_info.rs | 4 +- crates/lune-std-ffi/src/c/types/f32.rs | 2 +- crates/lune-std-ffi/src/c/types/f64.rs | 2 +- crates/lune-std-ffi/src/c/types/i128.rs | 2 +- crates/lune-std-ffi/src/c/types/i16.rs | 2 +- crates/lune-std-ffi/src/c/types/i32.rs | 2 +- crates/lune-std-ffi/src/c/types/i64.rs | 2 +- crates/lune-std-ffi/src/c/types/i8.rs | 2 +- crates/lune-std-ffi/src/c/types/isize.rs | 2 +- crates/lune-std-ffi/src/c/types/mod.rs | 2 +- crates/lune-std-ffi/src/c/types/u128.rs | 2 +- crates/lune-std-ffi/src/c/types/u16.rs | 2 +- crates/lune-std-ffi/src/c/types/u32.rs | 2 +- crates/lune-std-ffi/src/c/types/u64.rs | 2 +- crates/lune-std-ffi/src/c/types/u8.rs | 2 +- crates/lune-std-ffi/src/c/types/usize.rs | 2 +- crates/lune-std-ffi/src/data/box_data/flag.rs | 4 +- crates/lune-std-ffi/src/data/box_data/mod.rs | 12 +- crates/lune-std-ffi/src/data/callable_data.rs | 20 +-- crates/lune-std-ffi/src/data/closure_data.rs | 133 +++++++++------- crates/lune-std-ffi/src/data/lib_data.rs | 12 +- crates/lune-std-ffi/src/data/mod.rs | 19 +-- .../lune-std-ffi/src/data/ref_data/bounds.rs | 8 +- crates/lune-std-ffi/src/data/ref_data/flag.rs | 4 +- crates/lune-std-ffi/src/data/ref_data/mod.rs | 22 +-- crates/lune-std-ffi/src/ffi/arg.rs | 16 -- crates/lune-std-ffi/src/ffi/libffi_helper.rs | 2 +- crates/lune-std-ffi/src/ffi/mod.rs | 28 +++- crates/lune-std-ffi/src/ffi/result.rs | 12 -- crates/lune-std-ffi/src/lib.rs | 2 +- 37 files changed, 306 insertions(+), 216 deletions(-) delete mode 100644 crates/lune-std-ffi/src/ffi/arg.rs delete mode 100644 crates/lune-std-ffi/src/ffi/result.rs diff --git a/crates/lune-std-ffi/README.md b/crates/lune-std-ffi/README.md index 1b8c6ca3..05a98ee1 100644 --- a/crates/lune-std-ffi/README.md +++ b/crates/lune-std-ffi/README.md @@ -9,7 +9,7 @@ Define C-ABI type information and provide conversion and casting - [**Struct ` CArrInfo`:**](./src/c/struct_info.rs) Represents C Array type - [**Struct ` CPtrInfo`:**](./src/c/ptr_info.rs) Represents C Pointer type - [**Struct ` CFnInfo`:**](./src/c/fn_info.rs) Represents C Function signature - provide CallableData and ClosureData creation + > provide CallableData and ClosureData creation - [**Struct ` CStructInfo`:**](./src/c/struct_info.rs) Represents C Struct type - [**Struct ` CTypeInfo`:**](./src/c/type_info.rs) Represents C type, extended in `/c/types` @@ -55,6 +55,11 @@ Implememt type-casting for all CTypes - **Trait `FfiSignedness`** - **Trait `FfiConvert`:** Provide read LuaValue from FfiData or write LuaValue into FfiData +**Traits:** Provide call information trait + +- **Trait `FfiArg`:** Used for argument boundary checking and callback argument ref flag +- **Trait `FfiResult`:** Used for result boundary checking + **Trait `FfiData`:** Provide common data handle, including methods below - **Method `check_boundary`:** check boundary with offset and size @@ -66,14 +71,22 @@ Implememt type-casting for all CTypes **Mods:** Provide common helper functions -- **`association.rs`:** GC utility, used for inner, ret and arg type holding in subtype -- **`bit_mask.rs`:** u8 bitfield helper -- **`cast.rs`:** library +- [**Mod `association.rs`:**](./src/ffi/association.rs) GC utility, used for inner, ret and arg type holding in subtype +- [**Mod `bit_mask.rs`:**](./src/ffi/bit_mask.rs) u8 bitfield helper +- [**Mod `cast.rs`:**](./src/ffi/cast.rs) library - **Function `num_cast(from: FfiData, from: FfiData)`:** Cast number type value inno another number type -- **`libffi_helper.rs`:** +- [**Mod `libffi_helper.rs`:**](./src/ffi/libffi_helper.rs) - **Const `FFI_STATUS_NAMES`:** Used for ffi_status stringify - **Function `get_ensured_size`:** Returns ensured ffi_type size - **Const `SIEE_OF_POINTER`:** Platform specific pointer size (Compile time known) ## TODO + +Add `CTypeInfo:add(target, from1, from2, ...)` and `:sub` `:mul` `:div` `:mod` `:pow` for math operation. + +> Luau cannot handle i64 or i128 + +Add bor band and such bit-related operation + +> Luau only supports 32bit bit operations diff --git a/crates/lune-std-ffi/src/c/arr_info.rs b/crates/lune-std-ffi/src/c/arr_info.rs index 088fe340..16d3d0ce 100644 --- a/crates/lune-std-ffi/src/c/arr_info.rs +++ b/crates/lune-std-ffi/src/c/arr_info.rs @@ -4,10 +4,7 @@ use libffi::middle::Type; use mlua::prelude::*; use super::{association_names::CARR_INNER, helper, method_provider}; -use crate::{ - data::{FfiConvert, FfiData, FfiSize}, - ffi::{association, libffi_helper::get_ensured_size}, -}; +use crate::ffi::{association, libffi_helper::get_ensured_size, FfiConvert, FfiData, FfiSize}; // This is a series of some type. // It provides the final size and the offset of the index, diff --git a/crates/lune-std-ffi/src/c/fn_info.rs b/crates/lune-std-ffi/src/c/fn_info.rs index b2942a4f..146d6fa5 100644 --- a/crates/lune-std-ffi/src/c/fn_info.rs +++ b/crates/lune-std-ffi/src/c/fn_info.rs @@ -4,12 +4,15 @@ use libffi::middle::{Cif, Type}; use mlua::prelude::*; use super::{ - association_names::{CALLABLE_CFN, CALLABLE_REF, CFN_ARGS, CFN_RESULT}, - helper, method_provider, + association_names::{ + CALLABLE_CFN, CALLABLE_REF, CFN_ARGS, CFN_RESULT, CLOSURE_CFN, CLOSURE_FUNC, + }, + ctype_helper::is_ctype, + helper, method_provider, CArrInfo, CPtrInfo, CStructInfo, }; use crate::{ - data::{CallableData, RefData, RefDataFlag}, - ffi::{association, bit_mask::*, FfiArgInfo, FfiData, FfiResultInfo, FfiSignedness, FfiSize}, + data::{CallableData, ClosureData, RefData, RefFlag}, + ffi::{association, bit_mask::*, FfiArg, FfiData, FfiResult, FfiSignedness, FfiSize}, }; // cfn is a type declaration for a function. @@ -30,8 +33,8 @@ use crate::{ pub struct CFnInfo { cif: Cif, - arg_info_list: Vec, - result_info: FfiResultInfo, + arg_info_list: Vec, + result_info: FfiResult, } impl FfiSignedness for CFnInfo { @@ -45,15 +48,39 @@ impl FfiSize for CFnInfo { } } +const CALLBACK_ARG_REF_FLAG_TYPE: u8 = RefFlag::Readable.value(); +const CALLBACK_ARG_REF_FLAG_PTR: u8 = RefFlag::Dereferenceable.value() | RefFlag::Readable.value(); +const CALLBACK_ARG_REF_FLAG_ARR: u8 = RefFlag::Readable.value() | RefFlag::Offsetable.value(); +const CALLBACK_ARG_REF_FLAG_STRUCT: u8 = RefFlag::Readable.value() | RefFlag::Offsetable.value(); +const CALLBACK_ARG_REF_FLAG_CFN: u8 = RefFlag::Function.value(); + +fn create_arg_info(userdata: &LuaAnyUserData) -> LuaResult { + let callback_ref_flag = if is_ctype(userdata) { + CALLBACK_ARG_REF_FLAG_TYPE + } else if userdata.is::() { + CALLBACK_ARG_REF_FLAG_PTR + } else if userdata.is::() { + CALLBACK_ARG_REF_FLAG_ARR + } else if userdata.is::() { + CALLBACK_ARG_REF_FLAG_STRUCT + } else if userdata.is::() { + CALLBACK_ARG_REF_FLAG_CFN + } else { + return Err(LuaError::external("unexpected type userdata")); + }; + Ok(FfiArg { + size: helper::get_size(userdata)?, + callback_ref_flag, + }) +} + impl CFnInfo { pub fn new( args: Vec, ret: Type, - arg_info_list: Vec, - result_info: FfiResultInfo, + arg_info_list: Vec, + result_info: FfiResult, ) -> LuaResult { - // let cif = ; - Ok(Self { cif: Cif::new(args.clone(), ret.clone()), arg_info_list, @@ -61,7 +88,7 @@ impl CFnInfo { }) } - pub fn new_from_table<'lua>( + pub fn from_table<'lua>( lua: &'lua Lua, arg_table: LuaTable, ret: LuaAnyUserData, @@ -70,16 +97,12 @@ impl CFnInfo { let ret_type = helper::get_middle_type(&ret)?; let arg_len = arg_table.raw_len(); - let mut arg_info_list = Vec::::with_capacity(arg_len); + let mut arg_info_list = Vec::::with_capacity(arg_len); for index in 0..arg_len { let userdata = helper::get_userdata(arg_table.raw_get(index + 1)?)?; - arg_info_list.push(FfiArgInfo { - conv: unsafe { helper::get_conv(&userdata)? }, - size: helper::get_size(&userdata)?, - }); + arg_info_list.push(create_arg_info(&userdata)?); } - let result_info = FfiResultInfo { - conv: unsafe { helper::get_conv(&ret)? }, + let result_info = FfiResult { size: helper::get_size(&ret)?, }; @@ -122,6 +145,57 @@ impl CFnInfo { Err(LuaError::external("failed to get inner type userdata.")) } } + + pub fn create_closure<'lua>( + &self, + lua: &'lua Lua, + this: &LuaAnyUserData, + lua_function: LuaFunction<'lua>, + ) -> LuaResult> { + let closure = ClosureData::new( + ptr::from_ref(lua), + self.cif.as_raw_ptr(), + self.arg_info_list.clone(), + self.result_info.clone(), + lua.create_registry_value(&lua_function)?, + )?; + let closure_userdata = lua.create_userdata(closure)?; + + association::set(lua, CLOSURE_CFN, &closure_userdata, this)?; + association::set(lua, CLOSURE_FUNC, &closure_userdata, lua_function)?; + + Ok(closure_userdata) + } + + pub fn create_callable<'lua>( + &self, + lua: &'lua Lua, + this: &LuaAnyUserData, + target_ref: &LuaAnyUserData, + ) -> LuaResult> { + if !target_ref.is::() { + return Err(LuaError::external("argument 0 must be ffiref")); + } + + let ffi_ref = target_ref.borrow::()?; + if u8_test_not(ffi_ref.flags, RefFlag::Function.value()) { + return Err(LuaError::external("not a function ref")); + } + + let callable = lua.create_userdata(unsafe { + CallableData::new( + self.cif.as_raw_ptr(), + self.arg_info_list.clone(), + self.result_info.clone(), + ffi_ref.get_pointer(), + ) + })?; + + association::set(lua, CALLABLE_CFN, &callable, this)?; + association::set(lua, CALLABLE_REF, &callable, target_ref)?; + + Ok(callable) + } } impl LuaUserData for CFnInfo { @@ -134,36 +208,18 @@ impl LuaUserData for CFnInfo { 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( + "closure", + |lua, (cfn, func): (LuaAnyUserData, LuaFunction)| { + let this = cfn.borrow::()?; + this.create_closure(lua, cfn.as_ref(), func) + }, + ); methods.add_function( "callable", - |lua, (cfn, function_ref): (LuaAnyUserData, LuaAnyUserData)| { + |lua, (cfn, target): (LuaAnyUserData, LuaAnyUserData)| { let this = cfn.borrow::()?; - - if !function_ref.is::() { - return Err(LuaError::external("argument 0 must be ffiref")); - } - - let ffi_ref = function_ref.borrow::()?; - if u8_test_not(ffi_ref.flags, RefDataFlag::Function.value()) { - return Err(LuaError::external("not a function ref")); - } - - let callable = lua.create_userdata(unsafe { - CallableData::new( - this.cif.as_raw_ptr(), - ptr::from_ref(&this.arg_info_list), - ptr::from_ref(&this.result_info), - ffi_ref.get_pointer(), - ) - })?; - - association::set(lua, CALLABLE_CFN, &callable, cfn.clone())?; - association::set(lua, CALLABLE_REF, &callable, function_ref.clone())?; - - Ok(callable) + this.create_callable(lua, cfn.as_ref(), &target) }, ); } diff --git a/crates/lune-std-ffi/src/c/helper.rs b/crates/lune-std-ffi/src/c/helper.rs index 7f7b5ae1..04465ab8 100644 --- a/crates/lune-std-ffi/src/c/helper.rs +++ b/crates/lune-std-ffi/src/c/helper.rs @@ -3,7 +3,10 @@ use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; use mlua::prelude::*; use super::{ctype_helper, CArrInfo, CFnInfo, CPtrInfo, CStructInfo}; -use crate::data::{BoxData, FfiConvert, FfiSize, GetFfiData}; +use crate::{ + data::{BoxData, GetFfiData}, + ffi::{FfiConvert, FfiSize}, +}; pub mod method_provider { use super::*; diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index 075c8869..ad5b8f1c 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -25,4 +25,6 @@ mod association_names { pub const CFN_ARGS: &str = "__cfn_args"; pub const CALLABLE_REF: &str = "__callable_ref"; pub const CALLABLE_CFN: &str = "__callable_cfn"; + pub const CLOSURE_FUNC: &str = "__closure_func"; + pub const CLOSURE_CFN: &str = "__closure_cfn"; } diff --git a/crates/lune-std-ffi/src/c/ptr_info.rs b/crates/lune-std-ffi/src/c/ptr_info.rs index 4383da8c..d34d44e3 100644 --- a/crates/lune-std-ffi/src/c/ptr_info.rs +++ b/crates/lune-std-ffi/src/c/ptr_info.rs @@ -5,8 +5,10 @@ use mlua::prelude::*; use super::{association_names::CPTR_INNER, ctype_helper, helper, method_provider}; use crate::{ - data::{FfiConvert, FfiData, FfiSignedness, FfiSize, RefData}, - ffi::{association, libffi_helper::SIEE_OF_POINTER}, + data::RefData, + ffi::{ + association, libffi_helper::SIZE_OF_POINTER, FfiConvert, FfiData, FfiSignedness, FfiSize, + }, }; pub struct CPtrInfo { @@ -20,7 +22,7 @@ impl FfiSignedness for CPtrInfo { } impl FfiSize for CPtrInfo { fn get_size(&self) -> usize { - SIEE_OF_POINTER + SIZE_OF_POINTER } } impl FfiConvert for CPtrInfo { diff --git a/crates/lune-std-ffi/src/c/struct_info.rs b/crates/lune-std-ffi/src/c/struct_info.rs index dd3d55fe..4c67fcc9 100644 --- a/crates/lune-std-ffi/src/c/struct_info.rs +++ b/crates/lune-std-ffi/src/c/struct_info.rs @@ -4,9 +4,8 @@ use libffi::{low, middle::Type, raw}; use mlua::prelude::*; use super::{association_names::CSTRUCT_INNER, helper, method_provider}; -use crate::{ - data::{FfiConvert, FfiData, FfiSignedness, FfiSize}, - ffi::{association, libffi_helper::FFI_STATUS_NAMES}, +use crate::ffi::{ + association, libffi_helper::FFI_STATUS_NAMES, FfiConvert, FfiData, FfiSignedness, FfiSize, }; pub struct CStructInfo { diff --git a/crates/lune-std-ffi/src/c/type_info.rs b/crates/lune-std-ffi/src/c/type_info.rs index dd459e85..53cb879a 100644 --- a/crates/lune-std-ffi/src/c/type_info.rs +++ b/crates/lune-std-ffi/src/c/type_info.rs @@ -8,8 +8,8 @@ use mlua::prelude::*; use super::method_provider; use crate::{ - data::{FfiConvert, FfiData, FfiSignedness, FfiSize, GetFfiData}, - ffi::libffi_helper::get_ensured_size, + data::GetFfiData, + ffi::{libffi_helper::get_ensured_size, FfiConvert, FfiData, FfiSignedness, FfiSize}, }; // Cast native data diff --git a/crates/lune-std-ffi/src/c/types/f32.rs b/crates/lune-std-ffi/src/c/types/f32.rs index f397433a..434c9810 100644 --- a/crates/lune-std-ffi/src/c/types/f32.rs +++ b/crates/lune-std-ffi/src/c/types/f32.rs @@ -5,7 +5,7 @@ use num::cast::AsPrimitive; use crate::{ c::type_info::CTypeInfo, - data::{FfiConvert, FfiData, FfiSignedness}, + ffi::{FfiConvert, FfiData, FfiSignedness}, }; impl FfiSignedness for CTypeInfo { diff --git a/crates/lune-std-ffi/src/c/types/f64.rs b/crates/lune-std-ffi/src/c/types/f64.rs index 1055c5c9..dd59a89a 100644 --- a/crates/lune-std-ffi/src/c/types/f64.rs +++ b/crates/lune-std-ffi/src/c/types/f64.rs @@ -5,7 +5,7 @@ use num::cast::AsPrimitive; use crate::{ c::type_info::CTypeInfo, - data::{FfiConvert, FfiData, FfiSignedness}, + ffi::{FfiConvert, FfiData, FfiSignedness}, }; impl FfiSignedness for CTypeInfo { diff --git a/crates/lune-std-ffi/src/c/types/i128.rs b/crates/lune-std-ffi/src/c/types/i128.rs index 6a0b55c0..2c51f797 100644 --- a/crates/lune-std-ffi/src/c/types/i128.rs +++ b/crates/lune-std-ffi/src/c/types/i128.rs @@ -5,7 +5,7 @@ use num::cast::AsPrimitive; use crate::{ c::type_info::CTypeInfo, - data::{FfiConvert, FfiData, FfiSignedness}, + ffi::{FfiConvert, FfiData, FfiSignedness}, }; impl FfiSignedness for CTypeInfo { diff --git a/crates/lune-std-ffi/src/c/types/i16.rs b/crates/lune-std-ffi/src/c/types/i16.rs index a6c29486..077eb2ab 100644 --- a/crates/lune-std-ffi/src/c/types/i16.rs +++ b/crates/lune-std-ffi/src/c/types/i16.rs @@ -5,7 +5,7 @@ use num::cast::AsPrimitive; use crate::{ c::type_info::CTypeInfo, - data::{FfiConvert, FfiData, FfiSignedness}, + ffi::{FfiConvert, FfiData, FfiSignedness}, }; impl FfiSignedness for CTypeInfo { diff --git a/crates/lune-std-ffi/src/c/types/i32.rs b/crates/lune-std-ffi/src/c/types/i32.rs index 8afd129c..bfdf543c 100644 --- a/crates/lune-std-ffi/src/c/types/i32.rs +++ b/crates/lune-std-ffi/src/c/types/i32.rs @@ -5,7 +5,7 @@ use num::cast::AsPrimitive; use crate::{ c::type_info::CTypeInfo, - data::{FfiConvert, FfiData, FfiSignedness}, + ffi::{FfiConvert, FfiData, FfiSignedness}, }; impl FfiSignedness for CTypeInfo { diff --git a/crates/lune-std-ffi/src/c/types/i64.rs b/crates/lune-std-ffi/src/c/types/i64.rs index f4f914fd..1dea3471 100644 --- a/crates/lune-std-ffi/src/c/types/i64.rs +++ b/crates/lune-std-ffi/src/c/types/i64.rs @@ -5,7 +5,7 @@ use num::cast::AsPrimitive; use crate::{ c::type_info::CTypeInfo, - data::{FfiConvert, FfiData, FfiSignedness}, + ffi::{FfiConvert, FfiData, FfiSignedness}, }; impl FfiSignedness for CTypeInfo { diff --git a/crates/lune-std-ffi/src/c/types/i8.rs b/crates/lune-std-ffi/src/c/types/i8.rs index 53ec8533..6ac64ff5 100644 --- a/crates/lune-std-ffi/src/c/types/i8.rs +++ b/crates/lune-std-ffi/src/c/types/i8.rs @@ -5,7 +5,7 @@ use num::cast::AsPrimitive; use crate::{ c::type_info::CTypeInfo, - data::{FfiConvert, FfiData, FfiSignedness}, + ffi::{FfiConvert, FfiData, FfiSignedness}, }; impl FfiSignedness for CTypeInfo { diff --git a/crates/lune-std-ffi/src/c/types/isize.rs b/crates/lune-std-ffi/src/c/types/isize.rs index ccd54059..d1fda6c4 100644 --- a/crates/lune-std-ffi/src/c/types/isize.rs +++ b/crates/lune-std-ffi/src/c/types/isize.rs @@ -5,7 +5,7 @@ use num::cast::AsPrimitive; use crate::{ c::type_info::CTypeInfo, - data::{FfiConvert, FfiData, FfiSignedness}, + ffi::{FfiConvert, FfiData, FfiSignedness}, }; impl FfiSignedness for CTypeInfo { diff --git a/crates/lune-std-ffi/src/c/types/mod.rs b/crates/lune-std-ffi/src/c/types/mod.rs index 0e0387e6..6d4169f8 100644 --- a/crates/lune-std-ffi/src/c/types/mod.rs +++ b/crates/lune-std-ffi/src/c/types/mod.rs @@ -8,7 +8,7 @@ use mlua::prelude::*; use num::cast::AsPrimitive; use super::{CTypeCast, CTypeInfo}; -use crate::data::{num_cast, FfiConvert, FfiData, FfiSize}; +use crate::ffi::{num_cast, FfiConvert, FfiData, FfiSize}; pub mod f32; pub mod f64; diff --git a/crates/lune-std-ffi/src/c/types/u128.rs b/crates/lune-std-ffi/src/c/types/u128.rs index 34af1e59..a22ce8f9 100644 --- a/crates/lune-std-ffi/src/c/types/u128.rs +++ b/crates/lune-std-ffi/src/c/types/u128.rs @@ -5,7 +5,7 @@ use num::cast::AsPrimitive; use crate::{ c::type_info::CTypeInfo, - data::{FfiConvert, FfiData, FfiSignedness}, + ffi::{FfiConvert, FfiData, FfiSignedness}, }; impl FfiSignedness for CTypeInfo { diff --git a/crates/lune-std-ffi/src/c/types/u16.rs b/crates/lune-std-ffi/src/c/types/u16.rs index b3428347..c6946c61 100644 --- a/crates/lune-std-ffi/src/c/types/u16.rs +++ b/crates/lune-std-ffi/src/c/types/u16.rs @@ -5,7 +5,7 @@ use num::cast::AsPrimitive; use crate::{ c::type_info::CTypeInfo, - data::{FfiConvert, FfiData, FfiSignedness}, + ffi::{FfiConvert, FfiData, FfiSignedness}, }; impl FfiSignedness for CTypeInfo { diff --git a/crates/lune-std-ffi/src/c/types/u32.rs b/crates/lune-std-ffi/src/c/types/u32.rs index 09d9a07b..b63b67f1 100644 --- a/crates/lune-std-ffi/src/c/types/u32.rs +++ b/crates/lune-std-ffi/src/c/types/u32.rs @@ -5,7 +5,7 @@ use num::cast::AsPrimitive; use crate::{ c::type_info::CTypeInfo, - data::{FfiConvert, FfiData, FfiSignedness}, + ffi::{FfiConvert, FfiData, FfiSignedness}, }; impl FfiSignedness for CTypeInfo { diff --git a/crates/lune-std-ffi/src/c/types/u64.rs b/crates/lune-std-ffi/src/c/types/u64.rs index beb1ba4e..ff90b761 100644 --- a/crates/lune-std-ffi/src/c/types/u64.rs +++ b/crates/lune-std-ffi/src/c/types/u64.rs @@ -5,7 +5,7 @@ use num::cast::AsPrimitive; use crate::{ c::type_info::CTypeInfo, - data::{FfiConvert, FfiData, FfiSignedness}, + ffi::{FfiConvert, FfiData, FfiSignedness}, }; impl FfiSignedness for CTypeInfo { diff --git a/crates/lune-std-ffi/src/c/types/u8.rs b/crates/lune-std-ffi/src/c/types/u8.rs index a7d9ad31..3278579b 100644 --- a/crates/lune-std-ffi/src/c/types/u8.rs +++ b/crates/lune-std-ffi/src/c/types/u8.rs @@ -5,7 +5,7 @@ use num::cast::AsPrimitive; use crate::{ c::type_info::CTypeInfo, - data::{FfiConvert, FfiData, FfiSignedness}, + ffi::{FfiConvert, FfiData, FfiSignedness}, }; impl FfiSignedness for CTypeInfo { diff --git a/crates/lune-std-ffi/src/c/types/usize.rs b/crates/lune-std-ffi/src/c/types/usize.rs index 0fa44424..1d7d0f44 100644 --- a/crates/lune-std-ffi/src/c/types/usize.rs +++ b/crates/lune-std-ffi/src/c/types/usize.rs @@ -5,7 +5,7 @@ use num::cast::AsPrimitive; use crate::{ c::type_info::CTypeInfo, - data::{FfiConvert, FfiData, FfiSignedness}, + ffi::{FfiConvert, FfiData, FfiSignedness}, }; impl FfiSignedness for CTypeInfo { diff --git a/crates/lune-std-ffi/src/data/box_data/flag.rs b/crates/lune-std-ffi/src/data/box_data/flag.rs index f54a1b5f..181326cf 100644 --- a/crates/lune-std-ffi/src/data/box_data/flag.rs +++ b/crates/lune-std-ffi/src/data/box_data/flag.rs @@ -1,10 +1,10 @@ use crate::ffi::bit_mask::*; -pub enum BoxDataFlag { +pub enum BoxFlag { Leaked, } -impl BoxDataFlag { +impl BoxFlag { pub const fn value(&self) -> u8 { match self { Self::Leaked => U8_MASK2, diff --git a/crates/lune-std-ffi/src/data/box_data/mod.rs b/crates/lune-std-ffi/src/data/box_data/mod.rs index ea5b1f43..97ee9e14 100644 --- a/crates/lune-std-ffi/src/data/box_data/mod.rs +++ b/crates/lune-std-ffi/src/data/box_data/mod.rs @@ -3,17 +3,17 @@ use std::{alloc, alloc::Layout, boxed::Box, mem::ManuallyDrop, ptr}; use mlua::prelude::*; use crate::{ - data::{association_names::REF_INNER, RefData, RefDataBounds, RefDataFlag}, + data::{association_names::REF_INNER, RefBounds, RefData, RefFlag}, ffi::{association, bit_mask::*, FfiData}, }; mod flag; -pub use self::flag::BoxDataFlag; +pub use self::flag::BoxFlag; // Ref which created by lua should not be dereferenceable, const BOX_REF_FLAGS: u8 = - RefDataFlag::Readable.value() | RefDataFlag::Writable.value() | RefDataFlag::Offsetable.value(); + RefFlag::Readable.value() | RefFlag::Writable.value() | RefFlag::Offsetable.value(); // It is an untyped, sized memory area that Lua can manage. // This area is safe within Lua. Operations have their boundaries checked. @@ -63,7 +63,7 @@ impl BoxData { } pub fn leak(&mut self) { - self.flags = u8_set(self.flags, BoxDataFlag::Leaked.value(), true); + self.flags = u8_set(self.flags, BoxFlag::Leaked.value(), true); } // Make FfiRef from box, with boundary checking @@ -73,7 +73,7 @@ impl BoxData { offset: Option, ) -> LuaResult> { let target = this.borrow::()?; - let mut bounds = RefDataBounds::new(0, target.size()); + let mut bounds = RefBounds::new(0, target.size()); let mut ptr = unsafe { target.get_pointer() }; // Calculate offset @@ -114,7 +114,7 @@ impl BoxData { impl Drop for BoxData { fn drop(&mut self) { - if u8_test_not(self.flags, BoxDataFlag::Leaked.value()) { + if u8_test_not(self.flags, BoxFlag::Leaked.value()) { unsafe { self.drop() }; } } diff --git a/crates/lune-std-ffi/src/data/callable_data.rs b/crates/lune-std-ffi/src/data/callable_data.rs index ca8f65c5..001ef7aa 100644 --- a/crates/lune-std-ffi/src/data/callable_data.rs +++ b/crates/lune-std-ffi/src/data/callable_data.rs @@ -7,20 +7,21 @@ use libffi::{ }; use mlua::prelude::*; -use super::{FfiArgInfo, FfiData, FfiResultInfo, GetFfiData}; +use super::{FfiData, GetFfiData}; +use crate::ffi::{FfiArg, FfiResult}; pub struct CallableData { cif: *mut ffi_cif, - arg_info_list: *const Vec, - result_info: *const FfiResultInfo, + arg_info_list: Vec, + result_info: FfiResult, code: CodePtr, } impl CallableData { pub unsafe fn new( cif: *mut ffi_cif, - arg_info_list: *const Vec, - result_info: *const FfiResultInfo, + arg_info_list: Vec, + result_info: FfiResult, function_pointer: *const (), ) -> Self { Self { @@ -35,16 +36,15 @@ impl CallableData { pub unsafe fn call(&self, result: &Ref, args: LuaMultiValue) -> LuaResult<()> { result - .check_boundary(0, self.result_info.as_ref().unwrap().size) + .check_boundary(0, self.result_info.size) .then_some(()) .ok_or_else(|| LuaError::external("result boundary check failed"))?; // cache Vec => unable to create async call but no allocation - let arg_info_list = self.arg_info_list.as_ref().unwrap(); - let mut arg_list = Vec::<*mut c_void>::with_capacity(arg_info_list.len()); + let mut arg_list = Vec::<*mut c_void>::with_capacity(self.arg_info_list.len()); - for index in 0..arg_info_list.len() { - let arg_info = arg_info_list.get(index).unwrap(); + for index in 0..self.arg_info_list.len() { + let arg_info = self.arg_info_list.get(index).unwrap(); let arg = args .get(index) .ok_or_else(|| LuaError::external(format!("argument {index} required")))?; diff --git a/crates/lune-std-ffi/src/data/closure_data.rs b/crates/lune-std-ffi/src/data/closure_data.rs index 8175be33..93eece37 100644 --- a/crates/lune-std-ffi/src/data/closure_data.rs +++ b/crates/lune-std-ffi/src/data/closure_data.rs @@ -1,5 +1,5 @@ use core::ffi::c_void; -use std::ptr; +use std::{borrow::Borrow, ptr}; use libffi::{ low::{closure_alloc, closure_free, ffi_cif, CodePtr}, @@ -7,19 +7,22 @@ use libffi::{ }; use mlua::prelude::*; -use super::{ - ref_data::{RefDataBounds, RefDataFlag}, - RefData, +use super::ref_data::{RefBounds, RefData, RefFlag}; +use crate::ffi::{ + libffi_helper::{FFI_STATUS_NAMES, SIZE_OF_POINTER}, + FfiArg, FfiData, FfiResult, }; -use crate::ffi::libffi_helper::FFI_STATUS_NAMES; -pub struct ClosureData<'a> { +pub struct ClosureData { + lua: *const Lua, closure: *mut ffi_closure, code: CodePtr, - userdata: CallbackUserdata<'a>, + arg_info_list: Vec, + result_info: FfiResult, + func: LuaRegistryKey, } -impl<'a> Drop for ClosureData<'a> { +impl Drop for ClosureData { fn drop(&mut self) { unsafe { closure_free(self.closure); @@ -27,69 +30,82 @@ impl<'a> Drop for ClosureData<'a> { } } -#[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 = RefDataFlag::Leaked.value() | RefDataFlag::Writable.value(); +const RESULT_REF_FLAGS: u8 = + RefFlag::Leaked.value() | RefFlag::Writable.value() | RefFlag::Offsetable.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, + closure_data: *mut c_void, ) { - let userdata = userdata.cast::(); + let closure_data = closure_data.cast::().as_ref().unwrap(); + let lua = closure_data.lua.as_ref().unwrap(); 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(RefData::new( - result_pointer.cast::<()>(), - RESULT_REF_FLAGS, - RefDataBounds::new(0, (*userdata).result_size), - )) - .unwrap(), + lua.create_userdata(RefData::new( + result_pointer.cast::<()>(), + RESULT_REF_FLAGS, + RefBounds::new(0, closure_data.result_info.size), + )) + .unwrap(), )); // Push arg pointer (ref) for i in 0..len { + let arg_info = closure_data.arg_info_list.get(i).unwrap(); args.push(LuaValue::UserData( - (*userdata) - .lua - .create_userdata(RefData::new( - (*arg_pointers.add(i)).cast::<()>(), - (*userdata).arg_ref_flags.get(i).unwrap().to_owned(), - RefDataBounds::new(0, (*userdata).arg_ref_size.get(i).unwrap().to_owned()), - )) - .unwrap(), + lua.create_userdata(RefData::new( + (*arg_pointers.add(i)).cast::<()>(), + arg_info.callback_ref_flag, + RefBounds::new(0, arg_info.size), + )) + .unwrap(), )); } - (*userdata).func.call::<_, ()>(args).unwrap(); + closure_data + .func + .borrow() + .into_lua(lua) + .unwrap() + .as_function() + .unwrap() + .call::<_, ()>(args) + .unwrap(); } -impl<'a> ClosureData<'a> { - pub unsafe fn new( +impl ClosureData { + pub fn new( + lua: *const Lua, cif: *mut ffi_cif, - userdata: CallbackUserdata<'a>, - ) -> LuaResult> { + arg_info_list: Vec, + result_info: FfiResult, + func: LuaRegistryKey, + ) -> LuaResult { let (closure, code) = closure_alloc(); - let prep_result = ffi_prep_closure_loc( + + let closure_data = ClosureData { + lua, closure, - cif, - Some(callback), - ptr::from_ref(&userdata).cast::().cast_mut(), - code.as_mut_ptr(), - ); + code, + arg_info_list, + result_info, + func, + }; + + let prep_result = unsafe { + ffi_prep_closure_loc( + closure, + cif, + Some(callback), + ptr::from_ref(&closure_data).cast::().cast_mut(), + code.as_mut_ptr(), + ) + }; if prep_result != 0 { Err(LuaError::external(format!( @@ -97,11 +113,24 @@ impl<'a> ClosureData<'a> { FFI_STATUS_NAMES[0], FFI_STATUS_NAMES[prep_result as usize] ))) } else { - Ok(ClosureData { - closure, - code, - userdata, - }) + Ok(closure_data) } } } + +impl FfiData for ClosureData { + unsafe fn get_pointer(&self) -> *mut () { + self.code.as_mut_ptr().cast::<()>() + } + fn check_boundary(&self, offset: isize, size: usize) -> bool { + (offset as usize) + size <= SIZE_OF_POINTER + } + fn is_readable(&self) -> bool { + false + } + fn is_writable(&self) -> bool { + false + } +} + +impl LuaUserData for ClosureData {} diff --git a/crates/lune-std-ffi/src/data/lib_data.rs b/crates/lune-std-ffi/src/data/lib_data.rs index 211dbda6..a7d38a45 100644 --- a/crates/lune-std-ffi/src/data/lib_data.rs +++ b/crates/lune-std-ffi/src/data/lib_data.rs @@ -2,15 +2,15 @@ use dlopen2::raw::Library; use mlua::prelude::*; use super::{ - association, association_names::SYM_INNER, - ref_data::{RefData, RefDataFlag, UNSIZED_BOUNDS}, + ref_data::{RefData, RefFlag, UNSIZED_BOUNDS}, }; +use crate::ffi::association; -const LIB_REF_FLAGS: u8 = RefDataFlag::Offsetable.value() - | RefDataFlag::Readable.value() - | RefDataFlag::Dereferenceable.value() - | RefDataFlag::Function.value(); +const LIB_REF_FLAGS: u8 = RefFlag::Offsetable.value() + | RefFlag::Readable.value() + | RefFlag::Dereferenceable.value() + | RefFlag::Function.value(); pub struct LibData(Library); diff --git a/crates/lune-std-ffi/src/data/mod.rs b/crates/lune-std-ffi/src/data/mod.rs index 6b5de23e..c2ddf5b3 100644 --- a/crates/lune-std-ffi/src/data/mod.rs +++ b/crates/lune-std-ffi/src/data/mod.rs @@ -9,19 +9,14 @@ mod closure_data; mod lib_data; mod ref_data; -pub use crate::{ - data::{ - box_data::BoxData, - callable_data::CallableData, - closure_data::ClosureData, - lib_data::LibData, - ref_data::{create_nullptr, RefData, RefDataBounds, RefDataFlag}, - }, - ffi::{ - association, num_cast, FfiArgInfo, FfiConvert, FfiData, FfiResultInfo, FfiSignedness, - FfiSize, - }, +pub use self::{ + box_data::BoxData, + callable_data::CallableData, + closure_data::ClosureData, + lib_data::LibData, + ref_data::{create_nullptr, RefBounds, RefData, RefFlag}, }; +use crate::ffi::FfiData; // Named registry table names mod association_names { diff --git a/crates/lune-std-ffi/src/data/ref_data/bounds.rs b/crates/lune-std-ffi/src/data/ref_data/bounds.rs index cfa16998..6d43491d 100644 --- a/crates/lune-std-ffi/src/data/ref_data/bounds.rs +++ b/crates/lune-std-ffi/src/data/ref_data/bounds.rs @@ -1,17 +1,17 @@ // Memory range for ref or box data. For boundary checking -pub struct RefDataBounds { +pub struct RefBounds { // Indicates how much data is above the pointer pub(crate) above: usize, // Indicates how much data is below the pointer pub(crate) below: usize, } -pub const UNSIZED_BOUNDS: RefDataBounds = RefDataBounds { +pub const UNSIZED_BOUNDS: RefBounds = RefBounds { above: usize::MAX, below: usize::MAX, }; -impl RefDataBounds { +impl RefBounds { pub fn new(above: usize, below: usize) -> Self { Self { above, below } } @@ -88,7 +88,7 @@ impl RefDataBounds { } } -impl Clone for RefDataBounds { +impl Clone for RefBounds { fn clone(&self) -> Self { Self { above: self.above, diff --git a/crates/lune-std-ffi/src/data/ref_data/flag.rs b/crates/lune-std-ffi/src/data/ref_data/flag.rs index 3cf3b11d..972431db 100644 --- a/crates/lune-std-ffi/src/data/ref_data/flag.rs +++ b/crates/lune-std-ffi/src/data/ref_data/flag.rs @@ -1,6 +1,6 @@ use crate::ffi::bit_mask::*; -pub enum RefDataFlag { +pub enum RefFlag { Leaked, Dereferenceable, Readable, @@ -9,7 +9,7 @@ pub enum RefDataFlag { Function, Uninit, } -impl RefDataFlag { +impl RefFlag { pub const fn value(&self) -> u8 { match self { Self::Leaked => U8_MASK1, diff --git a/crates/lune-std-ffi/src/data/ref_data/mod.rs b/crates/lune-std-ffi/src/data/ref_data/mod.rs index 4659cef2..b9a4cb68 100644 --- a/crates/lune-std-ffi/src/data/ref_data/mod.rs +++ b/crates/lune-std-ffi/src/data/ref_data/mod.rs @@ -11,13 +11,13 @@ mod bounds; mod flag; pub use self::{ - bounds::{RefDataBounds, UNSIZED_BOUNDS}, - flag::RefDataFlag, + bounds::{RefBounds, UNSIZED_BOUNDS}, + flag::RefFlag, }; // Box:ref():ref() should not be able to modify, Only for external const BOX_REF_REF_FLAGS: u8 = 0; -const UNINIT_REF_FLAGS: u8 = RefDataFlag::Uninit.value(); +const UNINIT_REF_FLAGS: u8 = RefFlag::Uninit.value(); // | FfiRefFlag::Writable.value() // | FfiRefFlag::Readable.value() // | FfiRefFlag::Dereferenceable.value() @@ -33,11 +33,11 @@ const UNINIT_REF_FLAGS: u8 = RefDataFlag::Uninit.value(); pub struct RefData { ptr: ManuallyDrop>, pub flags: u8, - pub boundary: RefDataBounds, + pub boundary: RefBounds, } impl RefData { - pub fn new(ptr: *mut (), flags: u8, boundary: RefDataBounds) -> Self { + pub fn new(ptr: *mut (), flags: u8, boundary: RefBounds) -> Self { Self { ptr: ManuallyDrop::new(Box::new(ptr)), flags, @@ -63,7 +63,7 @@ impl RefData { let luaref = lua.create_userdata(RefData::new( ptr::from_ref(&target.ptr) as *mut (), BOX_REF_REF_FLAGS, - RefDataBounds { + RefBounds { below: 0, above: size_of::(), }, @@ -76,7 +76,7 @@ impl RefData { } pub unsafe fn deref(&self) -> LuaResult { - u8_test(self.flags, RefDataFlag::Dereferenceable.value()) + u8_test(self.flags, RefFlag::Dereferenceable.value()) .then_some(()) .ok_or_else(|| LuaError::external("This pointer is not dereferenceable."))?; @@ -104,7 +104,7 @@ impl RefData { } pub unsafe fn offset(&self, offset: isize) -> LuaResult { - u8_test(self.flags, RefDataFlag::Offsetable.value()) + u8_test(self.flags, RefFlag::Offsetable.value()) .then_some(()) .ok_or_else(|| LuaError::external("This pointer is not offsetable."))?; @@ -132,7 +132,7 @@ impl RefData { impl Drop for RefData { fn drop(&mut self) { - if u8_test_not(self.flags, RefDataFlag::Leaked.value()) { + if u8_test_not(self.flags, RefFlag::Leaked.value()) { unsafe { ManuallyDrop::drop(&mut self.ptr) }; } } @@ -146,10 +146,10 @@ impl FfiData for RefData { **self.ptr } fn is_readable(&self) -> bool { - u8_test(self.flags, RefDataFlag::Readable.value()) + u8_test(self.flags, RefFlag::Readable.value()) } fn is_writable(&self) -> bool { - u8_test(self.flags, RefDataFlag::Writable.value()) + u8_test(self.flags, RefFlag::Writable.value()) } } diff --git a/crates/lune-std-ffi/src/ffi/arg.rs b/crates/lune-std-ffi/src/ffi/arg.rs deleted file mode 100644 index 9d895fe5..00000000 --- a/crates/lune-std-ffi/src/ffi/arg.rs +++ /dev/null @@ -1,16 +0,0 @@ -use super::FfiConvert; - -pub struct FfiArgRefOption { - pub flag: u8, -} - -pub enum FfiArgType { - FfiBox, - FfiRef(FfiArgRefOption), -} - -pub struct FfiArgInfo { - pub conv: *const dyn FfiConvert, - pub size: usize, - // pub kind: NativeArgType, -} diff --git a/crates/lune-std-ffi/src/ffi/libffi_helper.rs b/crates/lune-std-ffi/src/ffi/libffi_helper.rs index 2c0d1e06..fc93d04e 100644 --- a/crates/lune-std-ffi/src/ffi/libffi_helper.rs +++ b/crates/lune-std-ffi/src/ffi/libffi_helper.rs @@ -26,7 +26,7 @@ pub fn get_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult { unsafe { Ok((*ffi_type).size) } } -pub const SIEE_OF_POINTER: usize = size_of::<*mut ()>(); +pub const SIZE_OF_POINTER: usize = size_of::<*mut ()>(); // Converts ffi status into &str pub const FFI_STATUS_NAMES: [&str; 4] = [ diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index c1a68223..bebe31f9 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -2,12 +2,12 @@ use std::cell::Ref; use mlua::prelude::*; -mod arg; pub mod association; pub mod bit_mask; mod cast; pub mod libffi_helper; -mod result; + +pub use self::cast::num_cast; pub trait FfiSize { fn get_size(&self) -> usize; @@ -46,4 +46,26 @@ pub trait FfiData { fn is_readable(&self) -> bool; } -pub use self::{arg::FfiArgInfo, cast::num_cast, result::FfiResultInfo}; +pub struct FfiArg { + pub size: usize, + pub callback_ref_flag: u8, +} + +impl Clone for FfiArg { + fn clone(&self) -> Self { + Self { + size: self.size, + callback_ref_flag: self.callback_ref_flag, + } + } +} + +pub struct FfiResult { + pub size: usize, +} + +impl Clone for FfiResult { + fn clone(&self) -> Self { + Self { size: self.size } + } +} diff --git a/crates/lune-std-ffi/src/ffi/result.rs b/crates/lune-std-ffi/src/ffi/result.rs deleted file mode 100644 index 06bd8088..00000000 --- a/crates/lune-std-ffi/src/ffi/result.rs +++ /dev/null @@ -1,12 +0,0 @@ -use super::FfiConvert; - -// pub enum NativeResultType { -// FfiBox, -// FfiRef, -// } - -pub struct FfiResultInfo { - pub conv: *const dyn FfiConvert, - pub size: usize, - // kind: NativeResultType, -} diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs index 18b96481..b0085227 100644 --- a/crates/lune-std-ffi/src/lib.rs +++ b/crates/lune-std-ffi/src/lib.rs @@ -32,7 +32,7 @@ pub fn module(lua: &Lua) -> LuaResult { .with_function("uninitRef", |_lua, ()| Ok(RefData::new_uninit()))? .with_function("isInteger", |_lua, num: LuaValue| Ok(num.is_integer()))? .with_function("fnInfo", |lua, (args, ret): (LuaTable, LuaAnyUserData)| { - CFnInfo::new_from_table(lua, args, ret) + CFnInfo::from_table(lua, args, ret) })?; #[cfg(debug_assertions)] From 7ee757ac9c0350e0f02cc7dceed07f2e5e2a2763 Mon Sep 17 00:00:00 2001 From: qwreey Date: Thu, 17 Oct 2024 18:18:44 +0000 Subject: [PATCH 31/79] Provide ptr conversion and test case (#243) --- crates/lune-std-ffi/src/c/arr_info.rs | 4 +- crates/lune-std-ffi/src/c/fn_info.rs | 9 +-- crates/lune-std-ffi/src/c/helper.rs | 56 ++++++------- crates/lune-std-ffi/src/c/ptr_info.rs | 81 +++++++++++++------ crates/lune-std-ffi/src/c/struct_info.rs | 11 ++- crates/lune-std-ffi/src/c/type_info.rs | 10 +-- crates/lune-std-ffi/src/c/types/mod.rs | 2 +- crates/lune-std-ffi/src/data/callable_data.rs | 4 +- crates/lune-std-ffi/src/data/mod.rs | 32 ++++++-- tests/ffi/external_math/init.luau | 12 +-- tests/ffi/external_struct/init.luau | 10 +-- tests/ffi/utility/compile.luau | 2 +- types/ffi.luau | 34 +++++--- 13 files changed, 160 insertions(+), 107 deletions(-) diff --git a/crates/lune-std-ffi/src/c/arr_info.rs b/crates/lune-std-ffi/src/c/arr_info.rs index 16d3d0ce..759661b3 100644 --- a/crates/lune-std-ffi/src/c/arr_info.rs +++ b/crates/lune-std-ffi/src/c/arr_info.rs @@ -155,8 +155,8 @@ impl LuaUserData for CArrInfo { // Realize method_provider::provide_box(methods); - method_provider::provide_from_data(methods); - method_provider::provide_into_data(methods); + method_provider::provide_read_data(methods); + method_provider::provide_write_data(methods); methods.add_method("offset", |_, this, offset: isize| { if this.length > (offset as usize) && offset >= 0 { diff --git a/crates/lune-std-ffi/src/c/fn_info.rs b/crates/lune-std-ffi/src/c/fn_info.rs index 146d6fa5..3c701a5b 100644 --- a/crates/lune-std-ffi/src/c/fn_info.rs +++ b/crates/lune-std-ffi/src/c/fn_info.rs @@ -96,12 +96,7 @@ impl CFnInfo { let args_types = helper::get_middle_type_list(&arg_table)?; let ret_type = 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 = helper::get_userdata(arg_table.raw_get(index + 1)?)?; - arg_info_list.push(create_arg_info(&userdata)?); - } + let arg_info_list = helper::create_list(&arg_table, create_arg_info)?; let result_info = FfiResult { size: helper::get_size(&ret)?, }; @@ -117,7 +112,7 @@ impl CFnInfo { } // Stringify for pretty printing like: - // u8 )> + // 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))) = ( diff --git a/crates/lune-std-ffi/src/c/helper.rs b/crates/lune-std-ffi/src/c/helper.rs index 04465ab8..e00fd05c 100644 --- a/crates/lune-std-ffi/src/c/helper.rs +++ b/crates/lune-std-ffi/src/c/helper.rs @@ -23,7 +23,7 @@ pub mod method_provider { where M: LuaUserDataMethods<'lua, Target>, { - methods.add_function("pointerInfo", |lua, this: LuaAnyUserData| { + methods.add_function("ptrInfo", |lua, this: LuaAnyUserData| { CPtrInfo::from_userdata(lua, &this) }); } @@ -37,17 +37,17 @@ pub mod method_provider { }); } - pub fn provide_from_data<'lua, Target, M>(methods: &mut M) + pub fn provide_read_data<'lua, Target, M>(methods: &mut M) where Target: FfiSize + FfiConvert, M: LuaUserDataMethods<'lua, Target>, { methods.add_method( - "fromData", - |lua, this, (userdata, offset): (LuaAnyUserData, Option)| { + "readData", + |lua, this, (target, offset): (LuaAnyUserData, Option)| { let offset = offset.unwrap_or(0); - let data_handle = &userdata.get_data_handle()?; + let data_handle = &target.get_ffi_data()?; if !data_handle.check_boundary(offset, this.get_size()) { return Err(LuaError::external("Out of bounds")); } @@ -60,17 +60,17 @@ pub mod method_provider { ); } - pub fn provide_into_data<'lua, Target, M>(methods: &mut M) + pub fn provide_write_data<'lua, Target, M>(methods: &mut M) where Target: FfiSize + FfiConvert, M: LuaUserDataMethods<'lua, Target>, { methods.add_method( - "intoData", - |lua, this, (userdata, value, offset): (LuaAnyUserData, LuaValue, Option)| { + "writeData", + |lua, this, (target, value, offset): (LuaAnyUserData, LuaValue, Option)| { let offset = offset.unwrap_or(0); - let data_handle = &userdata.get_data_handle()?; + let data_handle = &target.get_ffi_data()?; // use or functions if !data_handle.check_boundary(offset, this.get_size()) { return Err(LuaError::external("Out of bounds")); @@ -91,7 +91,7 @@ pub mod method_provider { { methods.add_method("box", |lua, this, table: LuaValue| { let result = lua.create_userdata(BoxData::new(this.get_size()))?; - unsafe { this.value_into_data(lua, 0, &result.get_data_handle()?, table)? }; + unsafe { this.value_into_data(lua, 0, &result.get_ffi_data()?, table)? }; Ok(result) }); } @@ -121,20 +121,26 @@ pub unsafe fn get_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn FfiCon Ok(userdata.to_pointer().cast::() as *const dyn FfiConvert) } else { ctype_helper::get_conv(userdata) - // TODO: struct and more } } -pub unsafe fn get_conv_list(table: &LuaTable) -> LuaResult> { +pub fn create_list( + table: &LuaTable, + callback: fn(&LuaAnyUserData) -> LuaResult, +) -> LuaResult> { let len: usize = table.raw_len(); - let mut conv_list = Vec::<*const dyn FfiConvert>::with_capacity(len); + let mut list = Vec::::with_capacity(len); for i in 0..len { let value: LuaValue = table.raw_get(i + 1)?; - conv_list.push(get_conv(&get_userdata(value)?)?); + list.push(callback(&get_userdata(value)?)?); } - Ok(conv_list) + Ok(list) +} + +pub unsafe fn get_conv_list(table: &LuaTable) -> LuaResult> { + create_list(table, |userdata| get_conv(userdata)) } pub fn get_size(this: &LuaAnyUserData) -> LuaResult { @@ -174,23 +180,7 @@ pub fn get_middle_type(userdata: &LuaAnyUserData) -> LuaResult { // 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) + create_list(table, get_middle_type) } // stringify any c-type userdata (for recursive) @@ -219,7 +209,7 @@ pub fn get_tag_name(userdata: &LuaAnyUserData) -> LuaResult { } else if userdata.is::() { String::from("CPtr") } else if userdata.is::() { - String::from("CFunc") + String::from("CFn") } else if ctype_helper::is_ctype(userdata) { String::from("CType") } else { diff --git a/crates/lune-std-ffi/src/c/ptr_info.rs b/crates/lune-std-ffi/src/c/ptr_info.rs index d34d44e3..519b9220 100644 --- a/crates/lune-std-ffi/src/c/ptr_info.rs +++ b/crates/lune-std-ffi/src/c/ptr_info.rs @@ -5,14 +5,22 @@ use mlua::prelude::*; use super::{association_names::CPTR_INNER, ctype_helper, helper, method_provider}; use crate::{ - data::RefData, + data::{GetFfiData, RefBounds, RefData, RefFlag}, ffi::{ association, libffi_helper::SIZE_OF_POINTER, FfiConvert, FfiData, FfiSignedness, FfiSize, }, }; +const READ_CPTR_REF_FLAGS: u8 = + RefFlag::Dereferenceable.value() | RefFlag::Offsetable.value() | RefFlag::Leaked.value(); +const READ_REF_FLAGS: u8 = RefFlag::Offsetable.value() + | RefFlag::Leaked.value() + | RefFlag::Readable.value() + | RefFlag::Writable.value(); + pub struct CPtrInfo { inner_size: usize, + inner_is_cptr: bool, } impl FfiSignedness for CPtrInfo { @@ -34,34 +42,47 @@ impl FfiConvert for CPtrInfo { data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { - if let LuaValue::UserData(value_userdata) = value { - if value_userdata.is::() { - let value_ref = value_userdata.borrow::()?; - value_ref - .check_boundary(0, self.inner_size) - .then_some(()) - .ok_or_else(|| LuaError::external("boundary check failed"))?; - *data_handle - .get_pointer() - .byte_offset(offset) - .cast::<*mut ()>() = value_ref.get_pointer(); - Ok(()) - } else { - Err(LuaError::external("Ptr:into only allows FfiRef")) - } - } else { - Err(LuaError::external("Conversion of pointer is not allowed")) - } + let value_userdata = value + .as_userdata() + .ok_or_else(|| LuaError::external("CPtrInfo:writeRef only allows data"))?; + + data_handle + .check_boundary(offset, self.get_size()) + .then_some(()) + .ok_or_else(|| LuaError::external("Out of bounds"))?; + data_handle + .is_writable() + .then_some(()) + .ok_or_else(|| LuaError::external("Unwritable data handle"))?; + + *data_handle + .get_pointer() + .byte_offset(offset) + .cast::<*mut ()>() = value_userdata.get_ffi_data()?.get_pointer(); + + Ok(()) } // Read data from ptr, then convert into luavalue unsafe fn value_from_data<'lua>( &self, - _lua: &'lua Lua, - _offset: isize, - _data_handle: &Ref, + lua: &'lua Lua, + offset: isize, + data_handle: &Ref, ) -> LuaResult> { - Err(LuaError::external("Conversion of pointer is not allowed")) + if !data_handle.check_boundary(offset, SIZE_OF_POINTER) { + return Err(LuaError::external("Out of bounds")); + } + + Ok(LuaValue::UserData(lua.create_userdata(RefData::new( + unsafe { data_handle.get_pointer().byte_offset(offset) }, + if self.inner_is_cptr { + READ_CPTR_REF_FLAGS + } else { + READ_REF_FLAGS + }, + RefBounds::new(0, self.inner_size), + ))?)) } } @@ -74,6 +95,7 @@ impl CPtrInfo { ) -> LuaResult> { let value = lua.create_userdata(Self { inner_size: helper::get_size(inner)?, + inner_is_cptr: inner.is::(), })?; association::set(lua, CPTR_INNER, &value, inner)?; @@ -118,5 +140,18 @@ impl LuaUserData for CPtrInfo { // ToString method_provider::provide_to_string(methods); + + methods.add_method( + "readRef", + |lua, this, (target, offset): (LuaAnyUserData, Option)| unsafe { + this.value_from_data(lua, offset.unwrap_or(0), &target.get_ffi_data()?) + }, + ); + methods.add_method( + "writeRef", + |lua, this, (target, value, offset): (LuaAnyUserData, LuaValue, Option)| unsafe { + this.value_into_data(lua, offset.unwrap_or(0), &target.get_ffi_data()?, value) + }, + ); } } diff --git a/crates/lune-std-ffi/src/c/struct_info.rs b/crates/lune-std-ffi/src/c/struct_info.rs index 4c67fcc9..836dbe38 100644 --- a/crates/lune-std-ffi/src/c/struct_info.rs +++ b/crates/lune-std-ffi/src/c/struct_info.rs @@ -115,7 +115,6 @@ impl FfiSignedness for CStructInfo { } } impl FfiConvert for CStructInfo { - // FIXME: FfiBox, FfiRef support required unsafe fn value_into_data<'lua>( &self, lua: &'lua Lua, @@ -126,9 +125,9 @@ impl FfiConvert for CStructInfo { let LuaValue::Table(ref table) = value else { return Err(LuaError::external("Value is not a table")); }; - 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)?; + for (index, conv) in self.inner_conv_list.iter().enumerate() { + let field_offset = self.offset(index)? as isize; + let data: LuaValue = table.get(index + 1)?; conv.as_ref().unwrap().value_into_data( lua, @@ -174,8 +173,8 @@ impl LuaUserData for CStructInfo { // Realize method_provider::provide_box(methods); - method_provider::provide_from_data(methods); - method_provider::provide_into_data(methods); + method_provider::provide_read_data(methods); + method_provider::provide_write_data(methods); methods.add_method("offset", |_, this, index: usize| { let offset = this.offset(index)?; diff --git a/crates/lune-std-ffi/src/c/type_info.rs b/crates/lune-std-ffi/src/c/type_info.rs index 53cb879a..e60e1439 100644 --- a/crates/lune-std-ffi/src/c/type_info.rs +++ b/crates/lune-std-ffi/src/c/type_info.rs @@ -58,7 +58,7 @@ where T: 'static, Self: CTypeCast + FfiSignedness + FfiConvert + FfiSize, { - pub fn new_with_libffi_type<'lua>( + pub fn from_middle_type<'lua>( lua: &'lua Lua, libffi_type: Type, name: &'static str, @@ -106,8 +106,8 @@ where // Realize method_provider::provide_box(methods); - method_provider::provide_from_data(methods); - method_provider::provide_into_data(methods); + method_provider::provide_read_data(methods); + method_provider::provide_write_data(methods); methods.add_function( "cast", @@ -121,8 +121,8 @@ where from_type.borrow::()?.cast( &from_type, &into_type, - &from.get_data_handle()?, - &into.get_data_handle()?, + &from.get_ffi_data()?, + &into.get_ffi_data()?, ) }, ); diff --git a/crates/lune-std-ffi/src/c/types/mod.rs b/crates/lune-std-ffi/src/c/types/mod.rs index 6d4169f8..98a88933 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, - CTypeInfo::<$rust_type>::new_with_libffi_type($lua, $libffi_type, $name)?, + CTypeInfo::<$rust_type>::from_middle_type($lua, $libffi_type, $name)?, ),)*]) }; } diff --git a/crates/lune-std-ffi/src/data/callable_data.rs b/crates/lune-std-ffi/src/data/callable_data.rs index 001ef7aa..d5c9bd83 100644 --- a/crates/lune-std-ffi/src/data/callable_data.rs +++ b/crates/lune-std-ffi/src/data/callable_data.rs @@ -49,7 +49,7 @@ impl CallableData { .get(index) .ok_or_else(|| LuaError::external(format!("argument {index} required")))?; let arg_pointer = if let LuaValue::UserData(userdata) = arg { - let data_handle = userdata.get_data_handle()?; + let data_handle = userdata.get_ffi_data()?; data_handle .check_boundary(0, arg_info.size) .then_some(()) @@ -86,7 +86,7 @@ impl LuaUserData for CallableData { return Err(LuaError::external("")); }; // FIXME: clone - unsafe { this.call(&result.clone().get_data_handle()?, args) } + unsafe { this.call(&result.clone().get_ffi_data()?, args) } }, ); // ref, leak ..? diff --git a/crates/lune-std-ffi/src/data/mod.rs b/crates/lune-std-ffi/src/data/mod.rs index c2ddf5b3..1de4df1e 100644 --- a/crates/lune-std-ffi/src/data/mod.rs +++ b/crates/lune-std-ffi/src/data/mod.rs @@ -25,24 +25,44 @@ mod association_names { } pub trait GetFfiData { - fn get_data_handle(&self) -> LuaResult>; + fn get_ffi_data(&self) -> LuaResult>; + fn is_ffi_data(&self) -> bool; } impl GetFfiData for LuaAnyUserData<'_> { - fn get_data_handle(&self) -> LuaResult> { + fn get_ffi_data(&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 if self.is::() { + Ok(self.borrow::()? as Ref) } else { let config = ValueFormatConfig::new(); Err(LuaError::external(format!( - "Expected FfiBox, FfiRef or FfiRaw. got {}", - // what? + "Expected FfiBox, FfiRef or ClosureData. got {}", pretty_format_value(&LuaValue::UserData(self.to_owned()), &config) ))) } } + fn is_ffi_data(&self) -> bool { + self.is::() | self.is::() | self.is::() + } +} + +impl GetFfiData for LuaValue<'_> { + fn get_ffi_data(&self) -> LuaResult> { + self.as_userdata() + .ok_or_else(|| { + let config = ValueFormatConfig::new(); + LuaError::external(format!( + "Expected FfiBox, FfiRef or ClosureData. got {}", + pretty_format_value(self, &config) + )) + })? + .get_ffi_data() + } + fn is_ffi_data(&self) -> bool { + self.as_userdata().map_or(false, GetFfiData::is_ffi_data) + } } diff --git a/tests/ffi/external_math/init.luau b/tests/ffi/external_math/init.luau index 3b76871c..0d005413 100644 --- a/tests/ffi/external_math/init.luau +++ b/tests/ffi/external_math/init.luau @@ -8,16 +8,16 @@ compile(`{testdir}/lib.c`, `{testdir}/lib.so`) local lib = ffi.open(`{testdir}/lib.so`) local function test_add_int() - local add_int = ffi.fn({ ffi.int, ffi.int }, ffi.int) + local add_int = ffi.fnInfo({ ffi.int, ffi.int }, ffi.int) - local add_int_caller = add_int:caller(lib:find("add_int")) + local add_int_caller = add_int:callable(lib:find("add_int")) local resultBox = ffi.box(ffi.int.size) local arg1 = ffi.int:box(100) local arg2 = ffi.int:box(200) add_int_caller:call(resultBox, arg1, arg2) - local result = ffi.int:from(resultBox) + local result = ffi.int:readData(resultBox) assert(result == 300, `add_int failed. result expected 300, got {result}`) end @@ -25,16 +25,16 @@ end test_add_int() local function test_mul_int() - local mul_int = ffi.fn({ ffi.int, ffi.int }, ffi.int) + local mul_int = ffi.fnInfo({ ffi.int, ffi.int }, ffi.int) - local mul_int_caller = mul_int:caller(lib:find("mul_int")) + local mul_int_caller = mul_int:callable(lib:find("mul_int")) local resultBox = ffi.box(ffi.int.size) local arg1 = ffi.int:box(100) local arg2 = ffi.int:box(200) mul_int_caller:call(resultBox, arg1, arg2) - local result = ffi.int:from(resultBox) + local result = ffi.int:readData(resultBox) assert(result == 20000, `mul_int failed. result expected 20000, got {result}`) end diff --git a/tests/ffi/external_struct/init.luau b/tests/ffi/external_struct/init.luau index d07cf420..76213dfc 100644 --- a/tests/ffi/external_struct/init.luau +++ b/tests/ffi/external_struct/init.luau @@ -8,12 +8,12 @@ compile(`{testdir}/lib.c`, `{testdir}/lib.so`) local lib = ffi.open(`{testdir}/lib.so`) local function test_AB() - local ArgStruct = ffi.struct({ ffi.int, ffi.int:ptr() }) - local ResultStruct = ffi.struct({ ffi.int, ffi.int }) + local ArgStruct = ffi.structInfo({ ffi.int, ffi.int:ptrInfo() }) + local ResultStruct = ffi.structInfo({ ffi.int, ffi.int }) - local AB = ffi.fn({ ArgStruct }, ResultStruct) + local AB = ffi.fnInfo({ ArgStruct }, ResultStruct) - local AB_caller = AB:caller(lib:find("AB")) + local AB_caller = AB:callable(lib:find("AB")) local resultBox = ffi.box(ffi.int.size) local a = ffi.int:box(100) @@ -21,7 +21,7 @@ local function test_AB() local arg = ArgStruct:box({ a, b:leak() }) AB_caller:call(resultBox, arg) - local result = ResultStruct:from(resultBox) + local result = ResultStruct:readData(resultBox) assert(result[0] == 300, `AB failed. result expected 300, got {result}`) assert(result[1] == 20000, `AB failed. result expected 300, got {result}`) diff --git a/tests/ffi/utility/compile.luau b/tests/ffi/utility/compile.luau index 0b67f4c4..5cb24347 100644 --- a/tests/ffi/utility/compile.luau +++ b/tests/ffi/utility/compile.luau @@ -1,6 +1,6 @@ local process = require("@lune/process") local function compile(file, out) - local gcc = process.spawn("gcc", { "-shared", "-o", out, "-fPIC", file }) + local gcc = process.exec("gcc", { "-shared", "-o", out, "-fPIC", file }) if not gcc.ok then error("Failed to execute gcc command\n" .. gcc.stdout .. gcc.stderr) end diff --git a/types/ffi.luau b/types/ffi.luau index 9db46478..9c890e1d 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -9,9 +9,9 @@ export type CTypeInfo = { -- realize box: (self: CTypeInfo, val: R) -> Box, - fromData: (self: CTypeInfo, data: (Ref|Box), offset: number?) -> R, - intoData: (self: CTypeInfo, data: (Ref|Box), value: R, offset: number?) -> (), - + readData: (self: CTypeInfo, target: (Ref|Box), offset: number?) -> R, + writeData: (self: CTypeInfo, target: (Ref|Box), value: R, offset: number?) -> (), + -- FIXME: recursive types; 'intoType' should be CTypes cast: (self: CTypeInfo, intoType: any, fromData: (Ref|Box), intoData: (Ref|Box)) -> (), } & { ["__phantom"]: T } @@ -24,6 +24,10 @@ export type CPtrInfo = { -- FIXME: recursive types; 'any' should be CPtrInfo arrInfo: (self: CPtrInfo, len: number) -> any, ptrInfo: (self: CPtrInfo) -> any, + + readRef: (self: CPtrInfo, target: (Ref|Box), offset: number?) -> Ref, + writeRef: (self: CPtrInfo, target: (Ref|Box), value: (Ref|Box), offset: number?) -> (), + } export type CArrInfo = { @@ -36,19 +40,24 @@ export type CArrInfo = { -- realize box: (self: CArrInfo, table: { T }) -> Box, - fromData: (self: CArrInfo, data: (Ref|Box), offset: number?) -> { T }, - intoData: (self: CArrInfo, data: (Ref|Box), value: { T }, offset: number?) -> (), + readData: (self: CArrInfo, target: (Ref|Box), offset: number?) -> { T }, + writeData: (self: CArrInfo, target: (Ref|Box), value: { T }, offset: number?) -> (), offset: (self: CArrInfo, offset: number) -> number, } -export type CFuncInfo = { - callable: (self: CFuncInfo, functionRef: Ref) -> Callable, +export type CFnInfo = { + callable: (self: CFnInfo, functionRef: Ref) -> Callable, + closure: (self: CFnInfo, (...Ref)->()) -> (), } export type CStructInfo = { arrInfo: (self: CStructInfo, len: number) -> CArrInfo, ptrInfo: (self: CStructInfo) -> CPtrInfo, + + box: (self: CStructInfo, table: { any }) -> Box, + readData: (self: CStructInfo, target: (Ref|Box), offset: number?) -> { any }, + writeData: (self: CStructInfo, target: (Ref|Box), table: { any }, offset: number?) -> (), } type NumCType = CTypeInfo @@ -114,7 +123,8 @@ export type CTypes = | ulonglong | CArrInfo | CPtrInfo - | CFuncInfo + | CFnInfo + | CStructInfo export type Ref = { deref: (self: Ref) -> Ref, @@ -136,7 +146,7 @@ export type Lib = { } export type Callable = { - call: (self: Callable, result: Ref, ...(Ref | Box))->(); + call: (self: Callable, result: (Ref | Box), ...(Ref | Box))->(); } local ffi = {} @@ -190,7 +200,11 @@ function ffi.isInteger(val: T): boolean return nil :: any end -function ffi.funcInfo(args: { CTypes }, ret: CTypes): CFuncInfo +function ffi.fnInfo(args: { CTypes }, ret: CTypes): CFnInfo + return nil :: any +end + +function ffi.structInfo(inner: { CTypes }): CStructInfo return nil :: any end From 27e250daa5196b3153ee2901f20e07bc985f57c4 Mon Sep 17 00:00:00 2001 From: qwreey Date: Fri, 18 Oct 2024 06:12:53 +0000 Subject: [PATCH 32/79] Implememt CVoid, StringifyData and CopyData (#243) --- crates/lune-std-ffi/README.md | 6 + crates/lune-std-ffi/src/c/arr_info.rs | 18 ++- crates/lune-std-ffi/src/c/helper.rs | 121 ++++++++++++++++--- crates/lune-std-ffi/src/c/mod.rs | 1 + crates/lune-std-ffi/src/c/ptr_info.rs | 30 +++-- crates/lune-std-ffi/src/c/struct_info.rs | 106 ++++++++-------- crates/lune-std-ffi/src/c/type_info.rs | 2 + crates/lune-std-ffi/src/c/types/f32.rs | 21 +++- crates/lune-std-ffi/src/c/types/f64.rs | 21 +++- crates/lune-std-ffi/src/c/types/i128.rs | 21 +++- crates/lune-std-ffi/src/c/types/i16.rs | 21 +++- crates/lune-std-ffi/src/c/types/i32.rs | 21 +++- crates/lune-std-ffi/src/c/types/i64.rs | 21 +++- crates/lune-std-ffi/src/c/types/i8.rs | 21 +++- crates/lune-std-ffi/src/c/types/isize.rs | 25 +++- crates/lune-std-ffi/src/c/types/u128.rs | 21 +++- crates/lune-std-ffi/src/c/types/u16.rs | 21 +++- crates/lune-std-ffi/src/c/types/u32.rs | 21 +++- crates/lune-std-ffi/src/c/types/u64.rs | 21 +++- crates/lune-std-ffi/src/c/types/u8.rs | 21 +++- crates/lune-std-ffi/src/c/types/usize.rs | 25 +++- crates/lune-std-ffi/src/c/void_info.rs | 25 +++- crates/lune-std-ffi/src/data/closure_data.rs | 15 +-- crates/lune-std-ffi/src/ffi/libffi_helper.rs | 11 ++ crates/lune-std-ffi/src/ffi/mod.rs | 18 +++ types/ffi.luau | 3 +- 26 files changed, 551 insertions(+), 107 deletions(-) diff --git a/crates/lune-std-ffi/README.md b/crates/lune-std-ffi/README.md index 05a98ee1..192f298d 100644 --- a/crates/lune-std-ffi/README.md +++ b/crates/lune-std-ffi/README.md @@ -90,3 +90,9 @@ Add `CTypeInfo:add(target, from1, from2, ...)` and `:sub` `:mul` `:div` `:mod` ` Add bor band and such bit-related operation > Luau only supports 32bit bit operations + +wchar and wstring support + +string(null ending) / buffer support + +void support diff --git a/crates/lune-std-ffi/src/c/arr_info.rs b/crates/lune-std-ffi/src/c/arr_info.rs index 759661b3..59dce1a9 100644 --- a/crates/lune-std-ffi/src/c/arr_info.rs +++ b/crates/lune-std-ffi/src/c/arr_info.rs @@ -59,7 +59,7 @@ impl CArrInfo { self.length } - pub fn get_type(&self) -> Type { + pub fn get_middle_type(&self) -> Type { self.struct_type.clone() } @@ -87,7 +87,6 @@ impl FfiSize for CArrInfo { } } impl FfiConvert for CArrInfo { - // FIXME: FfiBox, FfiRef support required unsafe fn value_into_data<'lua>( &self, lua: &'lua Lua, @@ -132,6 +131,20 @@ impl FfiConvert for CArrInfo { } Ok(LuaValue::Table(table)) } + + unsafe fn copy_data( + &self, + _lua: &Lua, + dst_offset: isize, + src_offset: isize, + dst: &Ref, + src: &Ref, + ) -> LuaResult<()> { + dst.get_pointer() + .byte_offset(dst_offset) + .copy_from(src.get_pointer().byte_offset(src_offset), self.get_size()); + Ok(()) + } } impl LuaUserData for CArrInfo { @@ -157,6 +170,7 @@ impl LuaUserData for CArrInfo { method_provider::provide_box(methods); method_provider::provide_read_data(methods); method_provider::provide_write_data(methods); + method_provider::provide_copy_data(methods); methods.add_method("offset", |_, this, offset: isize| { if this.length > (offset as usize) && offset >= 0 { diff --git a/crates/lune-std-ffi/src/c/helper.rs b/crates/lune-std-ffi/src/c/helper.rs index e00fd05c..8a22a5bb 100644 --- a/crates/lune-std-ffi/src/c/helper.rs +++ b/crates/lune-std-ffi/src/c/helper.rs @@ -2,7 +2,7 @@ use libffi::middle::Type; use lune_utils::fmt::{pretty_format_value, ValueFormatConfig}; use mlua::prelude::*; -use super::{ctype_helper, CArrInfo, CFnInfo, CPtrInfo, CStructInfo}; +use super::{ctype_helper, void_info::CVoidInfo, CArrInfo, CFnInfo, CPtrInfo, CStructInfo}; use crate::{ data::{BoxData, GetFfiData}, ffi::{FfiConvert, FfiSize}, @@ -84,17 +84,104 @@ pub mod method_provider { ); } + pub fn provide_copy_data<'lua, Target, M>(methods: &mut M) + where + Target: FfiSize + FfiConvert, + M: LuaUserDataMethods<'lua, Target>, + { + methods.add_method( + "copyData", + |lua, + this, + (dst, src, dst_offset, src_offset): ( + LuaAnyUserData, + LuaAnyUserData, + Option, + Option, + )| { + let dst_offset = dst_offset.unwrap_or(0); + let src_offset = src_offset.unwrap_or(0); + + let dst = &dst.get_ffi_data()?; + // use or functions + if !dst.check_boundary(dst_offset, this.get_size()) { + return Err(LuaError::external("Out of bounds")); + } + if !dst.is_writable() { + return Err(LuaError::external("Unwritable data handle")); + } + + let src = &src.get_ffi_data()?; + if !src.check_boundary(dst_offset, this.get_size()) { + return Err(LuaError::external("Out of bounds")); + } + if !src.is_readable() { + return Err(LuaError::external("Unreadable value data handle")); + } + + unsafe { this.copy_data(lua, dst_offset, src_offset, dst, src) } + }, + ); + } + + pub fn provide_stringify_data<'lua, Target, M>(methods: &mut M) + where + Target: FfiSize + FfiConvert, + M: LuaUserDataMethods<'lua, Target>, + { + methods.add_method( + "stringifyData", + |lua, this, (target, offset): (LuaAnyUserData, Option)| unsafe { + this.stringify_data(lua, offset.unwrap_or(0), &target.get_ffi_data()?) + }, + ); + } + pub fn provide_box<'lua, Target, M>(methods: &mut M) where Target: FfiSize + FfiConvert, M: LuaUserDataMethods<'lua, Target>, { - methods.add_method("box", |lua, this, table: LuaValue| { + methods.add_method("box", |lua, this, value: LuaValue| { let result = lua.create_userdata(BoxData::new(this.get_size()))?; - unsafe { this.value_into_data(lua, 0, &result.get_ffi_data()?, table)? }; + unsafe { this.value_into_data(lua, 0, &result.get_ffi_data()?, value)? }; Ok(result) }); } + + // FIXME: Buffer support should be part of another PR + // pub fn provide_write_buffer<'lua, Target, M>(methods: &mut M) + // where + // Target: FfiSize + FfiConvert, + // M: LuaUserDataMethods<'lua, Target>, + // { + // methods.add_method( + // "writeBuffer", + // |lua, this, (target, value, offset): (LuaValue, LuaValue, Option)| { + // if !target.is_buffer() { + // return Err(LuaError::external(format!( + // "Argument target must be a buffer, got {}", + // target.type_name() + // ))); + // } + + // target.to_pointer() + // target.as_userdata().unwrap().to_pointer() + // let offset = offset.unwrap_or(0); + + // let data_handle = &target.get_ffi_data()?; + // // use or functions + // 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.value_into_data(lua, offset, data_handle, value) } + // }, + // ); + // } } pub fn get_userdata(value: LuaValue) -> LuaResult { @@ -143,28 +230,32 @@ pub unsafe fn get_conv_list(table: &LuaTable) -> LuaResult LuaResult { - if this.is::() { - Ok(this.borrow::()?.get_size()) - } else if this.is::() { - Ok(this.borrow::()?.get_size()) - } else if this.is::() { - Ok(this.borrow::()?.get_size()) +pub fn get_size(userdata: &LuaAnyUserData) -> LuaResult { + if userdata.is::() { + Ok(userdata.borrow::()?.get_size()) + } else if userdata.is::() { + Ok(userdata.borrow::()?.get_size()) + } else if userdata.is::() { + Ok(userdata.borrow::()?.get_size()) + } else if userdata.is::() { + Ok(userdata.borrow::()?.get_size()) } else { - ctype_helper::get_size(this) + ctype_helper::get_size(userdata) } } // get libffi_type from any c-type userdata pub fn get_middle_type(userdata: &LuaAnyUserData) -> LuaResult { if userdata.is::() { - Ok(userdata.borrow::()?.get_type()) + Ok(userdata.borrow::()?.get_middle_type()) } else if let Some(middle_type) = ctype_helper::get_middle_type(userdata)? { Ok(middle_type) } else if userdata.is::() { - Ok(userdata.borrow::()?.get_type()) + Ok(userdata.borrow::()?.get_middle_type()) } else if userdata.is::() { - Ok(CPtrInfo::get_type()) + Ok(CPtrInfo::get_middle_type()) + } else if userdata.is::() { + Ok(CVoidInfo::get_middle_type()) } else { Err(LuaError::external(format!( "Unexpected field. CStruct, CType, CString or CArr is required for element but got {}", @@ -210,6 +301,8 @@ pub fn get_tag_name(userdata: &LuaAnyUserData) -> LuaResult { String::from("CPtr") } else if userdata.is::() { String::from("CFn") + } else if userdata.is::() { + String::from("CVoid") } else if ctype_helper::is_ctype(userdata) { String::from("CType") } else { diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index ad5b8f1c..c2cdbc38 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -5,6 +5,7 @@ mod ptr_info; mod struct_info; mod type_info; mod types; +mod void_info; pub use self::{ arr_info::CArrInfo, diff --git a/crates/lune-std-ffi/src/c/ptr_info.rs b/crates/lune-std-ffi/src/c/ptr_info.rs index 519b9220..603c63f6 100644 --- a/crates/lune-std-ffi/src/c/ptr_info.rs +++ b/crates/lune-std-ffi/src/c/ptr_info.rs @@ -45,21 +45,10 @@ impl FfiConvert for CPtrInfo { let value_userdata = value .as_userdata() .ok_or_else(|| LuaError::external("CPtrInfo:writeRef only allows data"))?; - - data_handle - .check_boundary(offset, self.get_size()) - .then_some(()) - .ok_or_else(|| LuaError::external("Out of bounds"))?; - data_handle - .is_writable() - .then_some(()) - .ok_or_else(|| LuaError::external("Unwritable data handle"))?; - *data_handle .get_pointer() .byte_offset(offset) .cast::<*mut ()>() = value_userdata.get_ffi_data()?.get_pointer(); - Ok(()) } @@ -70,10 +59,6 @@ impl FfiConvert for CPtrInfo { offset: isize, data_handle: &Ref, ) -> LuaResult> { - if !data_handle.check_boundary(offset, SIZE_OF_POINTER) { - return Err(LuaError::external("Out of bounds")); - } - Ok(LuaValue::UserData(lua.create_userdata(RefData::new( unsafe { data_handle.get_pointer().byte_offset(offset) }, if self.inner_is_cptr { @@ -84,6 +69,19 @@ impl FfiConvert for CPtrInfo { RefBounds::new(0, self.inner_size), ))?)) } + + unsafe fn copy_data( + &self, + _lua: &Lua, + dst_offset: isize, + src_offset: isize, + dst: &Ref, + src: &Ref, + ) -> LuaResult<()> { + *dst.get_pointer().byte_offset(dst_offset).cast::<*mut ()>() = + src.get_pointer().byte_offset(src_offset); + Ok(()) + } } impl CPtrInfo { @@ -118,7 +116,7 @@ impl CPtrInfo { } // Return void* - pub fn get_type() -> Type { + pub fn get_middle_type() -> Type { Type::pointer() } } diff --git a/crates/lune-std-ffi/src/c/struct_info.rs b/crates/lune-std-ffi/src/c/struct_info.rs index 836dbe38..9430a2fa 100644 --- a/crates/lune-std-ffi/src/c/struct_info.rs +++ b/crates/lune-std-ffi/src/c/struct_info.rs @@ -1,11 +1,11 @@ use std::{cell::Ref, vec::Vec}; -use libffi::{low, middle::Type, raw}; +use libffi::{low, middle::Type, raw::ffi_get_struct_offsets}; use mlua::prelude::*; use super::{association_names::CSTRUCT_INNER, helper, method_provider}; use crate::ffi::{ - association, libffi_helper::FFI_STATUS_NAMES, FfiConvert, FfiData, FfiSignedness, FfiSize, + association, libffi_helper::ffi_status_assert, FfiConvert, FfiData, FfiSignedness, FfiSize, }; pub struct CStructInfo { @@ -15,6 +15,21 @@ pub struct CStructInfo { inner_conv_list: Vec<*const dyn FfiConvert>, } +fn get_field_table<'lua>( + lua: &'lua Lua, + userdata: &LuaAnyUserData<'lua>, +) -> LuaResult> { + let value = association::get(lua, CSTRUCT_INNER, userdata)? + .ok_or_else(|| LuaError::external("Failed to get inner field table. not found"))?; + if let LuaValue::Table(table) = value { + Ok(table) + } else { + Err(LuaError::external( + "Failed to get inner field table. not a table", + )) + } +} + impl CStructInfo { pub fn new(fields: Vec, inner_conv_list: Vec<*const dyn FfiConvert>) -> LuaResult { let len = fields.len(); @@ -23,17 +38,11 @@ impl CStructInfo { // Get field offsets with ffi_get_struct_offsets unsafe { - let offset_result: raw::ffi_status = raw::ffi_get_struct_offsets( + ffi_status_assert(ffi_get_struct_offsets( low::ffi_abi_FFI_DEFAULT_ABI, middle_type.as_raw_ptr(), inner_offset_list.as_mut_ptr(), - ); - if offset_result != raw::ffi_status_FFI_OK { - return Err(LuaError::external(format!( - "ffi_get_struct_offsets failed. expected result {}, got {}", - FFI_STATUS_NAMES[0], FFI_STATUS_NAMES[offset_result as usize] - ))); - } + ))?; inner_offset_list.set_len(len); } @@ -50,7 +59,7 @@ impl CStructInfo { }) } - // Create new CStruct UserData with LuaTable. + // Create new CStruct UserData from LuaTable. // Lock and hold table for .inner ref pub fn from_table<'lua>( lua: &'lua Lua, @@ -60,7 +69,6 @@ impl CStructInfo { .create_userdata(Self::new(helper::get_middle_type_list(&table)?, unsafe { helper::get_conv_list(&table)? })?)?; - table.set_readonly(true); association::set(lua, CSTRUCT_INNER, &cstruct, table)?; Ok(cstruct) @@ -69,24 +77,20 @@ impl CStructInfo { // Stringify cstruct for pretty printing like: // pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { - if let LuaValue::Table(fields) = association::get(lua, CSTRUCT_INNER, userdata)? - .ok_or_else(|| LuaError::external("Field table not found"))? - { - let mut result = String::from(" "); - for i in 0..fields.raw_len() { - let child: LuaAnyUserData = fields.raw_get(i + 1)?; - let pretty_formatted = helper::pretty_format(lua, &child)?; - result.push_str(format!("{pretty_formatted}, ").as_str()); - } - - // size of - result.push_str( - format!("size = {} ", userdata.borrow::()?.get_size()).as_str(), - ); - Ok(result) - } else { - Err(LuaError::external("failed to get inner type table.")) + let fields = get_field_table(lua, userdata)?; + let mut stringified = String::from(" "); + + // children + for i in 0..fields.raw_len() { + let child: LuaAnyUserData = fields.raw_get(i + 1)?; + let pretty_formatted = helper::pretty_format(lua, &child)?; + stringified.push_str(format!("{pretty_formatted}, ").as_str()); } + + // size of + stringified + .push_str(format!("size = {} ", userdata.borrow::()?.get_size()).as_str()); + Ok(stringified) } // Get byte offset of nth field @@ -99,7 +103,7 @@ impl CStructInfo { Ok(offset) } - pub fn get_type(&self) -> Type { + pub fn get_middle_type(&self) -> Type { self.middle_type.clone() } } @@ -128,7 +132,6 @@ impl FfiConvert for CStructInfo { for (index, conv) in self.inner_conv_list.iter().enumerate() { let field_offset = self.offset(index)? as isize; let data: LuaValue = table.get(index + 1)?; - conv.as_ref().unwrap().value_into_data( lua, field_offset + offset, @@ -157,6 +160,19 @@ impl FfiConvert for CStructInfo { } Ok(LuaValue::Table(table)) } + unsafe fn copy_data( + &self, + _lua: &Lua, + dst_offset: isize, + src_offset: isize, + dst: &Ref, + src: &Ref, + ) -> LuaResult<()> { + dst.get_pointer() + .byte_offset(dst_offset) + .copy_from(src.get_pointer().byte_offset(src_offset), self.get_size()); + Ok(()) + } } impl LuaUserData for CStructInfo { @@ -175,22 +191,16 @@ impl LuaUserData for CStructInfo { method_provider::provide_box(methods); method_provider::provide_read_data(methods); method_provider::provide_write_data(methods); - - methods.add_method("offset", |_, this, index: usize| { - let offset = this.offset(index)?; - Ok(offset) - }); - // 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(fields) = association::get(lua, CSTRUCT_INNER, this)? - .ok_or_else(|| LuaError::external("Field table not found"))? - { - let value: LuaValue = fields.raw_get(field + 1)?; - Ok(value) - } else { - Err(LuaError::external("Failed to read field table")) - } - }); + method_provider::provide_copy_data(methods); + + methods.add_method("offset", |_, this, index: usize| this.offset(index)); + // Get nth field type userdata + methods.add_function( + "field", + |lua, (this, field_index): (LuaAnyUserData, usize)| { + let field_table = get_field_table(lua, &this)?; + field_table.raw_get::<_, LuaAnyUserData>(field_index + 1) + }, + ); } } diff --git a/crates/lune-std-ffi/src/c/type_info.rs b/crates/lune-std-ffi/src/c/type_info.rs index e60e1439..7e4b16d7 100644 --- a/crates/lune-std-ffi/src/c/type_info.rs +++ b/crates/lune-std-ffi/src/c/type_info.rs @@ -108,6 +108,8 @@ where method_provider::provide_box(methods); method_provider::provide_read_data(methods); method_provider::provide_write_data(methods); + method_provider::provide_copy_data(methods); + method_provider::provide_stringify_data(methods); methods.add_function( "cast", diff --git a/crates/lune-std-ffi/src/c/types/f32.rs b/crates/lune-std-ffi/src/c/types/f32.rs index 434c9810..00d06fb1 100644 --- a/crates/lune-std-ffi/src/c/types/f32.rs +++ b/crates/lune-std-ffi/src/c/types/f32.rs @@ -18,7 +18,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, value: LuaValue<'lua>, @@ -54,4 +53,24 @@ impl FfiConvert for CTypeInfo { }; Ok(value) } + unsafe fn copy_data( + &self, + _lua: &Lua, + dst_offset: isize, + src_offset: isize, + dst: &Ref, + src: &Ref, + ) -> LuaResult<()> { + *dst.get_pointer().byte_offset(dst_offset).cast::() = + *src.get_pointer().byte_offset(src_offset).cast::(); + Ok(()) + } + unsafe fn stringify_data( + &self, + _lua: &Lua, + offset: isize, + data_handle: &Ref, + ) -> LuaResult { + Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + } } diff --git a/crates/lune-std-ffi/src/c/types/f64.rs b/crates/lune-std-ffi/src/c/types/f64.rs index dd59a89a..fafa98d9 100644 --- a/crates/lune-std-ffi/src/c/types/f64.rs +++ b/crates/lune-std-ffi/src/c/types/f64.rs @@ -18,7 +18,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, value: LuaValue<'lua>, @@ -54,4 +53,24 @@ impl FfiConvert for CTypeInfo { }; Ok(value) } + unsafe fn copy_data( + &self, + _lua: &Lua, + dst_offset: isize, + src_offset: isize, + dst: &Ref, + src: &Ref, + ) -> LuaResult<()> { + *dst.get_pointer().byte_offset(dst_offset).cast::() = + *src.get_pointer().byte_offset(src_offset).cast::(); + Ok(()) + } + unsafe fn stringify_data( + &self, + _lua: &Lua, + offset: isize, + data_handle: &Ref, + ) -> LuaResult { + Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + } } diff --git a/crates/lune-std-ffi/src/c/types/i128.rs b/crates/lune-std-ffi/src/c/types/i128.rs index 2c51f797..6069e742 100644 --- a/crates/lune-std-ffi/src/c/types/i128.rs +++ b/crates/lune-std-ffi/src/c/types/i128.rs @@ -18,7 +18,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, value: LuaValue<'lua>, @@ -54,4 +53,24 @@ impl FfiConvert for CTypeInfo { }; Ok(value) } + unsafe fn copy_data( + &self, + _lua: &Lua, + dst_offset: isize, + src_offset: isize, + dst: &Ref, + src: &Ref, + ) -> LuaResult<()> { + *dst.get_pointer().byte_offset(dst_offset).cast::() = + *src.get_pointer().byte_offset(src_offset).cast::(); + Ok(()) + } + unsafe fn stringify_data( + &self, + _lua: &Lua, + offset: isize, + data_handle: &Ref, + ) -> LuaResult { + Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + } } diff --git a/crates/lune-std-ffi/src/c/types/i16.rs b/crates/lune-std-ffi/src/c/types/i16.rs index 077eb2ab..a1c702ad 100644 --- a/crates/lune-std-ffi/src/c/types/i16.rs +++ b/crates/lune-std-ffi/src/c/types/i16.rs @@ -18,7 +18,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, value: LuaValue<'lua>, @@ -54,4 +53,24 @@ impl FfiConvert for CTypeInfo { }; Ok(value) } + unsafe fn copy_data( + &self, + _lua: &Lua, + dst_offset: isize, + src_offset: isize, + dst: &Ref, + src: &Ref, + ) -> LuaResult<()> { + *dst.get_pointer().byte_offset(dst_offset).cast::() = + *src.get_pointer().byte_offset(src_offset).cast::(); + Ok(()) + } + unsafe fn stringify_data( + &self, + _lua: &Lua, + offset: isize, + data_handle: &Ref, + ) -> LuaResult { + Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + } } diff --git a/crates/lune-std-ffi/src/c/types/i32.rs b/crates/lune-std-ffi/src/c/types/i32.rs index bfdf543c..fa2b982d 100644 --- a/crates/lune-std-ffi/src/c/types/i32.rs +++ b/crates/lune-std-ffi/src/c/types/i32.rs @@ -18,7 +18,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, value: LuaValue<'lua>, @@ -54,4 +53,24 @@ impl FfiConvert for CTypeInfo { }; Ok(value) } + unsafe fn copy_data( + &self, + _lua: &Lua, + dst_offset: isize, + src_offset: isize, + dst: &Ref, + src: &Ref, + ) -> LuaResult<()> { + *dst.get_pointer().byte_offset(dst_offset).cast::() = + *src.get_pointer().byte_offset(src_offset).cast::(); + Ok(()) + } + unsafe fn stringify_data( + &self, + _lua: &Lua, + offset: isize, + data_handle: &Ref, + ) -> LuaResult { + Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + } } diff --git a/crates/lune-std-ffi/src/c/types/i64.rs b/crates/lune-std-ffi/src/c/types/i64.rs index 1dea3471..f458f9ce 100644 --- a/crates/lune-std-ffi/src/c/types/i64.rs +++ b/crates/lune-std-ffi/src/c/types/i64.rs @@ -18,7 +18,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, value: LuaValue<'lua>, @@ -54,4 +53,24 @@ impl FfiConvert for CTypeInfo { }; Ok(value) } + unsafe fn copy_data( + &self, + _lua: &Lua, + dst_offset: isize, + src_offset: isize, + dst: &Ref, + src: &Ref, + ) -> LuaResult<()> { + *dst.get_pointer().byte_offset(dst_offset).cast::() = + *src.get_pointer().byte_offset(src_offset).cast::(); + Ok(()) + } + unsafe fn stringify_data( + &self, + _lua: &Lua, + offset: isize, + data_handle: &Ref, + ) -> LuaResult { + Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + } } diff --git a/crates/lune-std-ffi/src/c/types/i8.rs b/crates/lune-std-ffi/src/c/types/i8.rs index 6ac64ff5..5f902cd7 100644 --- a/crates/lune-std-ffi/src/c/types/i8.rs +++ b/crates/lune-std-ffi/src/c/types/i8.rs @@ -18,7 +18,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, value: LuaValue<'lua>, @@ -49,4 +48,24 @@ impl FfiConvert for CTypeInfo { unsafe { (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; Ok(value) } + unsafe fn copy_data( + &self, + _lua: &Lua, + dst_offset: isize, + src_offset: isize, + dst: &Ref, + src: &Ref, + ) -> LuaResult<()> { + *dst.get_pointer().byte_offset(dst_offset).cast::() = + *src.get_pointer().byte_offset(src_offset).cast::(); + Ok(()) + } + unsafe fn stringify_data( + &self, + _lua: &Lua, + offset: isize, + data_handle: &Ref, + ) -> LuaResult { + Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + } } diff --git a/crates/lune-std-ffi/src/c/types/isize.rs b/crates/lune-std-ffi/src/c/types/isize.rs index d1fda6c4..6e1ef6cc 100644 --- a/crates/lune-std-ffi/src/c/types/isize.rs +++ b/crates/lune-std-ffi/src/c/types/isize.rs @@ -18,7 +18,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, value: LuaValue<'lua>, @@ -61,4 +60,28 @@ impl FfiConvert for CTypeInfo { }; Ok(value) } + unsafe fn copy_data( + &self, + _lua: &Lua, + dst_offset: isize, + src_offset: isize, + dst: &Ref, + src: &Ref, + ) -> LuaResult<()> { + *dst.get_pointer().byte_offset(dst_offset).cast::() = + *src.get_pointer().byte_offset(src_offset).cast::(); + Ok(()) + } + unsafe fn stringify_data( + &self, + _lua: &Lua, + offset: isize, + data_handle: &Ref, + ) -> LuaResult { + Ok((*data_handle + .get_pointer() + .byte_offset(offset) + .cast::()) + .to_string()) + } } diff --git a/crates/lune-std-ffi/src/c/types/u128.rs b/crates/lune-std-ffi/src/c/types/u128.rs index a22ce8f9..12b06521 100644 --- a/crates/lune-std-ffi/src/c/types/u128.rs +++ b/crates/lune-std-ffi/src/c/types/u128.rs @@ -18,7 +18,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, value: LuaValue<'lua>, @@ -54,4 +53,24 @@ impl FfiConvert for CTypeInfo { }; Ok(value) } + unsafe fn copy_data( + &self, + _lua: &Lua, + dst_offset: isize, + src_offset: isize, + dst: &Ref, + src: &Ref, + ) -> LuaResult<()> { + *dst.get_pointer().byte_offset(dst_offset).cast::() = + *src.get_pointer().byte_offset(src_offset).cast::(); + Ok(()) + } + unsafe fn stringify_data( + &self, + _lua: &Lua, + offset: isize, + data_handle: &Ref, + ) -> LuaResult { + Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + } } diff --git a/crates/lune-std-ffi/src/c/types/u16.rs b/crates/lune-std-ffi/src/c/types/u16.rs index c6946c61..fd51298e 100644 --- a/crates/lune-std-ffi/src/c/types/u16.rs +++ b/crates/lune-std-ffi/src/c/types/u16.rs @@ -19,7 +19,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, value: LuaValue<'lua>, @@ -55,4 +54,24 @@ impl FfiConvert for CTypeInfo { }; Ok(value) } + unsafe fn copy_data( + &self, + _lua: &Lua, + dst_offset: isize, + src_offset: isize, + dst: &Ref, + src: &Ref, + ) -> LuaResult<()> { + *dst.get_pointer().byte_offset(dst_offset).cast::() = + *src.get_pointer().byte_offset(src_offset).cast::(); + Ok(()) + } + unsafe fn stringify_data( + &self, + _lua: &Lua, + offset: isize, + data_handle: &Ref, + ) -> LuaResult { + Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + } } diff --git a/crates/lune-std-ffi/src/c/types/u32.rs b/crates/lune-std-ffi/src/c/types/u32.rs index b63b67f1..d28d3102 100644 --- a/crates/lune-std-ffi/src/c/types/u32.rs +++ b/crates/lune-std-ffi/src/c/types/u32.rs @@ -18,7 +18,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, value: LuaValue<'lua>, @@ -54,4 +53,24 @@ impl FfiConvert for CTypeInfo { }; Ok(value) } + unsafe fn copy_data( + &self, + _lua: &Lua, + dst_offset: isize, + src_offset: isize, + dst: &Ref, + src: &Ref, + ) -> LuaResult<()> { + *dst.get_pointer().byte_offset(dst_offset).cast::() = + *src.get_pointer().byte_offset(src_offset).cast::(); + Ok(()) + } + unsafe fn stringify_data( + &self, + _lua: &Lua, + offset: isize, + data_handle: &Ref, + ) -> LuaResult { + Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + } } diff --git a/crates/lune-std-ffi/src/c/types/u64.rs b/crates/lune-std-ffi/src/c/types/u64.rs index ff90b761..2ef7afc7 100644 --- a/crates/lune-std-ffi/src/c/types/u64.rs +++ b/crates/lune-std-ffi/src/c/types/u64.rs @@ -18,7 +18,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, value: LuaValue<'lua>, @@ -54,4 +53,24 @@ impl FfiConvert for CTypeInfo { }; Ok(value) } + unsafe fn copy_data( + &self, + _lua: &Lua, + dst_offset: isize, + src_offset: isize, + dst: &Ref, + src: &Ref, + ) -> LuaResult<()> { + *dst.get_pointer().byte_offset(dst_offset).cast::() = + *src.get_pointer().byte_offset(src_offset).cast::(); + Ok(()) + } + unsafe fn stringify_data( + &self, + _lua: &Lua, + offset: isize, + data_handle: &Ref, + ) -> LuaResult { + Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + } } diff --git a/crates/lune-std-ffi/src/c/types/u8.rs b/crates/lune-std-ffi/src/c/types/u8.rs index 3278579b..ad6436fb 100644 --- a/crates/lune-std-ffi/src/c/types/u8.rs +++ b/crates/lune-std-ffi/src/c/types/u8.rs @@ -19,7 +19,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, value: LuaValue<'lua>, @@ -52,4 +51,24 @@ impl FfiConvert for CTypeInfo { unsafe { (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; Ok(value) } + unsafe fn copy_data( + &self, + _lua: &Lua, + dst_offset: isize, + src_offset: isize, + dst: &Ref, + src: &Ref, + ) -> LuaResult<()> { + *dst.get_pointer().byte_offset(dst_offset).cast::() = + *src.get_pointer().byte_offset(src_offset).cast::(); + Ok(()) + } + unsafe fn stringify_data( + &self, + _lua: &Lua, + offset: isize, + data_handle: &Ref, + ) -> LuaResult { + Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + } } diff --git a/crates/lune-std-ffi/src/c/types/usize.rs b/crates/lune-std-ffi/src/c/types/usize.rs index 1d7d0f44..007c3caf 100644 --- a/crates/lune-std-ffi/src/c/types/usize.rs +++ b/crates/lune-std-ffi/src/c/types/usize.rs @@ -18,7 +18,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, value: LuaValue<'lua>, @@ -61,4 +60,28 @@ impl FfiConvert for CTypeInfo { }; Ok(value) } + unsafe fn copy_data( + &self, + _lua: &Lua, + dst_offset: isize, + src_offset: isize, + dst: &Ref, + src: &Ref, + ) -> LuaResult<()> { + *dst.get_pointer().byte_offset(dst_offset).cast::() = + *src.get_pointer().byte_offset(src_offset).cast::(); + Ok(()) + } + unsafe fn stringify_data( + &self, + _lua: &Lua, + offset: isize, + data_handle: &Ref, + ) -> LuaResult { + Ok((*data_handle + .get_pointer() + .byte_offset(offset) + .cast::()) + .to_string()) + } } diff --git a/crates/lune-std-ffi/src/c/void_info.rs b/crates/lune-std-ffi/src/c/void_info.rs index b1e6fcbb..6d700819 100644 --- a/crates/lune-std-ffi/src/c/void_info.rs +++ b/crates/lune-std-ffi/src/c/void_info.rs @@ -1 +1,24 @@ -use core::ffi::c_void; +use libffi::middle::Type; +use mlua::prelude::*; + +use crate::ffi::{FfiSignedness, FfiSize}; + +pub struct CVoidInfo(); + +impl FfiSignedness for CVoidInfo { + fn get_signedness(&self) -> bool { + false + } +} +impl FfiSize for CVoidInfo { + fn get_size(&self) -> usize { + 0 + } +} +impl CVoidInfo { + pub fn get_middle_type() -> Type { + Type::void() + } +} + +impl LuaUserData for CVoidInfo {} diff --git a/crates/lune-std-ffi/src/data/closure_data.rs b/crates/lune-std-ffi/src/data/closure_data.rs index 93eece37..e05e9614 100644 --- a/crates/lune-std-ffi/src/data/closure_data.rs +++ b/crates/lune-std-ffi/src/data/closure_data.rs @@ -9,7 +9,7 @@ use mlua::prelude::*; use super::ref_data::{RefBounds, RefData, RefFlag}; use crate::ffi::{ - libffi_helper::{FFI_STATUS_NAMES, SIZE_OF_POINTER}, + libffi_helper::{ffi_status_assert, SIZE_OF_POINTER}, FfiArg, FfiData, FfiResult, }; @@ -97,7 +97,7 @@ impl ClosureData { func, }; - let prep_result = unsafe { + ffi_status_assert(unsafe { ffi_prep_closure_loc( closure, cif, @@ -105,16 +105,9 @@ impl ClosureData { ptr::from_ref(&closure_data).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(closure_data) - } + Ok(closure_data) } } diff --git a/crates/lune-std-ffi/src/ffi/libffi_helper.rs b/crates/lune-std-ffi/src/ffi/libffi_helper.rs index fc93d04e..04d764db 100644 --- a/crates/lune-std-ffi/src/ffi/libffi_helper.rs +++ b/crates/lune-std-ffi/src/ffi/libffi_helper.rs @@ -35,3 +35,14 @@ pub const FFI_STATUS_NAMES: [&str; 4] = [ "ffi_status_FFI_BAD_ABI", "ffi_status_FFI_BAD_ARGTYPE", ]; + +pub fn ffi_status_assert(result: raw::ffi_status) -> LuaResult<()> { + if result == raw::ffi_status_FFI_OK { + Ok(()) + } else { + Err(LuaError::external(format!( + "ffi_status assertion failed. expected result {}, got {}", + FFI_STATUS_NAMES[0], FFI_STATUS_NAMES[result as usize] + ))) + } +} diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index bebe31f9..5144bbd7 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -37,6 +37,24 @@ pub trait FfiConvert { offset: isize, data_handle: &Ref, ) -> LuaResult>; + + unsafe fn copy_data( + &self, + lua: &Lua, + dst_offset: isize, + src_offset: isize, + dst: &Ref, + src: &Ref, + ) -> LuaResult<()>; + + unsafe fn stringify_data( + &self, + _lua: &Lua, + _offset: isize, + _data_handle: &Ref, + ) -> LuaResult { + Err(LuaError::external("stringify not implemented")) + } } pub trait FfiData { diff --git a/types/ffi.luau b/types/ffi.luau index 9c890e1d..80927a1c 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -11,6 +11,7 @@ export type CTypeInfo = { box: (self: CTypeInfo, val: R) -> Box, readData: (self: CTypeInfo, target: (Ref|Box), offset: number?) -> R, writeData: (self: CTypeInfo, target: (Ref|Box), value: R, offset: number?) -> (), + stringifyData: (self: CTypeInfo, target: (Ref|Box), offset: number?) -> string, -- FIXME: recursive types; 'intoType' should be CTypes cast: (self: CTypeInfo, intoType: any, fromData: (Ref|Box), intoData: (Ref|Box)) -> (), @@ -27,7 +28,6 @@ export type CPtrInfo = { readRef: (self: CPtrInfo, target: (Ref|Box), offset: number?) -> Ref, writeRef: (self: CPtrInfo, target: (Ref|Box), value: (Ref|Box), offset: number?) -> (), - } export type CArrInfo = { @@ -42,6 +42,7 @@ export type CArrInfo = { box: (self: CArrInfo, table: { T }) -> Box, readData: (self: CArrInfo, target: (Ref|Box), offset: number?) -> { T }, writeData: (self: CArrInfo, target: (Ref|Box), value: { T }, offset: number?) -> (), + copyData: (self: CArrInfo, dst: (Ref|Box), src: (Ref|Box), dst_offset: number?, src_offset: number?) -> (), offset: (self: CArrInfo, offset: number) -> number, } From a67661a75378191c178345b6c49ca54b7320f37e Mon Sep 17 00:00:00 2001 From: qwreey Date: Sat, 19 Oct 2024 07:31:45 +0000 Subject: [PATCH 33/79] Void type support in call (#243) --- crates/lune-std-ffi/src/c/fn_info.rs | 4 ++ crates/lune-std-ffi/src/c/helper.rs | 15 +++++- crates/lune-std-ffi/src/c/mod.rs | 1 + crates/lune-std-ffi/src/c/struct_info.rs | 4 ++ crates/lune-std-ffi/src/c/void_info.rs | 3 ++ crates/lune-std-ffi/src/data/callable_data.rs | 47 ++++++++++--------- crates/lune-std-ffi/src/lib.rs | 2 + tests/ffi/external_print/init.luau | 18 +++++++ tests/ffi/external_print/lib.c | 5 ++ types/ffi.luau | 11 ++++- 10 files changed, 86 insertions(+), 24 deletions(-) create mode 100644 tests/ffi/external_print/init.luau create mode 100644 tests/ffi/external_print/lib.c diff --git a/crates/lune-std-ffi/src/c/fn_info.rs b/crates/lune-std-ffi/src/c/fn_info.rs index 3c701a5b..1fe4ec74 100644 --- a/crates/lune-std-ffi/src/c/fn_info.rs +++ b/crates/lune-std-ffi/src/c/fn_info.rs @@ -93,6 +93,10 @@ impl CFnInfo { arg_table: LuaTable, ret: LuaAnyUserData, ) -> LuaResult> { + if helper::has_void(&arg_table)? { + return Err(LuaError::external("Arguments can not include void type")); + } + let args_types = helper::get_middle_type_list(&arg_table)?; let ret_type = helper::get_middle_type(&ret)?; diff --git a/crates/lune-std-ffi/src/c/helper.rs b/crates/lune-std-ffi/src/c/helper.rs index 8a22a5bb..7f452fea 100644 --- a/crates/lune-std-ffi/src/c/helper.rs +++ b/crates/lune-std-ffi/src/c/helper.rs @@ -211,6 +211,7 @@ pub unsafe fn get_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn FfiCon } } +// Create vec from table with (userdata)->T pub fn create_list( table: &LuaTable, callback: fn(&LuaAnyUserData) -> LuaResult, @@ -226,10 +227,12 @@ pub fn create_list( Ok(list) } +//Get pub unsafe fn get_conv_list(table: &LuaTable) -> LuaResult> { create_list(table, |userdata| get_conv(userdata)) } +// Get type size from ctype userdata pub fn get_size(userdata: &LuaAnyUserData) -> LuaResult { if userdata.is::() { Ok(userdata.borrow::()?.get_size()) @@ -244,7 +247,7 @@ pub fn get_size(userdata: &LuaAnyUserData) -> LuaResult { } } -// get libffi_type from any c-type userdata +// Get libffi_type from ctype userdata pub fn get_middle_type(userdata: &LuaAnyUserData) -> LuaResult { if userdata.is::() { Ok(userdata.borrow::()?.get_middle_type()) @@ -274,6 +277,16 @@ pub fn get_middle_type_list(table: &LuaTable) -> LuaResult> { create_list(table, get_middle_type) } +pub fn has_void(table: &LuaTable) -> LuaResult { + for i in 0..table.raw_len() { + let value: LuaValue = table.raw_get(i + 1)?; + if get_userdata(value)?.is::() { + return Ok(false); + } + } + Ok(false) +} + // stringify any c-type userdata (for recursive) pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { if userdata.is::() { diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index c2cdbc38..ffd4562b 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -15,6 +15,7 @@ pub use self::{ struct_info::CStructInfo, type_info::{CTypeCast, CTypeInfo}, types::{ctype_helper, export_ctypes}, + void_info::CVoidInfo, }; // Named registry table names diff --git a/crates/lune-std-ffi/src/c/struct_info.rs b/crates/lune-std-ffi/src/c/struct_info.rs index 9430a2fa..1e52e369 100644 --- a/crates/lune-std-ffi/src/c/struct_info.rs +++ b/crates/lune-std-ffi/src/c/struct_info.rs @@ -65,6 +65,10 @@ impl CStructInfo { lua: &'lua Lua, table: LuaTable<'lua>, ) -> LuaResult> { + if helper::has_void(&table)? { + return Err(LuaError::external("Void field in sturct is not allowed")); + } + let cstruct = lua .create_userdata(Self::new(helper::get_middle_type_list(&table)?, unsafe { helper::get_conv_list(&table)? diff --git a/crates/lune-std-ffi/src/c/void_info.rs b/crates/lune-std-ffi/src/c/void_info.rs index 6d700819..0d36a35c 100644 --- a/crates/lune-std-ffi/src/c/void_info.rs +++ b/crates/lune-std-ffi/src/c/void_info.rs @@ -16,6 +16,9 @@ impl FfiSize for CVoidInfo { } } impl CVoidInfo { + pub fn new() -> Self { + Self() + } pub fn get_middle_type() -> Type { Type::void() } diff --git a/crates/lune-std-ffi/src/data/callable_data.rs b/crates/lune-std-ffi/src/data/callable_data.rs index d5c9bd83..8a3f6ac4 100644 --- a/crates/lune-std-ffi/src/data/callable_data.rs +++ b/crates/lune-std-ffi/src/data/callable_data.rs @@ -1,5 +1,5 @@ use core::ffi::c_void; -use std::cell::Ref; +use std::ptr; use libffi::{ low::{ffi_cif, CodePtr}, @@ -7,7 +7,7 @@ use libffi::{ }; use mlua::prelude::*; -use super::{FfiData, GetFfiData}; +use super::GetFfiData; use crate::ffi::{FfiArg, FfiResult}; pub struct CallableData { @@ -34,30 +34,38 @@ impl CallableData { // TODO? async call: if have no lua closure in arguments, fficallble can be called with async way - pub unsafe fn call(&self, result: &Ref, args: LuaMultiValue) -> LuaResult<()> { - result - .check_boundary(0, self.result_info.size) - .then_some(()) - .ok_or_else(|| LuaError::external("result boundary check failed"))?; - + pub unsafe fn call(&self, result: LuaValue, args: LuaMultiValue) -> LuaResult<()> { // cache Vec => unable to create async call but no allocation let mut arg_list = Vec::<*mut c_void>::with_capacity(self.arg_info_list.len()); + let result_pointer = if self.result_info.size == 0 { + ptr::null_mut() + } else { + let result_data = result.get_ffi_data()?; + if result_data.check_boundary(0, self.result_info.size) { + return Err(LuaError::external("Result boundary check failed")); + } + result_data.get_pointer() + } + .cast::(); + for index in 0..self.arg_info_list.len() { let arg_info = self.arg_info_list.get(index).unwrap(); let arg = args .get(index) .ok_or_else(|| LuaError::external(format!("argument {index} required")))?; + let arg_pointer = if let LuaValue::UserData(userdata) = arg { + // BoxData, RefData, ... let data_handle = userdata.get_ffi_data()?; - data_handle - .check_boundary(0, arg_info.size) - .then_some(()) - .ok_or_else(|| { - LuaError::external(format!("argument {index} boundary check failed")) - })?; + if !data_handle.check_boundary(0, arg_info.size) { + return Err(LuaError::external(format!( + "argument {index} boundary check failed" + ))); + } data_handle.get_pointer() } else { + // FIXME: buffer, string here return Err(LuaError::external("unimpl")); }; arg_list.push(arg_pointer.cast::()); @@ -66,7 +74,7 @@ impl CallableData { ffi_call( self.cif, Some(*self.code.as_safe_fun()), - result.get_pointer().cast::(), + result_pointer, arg_list.as_mut_ptr(), ); @@ -79,14 +87,11 @@ impl LuaUserData for CallableData { methods.add_method( "call", |_lua, this: &CallableData, mut args: LuaMultiValue| { - let result_userdata = args.pop_front().ok_or_else(|| { - LuaError::external("first argument must be result data handle") + let result = args.pop_front().ok_or_else(|| { + LuaError::external("First argument must be result data handle or nil") })?; - let LuaValue::UserData(result) = result_userdata else { - return Err(LuaError::external("")); - }; // FIXME: clone - unsafe { this.call(&result.clone().get_ffi_data()?, args) } + unsafe { this.call(result, args) } }, ); // ref, leak ..? diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs index b0085227..917602f1 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 c::CVoidInfo; use data::RefData; use lune_utils::TableBuilder; use mlua::prelude::*; @@ -23,6 +24,7 @@ use crate::{ pub fn module(lua: &Lua) -> LuaResult { let result = TableBuilder::new(lua)? .with_values(export_ctypes(lua)?)? + .with_value("void", CVoidInfo::new())? .with_function("nullRef", |lua, ()| create_nullptr(lua))? .with_function("box", |_lua, size: usize| Ok(BoxData::new(size)))? .with_function("open", |_lua, name: String| LibData::new(name))? diff --git a/tests/ffi/external_print/init.luau b/tests/ffi/external_print/init.luau new file mode 100644 index 00000000..4dad5233 --- /dev/null +++ b/tests/ffi/external_print/init.luau @@ -0,0 +1,18 @@ +local ffi = require("@lune/ffi") + +local testdir = "./tests/ffi/external_print" + +local compile = require("../utility/compile") +compile(`{testdir}/lib.c`, `{testdir}/lib.so`) + +local lib = ffi.open(`{testdir}/lib.so`) + +local function test_hello_world() + local add_int = ffi.fnInfo({}, ffi.void) + + local hello_world_caller = add_int:callable(lib:find("hello_world")) + + hello_world_caller:call(nil) +end + +test_hello_world() diff --git a/tests/ffi/external_print/lib.c b/tests/ffi/external_print/lib.c new file mode 100644 index 00000000..d6504921 --- /dev/null +++ b/tests/ffi/external_print/lib.c @@ -0,0 +1,5 @@ +#include + +void hello_world() { + printf("Hello world from external function!"); +} diff --git a/types/ffi.luau b/types/ffi.luau index 80927a1c..2a7d767b 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -61,6 +61,10 @@ export type CStructInfo = { writeData: (self: CStructInfo, target: (Ref|Box), table: { any }, offset: number?) -> (), } +export type CVoidInfo = { + ptrInfo: (self: CVoidInfo) -> CPtrInfo, +} + type NumCType = CTypeInfo -- Fixed size Rust-style types -- @@ -126,6 +130,7 @@ export type CTypes = | CPtrInfo | CFnInfo | CStructInfo + | CVoidInfo export type Ref = { deref: (self: Ref) -> Ref, @@ -147,12 +152,12 @@ export type Lib = { } export type Callable = { - call: (self: Callable, result: (Ref | Box), ...(Ref | Box))->(); + call: (self: Callable, result: (Ref | Box)?, ...(Ref | Box))->(); } local ffi = {} -ffi.u8 = (nil :: unknown) :: u8 +ffi.u8 = {} :: u8 ffi.u16 = {} :: u16 ffi.u32 = {} :: u32 ffi.u64 = {} :: u64 @@ -181,6 +186,8 @@ ffi.ulong = {} :: ulong ffi.longlong = {} :: longlong ffi.ulonglong = {} :: ulonglong +ffi.void = {} :: CVoidInfo + function ffi.nullRef(): Ref return nil :: any end From b31f81459f2e2270938520ebf8d41406137b0a35 Mon Sep 17 00:00:00 2001 From: qwreey Date: Mon, 21 Oct 2024 10:52:58 +0000 Subject: [PATCH 34/79] Move c ABI related object and functions into ffi.c (#243) --- crates/lune-std-ffi/src/c/arr_info.rs | 6 +- crates/lune-std-ffi/src/c/fn_info.rs | 18 ++- crates/lune-std-ffi/src/c/helper.rs | 25 ++-- crates/lune-std-ffi/src/c/mod.rs | 16 +++ crates/lune-std-ffi/src/c/ptr_info.rs | 15 +-- crates/lune-std-ffi/src/c/string_info.rs | 0 crates/lune-std-ffi/src/c/struct_info.rs | 11 +- crates/lune-std-ffi/src/c/type_info.rs | 4 +- crates/lune-std-ffi/src/c/types/f32.rs | 10 +- crates/lune-std-ffi/src/c/types/f64.rs | 10 +- crates/lune-std-ffi/src/c/types/i128.rs | 10 +- crates/lune-std-ffi/src/c/types/i16.rs | 10 +- crates/lune-std-ffi/src/c/types/i32.rs | 10 +- crates/lune-std-ffi/src/c/types/i64.rs | 10 +- crates/lune-std-ffi/src/c/types/i8.rs | 24 +++- crates/lune-std-ffi/src/c/types/isize.rs | 10 +- crates/lune-std-ffi/src/c/types/u128.rs | 10 +- crates/lune-std-ffi/src/c/types/u16.rs | 10 +- crates/lune-std-ffi/src/c/types/u32.rs | 10 +- crates/lune-std-ffi/src/c/types/u64.rs | 10 +- crates/lune-std-ffi/src/c/types/u8.rs | 10 +- crates/lune-std-ffi/src/c/types/usize.rs | 14 ++- crates/lune-std-ffi/src/c/void_info.rs | 2 + crates/lune-std-ffi/src/data/box_data/mod.rs | 6 +- crates/lune-std-ffi/src/data/callable_data.rs | 39 +++---- crates/lune-std-ffi/src/data/closure_data.rs | 21 +++- crates/lune-std-ffi/src/data/ref_data/mod.rs | 25 ++-- crates/lune-std-ffi/src/ffi/cast.rs | 4 +- crates/lune-std-ffi/src/ffi/mod.rs | 4 +- crates/lune-std-ffi/src/lib.rs | 17 +-- tests/ffi/external_closure/init.luau | 24 ++++ tests/ffi/external_closure/lib.c | 14 +++ tests/ffi/external_math/init.luau | 29 +++-- tests/ffi/external_pointer/init.luau | 23 ++++ tests/ffi/external_pointer/lib.c | 3 + tests/ffi/external_print/init.luau | 6 +- types/ffi.luau | 107 ++++++++++-------- 37 files changed, 345 insertions(+), 232 deletions(-) create mode 100644 crates/lune-std-ffi/src/c/string_info.rs create mode 100644 tests/ffi/external_closure/init.luau create mode 100644 tests/ffi/external_closure/lib.c create mode 100644 tests/ffi/external_pointer/init.luau create mode 100644 tests/ffi/external_pointer/lib.c diff --git a/crates/lune-std-ffi/src/c/arr_info.rs b/crates/lune-std-ffi/src/c/arr_info.rs index 59dce1a9..4facbd21 100644 --- a/crates/lune-std-ffi/src/c/arr_info.rs +++ b/crates/lune-std-ffi/src/c/arr_info.rs @@ -140,9 +140,9 @@ impl FfiConvert for CArrInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - dst.get_pointer() + dst.get_inner_pointer() .byte_offset(dst_offset) - .copy_from(src.get_pointer().byte_offset(src_offset), self.get_size()); + .copy_from(src.get_inner_pointer().byte_offset(src_offset), self.get_size()); Ok(()) } } @@ -161,7 +161,7 @@ impl LuaUserData for CArrInfo { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { // Subtype - method_provider::provide_ptr_info(methods); + method_provider::provide_ptr(methods); // ToString method_provider::provide_to_string(methods); diff --git a/crates/lune-std-ffi/src/c/fn_info.rs b/crates/lune-std-ffi/src/c/fn_info.rs index 1fe4ec74..62df9e8d 100644 --- a/crates/lune-std-ffi/src/c/fn_info.rs +++ b/crates/lune-std-ffi/src/c/fn_info.rs @@ -12,7 +12,10 @@ use super::{ }; use crate::{ data::{CallableData, ClosureData, RefData, RefFlag}, - ffi::{association, bit_mask::*, FfiArg, FfiData, FfiResult, FfiSignedness, FfiSize}, + ffi::{ + association, bit_mask::*, libffi_helper::SIZE_OF_POINTER, FfiArg, FfiData, FfiResult, + FfiSignedness, FfiSize, + }, }; // cfn is a type declaration for a function. @@ -42,9 +45,10 @@ impl FfiSignedness for CFnInfo { false } } + impl FfiSize for CFnInfo { fn get_size(&self) -> usize { - size_of::<*mut ()>() + SIZE_OF_POINTER } } @@ -186,7 +190,7 @@ impl CFnInfo { self.cif.as_raw_ptr(), self.arg_info_list.clone(), self.result_info.clone(), - ffi_ref.get_pointer(), + ffi_ref.get_inner_pointer(), ) })?; @@ -195,13 +199,17 @@ impl CFnInfo { Ok(callable) } + + pub fn get_middle_type() -> Type { + Type::void() + } } impl LuaUserData for CFnInfo { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { // Subtype - method_provider::provide_ptr_info(methods); - method_provider::provide_arr_info(methods); + 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/helper.rs b/crates/lune-std-ffi/src/c/helper.rs index 7f452fea..65e5dd28 100644 --- a/crates/lune-std-ffi/src/c/helper.rs +++ b/crates/lune-std-ffi/src/c/helper.rs @@ -10,6 +10,7 @@ use crate::{ pub mod method_provider { use super::*; + pub fn provide_to_string<'lua, Target, M>(methods: &mut M) where M: LuaUserDataMethods<'lua, Target>, @@ -19,20 +20,20 @@ pub mod method_provider { }); } - pub fn provide_ptr_info<'lua, Target, M>(methods: &mut M) + pub fn provide_ptr<'lua, Target, M>(methods: &mut M) where M: LuaUserDataMethods<'lua, Target>, { - methods.add_function("ptrInfo", |lua, this: LuaAnyUserData| { + methods.add_function("ptr", |lua, this: LuaAnyUserData| { CPtrInfo::from_userdata(lua, &this) }); } - pub fn provide_arr_info<'lua, Target, M>(methods: &mut M) + pub fn provide_arr<'lua, Target, M>(methods: &mut M) where M: LuaUserDataMethods<'lua, Target>, { - methods.add_function("ArrInfo", |lua, (this, length): (LuaAnyUserData, usize)| { + methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| { CArrInfo::from_userdata(lua, &this, length) }); } @@ -48,7 +49,7 @@ pub mod method_provider { let offset = offset.unwrap_or(0); let data_handle = &target.get_ffi_data()?; - if !data_handle.check_boundary(offset, this.get_size()) { + if !data_handle.check_inner_boundary(offset, this.get_size()) { return Err(LuaError::external("Out of bounds")); } if !data_handle.is_readable() { @@ -72,7 +73,7 @@ pub mod method_provider { let data_handle = &target.get_ffi_data()?; // use or functions - if !data_handle.check_boundary(offset, this.get_size()) { + if !data_handle.check_inner_boundary(offset, this.get_size()) { return Err(LuaError::external("Out of bounds")); } if !data_handle.is_writable() { @@ -104,7 +105,7 @@ pub mod method_provider { let dst = &dst.get_ffi_data()?; // use or functions - if !dst.check_boundary(dst_offset, this.get_size()) { + if !dst.check_inner_boundary(dst_offset, this.get_size()) { return Err(LuaError::external("Out of bounds")); } if !dst.is_writable() { @@ -112,7 +113,7 @@ pub mod method_provider { } let src = &src.get_ffi_data()?; - if !src.check_boundary(dst_offset, this.get_size()) { + if !src.check_inner_boundary(dst_offset, this.get_size()) { return Err(LuaError::external("Out of bounds")); } if !src.is_readable() { @@ -189,7 +190,7 @@ pub fn get_userdata(value: LuaValue) -> LuaResult { Ok(field_type) } else { Err(LuaError::external(format!( - "Unexpected field. CStruct, CType or CArr is required for element but got {}", + "CStruct, CType, CFn, CVoid or CArr is required but got {}", pretty_format_value(&value, &ValueFormatConfig::new()) ))) } @@ -242,6 +243,8 @@ pub fn get_size(userdata: &LuaAnyUserData) -> LuaResult { Ok(userdata.borrow::()?.get_size()) } else if userdata.is::() { Ok(userdata.borrow::()?.get_size()) + } else if userdata.is::() { + Ok(userdata.borrow::()?.get_size()) } else { ctype_helper::get_size(userdata) } @@ -259,9 +262,11 @@ pub fn get_middle_type(userdata: &LuaAnyUserData) -> LuaResult { Ok(CPtrInfo::get_middle_type()) } else if userdata.is::() { Ok(CVoidInfo::get_middle_type()) + } else if userdata.is::() { + Ok(CFnInfo::get_middle_type()) } else { Err(LuaError::external(format!( - "Unexpected field. CStruct, CType, CString or CArr is required for element but got {}", + "CStruct, CType, CFn, CVoid or CArr is required but got {}", pretty_format_value( // Since the data is in the Lua location, // there is no problem with the clone. diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index ffd4562b..10b9e688 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -1,3 +1,6 @@ +use lune_utils::TableBuilder; +use mlua::prelude::*; + mod arr_info; mod fn_info; pub mod helper; @@ -30,3 +33,16 @@ mod association_names { pub const CLOSURE_FUNC: &str = "__closure_func"; pub const CLOSURE_CFN: &str = "__closure_cfn"; } + +pub fn export(lua: &Lua) -> LuaResult { + TableBuilder::new(lua)? + .with_value("void", CVoidInfo::new())? + .with_values(export_ctypes(lua)?)? + .with_function("struct", |lua, types: LuaTable| { + CStructInfo::from_table(lua, types) + })? + .with_function("fn", |lua, (args, ret): (LuaTable, LuaAnyUserData)| { + CFnInfo::from_table(lua, args, ret) + })? + .build_readonly() +} diff --git a/crates/lune-std-ffi/src/c/ptr_info.rs b/crates/lune-std-ffi/src/c/ptr_info.rs index 603c63f6..f39b4251 100644 --- a/crates/lune-std-ffi/src/c/ptr_info.rs +++ b/crates/lune-std-ffi/src/c/ptr_info.rs @@ -46,9 +46,9 @@ impl FfiConvert for CPtrInfo { .as_userdata() .ok_or_else(|| LuaError::external("CPtrInfo:writeRef only allows data"))?; *data_handle - .get_pointer() + .get_inner_pointer() .byte_offset(offset) - .cast::<*mut ()>() = value_userdata.get_ffi_data()?.get_pointer(); + .cast::<*mut ()>() = value_userdata.get_ffi_data()?.get_inner_pointer(); Ok(()) } @@ -60,7 +60,7 @@ impl FfiConvert for CPtrInfo { data_handle: &Ref, ) -> LuaResult> { Ok(LuaValue::UserData(lua.create_userdata(RefData::new( - unsafe { data_handle.get_pointer().byte_offset(offset) }, + unsafe { data_handle.get_inner_pointer().byte_offset(offset) }, if self.inner_is_cptr { READ_CPTR_REF_FLAGS } else { @@ -78,8 +78,9 @@ impl FfiConvert for CPtrInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_pointer().byte_offset(dst_offset).cast::<*mut ()>() = - src.get_pointer().byte_offset(src_offset); + *dst.get_inner_pointer() + .byte_offset(dst_offset) + .cast::<*mut ()>() = src.get_inner_pointer().byte_offset(src_offset); Ok(()) } } @@ -133,8 +134,8 @@ impl LuaUserData for CPtrInfo { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { // Subtype - method_provider::provide_ptr_info(methods); - method_provider::provide_arr_info(methods); + 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/string_info.rs b/crates/lune-std-ffi/src/c/string_info.rs new file mode 100644 index 00000000..e69de29b diff --git a/crates/lune-std-ffi/src/c/struct_info.rs b/crates/lune-std-ffi/src/c/struct_info.rs index 1e52e369..3abbe73f 100644 --- a/crates/lune-std-ffi/src/c/struct_info.rs +++ b/crates/lune-std-ffi/src/c/struct_info.rs @@ -172,9 +172,10 @@ impl FfiConvert for CStructInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - dst.get_pointer() - .byte_offset(dst_offset) - .copy_from(src.get_pointer().byte_offset(src_offset), self.get_size()); + dst.get_inner_pointer().byte_offset(dst_offset).copy_from( + src.get_inner_pointer().byte_offset(src_offset), + self.get_size(), + ); Ok(()) } } @@ -185,8 +186,8 @@ impl LuaUserData for CStructInfo { } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { // Subtype - method_provider::provide_ptr_info(methods); - method_provider::provide_arr_info(methods); + 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/type_info.rs b/crates/lune-std-ffi/src/c/type_info.rs index 7e4b16d7..38bc8dbc 100644 --- a/crates/lune-std-ffi/src/c/type_info.rs +++ b/crates/lune-std-ffi/src/c/type_info.rs @@ -98,8 +98,8 @@ where fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { // Subtype - method_provider::provide_ptr_info(methods); - method_provider::provide_arr_info(methods); + 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/types/f32.rs b/crates/lune-std-ffi/src/c/types/f32.rs index 00d06fb1..10c12342 100644 --- a/crates/lune-std-ffi/src/c/types/f32.rs +++ b/crates/lune-std-ffi/src/c/types/f32.rs @@ -37,7 +37,7 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; + *(data_handle.get_inner_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -49,7 +49,7 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult> { let value = unsafe { - (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? + (*data_handle.get_inner_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; Ok(value) } @@ -61,8 +61,8 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_pointer().byte_offset(dst_offset).cast::() = - *src.get_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = + *src.get_inner_pointer().byte_offset(src_offset).cast::(); Ok(()) } unsafe fn stringify_data( @@ -71,6 +71,6 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle.get_inner_pointer().byte_offset(offset).cast::()).to_string()) } } diff --git a/crates/lune-std-ffi/src/c/types/f64.rs b/crates/lune-std-ffi/src/c/types/f64.rs index fafa98d9..ccbe4316 100644 --- a/crates/lune-std-ffi/src/c/types/f64.rs +++ b/crates/lune-std-ffi/src/c/types/f64.rs @@ -37,7 +37,7 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; + *(data_handle.get_inner_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -49,7 +49,7 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult> { let value = unsafe { - (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? + (*data_handle.get_inner_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; Ok(value) } @@ -61,8 +61,8 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_pointer().byte_offset(dst_offset).cast::() = - *src.get_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = + *src.get_inner_pointer().byte_offset(src_offset).cast::(); Ok(()) } unsafe fn stringify_data( @@ -71,6 +71,6 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle.get_inner_pointer().byte_offset(offset).cast::()).to_string()) } } diff --git a/crates/lune-std-ffi/src/c/types/i128.rs b/crates/lune-std-ffi/src/c/types/i128.rs index 6069e742..1ceeaaf4 100644 --- a/crates/lune-std-ffi/src/c/types/i128.rs +++ b/crates/lune-std-ffi/src/c/types/i128.rs @@ -37,7 +37,7 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; + *(data_handle.get_inner_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -49,7 +49,7 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult> { let value = unsafe { - (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? + (*data_handle.get_inner_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; Ok(value) } @@ -61,8 +61,8 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_pointer().byte_offset(dst_offset).cast::() = - *src.get_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = + *src.get_inner_pointer().byte_offset(src_offset).cast::(); Ok(()) } unsafe fn stringify_data( @@ -71,6 +71,6 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle.get_inner_pointer().byte_offset(offset).cast::()).to_string()) } } diff --git a/crates/lune-std-ffi/src/c/types/i16.rs b/crates/lune-std-ffi/src/c/types/i16.rs index a1c702ad..2cc5ed88 100644 --- a/crates/lune-std-ffi/src/c/types/i16.rs +++ b/crates/lune-std-ffi/src/c/types/i16.rs @@ -37,7 +37,7 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; + *(data_handle.get_inner_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -49,7 +49,7 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult> { let value = unsafe { - (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? + (*data_handle.get_inner_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; Ok(value) } @@ -61,8 +61,8 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_pointer().byte_offset(dst_offset).cast::() = - *src.get_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = + *src.get_inner_pointer().byte_offset(src_offset).cast::(); Ok(()) } unsafe fn stringify_data( @@ -71,6 +71,6 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle.get_inner_pointer().byte_offset(offset).cast::()).to_string()) } } diff --git a/crates/lune-std-ffi/src/c/types/i32.rs b/crates/lune-std-ffi/src/c/types/i32.rs index fa2b982d..7cbfa81e 100644 --- a/crates/lune-std-ffi/src/c/types/i32.rs +++ b/crates/lune-std-ffi/src/c/types/i32.rs @@ -37,7 +37,7 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; + *(data_handle.get_inner_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -49,7 +49,7 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult> { let value = unsafe { - (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? + (*data_handle.get_inner_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; Ok(value) } @@ -61,8 +61,8 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_pointer().byte_offset(dst_offset).cast::() = - *src.get_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = + *src.get_inner_pointer().byte_offset(src_offset).cast::(); Ok(()) } unsafe fn stringify_data( @@ -71,6 +71,6 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle.get_inner_pointer().byte_offset(offset).cast::()).to_string()) } } diff --git a/crates/lune-std-ffi/src/c/types/i64.rs b/crates/lune-std-ffi/src/c/types/i64.rs index f458f9ce..cc16c988 100644 --- a/crates/lune-std-ffi/src/c/types/i64.rs +++ b/crates/lune-std-ffi/src/c/types/i64.rs @@ -37,7 +37,7 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; + *(data_handle.get_inner_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -49,7 +49,7 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult> { let value = unsafe { - (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? + (*data_handle.get_inner_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; Ok(value) } @@ -61,8 +61,8 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_pointer().byte_offset(dst_offset).cast::() = - *src.get_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = + *src.get_inner_pointer().byte_offset(src_offset).cast::(); Ok(()) } unsafe fn stringify_data( @@ -71,6 +71,6 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle.get_inner_pointer().byte_offset(offset).cast::()).to_string()) } } diff --git a/crates/lune-std-ffi/src/c/types/i8.rs b/crates/lune-std-ffi/src/c/types/i8.rs index 5f902cd7..ea778e2c 100644 --- a/crates/lune-std-ffi/src/c/types/i8.rs +++ b/crates/lune-std-ffi/src/c/types/i8.rs @@ -33,7 +33,10 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; + *(data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) = value; } Ok(()) } @@ -44,8 +47,13 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult> { - let value = - unsafe { (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; + let value = unsafe { + (*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .into_lua(lua)? + }; Ok(value) } unsafe fn copy_data( @@ -56,8 +64,8 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_pointer().byte_offset(dst_offset).cast::() = - *src.get_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = + *src.get_inner_pointer().byte_offset(src_offset).cast::(); Ok(()) } unsafe fn stringify_data( @@ -66,6 +74,10 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .to_string()) } } diff --git a/crates/lune-std-ffi/src/c/types/isize.rs b/crates/lune-std-ffi/src/c/types/isize.rs index 6e1ef6cc..3ded3134 100644 --- a/crates/lune-std-ffi/src/c/types/isize.rs +++ b/crates/lune-std-ffi/src/c/types/isize.rs @@ -38,7 +38,7 @@ impl FfiConvert for CTypeInfo { }; unsafe { *(data_handle - .get_pointer() + .get_inner_pointer() .byte_offset(offset) .cast::()) = value; } @@ -53,7 +53,7 @@ impl FfiConvert for CTypeInfo { ) -> LuaResult> { let value = unsafe { (*data_handle - .get_pointer() + .get_inner_pointer() .byte_offset(offset) .cast::()) .into_lua(lua)? @@ -68,8 +68,8 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_pointer().byte_offset(dst_offset).cast::() = - *src.get_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = + *src.get_inner_pointer().byte_offset(src_offset).cast::(); Ok(()) } unsafe fn stringify_data( @@ -79,7 +79,7 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult { Ok((*data_handle - .get_pointer() + .get_inner_pointer() .byte_offset(offset) .cast::()) .to_string()) diff --git a/crates/lune-std-ffi/src/c/types/u128.rs b/crates/lune-std-ffi/src/c/types/u128.rs index 12b06521..880bb05f 100644 --- a/crates/lune-std-ffi/src/c/types/u128.rs +++ b/crates/lune-std-ffi/src/c/types/u128.rs @@ -37,7 +37,7 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; + *(data_handle.get_inner_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -49,7 +49,7 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult> { let value = unsafe { - (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? + (*data_handle.get_inner_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; Ok(value) } @@ -61,8 +61,8 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_pointer().byte_offset(dst_offset).cast::() = - *src.get_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = + *src.get_inner_pointer().byte_offset(src_offset).cast::(); Ok(()) } unsafe fn stringify_data( @@ -71,6 +71,6 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle.get_inner_pointer().byte_offset(offset).cast::()).to_string()) } } diff --git a/crates/lune-std-ffi/src/c/types/u16.rs b/crates/lune-std-ffi/src/c/types/u16.rs index fd51298e..9a367b32 100644 --- a/crates/lune-std-ffi/src/c/types/u16.rs +++ b/crates/lune-std-ffi/src/c/types/u16.rs @@ -38,7 +38,7 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; + *(data_handle.get_inner_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -50,7 +50,7 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult> { let value = unsafe { - (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? + (*data_handle.get_inner_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; Ok(value) } @@ -62,8 +62,8 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_pointer().byte_offset(dst_offset).cast::() = - *src.get_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = + *src.get_inner_pointer().byte_offset(src_offset).cast::(); Ok(()) } unsafe fn stringify_data( @@ -72,6 +72,6 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle.get_inner_pointer().byte_offset(offset).cast::()).to_string()) } } diff --git a/crates/lune-std-ffi/src/c/types/u32.rs b/crates/lune-std-ffi/src/c/types/u32.rs index d28d3102..59c7691a 100644 --- a/crates/lune-std-ffi/src/c/types/u32.rs +++ b/crates/lune-std-ffi/src/c/types/u32.rs @@ -37,7 +37,7 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; + *(data_handle.get_inner_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -49,7 +49,7 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult> { let value = unsafe { - (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? + (*data_handle.get_inner_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; Ok(value) } @@ -61,8 +61,8 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_pointer().byte_offset(dst_offset).cast::() = - *src.get_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = + *src.get_inner_pointer().byte_offset(src_offset).cast::(); Ok(()) } unsafe fn stringify_data( @@ -71,6 +71,6 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle.get_inner_pointer().byte_offset(offset).cast::()).to_string()) } } diff --git a/crates/lune-std-ffi/src/c/types/u64.rs b/crates/lune-std-ffi/src/c/types/u64.rs index 2ef7afc7..ef08a104 100644 --- a/crates/lune-std-ffi/src/c/types/u64.rs +++ b/crates/lune-std-ffi/src/c/types/u64.rs @@ -37,7 +37,7 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; + *(data_handle.get_inner_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -49,7 +49,7 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult> { let value = unsafe { - (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? + (*data_handle.get_inner_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; Ok(value) } @@ -61,8 +61,8 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_pointer().byte_offset(dst_offset).cast::() = - *src.get_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = + *src.get_inner_pointer().byte_offset(src_offset).cast::(); Ok(()) } unsafe fn stringify_data( @@ -71,6 +71,6 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle.get_inner_pointer().byte_offset(offset).cast::()).to_string()) } } diff --git a/crates/lune-std-ffi/src/c/types/u8.rs b/crates/lune-std-ffi/src/c/types/u8.rs index ad6436fb..b1e421eb 100644 --- a/crates/lune-std-ffi/src/c/types/u8.rs +++ b/crates/lune-std-ffi/src/c/types/u8.rs @@ -34,7 +34,7 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_pointer().byte_offset(offset).cast::()) = value; + *(data_handle.get_inner_pointer().byte_offset(offset).cast::()) = value; } Ok(()) } @@ -48,7 +48,7 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult> { let value = - unsafe { (*data_handle.get_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; + unsafe { (*data_handle.get_inner_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; Ok(value) } unsafe fn copy_data( @@ -59,8 +59,8 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_pointer().byte_offset(dst_offset).cast::() = - *src.get_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = + *src.get_inner_pointer().byte_offset(src_offset).cast::(); Ok(()) } unsafe fn stringify_data( @@ -69,6 +69,6 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle.get_inner_pointer().byte_offset(offset).cast::()).to_string()) } } diff --git a/crates/lune-std-ffi/src/c/types/usize.rs b/crates/lune-std-ffi/src/c/types/usize.rs index 007c3caf..ab97d232 100644 --- a/crates/lune-std-ffi/src/c/types/usize.rs +++ b/crates/lune-std-ffi/src/c/types/usize.rs @@ -38,7 +38,7 @@ impl FfiConvert for CTypeInfo { }; unsafe { *(data_handle - .get_pointer() + .get_inner_pointer() .byte_offset(offset) .cast::()) = value; } @@ -53,7 +53,7 @@ impl FfiConvert for CTypeInfo { ) -> LuaResult> { let value = unsafe { (*data_handle - .get_pointer() + .get_inner_pointer() .byte_offset(offset) .cast::()) .into_lua(lua)? @@ -68,8 +68,12 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_pointer().byte_offset(dst_offset).cast::() = - *src.get_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer() + .byte_offset(dst_offset) + .cast::() = *src + .get_inner_pointer() + .byte_offset(src_offset) + .cast::(); Ok(()) } unsafe fn stringify_data( @@ -79,7 +83,7 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult { Ok((*data_handle - .get_pointer() + .get_inner_pointer() .byte_offset(offset) .cast::()) .to_string()) diff --git a/crates/lune-std-ffi/src/c/void_info.rs b/crates/lune-std-ffi/src/c/void_info.rs index 0d36a35c..5601ab06 100644 --- a/crates/lune-std-ffi/src/c/void_info.rs +++ b/crates/lune-std-ffi/src/c/void_info.rs @@ -3,6 +3,8 @@ use mlua::prelude::*; use crate::ffi::{FfiSignedness, FfiSize}; +use super::method_provider; + pub struct CVoidInfo(); impl FfiSignedness for CVoidInfo { diff --git a/crates/lune-std-ffi/src/data/box_data/mod.rs b/crates/lune-std-ffi/src/data/box_data/mod.rs index 97ee9e14..1ca07704 100644 --- a/crates/lune-std-ffi/src/data/box_data/mod.rs +++ b/crates/lune-std-ffi/src/data/box_data/mod.rs @@ -74,7 +74,7 @@ impl BoxData { ) -> LuaResult> { let target = this.borrow::()?; let mut bounds = RefBounds::new(0, target.size()); - let mut ptr = unsafe { target.get_pointer() }; + let mut ptr = unsafe { target.get_inner_pointer() }; // Calculate offset if let Some(t) = offset { @@ -121,13 +121,13 @@ impl Drop for BoxData { } impl FfiData for BoxData { - fn check_boundary(&self, offset: isize, size: usize) -> bool { + fn check_inner_boundary(&self, offset: isize, size: usize) -> bool { if offset < 0 { return false; } self.size() - (offset as usize) >= size } - unsafe fn get_pointer(&self) -> *mut () { + unsafe fn get_inner_pointer(&self) -> *mut () { self.data.as_ptr().cast_mut().cast::<()>() } fn is_readable(&self) -> bool { diff --git a/crates/lune-std-ffi/src/data/callable_data.rs b/crates/lune-std-ffi/src/data/callable_data.rs index 8a3f6ac4..51673de7 100644 --- a/crates/lune-std-ffi/src/data/callable_data.rs +++ b/crates/lune-std-ffi/src/data/callable_data.rs @@ -7,8 +7,8 @@ use libffi::{ }; use mlua::prelude::*; -use super::GetFfiData; -use crate::ffi::{FfiArg, FfiResult}; +use super::{GetFfiData, RefData}; +use crate::ffi::{FfiArg, FfiData, FfiResult}; pub struct CallableData { cif: *mut ffi_cif, @@ -42,33 +42,24 @@ impl CallableData { ptr::null_mut() } else { let result_data = result.get_ffi_data()?; - if result_data.check_boundary(0, self.result_info.size) { + if !result_data.check_inner_boundary(0, self.result_info.size) { return Err(LuaError::external("Result boundary check failed")); } - result_data.get_pointer() + result_data.get_inner_pointer() } .cast::(); for index in 0..self.arg_info_list.len() { - let arg_info = self.arg_info_list.get(index).unwrap(); - let arg = args + // let arg_info = self.arg_info_list.get(index).unwrap(); + let arg_value = args .get(index) - .ok_or_else(|| LuaError::external(format!("argument {index} required")))?; + .ok_or_else(|| LuaError::external(format!("argument {index} required")))? + .as_userdata() + .ok_or_else(|| LuaError::external("argument should be Ref"))?; - let arg_pointer = if let LuaValue::UserData(userdata) = arg { - // BoxData, RefData, ... - let data_handle = userdata.get_ffi_data()?; - if !data_handle.check_boundary(0, arg_info.size) { - return Err(LuaError::external(format!( - "argument {index} boundary check failed" - ))); - } - data_handle.get_pointer() - } else { - // FIXME: buffer, string here - return Err(LuaError::external("unimpl")); - }; - arg_list.push(arg_pointer.cast::()); + let arg_ref = arg_value.borrow::()?; + + arg_list.push(arg_ref.get_inner_pointer().cast::()); } ffi_call( @@ -84,16 +75,14 @@ impl CallableData { impl LuaUserData for CallableData { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { - methods.add_method( - "call", + methods.add_meta_method( + LuaMetaMethod::Call, |_lua, this: &CallableData, mut args: LuaMultiValue| { let result = args.pop_front().ok_or_else(|| { LuaError::external("First argument must be result data handle or nil") })?; - // FIXME: clone unsafe { this.call(result, args) } }, ); - // ref, leak ..? } } diff --git a/crates/lune-std-ffi/src/data/closure_data.rs b/crates/lune-std-ffi/src/data/closure_data.rs index e05e9614..7f498780 100644 --- a/crates/lune-std-ffi/src/data/closure_data.rs +++ b/crates/lune-std-ffi/src/data/closure_data.rs @@ -39,11 +39,14 @@ unsafe extern "C" fn callback( arg_pointers: *mut *mut c_void, closure_data: *mut c_void, ) { + dbg!("before ud"); let closure_data = closure_data.cast::().as_ref().unwrap(); let lua = closure_data.lua.as_ref().unwrap(); let len = (*cif).nargs as usize; let mut args = Vec::::with_capacity(len + 1); + dbg!("before result"); + // Push result pointer (ref) args.push(LuaValue::UserData( lua.create_userdata(RefData::new( @@ -54,6 +57,8 @@ unsafe extern "C" fn callback( .unwrap(), )); + dbg!("before arg"); + // Push arg pointer (ref) for i in 0..len { let arg_info = closure_data.arg_info_list.get(i).unwrap(); @@ -67,6 +72,8 @@ unsafe extern "C" fn callback( )); } + dbg!("before call"); + closure_data .func .borrow() @@ -112,10 +119,12 @@ impl ClosureData { } impl FfiData for ClosureData { - unsafe fn get_pointer(&self) -> *mut () { - self.code.as_mut_ptr().cast::<()>() + unsafe fn get_inner_pointer(&self) -> *mut () { + ptr::from_ref(&self.code.as_mut_ptr()) + .cast_mut() + .cast::<()>() } - fn check_boundary(&self, offset: isize, size: usize) -> bool { + fn check_inner_boundary(&self, offset: isize, size: usize) -> bool { (offset as usize) + size <= SIZE_OF_POINTER } fn is_readable(&self) -> bool { @@ -126,4 +135,8 @@ impl FfiData for ClosureData { } } -impl LuaUserData for ClosureData {} +impl LuaUserData for ClosureData { + fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + // methods.add_function("ref", function); + } +} diff --git a/crates/lune-std-ffi/src/data/ref_data/mod.rs b/crates/lune-std-ffi/src/data/ref_data/mod.rs index b9a4cb68..b22b840f 100644 --- a/crates/lune-std-ffi/src/data/ref_data/mod.rs +++ b/crates/lune-std-ffi/src/data/ref_data/mod.rs @@ -61,7 +61,7 @@ impl RefData { let target = this.borrow::()?; let luaref = lua.create_userdata(RefData::new( - ptr::from_ref(&target.ptr) as *mut (), + ptr::from_ref(&**target.ptr) as *mut (), BOX_REF_REF_FLAGS, RefBounds { below: 0, @@ -76,18 +76,15 @@ impl RefData { } pub unsafe fn deref(&self) -> LuaResult { - u8_test(self.flags, RefFlag::Dereferenceable.value()) - .then_some(()) - .ok_or_else(|| LuaError::external("This pointer is not dereferenceable."))?; + if !u8_test(self.flags, RefFlag::Dereferenceable.value()) { + return Err(LuaError::external("This pointer is not dereferenceable.")); + } - self.boundary - .check_sized(0, size_of::()) - .then_some(()) - .ok_or_else(|| { - LuaError::external( - "Offset is out of bounds. Dereferencing pointer requires size of usize", - ) - })?; + if !self.boundary.check_sized(0, size_of::()) { + return Err(LuaError::external( + "Offset is out of bounds. Dereferencing pointer requires size of usize", + )); + } // FIXME flags Ok(Self::new( @@ -139,10 +136,10 @@ impl Drop for RefData { } impl FfiData for RefData { - fn check_boundary(&self, offset: isize, size: usize) -> bool { + fn check_inner_boundary(&self, offset: isize, size: usize) -> bool { self.boundary.check_sized(offset, size) } - unsafe fn get_pointer(&self) -> *mut () { + unsafe fn get_inner_pointer(&self) -> *mut () { **self.ptr } fn is_readable(&self) -> bool { diff --git a/crates/lune-std-ffi/src/ffi/cast.rs b/crates/lune-std-ffi/src/ffi/cast.rs index 76fd18e1..f0dc7bae 100644 --- a/crates/lune-std-ffi/src/ffi/cast.rs +++ b/crates/lune-std-ffi/src/ffi/cast.rs @@ -11,8 +11,8 @@ where From: AsPrimitive, Into: 'static + Copy, { - let from_ptr = unsafe { from.get_pointer().cast::() }; - let into_ptr = unsafe { into.get_pointer().cast::() }; + let from_ptr = unsafe { from.get_inner_pointer().cast::() }; + let into_ptr = unsafe { into.get_inner_pointer().cast::() }; unsafe { *into_ptr = (*from_ptr).as_(); diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index 5144bbd7..66a11da3 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -58,8 +58,8 @@ pub trait FfiConvert { } pub trait FfiData { - fn check_boundary(&self, offset: isize, size: usize) -> bool; - unsafe fn get_pointer(&self) -> *mut (); + fn check_inner_boundary(&self, offset: isize, size: usize) -> bool; + unsafe fn get_inner_pointer(&self) -> *mut (); fn is_writable(&self) -> bool; fn is_readable(&self) -> bool; } diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs index 917602f1..6fe320ef 100644 --- a/crates/lune-std-ffi/src/lib.rs +++ b/crates/lune-std-ffi/src/lib.rs @@ -1,7 +1,5 @@ #![allow(clippy::cargo_common_metadata)] -use c::CVoidInfo; -use data::RefData; use lune_utils::TableBuilder; use mlua::prelude::*; @@ -10,8 +8,8 @@ mod data; mod ffi; use crate::{ - c::{export_ctypes, CFnInfo, CStructInfo}, - data::{create_nullptr, BoxData, LibData}, + c::export as c_export, + data::{create_nullptr, BoxData, LibData, RefData}, }; /** @@ -23,22 +21,15 @@ use crate::{ */ pub fn module(lua: &Lua) -> LuaResult { let result = TableBuilder::new(lua)? - .with_values(export_ctypes(lua)?)? - .with_value("void", CVoidInfo::new())? .with_function("nullRef", |lua, ()| create_nullptr(lua))? .with_function("box", |_lua, size: usize| Ok(BoxData::new(size)))? .with_function("open", |_lua, name: String| LibData::new(name))? - .with_function("structInfo", |lua, types: LuaTable| { - CStructInfo::from_table(lua, types) - })? .with_function("uninitRef", |_lua, ()| Ok(RefData::new_uninit()))? .with_function("isInteger", |_lua, num: LuaValue| Ok(num.is_integer()))? - .with_function("fnInfo", |lua, (args, ret): (LuaTable, LuaAnyUserData)| { - CFnInfo::from_table(lua, args, ret) - })?; + .with_value("c", c_export(lua)?)?; #[cfg(debug_assertions)] - let result = result.with_function("debug_associate", |lua, str: String| { + let result = result.with_function("debugAssociation", |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."); ffi::association::get_table(lua, str.as_ref()) })?; diff --git a/tests/ffi/external_closure/init.luau b/tests/ffi/external_closure/init.luau new file mode 100644 index 00000000..55b38e63 --- /dev/null +++ b/tests/ffi/external_closure/init.luau @@ -0,0 +1,24 @@ +local ffi = require("@lune/ffi") + +local testdir = "./tests/ffi/external_closure" + +local compile = require("../utility/compile") +compile(`{testdir}/lib.c`, `{testdir}/lib.so`) + +local lib = ffi.open(`{testdir}/lib.so`) + +local function test_closure() + local callback_info = ffi.c.fn({ ffi.c.int, ffi.c.int }, ffi.c.int) + local callback_closure = callback_info:closure(function(ret, a, b) + ffi.c.int:writeData(ret, ffi.c.int:readData(a) + ffi.c.int:readData(b)) + end) + + local closure_test_info = ffi.c.fn({ callback_info }, ffi.c.int) + + local closure_test_callable = closure_test_info:callable(lib:find("closure_test")) + + local result_box = ffi.box(ffi.c.int.size) + closure_test_callable(result_box, callback_closure:ref()) +end + +test_closure() diff --git a/tests/ffi/external_closure/lib.c b/tests/ffi/external_closure/lib.c new file mode 100644 index 00000000..e4579f40 --- /dev/null +++ b/tests/ffi/external_closure/lib.c @@ -0,0 +1,14 @@ +#include + +typedef int (*lua_callback_t)(int a, int b); + +int closure_test(lua_callback_t callback) { + printf("%p\n", callback); + printf("%d\n", (*callback)(12, 24)); + + return (*callback)(12, 24) * 2; +} + +int closure(int a, int b) { + return a+b; +} diff --git a/tests/ffi/external_math/init.luau b/tests/ffi/external_math/init.luau index 0d005413..fe486b91 100644 --- a/tests/ffi/external_math/init.luau +++ b/tests/ffi/external_math/init.luau @@ -1,23 +1,22 @@ local ffi = require("@lune/ffi") +local c = ffi.c local testdir = "./tests/ffi/external_math" - local compile = require("../utility/compile") compile(`{testdir}/lib.c`, `{testdir}/lib.so`) - local lib = ffi.open(`{testdir}/lib.so`) local function test_add_int() - local add_int = ffi.fnInfo({ ffi.int, ffi.int }, ffi.int) + local add_int_info = c.fn({ c.int, c.int }, c.int) - local add_int_caller = add_int:callable(lib:find("add_int")) + local add_int_callable = add_int_info:callable(lib:find("add_int")) - local resultBox = ffi.box(ffi.int.size) - local arg1 = ffi.int:box(100) - local arg2 = ffi.int:box(200) + local result_box = ffi.box(c.int.size) + local arg1 = c.int:box(100) + local arg2 = c.int:box(200) - add_int_caller:call(resultBox, arg1, arg2) - local result = ffi.int:readData(resultBox) + add_int_callable(result_box, arg1:ref(), arg2:ref()) + local result = c.int:readData(result_box) assert(result == 300, `add_int failed. result expected 300, got {result}`) end @@ -25,16 +24,16 @@ end test_add_int() local function test_mul_int() - local mul_int = ffi.fnInfo({ ffi.int, ffi.int }, ffi.int) + local mul_int = c.fn({ c.int, c.int }, c.int) local mul_int_caller = mul_int:callable(lib:find("mul_int")) - local resultBox = ffi.box(ffi.int.size) - local arg1 = ffi.int:box(100) - local arg2 = ffi.int:box(200) + local resultBox = ffi.box(c.int.size) + local arg1 = c.int:box(100) + local arg2 = c.int:box(200) - mul_int_caller:call(resultBox, arg1, arg2) - local result = ffi.int:readData(resultBox) + mul_int_caller(resultBox, arg1:ref(), arg2:ref()) + local result = c.int:readData(resultBox) assert(result == 20000, `mul_int failed. result expected 20000, got {result}`) end diff --git a/tests/ffi/external_pointer/init.luau b/tests/ffi/external_pointer/init.luau new file mode 100644 index 00000000..22ab2177 --- /dev/null +++ b/tests/ffi/external_pointer/init.luau @@ -0,0 +1,23 @@ +local ffi = require("@lune/ffi") +local c = ffi.c + +local testdir = "./tests/ffi/external_pointer" +local compile = require("../utility/compile") +compile(`{testdir}/lib.c`, `{testdir}/lib.so`) +local lib = ffi.open(`{testdir}/lib.so`) + +local function test_pointer() + local pointer_info = c.fn({ c.int:ptr() }, c.void) + + local pointer_callable = pointer_info:callable(lib:find("pointer")) + + local a = ffi.box(c.int.size) + + pointer_callable(nil, a:ref():ref()) + + local result = c.int:readData(a) + + assert(result == 123, `pointer failed. result expected 123, got {result}`) +end + +test_pointer() diff --git a/tests/ffi/external_pointer/lib.c b/tests/ffi/external_pointer/lib.c new file mode 100644 index 00000000..07146224 --- /dev/null +++ b/tests/ffi/external_pointer/lib.c @@ -0,0 +1,3 @@ +void pointer(int *a) { + *a = 123; +} diff --git a/tests/ffi/external_print/init.luau b/tests/ffi/external_print/init.luau index 4dad5233..43ac11d4 100644 --- a/tests/ffi/external_print/init.luau +++ b/tests/ffi/external_print/init.luau @@ -8,11 +8,11 @@ compile(`{testdir}/lib.c`, `{testdir}/lib.so`) local lib = ffi.open(`{testdir}/lib.so`) local function test_hello_world() - local add_int = ffi.fnInfo({}, ffi.void) + local hello_world_info = ffi.fnInfo({}, ffi.void) - local hello_world_caller = add_int:callable(lib:find("hello_world")) + local hello_world_callable = hello_world_info:callable(lib:find("hello_world")) - hello_world_caller:call(nil) + hello_world_callable:call(nil) end test_hello_world() diff --git a/types/ffi.luau b/types/ffi.luau index 2a7d767b..b6af6dda 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -4,8 +4,8 @@ export type CTypeInfo = { signedness: boolean, -- subtype - ptrInfo: (self: CTypeInfo) -> CPtrInfo>, - arrInfo: (self: CTypeInfo, len: number) -> CArrInfo, R>, + ptr: (self: CTypeInfo) -> CPtrInfo>, + arr: (self: CTypeInfo, len: number) -> CArrInfo, R>, -- realize box: (self: CTypeInfo, val: R) -> Box, @@ -23,8 +23,8 @@ export type CPtrInfo = { -- subtype -- FIXME: recursive types; 'any' should be CPtrInfo - arrInfo: (self: CPtrInfo, len: number) -> any, - ptrInfo: (self: CPtrInfo) -> any, + arr: (self: CPtrInfo, len: number) -> any, + ptr: (self: CPtrInfo) -> any, readRef: (self: CPtrInfo, target: (Ref|Box), offset: number?) -> Ref, writeRef: (self: CPtrInfo, target: (Ref|Box), value: (Ref|Box), offset: number?) -> (), @@ -36,7 +36,7 @@ export type CArrInfo = { inner: T, -- subtype - ptrInfo: (self: CArrInfo) -> CPtrInfo, + ptr: (self: CArrInfo) -> CPtrInfo, -- realize box: (self: CArrInfo, table: { T }) -> Box, @@ -49,12 +49,12 @@ export type CArrInfo = { export type CFnInfo = { callable: (self: CFnInfo, functionRef: Ref) -> Callable, - closure: (self: CFnInfo, (...Ref)->()) -> (), + closure: (self: CFnInfo, (ret: Ref, ...Ref)->()) -> Closure, } export type CStructInfo = { - arrInfo: (self: CStructInfo, len: number) -> CArrInfo, - ptrInfo: (self: CStructInfo) -> CPtrInfo, + arr: (self: CStructInfo, len: number) -> CArrInfo, + ptr: (self: CStructInfo) -> CPtrInfo, box: (self: CStructInfo, table: { any }) -> Box, readData: (self: CStructInfo, target: (Ref|Box), offset: number?) -> { any }, @@ -62,7 +62,7 @@ export type CStructInfo = { } export type CVoidInfo = { - ptrInfo: (self: CVoidInfo) -> CPtrInfo, + ptr: (self: CVoidInfo) -> CPtrInfo, } type NumCType = CTypeInfo @@ -151,42 +151,60 @@ export type Lib = { find: (self: Lib, sym: string) -> Ref, } -export type Callable = { - call: (self: Callable, result: (Ref | Box)?, ...(Ref | Box))->(); +-- export type AppliedCallable = ()->() + +export type Callable = (ret: (Ref|Box)?, ...Ref)->() & { + -- apply: (self: Callable, args: Args)->AppliedCallable, +} + +export type Closure = { + ref: (self: Closure)->Ref, } +local c = {} + +c.u8 = {} :: u8 +c.u16 = {} :: u16 +c.u32 = {} :: u32 +c.u64 = {} :: u64 +c.u128 = {} :: u128 +c.i8 = {} :: i8 +c.i16 = {} :: i16 +c.i32 = {} :: i32 +c.i64 = {} :: i64 +c.i128 = {} :: i128 +c.f32 = {} :: f32 +c.f64 = {} :: f64 +c.usize = {} :: usize +c.isize = {} :: isize + +c.char = {} :: char +c.float = {} :: float +c.double = {} :: double +c.uchar = {} :: uchar +c.schar = {} :: schar +c.short = {} :: short +c.ushort = {} :: ushort +c.int = {} :: int +c.uint = {} :: uint +c.long = {} :: long +c.ulong = {} :: ulong +c.longlong = {} :: longlong +c.ulonglong = {} :: ulonglong + +c.void = {} :: CVoidInfo + +function c.fn(args: { CTypes }, ret: CTypes): CFnInfo + return nil :: any +end + +function c.struct(inner: { CTypes }): CStructInfo + return nil :: any +end + local ffi = {} -ffi.u8 = {} :: u8 -ffi.u16 = {} :: u16 -ffi.u32 = {} :: u32 -ffi.u64 = {} :: u64 -ffi.u128 = {} :: u128 -ffi.i8 = {} :: i8 -ffi.i16 = {} :: i16 -ffi.i32 = {} :: i32 -ffi.i64 = {} :: i64 -ffi.i128 = {} :: i128 -ffi.f32 = {} :: f32 -ffi.f64 = {} :: f64 -ffi.usize = {} :: usize -ffi.isize = {} :: isize - -ffi.char = {} :: char -ffi.float = {} :: float -ffi.double = {} :: double -ffi.uchar = {} :: uchar -ffi.schar = {} :: schar -ffi.short = {} :: short -ffi.ushort = {} :: ushort -ffi.int = {} :: int -ffi.uint = {} :: uint -ffi.long = {} :: long -ffi.ulong = {} :: ulong -ffi.longlong = {} :: longlong -ffi.ulonglong = {} :: ulonglong - -ffi.void = {} :: CVoidInfo +ffi.c = c function ffi.nullRef(): Ref return nil :: any @@ -208,12 +226,5 @@ function ffi.isInteger(val: T): boolean return nil :: any end -function ffi.fnInfo(args: { CTypes }, ret: CTypes): CFnInfo - return nil :: any -end - -function ffi.structInfo(inner: { CTypes }): CStructInfo - return nil :: any -end return ffi From 658b5ef75cfbb514031d3e094f5afcd631acada9 Mon Sep 17 00:00:00 2001 From: qwreey Date: Mon, 21 Oct 2024 13:19:56 +0000 Subject: [PATCH 35/79] Move fixed size types into ffi, Fix test cases (#243) --- crates/lune-std-ffi/README.md | 21 +++-- crates/lune-std-ffi/src/c/arr_info.rs | 8 +- crates/lune-std-ffi/src/c/fn_info.rs | 16 ++-- crates/lune-std-ffi/src/c/helper.rs | 2 + crates/lune-std-ffi/src/c/mod.rs | 6 +- crates/lune-std-ffi/src/c/ptr_info.rs | 1 + crates/lune-std-ffi/src/c/struct_info.rs | 1 + crates/lune-std-ffi/src/c/type_info.rs | 1 + crates/lune-std-ffi/src/c/types/mod.rs | 13 ++-- crates/lune-std-ffi/src/c/void_info.rs | 14 +++- crates/lune-std-ffi/src/data/callable_data.rs | 8 ++ crates/lune-std-ffi/src/data/closure_data.rs | 76 ++++++++++++++----- crates/lune-std-ffi/src/data/mod.rs | 3 +- crates/lune-std-ffi/src/data/ref_data/flag.rs | 2 - crates/lune-std-ffi/src/data/ref_data/mod.rs | 14 +--- crates/lune-std-ffi/src/lib.rs | 10 +-- tests/ffi/README.md | 36 +++++++++ tests/ffi/box-recursion-gc.luau | 20 ----- .../init.luau | 3 +- .../lib.c | 6 +- .../init.luau | 2 +- .../{external_math => external-math}/lib.c | 0 .../init.luau | 2 +- .../lib.c | 0 .../init.luau | 9 +-- .../{external_print => external-print}/lib.c | 0 tests/ffi/external-struct/init.luau | 28 +++++++ .../lib.c | 0 tests/ffi/external.luau | 0 tests/ffi/external_struct/init.luau | 30 -------- tests/ffi/pretty-print.luau | 39 +++++----- types/ffi.luau | 38 ++++++---- 32 files changed, 248 insertions(+), 161 deletions(-) create mode 100644 tests/ffi/README.md delete mode 100644 tests/ffi/box-recursion-gc.luau rename tests/ffi/{external_closure => external-closure}/init.luau (90%) rename tests/ffi/{external_closure => external-closure}/lib.c (54%) rename tests/ffi/{external_math => external-math}/init.luau (96%) rename tests/ffi/{external_math => external-math}/lib.c (100%) rename tests/ffi/{external_pointer => external-pointer}/init.luau (91%) rename tests/ffi/{external_pointer => external-pointer}/lib.c (100%) rename tests/ffi/{external_print => external-print}/init.luau (70%) rename tests/ffi/{external_print => external-print}/lib.c (100%) create mode 100644 tests/ffi/external-struct/init.luau rename tests/ffi/{external_struct => external-struct}/lib.c (100%) delete mode 100644 tests/ffi/external.luau delete mode 100644 tests/ffi/external_struct/init.luau diff --git a/crates/lune-std-ffi/README.md b/crates/lune-std-ffi/README.md index 192f298d..0eca6a96 100644 --- a/crates/lune-std-ffi/README.md +++ b/crates/lune-std-ffi/README.md @@ -1,5 +1,9 @@ # `lune-std-ffi` +## Tests + +See [tests/ffi](../../tests/ffi/README.md) + ## Code structure ### /c @@ -83,16 +87,19 @@ Implememt type-casting for all CTypes ## TODO -Add `CTypeInfo:add(target, from1, from2, ...)` and `:sub` `:mul` `:div` `:mod` `:pow` for math operation. +- CString + +- Add buffer for owned data support -> Luau cannot handle i64 or i128 +- Add math operation. -Add bor band and such bit-related operation + > `CTypeInfo:add(target, from1, from2, ...)` and `:sub` `:mul` `:div` `:mod` `:pow` + > Luau cannot handle f64, i64 or i128, so we should provide math operation for it -> Luau only supports 32bit bit operations +- Add bit operation -wchar and wstring support + > Luau only supports 32bit bit operations -string(null ending) / buffer support +- Add wchar and wstring support -void support + > For windows API diff --git a/crates/lune-std-ffi/src/c/arr_info.rs b/crates/lune-std-ffi/src/c/arr_info.rs index 4facbd21..cfd72590 100644 --- a/crates/lune-std-ffi/src/c/arr_info.rs +++ b/crates/lune-std-ffi/src/c/arr_info.rs @@ -140,15 +140,17 @@ impl FfiConvert for CArrInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - dst.get_inner_pointer() - .byte_offset(dst_offset) - .copy_from(src.get_inner_pointer().byte_offset(src_offset), self.get_size()); + dst.get_inner_pointer().byte_offset(dst_offset).copy_from( + src.get_inner_pointer().byte_offset(src_offset), + self.get_size(), + ); Ok(()) } } impl LuaUserData for CArrInfo { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_meta_field(LuaMetaMethod::Type, "CArr"); 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| { diff --git a/crates/lune-std-ffi/src/c/fn_info.rs b/crates/lune-std-ffi/src/c/fn_info.rs index 62df9e8d..3dd5444b 100644 --- a/crates/lune-std-ffi/src/c/fn_info.rs +++ b/crates/lune-std-ffi/src/c/fn_info.rs @@ -1,5 +1,3 @@ -use std::ptr; - use libffi::middle::{Cif, Type}; use mlua::prelude::*; @@ -155,19 +153,18 @@ impl CFnInfo { this: &LuaAnyUserData, lua_function: LuaFunction<'lua>, ) -> LuaResult> { - let closure = ClosureData::new( - ptr::from_ref(lua), + let closure_data = ClosureData::alloc( + lua, self.cif.as_raw_ptr(), self.arg_info_list.clone(), self.result_info.clone(), lua.create_registry_value(&lua_function)?, )?; - let closure_userdata = lua.create_userdata(closure)?; - association::set(lua, CLOSURE_CFN, &closure_userdata, this)?; - association::set(lua, CLOSURE_FUNC, &closure_userdata, lua_function)?; + association::set(lua, CLOSURE_CFN, &closure_data, this)?; + association::set(lua, CLOSURE_FUNC, &closure_data, lua_function)?; - Ok(closure_userdata) + Ok(closure_data) } pub fn create_callable<'lua>( @@ -206,6 +203,9 @@ impl CFnInfo { } impl LuaUserData for CFnInfo { + fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_meta_field(LuaMetaMethod::Type, "CFn"); + } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { // Subtype method_provider::provide_ptr(methods); diff --git a/crates/lune-std-ffi/src/c/helper.rs b/crates/lune-std-ffi/src/c/helper.rs index 65e5dd28..8a54fdc8 100644 --- a/crates/lune-std-ffi/src/c/helper.rs +++ b/crates/lune-std-ffi/src/c/helper.rs @@ -302,6 +302,8 @@ pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { CPtrInfo::stringify(lua, userdata) } else if userdata.is::() { CFnInfo::stringify(lua, userdata) + } else if userdata.is::() { + CVoidInfo::stringify() } else if let Some(name) = ctype_helper::get_name(userdata)? { Ok(String::from(name)) } else { diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index 10b9e688..6db6a698 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -17,7 +17,7 @@ pub use self::{ ptr_info::CPtrInfo, struct_info::CStructInfo, type_info::{CTypeCast, CTypeInfo}, - types::{ctype_helper, export_ctypes}, + types::{ctype_helper, export_c_types, export_fixed_types}, void_info::CVoidInfo, }; @@ -34,10 +34,10 @@ mod association_names { pub const CLOSURE_CFN: &str = "__closure_cfn"; } -pub fn export(lua: &Lua) -> LuaResult { +pub fn export_c(lua: &Lua) -> LuaResult { TableBuilder::new(lua)? .with_value("void", CVoidInfo::new())? - .with_values(export_ctypes(lua)?)? + .with_values(export_c_types(lua)?)? .with_function("struct", |lua, types: LuaTable| { CStructInfo::from_table(lua, types) })? diff --git a/crates/lune-std-ffi/src/c/ptr_info.rs b/crates/lune-std-ffi/src/c/ptr_info.rs index f39b4251..d66c394c 100644 --- a/crates/lune-std-ffi/src/c/ptr_info.rs +++ b/crates/lune-std-ffi/src/c/ptr_info.rs @@ -124,6 +124,7 @@ impl CPtrInfo { impl LuaUserData for CPtrInfo { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_meta_field(LuaMetaMethod::Type, "CPtr"); fields.add_field_method_get("size", |_, _| Ok(size_of::())); fields.add_field_function_get("inner", |lua, this| { let inner = association::get(lua, CPTR_INNER, this)? diff --git a/crates/lune-std-ffi/src/c/struct_info.rs b/crates/lune-std-ffi/src/c/struct_info.rs index 3abbe73f..8917eb5f 100644 --- a/crates/lune-std-ffi/src/c/struct_info.rs +++ b/crates/lune-std-ffi/src/c/struct_info.rs @@ -182,6 +182,7 @@ impl FfiConvert for CStructInfo { impl LuaUserData for CStructInfo { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_meta_field(LuaMetaMethod::Type, "CStruct"); fields.add_field_method_get("size", |_, this| Ok(this.get_size())); } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { diff --git a/crates/lune-std-ffi/src/c/type_info.rs b/crates/lune-std-ffi/src/c/type_info.rs index 38bc8dbc..b12eebfe 100644 --- a/crates/lune-std-ffi/src/c/type_info.rs +++ b/crates/lune-std-ffi/src/c/type_info.rs @@ -91,6 +91,7 @@ where Self: CTypeCast + FfiSignedness + FfiConvert + FfiSize, { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_meta_field(LuaMetaMethod::Type, "CType"); 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())); diff --git a/crates/lune-std-ffi/src/c/types/mod.rs b/crates/lune-std-ffi/src/c/types/mod.rs index 98a88933..d778874a 100644 --- a/crates/lune-std-ffi/src/c/types/mod.rs +++ b/crates/lune-std-ffi/src/c/types/mod.rs @@ -34,7 +34,7 @@ macro_rules! create_ctypes { ),)*]) }; } -pub fn export_ctypes(lua: &Lua) -> LuaResult> { +pub fn export_c_types(lua: &Lua) -> LuaResult> { create_ctypes!( lua, // Export Compile-time known c-types @@ -55,6 +55,11 @@ pub fn export_ctypes(lua: &Lua) -> LuaResult ("ulong", c_ulong, Type::c_ulong()), ("longlong", c_longlong, Type::c_longlong()), ("ulonglong", c_ulonglong, Type::c_ulonglong()), + ) +} +pub fn export_fixed_types(lua: &Lua) -> LuaResult> { + create_ctypes!( + lua, // Export Source-time known c-types (fixed) ("u8", u8, Type::u8()), ("u16", u16, Type::u16()), @@ -70,10 +75,8 @@ pub fn export_ctypes(lua: &Lua) -> LuaResult ("f32", f32, Type::f32()), ("usize", usize, Type::usize()), ("isize", isize, Type::isize()), - // TODO: c_float and c_double sometime can be half and single, - // TODO: but libffi-rs doesn't support it. need work-around or drop support - ("float", f32, Type::f32()), - ("double", f64, Type::f64()), + ("f32", f32, Type::f32()), + ("f64", f64, Type::f64()), ) } diff --git a/crates/lune-std-ffi/src/c/void_info.rs b/crates/lune-std-ffi/src/c/void_info.rs index 5601ab06..b0008e2b 100644 --- a/crates/lune-std-ffi/src/c/void_info.rs +++ b/crates/lune-std-ffi/src/c/void_info.rs @@ -17,6 +17,7 @@ impl FfiSize for CVoidInfo { 0 } } + impl CVoidInfo { pub fn new() -> Self { Self() @@ -24,6 +25,17 @@ impl CVoidInfo { pub fn get_middle_type() -> Type { Type::void() } + pub fn stringify() -> LuaResult { + Ok(String::from("CVoid")) + } } -impl LuaUserData for CVoidInfo {} +impl LuaUserData for CVoidInfo { + fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_meta_field(LuaMetaMethod::Type, "CVoid"); + } + fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + method_provider::provide_to_string(methods); + method_provider::provide_ptr(methods); + } +} diff --git a/crates/lune-std-ffi/src/data/callable_data.rs b/crates/lune-std-ffi/src/data/callable_data.rs index 51673de7..780f4e28 100644 --- a/crates/lune-std-ffi/src/data/callable_data.rs +++ b/crates/lune-std-ffi/src/data/callable_data.rs @@ -59,6 +59,14 @@ impl CallableData { let arg_ref = arg_value.borrow::()?; + // unsafe { + // let argp = arg_ref.get_inner_pointer(); + // let fnr = transmute::<*mut c_void, unsafe extern "C" fn(i32, i32) -> i32>( + // *argp.cast::<*mut c_void>(), + // ); + // dbg!(fnr(1, 2)); + // } + arg_list.push(arg_ref.get_inner_pointer().cast::()); } diff --git a/crates/lune-std-ffi/src/data/closure_data.rs b/crates/lune-std-ffi/src/data/closure_data.rs index 7f498780..17cc71f4 100644 --- a/crates/lune-std-ffi/src/data/closure_data.rs +++ b/crates/lune-std-ffi/src/data/closure_data.rs @@ -1,14 +1,18 @@ use core::ffi::c_void; -use std::{borrow::Borrow, ptr}; +use std::{borrow::Borrow, mem::transmute, ptr}; use libffi::{ - low::{closure_alloc, closure_free, ffi_cif, CodePtr}, + low::{closure_alloc, closure_free, ffi_cif}, raw::{ffi_closure, ffi_prep_closure_loc}, }; use mlua::prelude::*; -use super::ref_data::{RefBounds, RefData, RefFlag}; +use super::{ + association_names::CLSOURE_REF_INNER, + ref_data::{RefBounds, RefData, RefFlag, UNSIZED_BOUNDS}, +}; use crate::ffi::{ + association, libffi_helper::{ffi_status_assert, SIZE_OF_POINTER}, FfiArg, FfiData, FfiResult, }; @@ -16,7 +20,7 @@ use crate::ffi::{ pub struct ClosureData { lua: *const Lua, closure: *mut ffi_closure, - code: CodePtr, + code: *mut c_void, arg_info_list: Vec, result_info: FfiResult, func: LuaRegistryKey, @@ -32,6 +36,7 @@ impl Drop for ClosureData { const RESULT_REF_FLAGS: u8 = RefFlag::Leaked.value() | RefFlag::Writable.value() | RefFlag::Offsetable.value(); +const CLOSURE_REF_FLAGS: u8 = RefFlag::Function.value(); unsafe extern "C" fn callback( cif: *mut ffi_cif, @@ -45,7 +50,7 @@ unsafe extern "C" fn callback( let len = (*cif).nargs as usize; let mut args = Vec::::with_capacity(len + 1); - dbg!("before result"); + dbg!("before result", closure_data.result_info.size); // Push result pointer (ref) args.push(LuaValue::UserData( @@ -81,48 +86,66 @@ unsafe extern "C" fn callback( .unwrap() .as_function() .unwrap() - .call::<_, ()>(args) + .call::<_, ()>(LuaMultiValue::from_vec(args)) .unwrap(); } impl ClosureData { - pub fn new( - lua: *const Lua, + pub fn alloc( + lua: &Lua, cif: *mut ffi_cif, arg_info_list: Vec, result_info: FfiResult, func: LuaRegistryKey, - ) -> LuaResult { + ) -> LuaResult { let (closure, code) = closure_alloc(); + let code = code.as_mut_ptr(); + + dbg!(result_info.size); - let closure_data = ClosureData { - lua, + let closure_data = lua.create_userdata(ClosureData { + lua: ptr::from_ref(lua), closure, code, arg_info_list, result_info, func, - }; + })?; + + dbg!(unsafe { + closure_data + .to_pointer() + .cast::() + .as_ref() + .unwrap() + .result_info + .size + }); ffi_status_assert(unsafe { ffi_prep_closure_loc( closure, cif, Some(callback), - ptr::from_ref(&closure_data).cast::().cast_mut(), - code.as_mut_ptr(), + closure_data.to_pointer().cast_mut(), + code, ) })?; + unsafe { + // let argp = closure_data.borrow::()?.get_inner_pointer(); + let fnr = transmute::<*mut c_void, unsafe extern "C" fn(i32, i32) -> i32>(code); + dbg!(fnr(1, 2)); + } + Ok(closure_data) } } impl FfiData for ClosureData { unsafe fn get_inner_pointer(&self) -> *mut () { - ptr::from_ref(&self.code.as_mut_ptr()) - .cast_mut() - .cast::<()>() + ptr::from_ref(&self.code).cast_mut().cast::<()>() + // self.code.cast::<()>() } fn check_inner_boundary(&self, offset: isize, size: usize) -> bool { (offset as usize) + size <= SIZE_OF_POINTER @@ -137,6 +160,23 @@ impl FfiData for ClosureData { impl LuaUserData for ClosureData { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { - // methods.add_function("ref", function); + methods.add_function("ref", |lua, this: LuaAnyUserData| { + let ref_data = lua.create_userdata(RefData::new( + unsafe { this.borrow::()?.get_inner_pointer() }, + CLOSURE_REF_FLAGS, + UNSIZED_BOUNDS, + ))?; + unsafe { + let mut b = this.borrow_mut::()?; + b.lua = ptr::from_ref(lua); + let argp = b.get_inner_pointer(); + let fnr = transmute::<*mut c_void, unsafe extern "C" fn(i32, i32) -> i32>( + *argp.cast::<*mut c_void>(), + ); + dbg!(fnr(1, 2)); + } + association::set(lua, CLSOURE_REF_INNER, &ref_data, &this)?; + Ok(ref_data) + }); } } diff --git a/crates/lune-std-ffi/src/data/mod.rs b/crates/lune-std-ffi/src/data/mod.rs index 1de4df1e..27d3f945 100644 --- a/crates/lune-std-ffi/src/data/mod.rs +++ b/crates/lune-std-ffi/src/data/mod.rs @@ -14,7 +14,7 @@ pub use self::{ callable_data::CallableData, closure_data::ClosureData, lib_data::LibData, - ref_data::{create_nullptr, RefBounds, RefData, RefFlag}, + ref_data::{create_nullref, RefBounds, RefData, RefFlag}, }; use crate::ffi::FfiData; @@ -22,6 +22,7 @@ use crate::ffi::FfiData; mod association_names { pub const REF_INNER: &str = "__ref_inner"; pub const SYM_INNER: &str = "__syn_inner"; + pub const CLSOURE_REF_INNER: &str = "__closure_ref_inner"; } pub trait GetFfiData { diff --git a/crates/lune-std-ffi/src/data/ref_data/flag.rs b/crates/lune-std-ffi/src/data/ref_data/flag.rs index 972431db..e607e714 100644 --- a/crates/lune-std-ffi/src/data/ref_data/flag.rs +++ b/crates/lune-std-ffi/src/data/ref_data/flag.rs @@ -7,7 +7,6 @@ pub enum RefFlag { Writable, Offsetable, Function, - Uninit, } impl RefFlag { pub const fn value(&self) -> u8 { @@ -18,7 +17,6 @@ impl RefFlag { Self::Readable => U8_MASK4, Self::Offsetable => U8_MASK5, Self::Function => U8_MASK6, - Self::Uninit => U8_MASK7, } } } diff --git a/crates/lune-std-ffi/src/data/ref_data/mod.rs b/crates/lune-std-ffi/src/data/ref_data/mod.rs index b22b840f..22a123ce 100644 --- a/crates/lune-std-ffi/src/data/ref_data/mod.rs +++ b/crates/lune-std-ffi/src/data/ref_data/mod.rs @@ -17,7 +17,6 @@ pub use self::{ // Box:ref():ref() should not be able to modify, Only for external const BOX_REF_REF_FLAGS: u8 = 0; -const UNINIT_REF_FLAGS: u8 = RefFlag::Uninit.value(); // | FfiRefFlag::Writable.value() // | FfiRefFlag::Readable.value() // | FfiRefFlag::Dereferenceable.value() @@ -45,14 +44,6 @@ impl RefData { } } - pub fn new_uninit() -> Self { - Self { - ptr: ManuallyDrop::new(Box::new(ptr::null_mut())), - flags: UNINIT_REF_FLAGS, - boundary: UNSIZED_BOUNDS, - } - } - // Make FfiRef from ref pub fn luaref<'lua>( lua: &'lua Lua, @@ -185,14 +176,11 @@ impl LuaUserData for RefData { } } -pub fn create_nullptr(lua: &Lua) -> LuaResult { - // https://en.cppreference.com/w/cpp/types/nullptr_t +pub fn create_nullref(lua: &Lua) -> LuaResult { lua.create_userdata(RefData::new( ptr::null_mut::<()>().cast(), 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 UNSIZED_BOUNDS, )) } diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs index 6fe320ef..f85a1bb9 100644 --- a/crates/lune-std-ffi/src/lib.rs +++ b/crates/lune-std-ffi/src/lib.rs @@ -8,8 +8,8 @@ mod data; mod ffi; use crate::{ - c::export as c_export, - data::{create_nullptr, BoxData, LibData, RefData}, + c::{export_c, export_fixed_types}, + data::{create_nullref, BoxData, LibData}, }; /** @@ -21,12 +21,12 @@ use crate::{ */ pub fn module(lua: &Lua) -> LuaResult { let result = TableBuilder::new(lua)? - .with_function("nullRef", |lua, ()| create_nullptr(lua))? + .with_values(export_fixed_types(lua)?)? + .with_function("nullRef", |lua, ()| create_nullref(lua))? .with_function("box", |_lua, size: usize| Ok(BoxData::new(size)))? .with_function("open", |_lua, name: String| LibData::new(name))? - .with_function("uninitRef", |_lua, ()| Ok(RefData::new_uninit()))? .with_function("isInteger", |_lua, num: LuaValue| Ok(num.is_integer()))? - .with_value("c", c_export(lua)?)?; + .with_value("c", export_c(lua)?)?; #[cfg(debug_assertions)] let result = result.with_function("debugAssociation", |lua, str: String| { diff --git a/tests/ffi/README.md b/tests/ffi/README.md new file mode 100644 index 00000000..5b339496 --- /dev/null +++ b/tests/ffi/README.md @@ -0,0 +1,36 @@ +# tests/ffi + +## Requirements + +gcc for library compiling (for external-\*) + +## Results + +**External tests** + +- [x] tests/ffi/external-math +- [x] tests/ffi/external-pointer +- [x] tests/ffi/external-print +- [x] tests/ffi/external-struct +- [ ] tests/ffi/external-closure + + > failed (segfault) + +**Luau-side** + +- [ ] tests/ffi/pretty-print :white_check_mark: + + > need box, ref test + +- [x] tests/ffi/isInteger +- [ ] tests/ffi/into-boundary + + > need assertion + +- [ ] tests/ffi/from-boundary + + > need assertion + +- [ ] tests/ffi/cast + + > need assertion diff --git a/tests/ffi/box-recursion-gc.luau b/tests/ffi/box-recursion-gc.luau deleted file mode 100644 index d86d0453..00000000 --- a/tests/ffi/box-recursion-gc.luau +++ /dev/null @@ -1,20 +0,0 @@ ---!nocheck ---!nolint - -local ffi = require("@lune/ffi") - -local box = ffi.box(ffi.u8:ptr().size) -local ref = box:ref() -ffi.u8:ptr():into(box, ref) - -local wt = setmetatable({}, { __mode = "v" }) - -wt[1] = box -wt[2] = ref - -box = nil -ref = nil - -collectgarbage("collect") - -assert(wt[1] == nil and wt[2] == nil, "Box - ref recursion GC test failed") diff --git a/tests/ffi/external_closure/init.luau b/tests/ffi/external-closure/init.luau similarity index 90% rename from tests/ffi/external_closure/init.luau rename to tests/ffi/external-closure/init.luau index 55b38e63..a5783a7c 100644 --- a/tests/ffi/external_closure/init.luau +++ b/tests/ffi/external-closure/init.luau @@ -1,6 +1,6 @@ local ffi = require("@lune/ffi") -local testdir = "./tests/ffi/external_closure" +local testdir = "./tests/ffi/external-closure" local compile = require("../utility/compile") compile(`{testdir}/lib.c`, `{testdir}/lib.so`) @@ -19,6 +19,7 @@ local function test_closure() local result_box = ffi.box(ffi.c.int.size) closure_test_callable(result_box, callback_closure:ref()) + print(callback_closure) end test_closure() diff --git a/tests/ffi/external_closure/lib.c b/tests/ffi/external-closure/lib.c similarity index 54% rename from tests/ffi/external_closure/lib.c rename to tests/ffi/external-closure/lib.c index e4579f40..167a2f5f 100644 --- a/tests/ffi/external_closure/lib.c +++ b/tests/ffi/external-closure/lib.c @@ -1,12 +1,12 @@ #include -typedef int (*lua_callback_t)(int a, int b); +typedef int (*lua_callback_t)(int, int); int closure_test(lua_callback_t callback) { printf("%p\n", callback); - printf("%d\n", (*callback)(12, 24)); + printf("%d\n", callback(12, 24)); - return (*callback)(12, 24) * 2; + return callback(12, 24) * 2; } int closure(int a, int b) { diff --git a/tests/ffi/external_math/init.luau b/tests/ffi/external-math/init.luau similarity index 96% rename from tests/ffi/external_math/init.luau rename to tests/ffi/external-math/init.luau index fe486b91..1cfd6238 100644 --- a/tests/ffi/external_math/init.luau +++ b/tests/ffi/external-math/init.luau @@ -1,7 +1,7 @@ local ffi = require("@lune/ffi") local c = ffi.c -local testdir = "./tests/ffi/external_math" +local testdir = "./tests/ffi/external-math" local compile = require("../utility/compile") compile(`{testdir}/lib.c`, `{testdir}/lib.so`) local lib = ffi.open(`{testdir}/lib.so`) diff --git a/tests/ffi/external_math/lib.c b/tests/ffi/external-math/lib.c similarity index 100% rename from tests/ffi/external_math/lib.c rename to tests/ffi/external-math/lib.c diff --git a/tests/ffi/external_pointer/init.luau b/tests/ffi/external-pointer/init.luau similarity index 91% rename from tests/ffi/external_pointer/init.luau rename to tests/ffi/external-pointer/init.luau index 22ab2177..57fc7199 100644 --- a/tests/ffi/external_pointer/init.luau +++ b/tests/ffi/external-pointer/init.luau @@ -1,7 +1,7 @@ local ffi = require("@lune/ffi") local c = ffi.c -local testdir = "./tests/ffi/external_pointer" +local testdir = "./tests/ffi/external-pointer" local compile = require("../utility/compile") compile(`{testdir}/lib.c`, `{testdir}/lib.so`) local lib = ffi.open(`{testdir}/lib.so`) diff --git a/tests/ffi/external_pointer/lib.c b/tests/ffi/external-pointer/lib.c similarity index 100% rename from tests/ffi/external_pointer/lib.c rename to tests/ffi/external-pointer/lib.c diff --git a/tests/ffi/external_print/init.luau b/tests/ffi/external-print/init.luau similarity index 70% rename from tests/ffi/external_print/init.luau rename to tests/ffi/external-print/init.luau index 43ac11d4..341481ba 100644 --- a/tests/ffi/external_print/init.luau +++ b/tests/ffi/external-print/init.luau @@ -1,18 +1,17 @@ local ffi = require("@lune/ffi") +local c = ffi.c -local testdir = "./tests/ffi/external_print" - +local testdir = "./tests/ffi/external-print" local compile = require("../utility/compile") compile(`{testdir}/lib.c`, `{testdir}/lib.so`) - local lib = ffi.open(`{testdir}/lib.so`) local function test_hello_world() - local hello_world_info = ffi.fnInfo({}, ffi.void) + local hello_world_info = c.fn({}, c.void) local hello_world_callable = hello_world_info:callable(lib:find("hello_world")) - hello_world_callable:call(nil) + hello_world_callable(nil) end test_hello_world() diff --git a/tests/ffi/external_print/lib.c b/tests/ffi/external-print/lib.c similarity index 100% rename from tests/ffi/external_print/lib.c rename to tests/ffi/external-print/lib.c diff --git a/tests/ffi/external-struct/init.luau b/tests/ffi/external-struct/init.luau new file mode 100644 index 00000000..0b3c8290 --- /dev/null +++ b/tests/ffi/external-struct/init.luau @@ -0,0 +1,28 @@ +local ffi = require("@lune/ffi") +local c = ffi.c + +local testdir = "./tests/ffi/external-struct" +local compile = require("../utility/compile") +compile(`{testdir}/lib.c`, `{testdir}/lib.so`) +local lib = ffi.open(`{testdir}/lib.so`) + +local function test_AB() + local ArgStruct = c.struct({ c.int, c.int:ptr() }) + local ResultStruct = c.struct({ c.int, c.int }) + + local AB = c.fn({ ArgStruct }, ResultStruct) + + local AB_callable = AB:callable(lib:find("AB")) + + local resultBox = ffi.box(ResultStruct.size) + local b = c.int:box(200) + local arg = ArgStruct:box({ 100, b:ref() }) + + AB_callable(resultBox, arg:ref()) + local result = ResultStruct:readData(resultBox) + + assert(result[1] == 300, `AB failed. result expected 300, got {result[1]}`) + assert(result[2] == 20000, `AB failed. result expected 300, got {result[2]}`) +end + +test_AB() diff --git a/tests/ffi/external_struct/lib.c b/tests/ffi/external-struct/lib.c similarity index 100% rename from tests/ffi/external_struct/lib.c rename to tests/ffi/external-struct/lib.c diff --git a/tests/ffi/external.luau b/tests/ffi/external.luau deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/ffi/external_struct/init.luau b/tests/ffi/external_struct/init.luau deleted file mode 100644 index 76213dfc..00000000 --- a/tests/ffi/external_struct/init.luau +++ /dev/null @@ -1,30 +0,0 @@ -local ffi = require("@lune/ffi") - -local testdir = "./tests/ffi/external_struct" - -local compile = require("../utility/compile") -compile(`{testdir}/lib.c`, `{testdir}/lib.so`) - -local lib = ffi.open(`{testdir}/lib.so`) - -local function test_AB() - local ArgStruct = ffi.structInfo({ ffi.int, ffi.int:ptrInfo() }) - local ResultStruct = ffi.structInfo({ ffi.int, ffi.int }) - - local AB = ffi.fnInfo({ ArgStruct }, ResultStruct) - - local AB_caller = AB:callable(lib:find("AB")) - - local resultBox = ffi.box(ffi.int.size) - local a = ffi.int:box(100) - local b = ffi.int:box(200) - local arg = ArgStruct:box({ a, b:leak() }) - - AB_caller:call(resultBox, arg) - local result = ResultStruct:readData(resultBox) - - assert(result[0] == 300, `AB failed. result expected 300, got {result}`) - assert(result[1] == 20000, `AB failed. result expected 300, got {result}`) -end - -test_AB() diff --git a/tests/ffi/pretty-print.luau b/tests/ffi/pretty-print.luau index 7e92e32c..bac478b6 100644 --- a/tests/ffi/pretty-print.luau +++ b/tests/ffi/pretty-print.luau @@ -1,29 +1,32 @@ local ffi = require("@lune/ffi") +local c = ffi.c -assert(typeof(ffi.int) == "CType") -assert(tostring(ffi.int) == "int") +assert(typeof(c.int) :: string == "CType") +assert(tostring(c.int) == "int") -assert(typeof(ffi.int:ptr()) == "CPtr") -assert(tostring(ffi.int:ptr()) == "int") -assert(tostring(ffi.int:arr(5):ptr()) == " ") +assert(typeof(c.int:ptr()) :: string == "CPtr") +assert(tostring(c.int:ptr()) == "int") +assert(tostring(c.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(c.int:arr(5)) :: string == "CArr") +assert(tostring(c.int:arr(5)) == " int, length = 5 ") +assert(tostring(c.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(typeof(c.fn({ c.int }, c.int)) :: string == "CFn") +assert(tostring(c.fn({ c.int }, c.int)) == " (int) -> int ") +assert(tostring(c.fn({ c.int, c.double }, c.int)) == " (int, double) -> int ") +assert(tostring(c.fn({ c.int:ptr() }, c.int)) == " () -> int ") +assert(tostring(c.fn({ c.int }, c.int:ptr())) == " (int) -> ") +assert(tostring(c.fn({ c.int:ptr() }, c.int:ptr())) == " () -> ") assert( - tostring(ffi.funcInfo({ ffi.int:ptr(), ffi.int:ptr() }, ffi.int:ptr())) + tostring(c.fn({ c.int:ptr(), c.int:ptr() }, c.int:ptr())) == " (, ) -> " ) -assert(typeof(ffi.structInfo({ ffi.int, ffi.char })) == "CStruct") +assert(typeof(c.struct({ c.int, c.char })) :: string == "CStruct") assert( - tostring(ffi.structInfo({ ffi.int, ffi.char:ptr() })) - == ` int, , size = {ffi.structInfo({ ffi.int, ffi.char:ptr() }).size} ` + tostring(c.struct({ c.int, c.char:ptr() })) + == ` int, , size = {c.struct({ c.int, c.char:ptr() }).size} ` ) + +-- FIXME: add box, ref pretty-print test diff --git a/types/ffi.luau b/types/ffi.luau index b6af6dda..eaa37db6 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -44,7 +44,7 @@ export type CArrInfo = { writeData: (self: CArrInfo, target: (Ref|Box), value: { T }, offset: number?) -> (), copyData: (self: CArrInfo, dst: (Ref|Box), src: (Ref|Box), dst_offset: number?, src_offset: number?) -> (), - offset: (self: CArrInfo, offset: number) -> number, + offset: (self: CArrInfo, index: number) -> number, } export type CFnInfo = { @@ -53,12 +53,18 @@ export type CFnInfo = { } export type CStructInfo = { + size: number, + arr: (self: CStructInfo, len: number) -> CArrInfo, ptr: (self: CStructInfo) -> CPtrInfo, box: (self: CStructInfo, table: { any }) -> Box, readData: (self: CStructInfo, target: (Ref|Box), offset: number?) -> { any }, writeData: (self: CStructInfo, target: (Ref|Box), table: { any }, offset: number?) -> (), + copyData: (self: CStructInfo, dst: (Ref|Box), src: (Ref|Box), dst_offset: number?, src_offset: number?) -> (), + + offset: (self: CStructInfo, index: number) -> number, + field: (self: CStructInfo, index: number) -> CTypes, } export type CVoidInfo = { @@ -163,21 +169,6 @@ export type Closure = { local c = {} -c.u8 = {} :: u8 -c.u16 = {} :: u16 -c.u32 = {} :: u32 -c.u64 = {} :: u64 -c.u128 = {} :: u128 -c.i8 = {} :: i8 -c.i16 = {} :: i16 -c.i32 = {} :: i32 -c.i64 = {} :: i64 -c.i128 = {} :: i128 -c.f32 = {} :: f32 -c.f64 = {} :: f64 -c.usize = {} :: usize -c.isize = {} :: isize - c.char = {} :: char c.float = {} :: float c.double = {} :: double @@ -206,6 +197,21 @@ local ffi = {} ffi.c = c +ffi.u8 = {} :: u8 +ffi.u16 = {} :: u16 +ffi.u32 = {} :: u32 +ffi.u64 = {} :: u64 +ffi.u128 = {} :: u128 +ffi.i8 = {} :: i8 +ffi.i16 = {} :: i16 +ffi.i32 = {} :: i32 +ffi.i64 = {} :: i64 +ffi.i128 = {} :: i128 +ffi.f32 = {} :: f32 +ffi.f64 = {} :: f64 +ffi.usize = {} :: usize +ffi.isize = {} :: isize + function ffi.nullRef(): Ref return nil :: any end From 5002088240776e68199a6afb5cd4c48dc3f7da16 Mon Sep 17 00:00:00 2001 From: qwreey Date: Mon, 21 Oct 2024 15:10:12 +0000 Subject: [PATCH 36/79] Fix closure error (#243) --- crates/lune-std-ffi/README.md | 38 +++++++-------- crates/lune-std-ffi/src/c/fn_info.rs | 2 +- crates/lune-std-ffi/src/data/callable_data.rs | 12 ----- crates/lune-std-ffi/src/data/closure_data.rs | 47 ++++--------------- tests/ffi/README.md | 20 ++++---- tests/ffi/external-closure/lib.c | 14 ------ .../init.luau | 22 +++++++-- tests/ffi/external_closure/lib.c | 12 +++++ .../init.luau | 2 +- .../{external-math => external_math}/lib.c | 0 .../init.luau | 12 ++--- .../lib.c | 0 .../init.luau | 2 +- .../{external-print => external_print}/lib.c | 0 .../init.luau | 2 +- .../lib.c | 0 ...{from-boundary.luau => from_boundary.luau} | 0 ...{into-boundary.luau => into_boundary.luau} | 0 .../{pretty-print.luau => pretty_print.luau} | 0 19 files changed, 78 insertions(+), 107 deletions(-) delete mode 100644 tests/ffi/external-closure/lib.c rename tests/ffi/{external-closure => external_closure}/init.luau (52%) create mode 100644 tests/ffi/external_closure/lib.c rename tests/ffi/{external-math => external_math}/init.luau (96%) rename tests/ffi/{external-math => external_math}/lib.c (100%) rename tests/ffi/{external-pointer => external_pointer}/init.luau (53%) rename tests/ffi/{external-pointer => external_pointer}/lib.c (100%) rename tests/ffi/{external-print => external_print}/init.luau (89%) rename tests/ffi/{external-print => external_print}/lib.c (100%) rename tests/ffi/{external-struct => external_struct}/init.luau (94%) rename tests/ffi/{external-struct => external_struct}/lib.c (100%) rename tests/ffi/{from-boundary.luau => from_boundary.luau} (100%) rename tests/ffi/{into-boundary.luau => into_boundary.luau} (100%) rename tests/ffi/{pretty-print.luau => pretty_print.luau} (100%) diff --git a/crates/lune-std-ffi/README.md b/crates/lune-std-ffi/README.md index 0eca6a96..61ef8afb 100644 --- a/crates/lune-std-ffi/README.md +++ b/crates/lune-std-ffi/README.md @@ -4,6 +4,25 @@ See [tests/ffi](../../tests/ffi/README.md) +## TODO + +- CString + +- Add buffer for owned data support + +- Add math operation. + + > `CTypeInfo:add(target, from1, from2, ...)` and `:sub` `:mul` `:div` `:mod` `:pow` + > Luau cannot handle f64, i64 or i128, so we should provide math operation for it + +- Add bit operation + + > Luau only supports 32bit bit operations + +- Add wchar and wstring support + + > For windows API + ## Code structure ### /c @@ -84,22 +103,3 @@ Implememt type-casting for all CTypes - **Const `FFI_STATUS_NAMES`:** Used for ffi_status stringify - **Function `get_ensured_size`:** Returns ensured ffi_type size - **Const `SIEE_OF_POINTER`:** Platform specific pointer size (Compile time known) - -## TODO - -- CString - -- Add buffer for owned data support - -- Add math operation. - - > `CTypeInfo:add(target, from1, from2, ...)` and `:sub` `:mul` `:div` `:mod` `:pow` - > Luau cannot handle f64, i64 or i128, so we should provide math operation for it - -- Add bit operation - - > Luau only supports 32bit bit operations - -- Add wchar and wstring support - - > For windows API diff --git a/crates/lune-std-ffi/src/c/fn_info.rs b/crates/lune-std-ffi/src/c/fn_info.rs index 3dd5444b..ca787401 100644 --- a/crates/lune-std-ffi/src/c/fn_info.rs +++ b/crates/lune-std-ffi/src/c/fn_info.rs @@ -198,7 +198,7 @@ impl CFnInfo { } pub fn get_middle_type() -> Type { - Type::void() + Type::pointer() } } diff --git a/crates/lune-std-ffi/src/data/callable_data.rs b/crates/lune-std-ffi/src/data/callable_data.rs index 780f4e28..24211434 100644 --- a/crates/lune-std-ffi/src/data/callable_data.rs +++ b/crates/lune-std-ffi/src/data/callable_data.rs @@ -32,10 +32,7 @@ impl CallableData { } } - // TODO? async call: if have no lua closure in arguments, fficallble can be called with async way - pub unsafe fn call(&self, result: LuaValue, args: LuaMultiValue) -> LuaResult<()> { - // cache Vec => unable to create async call but no allocation let mut arg_list = Vec::<*mut c_void>::with_capacity(self.arg_info_list.len()); let result_pointer = if self.result_info.size == 0 { @@ -50,7 +47,6 @@ impl CallableData { .cast::(); for index in 0..self.arg_info_list.len() { - // let arg_info = self.arg_info_list.get(index).unwrap(); let arg_value = args .get(index) .ok_or_else(|| LuaError::external(format!("argument {index} required")))? @@ -59,14 +55,6 @@ impl CallableData { let arg_ref = arg_value.borrow::()?; - // unsafe { - // let argp = arg_ref.get_inner_pointer(); - // let fnr = transmute::<*mut c_void, unsafe extern "C" fn(i32, i32) -> i32>( - // *argp.cast::<*mut c_void>(), - // ); - // dbg!(fnr(1, 2)); - // } - arg_list.push(arg_ref.get_inner_pointer().cast::()); } diff --git a/crates/lune-std-ffi/src/data/closure_data.rs b/crates/lune-std-ffi/src/data/closure_data.rs index 17cc71f4..bd4256f2 100644 --- a/crates/lune-std-ffi/src/data/closure_data.rs +++ b/crates/lune-std-ffi/src/data/closure_data.rs @@ -1,5 +1,5 @@ use core::ffi::c_void; -use std::{borrow::Borrow, mem::transmute, ptr}; +use std::{borrow::Borrow, ptr}; use libffi::{ low::{closure_alloc, closure_free, ffi_cif}, @@ -20,7 +20,7 @@ use crate::ffi::{ pub struct ClosureData { lua: *const Lua, closure: *mut ffi_closure, - code: *mut c_void, + code: Box<*mut c_void>, arg_info_list: Vec, result_info: FfiResult, func: LuaRegistryKey, @@ -44,14 +44,11 @@ unsafe extern "C" fn callback( arg_pointers: *mut *mut c_void, closure_data: *mut c_void, ) { - dbg!("before ud"); let closure_data = closure_data.cast::().as_ref().unwrap(); let lua = closure_data.lua.as_ref().unwrap(); let len = (*cif).nargs as usize; let mut args = Vec::::with_capacity(len + 1); - dbg!("before result", closure_data.result_info.size); - // Push result pointer (ref) args.push(LuaValue::UserData( lua.create_userdata(RefData::new( @@ -62,8 +59,6 @@ unsafe extern "C" fn callback( .unwrap(), )); - dbg!("before arg"); - // Push arg pointer (ref) for i in 0..len { let arg_info = closure_data.arg_info_list.get(i).unwrap(); @@ -77,8 +72,6 @@ unsafe extern "C" fn callback( )); } - dbg!("before call"); - closure_data .func .borrow() @@ -101,51 +94,36 @@ impl ClosureData { let (closure, code) = closure_alloc(); let code = code.as_mut_ptr(); - dbg!(result_info.size); - let closure_data = lua.create_userdata(ClosureData { lua: ptr::from_ref(lua), closure, - code, + code: Box::new(code), arg_info_list, result_info, func, })?; - dbg!(unsafe { - closure_data - .to_pointer() - .cast::() - .as_ref() - .unwrap() - .result_info - .size - }); + let closure_data_ptr = ptr::from_ref(&*closure_data.borrow::()?); ffi_status_assert(unsafe { ffi_prep_closure_loc( closure, cif, Some(callback), - closure_data.to_pointer().cast_mut(), + closure_data_ptr.cast::().cast_mut(), code, ) })?; - unsafe { - // let argp = closure_data.borrow::()?.get_inner_pointer(); - let fnr = transmute::<*mut c_void, unsafe extern "C" fn(i32, i32) -> i32>(code); - dbg!(fnr(1, 2)); - } - Ok(closure_data) } } impl FfiData for ClosureData { unsafe fn get_inner_pointer(&self) -> *mut () { - ptr::from_ref(&self.code).cast_mut().cast::<()>() - // self.code.cast::<()>() + ptr::from_ref::<*mut c_void>(&*self.code) + .cast::<()>() + .cast_mut() } fn check_inner_boundary(&self, offset: isize, size: usize) -> bool { (offset as usize) + size <= SIZE_OF_POINTER @@ -166,15 +144,6 @@ impl LuaUserData for ClosureData { CLOSURE_REF_FLAGS, UNSIZED_BOUNDS, ))?; - unsafe { - let mut b = this.borrow_mut::()?; - b.lua = ptr::from_ref(lua); - let argp = b.get_inner_pointer(); - let fnr = transmute::<*mut c_void, unsafe extern "C" fn(i32, i32) -> i32>( - *argp.cast::<*mut c_void>(), - ); - dbg!(fnr(1, 2)); - } association::set(lua, CLSOURE_REF_INNER, &ref_data, &this)?; Ok(ref_data) }); diff --git a/tests/ffi/README.md b/tests/ffi/README.md index 5b339496..4d093cc4 100644 --- a/tests/ffi/README.md +++ b/tests/ffi/README.md @@ -8,29 +8,29 @@ gcc for library compiling (for external-\*) **External tests** -- [x] tests/ffi/external-math -- [x] tests/ffi/external-pointer -- [x] tests/ffi/external-print -- [x] tests/ffi/external-struct -- [ ] tests/ffi/external-closure +- [x] [external_math](./external_math/init.luau) +- [x] [external_pointer](./external_pointer/init.luau) +- [x] [external_print](./external_print/init.luau) +- [x] [external_struct](./external_struct/init.luau) +- [ ] [external_closure](./external_closure/init.luau) > failed (segfault) **Luau-side** -- [ ] tests/ffi/pretty-print :white_check_mark: +- [ ] [pretty_print](./pretty_print) > need box, ref test -- [x] tests/ffi/isInteger -- [ ] tests/ffi/into-boundary +- [x] [isInteger](./isInteger) +- [ ] [into_boundary](./into_boundary) > need assertion -- [ ] tests/ffi/from-boundary +- [ ] [from_boundary](./from_boundary) > need assertion -- [ ] tests/ffi/cast +- [ ] [cast](./cast) > need assertion diff --git a/tests/ffi/external-closure/lib.c b/tests/ffi/external-closure/lib.c deleted file mode 100644 index 167a2f5f..00000000 --- a/tests/ffi/external-closure/lib.c +++ /dev/null @@ -1,14 +0,0 @@ -#include - -typedef int (*lua_callback_t)(int, int); - -int closure_test(lua_callback_t callback) { - printf("%p\n", callback); - printf("%d\n", callback(12, 24)); - - return callback(12, 24) * 2; -} - -int closure(int a, int b) { - return a+b; -} diff --git a/tests/ffi/external-closure/init.luau b/tests/ffi/external_closure/init.luau similarity index 52% rename from tests/ffi/external-closure/init.luau rename to tests/ffi/external_closure/init.luau index a5783a7c..4a3e4c78 100644 --- a/tests/ffi/external-closure/init.luau +++ b/tests/ffi/external_closure/init.luau @@ -1,6 +1,6 @@ local ffi = require("@lune/ffi") -local testdir = "./tests/ffi/external-closure" +local testdir = "./tests/ffi/external_closure" local compile = require("../utility/compile") compile(`{testdir}/lib.c`, `{testdir}/lib.so`) @@ -15,11 +15,27 @@ local function test_closure() local closure_test_info = ffi.c.fn({ callback_info }, ffi.c.int) - local closure_test_callable = closure_test_info:callable(lib:find("closure_test")) + local closure_test_callable = closure_test_info:callable(lib:find("closure")) local result_box = ffi.box(ffi.c.int.size) closure_test_callable(result_box, callback_closure:ref()) - print(callback_closure) + local result = ffi.c.int:readData(result_box) + assert(result == 72, `test_closure failed. result expected 20000, got {result}`) end test_closure() + +local function test_hello_world() + local callback_info = ffi.c.fn({}, ffi.c.void) + local callback_closure = callback_info:closure(function() + print("Hello world in lua closure!") + end) + + local closure_test_info = ffi.c.fn({ callback_info }, ffi.c.void) + + local closure_test_callable = closure_test_info:callable(lib:find("hello_world")) + + closure_test_callable(nil, callback_closure:ref()) +end + +test_hello_world() diff --git a/tests/ffi/external_closure/lib.c b/tests/ffi/external_closure/lib.c new file mode 100644 index 00000000..f14f1002 --- /dev/null +++ b/tests/ffi/external_closure/lib.c @@ -0,0 +1,12 @@ +#include + +typedef int (*lua_callback_t)(int, int); +typedef void (*lua_hello_world_callback_t)(); + +int closure(lua_callback_t lua_closure) { + return lua_closure(12, 24) * 2; +} + +void hello_world(lua_hello_world_callback_t lua_closure) { + lua_closure(); +} diff --git a/tests/ffi/external-math/init.luau b/tests/ffi/external_math/init.luau similarity index 96% rename from tests/ffi/external-math/init.luau rename to tests/ffi/external_math/init.luau index 1cfd6238..fe486b91 100644 --- a/tests/ffi/external-math/init.luau +++ b/tests/ffi/external_math/init.luau @@ -1,7 +1,7 @@ local ffi = require("@lune/ffi") local c = ffi.c -local testdir = "./tests/ffi/external-math" +local testdir = "./tests/ffi/external_math" local compile = require("../utility/compile") compile(`{testdir}/lib.c`, `{testdir}/lib.so`) local lib = ffi.open(`{testdir}/lib.so`) diff --git a/tests/ffi/external-math/lib.c b/tests/ffi/external_math/lib.c similarity index 100% rename from tests/ffi/external-math/lib.c rename to tests/ffi/external_math/lib.c diff --git a/tests/ffi/external-pointer/init.luau b/tests/ffi/external_pointer/init.luau similarity index 53% rename from tests/ffi/external-pointer/init.luau rename to tests/ffi/external_pointer/init.luau index 57fc7199..a78f7676 100644 --- a/tests/ffi/external-pointer/init.luau +++ b/tests/ffi/external_pointer/init.luau @@ -1,23 +1,23 @@ local ffi = require("@lune/ffi") local c = ffi.c -local testdir = "./tests/ffi/external-pointer" +local testdir = "./tests/ffi/external_pointer" local compile = require("../utility/compile") compile(`{testdir}/lib.c`, `{testdir}/lib.so`) local lib = ffi.open(`{testdir}/lib.so`) -local function test_pointer() - local pointer_info = c.fn({ c.int:ptr() }, c.void) +local function test_pointer_write() + local pointer_write_info = c.fn({ c.int:ptr() }, c.void) - local pointer_callable = pointer_info:callable(lib:find("pointer")) + local pointer_write_callable = pointer_write_info:callable(lib:find("pointer_write")) local a = ffi.box(c.int.size) - pointer_callable(nil, a:ref():ref()) + pointer_write_callable(nil, a:ref():ref()) local result = c.int:readData(a) assert(result == 123, `pointer failed. result expected 123, got {result}`) end -test_pointer() +test_pointer_write() diff --git a/tests/ffi/external-pointer/lib.c b/tests/ffi/external_pointer/lib.c similarity index 100% rename from tests/ffi/external-pointer/lib.c rename to tests/ffi/external_pointer/lib.c diff --git a/tests/ffi/external-print/init.luau b/tests/ffi/external_print/init.luau similarity index 89% rename from tests/ffi/external-print/init.luau rename to tests/ffi/external_print/init.luau index 341481ba..174fdc2c 100644 --- a/tests/ffi/external-print/init.luau +++ b/tests/ffi/external_print/init.luau @@ -1,7 +1,7 @@ local ffi = require("@lune/ffi") local c = ffi.c -local testdir = "./tests/ffi/external-print" +local testdir = "./tests/ffi/external_print" local compile = require("../utility/compile") compile(`{testdir}/lib.c`, `{testdir}/lib.so`) local lib = ffi.open(`{testdir}/lib.so`) diff --git a/tests/ffi/external-print/lib.c b/tests/ffi/external_print/lib.c similarity index 100% rename from tests/ffi/external-print/lib.c rename to tests/ffi/external_print/lib.c diff --git a/tests/ffi/external-struct/init.luau b/tests/ffi/external_struct/init.luau similarity index 94% rename from tests/ffi/external-struct/init.luau rename to tests/ffi/external_struct/init.luau index 0b3c8290..d3ae98ab 100644 --- a/tests/ffi/external-struct/init.luau +++ b/tests/ffi/external_struct/init.luau @@ -1,7 +1,7 @@ local ffi = require("@lune/ffi") local c = ffi.c -local testdir = "./tests/ffi/external-struct" +local testdir = "./tests/ffi/external_struct" local compile = require("../utility/compile") compile(`{testdir}/lib.c`, `{testdir}/lib.so`) local lib = ffi.open(`{testdir}/lib.so`) diff --git a/tests/ffi/external-struct/lib.c b/tests/ffi/external_struct/lib.c similarity index 100% rename from tests/ffi/external-struct/lib.c rename to tests/ffi/external_struct/lib.c diff --git a/tests/ffi/from-boundary.luau b/tests/ffi/from_boundary.luau similarity index 100% rename from tests/ffi/from-boundary.luau rename to tests/ffi/from_boundary.luau diff --git a/tests/ffi/into-boundary.luau b/tests/ffi/into_boundary.luau similarity index 100% rename from tests/ffi/into-boundary.luau rename to tests/ffi/into_boundary.luau diff --git a/tests/ffi/pretty-print.luau b/tests/ffi/pretty_print.luau similarity index 100% rename from tests/ffi/pretty-print.luau rename to tests/ffi/pretty_print.luau From 72fac28dab88387ee71c6099479a635721c5137d Mon Sep 17 00:00:00 2001 From: qwreey Date: Mon, 21 Oct 2024 17:05:53 +0000 Subject: [PATCH 37/79] Add Moonwave annotation partially (#243) --- crates/lune-std-ffi/README.md | 6 +- types/ffi.luau | 139 ++++++++++++++++++++++++++++++++-- 2 files changed, 135 insertions(+), 10 deletions(-) diff --git a/crates/lune-std-ffi/README.md b/crates/lune-std-ffi/README.md index 61ef8afb..546cc596 100644 --- a/crates/lune-std-ffi/README.md +++ b/crates/lune-std-ffi/README.md @@ -85,8 +85,8 @@ Implememt type-casting for all CTypes **Trait `FfiData`:** Provide common data handle, including methods below -- **Method `check_boundary`:** check boundary with offset and size -- **Method `get_pointer`:** returns raw pointer `*mut ()` +- **Method `check_inner_boundary`:** check boundary with offset and size +- **Method `get_inner_pointer`:** returns raw pointer `*mut ()` - **Method `is_writable`** - **Method `is_readable`** @@ -102,4 +102,4 @@ Implememt type-casting for all CTypes - [**Mod `libffi_helper.rs`:**](./src/ffi/libffi_helper.rs) - **Const `FFI_STATUS_NAMES`:** Used for ffi_status stringify - **Function `get_ensured_size`:** Returns ensured ffi_type size - - **Const `SIEE_OF_POINTER`:** Platform specific pointer size (Compile time known) + - **Const `SIZE_OF_POINTER`:** Platform specific pointer size (Compile time known) diff --git a/types/ffi.luau b/types/ffi.luau index eaa37db6..d6db5936 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -22,8 +22,9 @@ export type CPtrInfo = { inner: T, -- subtype - -- FIXME: recursive types; 'any' should be CPtrInfo + -- FIXME: recursive types; result 'any' should be CArrInfo> arr: (self: CPtrInfo, len: number) -> any, + -- FIXME: recursive types; result 'any' should be CPtrInfo> ptr: (self: CPtrInfo) -> any, readRef: (self: CPtrInfo, target: (Ref|Box), offset: number?) -> Ref, @@ -36,12 +37,12 @@ export type CArrInfo = { inner: T, -- subtype - ptr: (self: CArrInfo) -> CPtrInfo, + ptr: (self: CArrInfo) -> CPtrInfo>, -- realize box: (self: CArrInfo, table: { T }) -> Box, readData: (self: CArrInfo, target: (Ref|Box), offset: number?) -> { T }, - writeData: (self: CArrInfo, target: (Ref|Box), value: { T }, offset: number?) -> (), + writeData: (self: CArrInfo, target: (Ref|Box), value: { R }, target_offset: number?) -> (), copyData: (self: CArrInfo, dst: (Ref|Box), src: (Ref|Box), dst_offset: number?, src_offset: number?) -> (), offset: (self: CArrInfo, index: number) -> number, @@ -145,20 +146,82 @@ export type Ref = { isNull: (self: Ref) -> boolean, } +--[=[ + @class Box + + A user manageable heap memory +]=] export type Box = { + --[=[ + @within Box + @tag Field + @field size + + Size of the box. + ]=] size: number, + --[=[ + @within Box + @tag Method + @method zero + + Fill the box with zero. + + @return `Box` itself for convenience + ]=] zero: (self: Box) -> Box, + --[=[ + @within Box + @tag Method + @method leak + + Create a reference of the box after leaking it. + + GC doesn't manage destruction after this action. You must free it later + + @return A reference of the box + ]=] leak: (self: Box, offset: number?) -> Ref, + --[=[ + @within Box + @tag Method + @method ref + + Create a reference of the box. + + @return A reference of the box + ]=] ref: (self: Box, offset: number?) -> Ref, } +--[=[ + @class Lib + + A dynamic opened library handle +]=] export type Lib = { + --[=[ + @within Lib + @tag Method + @method find + + Find a symbol from the dynamic library. + + @param sym The name of the symbol + @return A `Ref` of the found symbol + ]=] find: (self: Lib, sym: string) -> Ref, } -- export type AppliedCallable = ()->() +--[=[ + @class Callable + @tag unsafe + + A callable external function +]=] export type Callable = (ret: (Ref|Box)?, ...Ref)->() & { -- apply: (self: Callable, args: Args)->AppliedCallable, } @@ -167,6 +230,12 @@ export type Closure = { ref: (self: Closure)->Ref, } +--[=[ + @class C + @within FFI + + Namespace for compile time sized c types. +]=] local c = {} c.char = {} :: char @@ -185,14 +254,41 @@ c.ulonglong = {} :: ulonglong c.void = {} :: CVoidInfo +--[=[ + @within C + + Create a function signature type information. + + @param args An array of CTypes represents the arguments of the function + @param ret The return type of the function + @return A function signature type information +]=] function c.fn(args: { CTypes }, ret: CTypes): CFnInfo return nil :: any end -function c.struct(inner: { CTypes }): CStructInfo +--[=[ + @within C + + Create a struct type information. + + @param fields An array of CTypes represents the fields of the struct + @return A struct type information +]=] +function c.struct(fields: { CTypes }): CStructInfo return nil :: any end +--[=[ + @class FFI + + Built-in library for foreign function interface + + ### Example usage + + ```lua + ``` +]=] local ffi = {} ffi.c = c @@ -212,22 +308,51 @@ ffi.f64 = {} :: f64 ffi.usize = {} :: usize ffi.isize = {} :: isize +--[=[ + @within FFI + + Create a `Ref` with address 0. + + Can be used for receive a pointer from external function or pass it as an argument. + + @return A zero initialized Ref +]=] function ffi.nullRef(): Ref return nil :: any end +--[=[ + @within FFI + + Create a `Box` with specific size. + + @param size The size of the new box + @return A allocated box +]=] function ffi.box(size: number): Box return nil :: any end +--[=[ + @within FFI + + Open a dynamic library. + + @param name The name of the target library + @return A dynamic library handle +]=] function ffi.open(name: string): Lib return nil :: any end -function ffi.uninitRef(): Ref - return nil :: any -end +--[=[ + @within FFI + + Return `true` if the second argument is an integer (i32) + @param val A lua value to check + @return Whether val is an integer or not +]=] function ffi.isInteger(val: T): boolean return nil :: any end From 12bf3bd9efb8b584811031f2fc3d99727e838e8a Mon Sep 17 00:00:00 2001 From: qwreey Date: Mon, 21 Oct 2024 18:40:02 +0000 Subject: [PATCH 38/79] Add gitignore for core dump file, Callable optimization (#243) --- .gitignore | 4 + crates/lune-std-ffi/src/data/callable_data.rs | 103 +++++++++++++++++- 2 files changed, 104 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index ba748c2d..b7719c3c 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,7 @@ scripts/physical_properties_enum_map.rs # Files generated by tests /tests/ffi/**/*.so + +# Core dump file + +/core diff --git a/crates/lune-std-ffi/src/data/callable_data.rs b/crates/lune-std-ffi/src/data/callable_data.rs index 24211434..f94d420d 100644 --- a/crates/lune-std-ffi/src/data/callable_data.rs +++ b/crates/lune-std-ffi/src/data/callable_data.rs @@ -1,5 +1,8 @@ use core::ffi::c_void; -use std::ptr; +use std::{ + mem::{self, MaybeUninit}, + ptr, +}; use libffi::{ low::{ffi_cif, CodePtr}, @@ -17,6 +20,95 @@ pub struct CallableData { code: CodePtr, } +const VOID_RESULT_PTR: *mut () = ptr::null_mut(); +const ZERO_SIZE_ARG_PTR: *mut *mut c_void = ptr::null_mut(); + +macro_rules! create_caller { + ($len:expr) => { + |callable: &CallableData, result: LuaValue, args: LuaMultiValue| unsafe { + let mut arg_list: [MaybeUninit<*mut c_void>; $len] = [MaybeUninit::uninit(); $len]; + + let result_pointer = if callable.result_info.size == 0 { + VOID_RESULT_PTR + } else { + let result_data = result.get_ffi_data()?; + if !result_data.check_inner_boundary(0, callable.result_info.size) { + return Err(LuaError::external("Result boundary check failed")); + } + result_data.get_inner_pointer() + } + .cast::(); + + for (index, arg) in arg_list.iter_mut().enumerate() { + let arg_value = args + .get(index) + .ok_or_else(|| LuaError::external(format!("argument {index} required")))? + .as_userdata() + .ok_or_else(|| LuaError::external("argument should be Ref"))?; + + let arg_ref = arg_value.borrow::()?; + + arg.write(arg_ref.get_inner_pointer().cast::()); + } + + ffi_call( + callable.cif, + Some(*callable.code.as_safe_fun()), + result_pointer, + // SAFETY: MaybeUninit has the same layout as `T`, and initialized above + mem::transmute::<[MaybeUninit<*mut c_void>; $len], [*mut c_void; $len]>(arg_list) + .as_mut_ptr(), + ); + + Ok(()) + } + }; +} + +unsafe fn zero_size_caller( + callable: &CallableData, + result: LuaValue, + _args: LuaMultiValue, +) -> LuaResult<()> { + let result_pointer = if callable.result_info.size == 0 { + VOID_RESULT_PTR + } else { + let result_data = result.get_ffi_data()?; + if !result_data.check_inner_boundary(0, callable.result_info.size) { + return Err(LuaError::external("Result boundary check failed")); + } + result_data.get_inner_pointer() + } + .cast::(); + + ffi_call( + callable.cif, + Some(*callable.code.as_safe_fun()), + result_pointer, + ZERO_SIZE_ARG_PTR, + ); + + Ok(()) +} + +type Caller = + unsafe fn(callable: &CallableData, result: LuaValue, args: LuaMultiValue) -> LuaResult<()>; +const SIZED_CALLERS: [Caller; 13] = [ + zero_size_caller, + create_caller!(1), + create_caller!(2), + create_caller!(3), + create_caller!(4), + create_caller!(5), + create_caller!(6), + create_caller!(7), + create_caller!(8), + create_caller!(9), + create_caller!(10), + create_caller!(11), + create_caller!(12), +]; + impl CallableData { pub unsafe fn new( cif: *mut ffi_cif, @@ -33,10 +125,15 @@ impl CallableData { } pub unsafe fn call(&self, result: LuaValue, args: LuaMultiValue) -> LuaResult<()> { - let mut arg_list = Vec::<*mut c_void>::with_capacity(self.arg_info_list.len()); + let arg_len = self.arg_info_list.len(); + if arg_len < SIZED_CALLERS.len() { + return SIZED_CALLERS[arg_len](self, result, args); + } + + let mut arg_list = Vec::<*mut c_void>::with_capacity(arg_len); let result_pointer = if self.result_info.size == 0 { - ptr::null_mut() + VOID_RESULT_PTR } else { let result_data = result.get_ffi_data()?; if !result_data.check_inner_boundary(0, self.result_info.size) { From 706efaf1e9fc97ad4273d14ee9603dc4a281c853 Mon Sep 17 00:00:00 2001 From: qwreey Date: Mon, 21 Oct 2024 19:58:23 +0000 Subject: [PATCH 39/79] Fix formatting (#243) --- crates/lune-std-ffi/src/c/string_info.rs | 1 + crates/lune-std-ffi/src/c/types/f32.rs | 25 +++++++++++++++++++----- crates/lune-std-ffi/src/c/types/f64.rs | 25 +++++++++++++++++++----- crates/lune-std-ffi/src/c/types/i128.rs | 25 +++++++++++++++++++----- crates/lune-std-ffi/src/c/types/i16.rs | 25 +++++++++++++++++++----- crates/lune-std-ffi/src/c/types/i32.rs | 25 +++++++++++++++++++----- crates/lune-std-ffi/src/c/types/i64.rs | 25 +++++++++++++++++++----- crates/lune-std-ffi/src/c/types/u128.rs | 25 +++++++++++++++++++----- crates/lune-std-ffi/src/c/types/u16.rs | 25 +++++++++++++++++++----- crates/lune-std-ffi/src/c/types/u64.rs | 25 +++++++++++++++++++----- crates/lune-std-ffi/src/c/types/u8.rs | 20 +++++++++++++++---- 11 files changed, 197 insertions(+), 49 deletions(-) diff --git a/crates/lune-std-ffi/src/c/string_info.rs b/crates/lune-std-ffi/src/c/string_info.rs index e69de29b..8b137891 100644 --- a/crates/lune-std-ffi/src/c/string_info.rs +++ b/crates/lune-std-ffi/src/c/string_info.rs @@ -0,0 +1 @@ + diff --git a/crates/lune-std-ffi/src/c/types/f32.rs b/crates/lune-std-ffi/src/c/types/f32.rs index 10c12342..6352e5b2 100644 --- a/crates/lune-std-ffi/src/c/types/f32.rs +++ b/crates/lune-std-ffi/src/c/types/f32.rs @@ -37,7 +37,10 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_inner_pointer().byte_offset(offset).cast::()) = value; + *(data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) = value; } Ok(()) } @@ -49,7 +52,11 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult> { let value = unsafe { - (*data_handle.get_inner_pointer().byte_offset(offset).cast::()).into_lua(lua)? + (*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .into_lua(lua)? }; Ok(value) } @@ -61,8 +68,12 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = - *src.get_inner_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer() + .byte_offset(dst_offset) + .cast::() = *src + .get_inner_pointer() + .byte_offset(src_offset) + .cast::(); Ok(()) } unsafe fn stringify_data( @@ -71,6 +82,10 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_inner_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .to_string()) } } diff --git a/crates/lune-std-ffi/src/c/types/f64.rs b/crates/lune-std-ffi/src/c/types/f64.rs index ccbe4316..8657052a 100644 --- a/crates/lune-std-ffi/src/c/types/f64.rs +++ b/crates/lune-std-ffi/src/c/types/f64.rs @@ -37,7 +37,10 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_inner_pointer().byte_offset(offset).cast::()) = value; + *(data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) = value; } Ok(()) } @@ -49,7 +52,11 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult> { let value = unsafe { - (*data_handle.get_inner_pointer().byte_offset(offset).cast::()).into_lua(lua)? + (*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .into_lua(lua)? }; Ok(value) } @@ -61,8 +68,12 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = - *src.get_inner_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer() + .byte_offset(dst_offset) + .cast::() = *src + .get_inner_pointer() + .byte_offset(src_offset) + .cast::(); Ok(()) } unsafe fn stringify_data( @@ -71,6 +82,10 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_inner_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .to_string()) } } diff --git a/crates/lune-std-ffi/src/c/types/i128.rs b/crates/lune-std-ffi/src/c/types/i128.rs index 1ceeaaf4..17eb8884 100644 --- a/crates/lune-std-ffi/src/c/types/i128.rs +++ b/crates/lune-std-ffi/src/c/types/i128.rs @@ -37,7 +37,10 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_inner_pointer().byte_offset(offset).cast::()) = value; + *(data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) = value; } Ok(()) } @@ -49,7 +52,11 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult> { let value = unsafe { - (*data_handle.get_inner_pointer().byte_offset(offset).cast::()).into_lua(lua)? + (*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .into_lua(lua)? }; Ok(value) } @@ -61,8 +68,12 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = - *src.get_inner_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer() + .byte_offset(dst_offset) + .cast::() = *src + .get_inner_pointer() + .byte_offset(src_offset) + .cast::(); Ok(()) } unsafe fn stringify_data( @@ -71,6 +82,10 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_inner_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .to_string()) } } diff --git a/crates/lune-std-ffi/src/c/types/i16.rs b/crates/lune-std-ffi/src/c/types/i16.rs index 2cc5ed88..39035b52 100644 --- a/crates/lune-std-ffi/src/c/types/i16.rs +++ b/crates/lune-std-ffi/src/c/types/i16.rs @@ -37,7 +37,10 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_inner_pointer().byte_offset(offset).cast::()) = value; + *(data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) = value; } Ok(()) } @@ -49,7 +52,11 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult> { let value = unsafe { - (*data_handle.get_inner_pointer().byte_offset(offset).cast::()).into_lua(lua)? + (*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .into_lua(lua)? }; Ok(value) } @@ -61,8 +68,12 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = - *src.get_inner_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer() + .byte_offset(dst_offset) + .cast::() = *src + .get_inner_pointer() + .byte_offset(src_offset) + .cast::(); Ok(()) } unsafe fn stringify_data( @@ -71,6 +82,10 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_inner_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .to_string()) } } diff --git a/crates/lune-std-ffi/src/c/types/i32.rs b/crates/lune-std-ffi/src/c/types/i32.rs index 7cbfa81e..4dae14ac 100644 --- a/crates/lune-std-ffi/src/c/types/i32.rs +++ b/crates/lune-std-ffi/src/c/types/i32.rs @@ -37,7 +37,10 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_inner_pointer().byte_offset(offset).cast::()) = value; + *(data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) = value; } Ok(()) } @@ -49,7 +52,11 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult> { let value = unsafe { - (*data_handle.get_inner_pointer().byte_offset(offset).cast::()).into_lua(lua)? + (*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .into_lua(lua)? }; Ok(value) } @@ -61,8 +68,12 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = - *src.get_inner_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer() + .byte_offset(dst_offset) + .cast::() = *src + .get_inner_pointer() + .byte_offset(src_offset) + .cast::(); Ok(()) } unsafe fn stringify_data( @@ -71,6 +82,10 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_inner_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .to_string()) } } diff --git a/crates/lune-std-ffi/src/c/types/i64.rs b/crates/lune-std-ffi/src/c/types/i64.rs index cc16c988..3e353101 100644 --- a/crates/lune-std-ffi/src/c/types/i64.rs +++ b/crates/lune-std-ffi/src/c/types/i64.rs @@ -37,7 +37,10 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_inner_pointer().byte_offset(offset).cast::()) = value; + *(data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) = value; } Ok(()) } @@ -49,7 +52,11 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult> { let value = unsafe { - (*data_handle.get_inner_pointer().byte_offset(offset).cast::()).into_lua(lua)? + (*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .into_lua(lua)? }; Ok(value) } @@ -61,8 +68,12 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = - *src.get_inner_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer() + .byte_offset(dst_offset) + .cast::() = *src + .get_inner_pointer() + .byte_offset(src_offset) + .cast::(); Ok(()) } unsafe fn stringify_data( @@ -71,6 +82,10 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_inner_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .to_string()) } } diff --git a/crates/lune-std-ffi/src/c/types/u128.rs b/crates/lune-std-ffi/src/c/types/u128.rs index 880bb05f..78851f0a 100644 --- a/crates/lune-std-ffi/src/c/types/u128.rs +++ b/crates/lune-std-ffi/src/c/types/u128.rs @@ -37,7 +37,10 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_inner_pointer().byte_offset(offset).cast::()) = value; + *(data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) = value; } Ok(()) } @@ -49,7 +52,11 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult> { let value = unsafe { - (*data_handle.get_inner_pointer().byte_offset(offset).cast::()).into_lua(lua)? + (*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .into_lua(lua)? }; Ok(value) } @@ -61,8 +68,12 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = - *src.get_inner_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer() + .byte_offset(dst_offset) + .cast::() = *src + .get_inner_pointer() + .byte_offset(src_offset) + .cast::(); Ok(()) } unsafe fn stringify_data( @@ -71,6 +82,10 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_inner_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .to_string()) } } diff --git a/crates/lune-std-ffi/src/c/types/u16.rs b/crates/lune-std-ffi/src/c/types/u16.rs index 9a367b32..2a9dc044 100644 --- a/crates/lune-std-ffi/src/c/types/u16.rs +++ b/crates/lune-std-ffi/src/c/types/u16.rs @@ -38,7 +38,10 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_inner_pointer().byte_offset(offset).cast::()) = value; + *(data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) = value; } Ok(()) } @@ -50,7 +53,11 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult> { let value = unsafe { - (*data_handle.get_inner_pointer().byte_offset(offset).cast::()).into_lua(lua)? + (*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .into_lua(lua)? }; Ok(value) } @@ -62,8 +69,12 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = - *src.get_inner_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer() + .byte_offset(dst_offset) + .cast::() = *src + .get_inner_pointer() + .byte_offset(src_offset) + .cast::(); Ok(()) } unsafe fn stringify_data( @@ -72,6 +83,10 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_inner_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .to_string()) } } diff --git a/crates/lune-std-ffi/src/c/types/u64.rs b/crates/lune-std-ffi/src/c/types/u64.rs index ef08a104..07911b5f 100644 --- a/crates/lune-std-ffi/src/c/types/u64.rs +++ b/crates/lune-std-ffi/src/c/types/u64.rs @@ -37,7 +37,10 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_inner_pointer().byte_offset(offset).cast::()) = value; + *(data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) = value; } Ok(()) } @@ -49,7 +52,11 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult> { let value = unsafe { - (*data_handle.get_inner_pointer().byte_offset(offset).cast::()).into_lua(lua)? + (*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .into_lua(lua)? }; Ok(value) } @@ -61,8 +68,12 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = - *src.get_inner_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer() + .byte_offset(dst_offset) + .cast::() = *src + .get_inner_pointer() + .byte_offset(src_offset) + .cast::(); Ok(()) } unsafe fn stringify_data( @@ -71,6 +82,10 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_inner_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .to_string()) } } diff --git a/crates/lune-std-ffi/src/c/types/u8.rs b/crates/lune-std-ffi/src/c/types/u8.rs index b1e421eb..a9d575b3 100644 --- a/crates/lune-std-ffi/src/c/types/u8.rs +++ b/crates/lune-std-ffi/src/c/types/u8.rs @@ -34,7 +34,10 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_inner_pointer().byte_offset(offset).cast::()) = value; + *(data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) = value; } Ok(()) } @@ -47,8 +50,13 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult> { - let value = - unsafe { (*data_handle.get_inner_pointer().byte_offset(offset).cast::()).into_lua(lua)? }; + let value = unsafe { + (*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .into_lua(lua)? + }; Ok(value) } unsafe fn copy_data( @@ -69,6 +77,10 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_inner_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .to_string()) } } From 144f49a11d88975f9c36ad6e2741c62af3c4b750 Mon Sep 17 00:00:00 2001 From: qwreey Date: Mon, 21 Oct 2024 21:05:55 +0000 Subject: [PATCH 40/79] More moonwave docs (#243) --- crates/lune-std-ffi/src/c/types/isize.rs | 8 +- crates/lune-std-ffi/src/c/types/u32.rs | 25 +- types/ffi.luau | 460 ++++++++++++++--------- 3 files changed, 314 insertions(+), 179 deletions(-) diff --git a/crates/lune-std-ffi/src/c/types/isize.rs b/crates/lune-std-ffi/src/c/types/isize.rs index 3ded3134..9c363eaa 100644 --- a/crates/lune-std-ffi/src/c/types/isize.rs +++ b/crates/lune-std-ffi/src/c/types/isize.rs @@ -68,8 +68,12 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = - *src.get_inner_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer() + .byte_offset(dst_offset) + .cast::() = *src + .get_inner_pointer() + .byte_offset(src_offset) + .cast::(); Ok(()) } unsafe fn stringify_data( diff --git a/crates/lune-std-ffi/src/c/types/u32.rs b/crates/lune-std-ffi/src/c/types/u32.rs index 59c7691a..04e95483 100644 --- a/crates/lune-std-ffi/src/c/types/u32.rs +++ b/crates/lune-std-ffi/src/c/types/u32.rs @@ -37,7 +37,10 @@ impl FfiConvert for CTypeInfo { } }; unsafe { - *(data_handle.get_inner_pointer().byte_offset(offset).cast::()) = value; + *(data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) = value; } Ok(()) } @@ -49,7 +52,11 @@ impl FfiConvert for CTypeInfo { data_handle: &Ref, ) -> LuaResult> { let value = unsafe { - (*data_handle.get_inner_pointer().byte_offset(offset).cast::()).into_lua(lua)? + (*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .into_lua(lua)? }; Ok(value) } @@ -61,8 +68,12 @@ impl FfiConvert for CTypeInfo { dst: &Ref, src: &Ref, ) -> LuaResult<()> { - *dst.get_inner_pointer().byte_offset(dst_offset).cast::() = - *src.get_inner_pointer().byte_offset(src_offset).cast::(); + *dst.get_inner_pointer() + .byte_offset(dst_offset) + .cast::() = *src + .get_inner_pointer() + .byte_offset(src_offset) + .cast::(); Ok(()) } unsafe fn stringify_data( @@ -71,6 +82,10 @@ impl FfiConvert for CTypeInfo { offset: isize, data_handle: &Ref, ) -> LuaResult { - Ok((*data_handle.get_inner_pointer().byte_offset(offset).cast::()).to_string()) + Ok((*data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::()) + .to_string()) } } diff --git a/types/ffi.luau b/types/ffi.luau index d6db5936..8cbabbbc 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -1,3 +1,131 @@ +--[=[ + @class FFI + + Built-in library for foreign function interface + + ### Example usage + + ```lua + ``` +]=] +local ffi = {} + +--[=[ + @class C + @within FFI + + Namespace for compile time sized c types. +]=] +local c = {} +ffi.c = c + +--#region Data -- + +--[=[ + @class RefData + + A user manageable memory reference +]=] +export type RefData = { + deref: (self: RefData) -> RefData, + offset: (self: RefData, offset: number) -> RefData, + ref: (self: RefData) -> RefData, + isNull: (self: RefData) -> boolean, +} + +--[=[ + @class BoxData + + A user manageable heap memory +]=] +export type BoxData = { + --[=[ + @within BoxData + @tag Field + @field size + + Size of the box. + ]=] + size: number, + + --[=[ + @within BoxData + @tag Method + @method zero + + Fill the box with zero. + + @return `Box` itself for convenience + ]=] + zero: (self: BoxData) -> BoxData, + --[=[ + @within BoxData + @tag Method + @method leak + + Create a reference of the box after leaking it. + + GC doesn't manage destruction after this action. You must free it later + + @return A reference of the box + ]=] + leak: (self: BoxData, offset: number?) -> RefData, + --[=[ + @within BoxData + @tag Method + @method ref + + Create a reference of the box. + + @return A reference of the box + ]=] + ref: (self: BoxData, offset: number?) -> RefData, +} + +--[=[ + @class LibData + + A dynamic opened library handle +]=] +export type LibData = { + --[=[ + @within LibData + @tag Method + @method find + + Find a symbol from the dynamic library. + + @param sym The name of the symbol + @return A `Ref` of the found symbol + ]=] + find: (self: LibData, sym: string) -> RefData, +} + +-- export type AppliedCallable = ()->() + +--[=[ + @class CallableData + @tag unsafe + + A callable external function +]=] +export type CallableData = (ret: (RefData|BoxData)?, ...RefData)->() & { + -- apply: (self: Callable, args: Args)->AppliedCallable, +} + +--[=[ + @class ClosureData + + A lua function wrapper for function pointer +]=] +export type ClosureData = { + ref: (self: ClosureData)->RefData, +} + +--#endregion Data -- + +--#region C ABI Type Infos -- + -- NOTE: T is a unique identifier for the `CType` and R is the closest Lua type. export type CTypeInfo = { size: number, @@ -8,14 +136,15 @@ export type CTypeInfo = { arr: (self: CTypeInfo, len: number) -> CArrInfo, R>, -- realize - box: (self: CTypeInfo, val: R) -> Box, - readData: (self: CTypeInfo, target: (Ref|Box), offset: number?) -> R, - writeData: (self: CTypeInfo, target: (Ref|Box), value: R, offset: number?) -> (), - stringifyData: (self: CTypeInfo, target: (Ref|Box), offset: number?) -> string, + box: (self: CTypeInfo, val: R) -> BoxData, + readData: (self: CTypeInfo, target: (RefData|BoxData), offset: number?) -> R, + writeData: (self: CTypeInfo, target: (RefData|BoxData), value: R, offset: number?) -> (), + stringifyData: (self: CTypeInfo, target: (RefData|BoxData), offset: number?) -> string, -- FIXME: recursive types; 'intoType' should be CTypes - cast: (self: CTypeInfo, intoType: any, fromData: (Ref|Box), intoData: (Ref|Box)) -> (), + cast: (self: CTypeInfo, intoType: any, fromData: (RefData|BoxData), intoData: (RefData|BoxData)) -> (), } & { ["__phantom"]: T } +type NumCType = CTypeInfo export type CPtrInfo = { size: number, @@ -27,8 +156,8 @@ export type CPtrInfo = { -- FIXME: recursive types; result 'any' should be CPtrInfo> ptr: (self: CPtrInfo) -> any, - readRef: (self: CPtrInfo, target: (Ref|Box), offset: number?) -> Ref, - writeRef: (self: CPtrInfo, target: (Ref|Box), value: (Ref|Box), offset: number?) -> (), + readRef: (self: CPtrInfo, target: (RefData|BoxData), offset: number?) -> RefData, + writeRef: (self: CPtrInfo, target: (RefData|BoxData), value: (RefData|BoxData), offset: number?) -> (), } export type CArrInfo = { @@ -40,17 +169,17 @@ export type CArrInfo = { ptr: (self: CArrInfo) -> CPtrInfo>, -- realize - box: (self: CArrInfo, table: { T }) -> Box, - readData: (self: CArrInfo, target: (Ref|Box), offset: number?) -> { T }, - writeData: (self: CArrInfo, target: (Ref|Box), value: { R }, target_offset: number?) -> (), - copyData: (self: CArrInfo, dst: (Ref|Box), src: (Ref|Box), dst_offset: number?, src_offset: number?) -> (), + box: (self: CArrInfo, table: { T }) -> BoxData, + readData: (self: CArrInfo, target: (RefData|BoxData), offset: number?) -> { T }, + writeData: (self: CArrInfo, target: (RefData|BoxData), value: { R }, target_offset: number?) -> (), + copyData: (self: CArrInfo, dst: (RefData|BoxData), src: (RefData|BoxData), dst_offset: number?, src_offset: number?) -> (), offset: (self: CArrInfo, index: number) -> number, } export type CFnInfo = { - callable: (self: CFnInfo, functionRef: Ref) -> Callable, - closure: (self: CFnInfo, (ret: Ref, ...Ref)->()) -> Closure, + callable: (self: CFnInfo, functionRef: RefData) -> CallableData, + closure: (self: CFnInfo, (ret: RefData, ...RefData)->()) -> ClosureData, } export type CStructInfo = { @@ -59,52 +188,184 @@ export type CStructInfo = { arr: (self: CStructInfo, len: number) -> CArrInfo, ptr: (self: CStructInfo) -> CPtrInfo, - box: (self: CStructInfo, table: { any }) -> Box, - readData: (self: CStructInfo, target: (Ref|Box), offset: number?) -> { any }, - writeData: (self: CStructInfo, target: (Ref|Box), table: { any }, offset: number?) -> (), - copyData: (self: CStructInfo, dst: (Ref|Box), src: (Ref|Box), dst_offset: number?, src_offset: number?) -> (), + box: (self: CStructInfo, table: { any }) -> BoxData, + readData: (self: CStructInfo, target: (RefData|BoxData), offset: number?) -> { any }, + writeData: (self: CStructInfo, target: (RefData|BoxData), table: { any }, offset: number?) -> (), + copyData: (self: CStructInfo, dst: (RefData|BoxData), src: (RefData|BoxData), dst_offset: number?, src_offset: number?) -> (), offset: (self: CStructInfo, index: number) -> number, field: (self: CStructInfo, index: number) -> CTypes, } +--[=[ + @class CVoidInfo + + A type that represents c void. can only be used for the function return type. +]=] export type CVoidInfo = { + --[=[ + @within CVoidInfo + @tag Method + @method ptr + + Create a generic pointer type + + @return Generic pointer type + ]=] ptr: (self: CVoidInfo) -> CPtrInfo, } +c.void = {} :: CVoidInfo -type NumCType = CTypeInfo +--#endregion C ABI Type Infos -- + +--#region Fixed size Rust-style types -- + +--[=[ + @class u8 + @within FFI --- Fixed size Rust-style types -- + A 8-bit sized unsigned integer, Equivalent to `uint8_t` in `stdint` +]=] +ffi.u8 = {} :: u8 export type u8 = NumCType<"u8"> +--[=[ + @class u16 + @within FFI + + A 16-bit sized unsigned integer, Equivalent to `uint16_t` in `stdint` +]=] +ffi.u16 = {} :: u16 export type u16 = NumCType<"u16"> +--[=[ + @class u32 + @within FFI + + A 32-bit sized unsigned integer, Equivalent to `uint32_t` in `stdint` +]=] +ffi.u32 = {} :: u32 export type u32 = NumCType<"u32"> +--[=[ + @class u64 + @within FFI + + A 64-bit sized unsigned integer, Equivalent to `uint64_t` in `stdint` +]=] +ffi.u64 = {} :: u64 export type u64 = NumCType<"u64"> +--[=[ + @class u128 + @within FFI + + A 128-bit sized unsigned integer, Equivalent to `uint128_t` in `stdint` +]=] +ffi.u128 = {} :: u128 export type u128 = NumCType<"u128"> +--[=[ + @class i8 + @within FFI + + A 8-bit sized signed integer, Equivalent to `int8_t` in `stdint` +]=] +ffi.i8 = {} :: i8 export type i8 = NumCType<"i8"> +--[=[ + @class i16 + @within FFI + + A 16-bit sized signed integer, Equivalent to `int16_t` in `stdint` +]=] +ffi.i16 = {} :: i16 export type i16 = NumCType<"i16"> +--[=[ + @class i32 + @within FFI + + A 32-bit sized signed integer, Equivalent to `int32_t` in `stdint` +]=] +ffi.i32 = {} :: i32 export type i32 = NumCType<"i32"> +--[=[ + @class i64 + @within FFI + + A 64-bit sized signed integer, Equivalent to `int64_t` in `stdint` +]=] +ffi.i64 = {} :: i64 export type i64 = NumCType<"i64"> +--[=[ + @class i128 + @within FFI + + A 128-bit sized signed integer, Equivalent to `int128_t` in `stdint` +]=] +ffi.i128 = {} :: i128 export type i128 = NumCType<"i128"> +--[=[ + @class f32 + @within FFI + + A single-precision 32-bit sized floating-point, Almost always equivalent to `float` in C +]=] +ffi.f32 = {} :: f32 export type f32 = NumCType<"f32"> +--[=[ + @class f64 + @within FFI + + A double-precision 64-bit sized floating-point, Almost always equivalent to `double` in C +]=] +ffi.f64 = {} :: f64 export type f64 = NumCType<"f64"> +--[=[ + @class usize + @within FFI + + A machine specific pointer sized unsigned integer, +]=] +ffi.usize = {} :: usize export type usize = NumCType<"usize"> +--[=[ + @class isize + @within FFI + + A machine specific pointer sized signed integer, +]=] +ffi.isize = {} :: isize export type isize = NumCType<"isize"> --- Variable size C-style types -- +--#endregion Fixed size Rust-style types -- + +--#region Variable size C-style types -- + +c.char = {} :: char export type char = NumCType<"char"> -export type float = NumCType<"float"> -export type double = NumCType<"double"> +-- c.float = {} :: float +-- export type float = NumCType<"float"> +-- c.double = {} :: double +-- export type double = NumCType<"double"> +c.uchar = {} :: uchar export type uchar = NumCType<"uchar"> +c.schar = {} :: schar export type schar = NumCType<"schar"> +c.short = {} :: short export type short = NumCType<"short"> +c.ushort = {} :: ushort export type ushort = NumCType<"ushort"> +c.int = {} :: int export type int = NumCType<"int"> +c.uint = {} :: uint export type uint = NumCType<"uint"> +c.long = {} :: long export type long = NumCType<"long"> +c.ulong = {} :: ulong export type ulong = NumCType<"ulong"> +c.longlong = {} :: longlong export type longlong = NumCType<"longlong"> +c.ulonglong = {} :: ulonglong export type ulonglong = NumCType<"ulonglong"> +--#endregion Variable size C-style types -- + export type CTypes = | u8 | u16 @@ -121,8 +382,8 @@ export type CTypes = | usize | isize | char - | float - | double + -- | float + -- | double | uchar | schar | short @@ -139,121 +400,6 @@ export type CTypes = | CStructInfo | CVoidInfo -export type Ref = { - deref: (self: Ref) -> Ref, - offset: (self: Ref, offset: number) -> Ref, - ref: (self: Ref) -> Ref, - isNull: (self: Ref) -> boolean, -} - ---[=[ - @class Box - - A user manageable heap memory -]=] -export type Box = { - --[=[ - @within Box - @tag Field - @field size - - Size of the box. - ]=] - size: number, - - --[=[ - @within Box - @tag Method - @method zero - - Fill the box with zero. - - @return `Box` itself for convenience - ]=] - zero: (self: Box) -> Box, - --[=[ - @within Box - @tag Method - @method leak - - Create a reference of the box after leaking it. - - GC doesn't manage destruction after this action. You must free it later - - @return A reference of the box - ]=] - leak: (self: Box, offset: number?) -> Ref, - --[=[ - @within Box - @tag Method - @method ref - - Create a reference of the box. - - @return A reference of the box - ]=] - ref: (self: Box, offset: number?) -> Ref, -} - ---[=[ - @class Lib - - A dynamic opened library handle -]=] -export type Lib = { - --[=[ - @within Lib - @tag Method - @method find - - Find a symbol from the dynamic library. - - @param sym The name of the symbol - @return A `Ref` of the found symbol - ]=] - find: (self: Lib, sym: string) -> Ref, -} - --- export type AppliedCallable = ()->() - ---[=[ - @class Callable - @tag unsafe - - A callable external function -]=] -export type Callable = (ret: (Ref|Box)?, ...Ref)->() & { - -- apply: (self: Callable, args: Args)->AppliedCallable, -} - -export type Closure = { - ref: (self: Closure)->Ref, -} - ---[=[ - @class C - @within FFI - - Namespace for compile time sized c types. -]=] -local c = {} - -c.char = {} :: char -c.float = {} :: float -c.double = {} :: double -c.uchar = {} :: uchar -c.schar = {} :: schar -c.short = {} :: short -c.ushort = {} :: ushort -c.int = {} :: int -c.uint = {} :: uint -c.long = {} :: long -c.ulong = {} :: ulong -c.longlong = {} :: longlong -c.ulonglong = {} :: ulonglong - -c.void = {} :: CVoidInfo - --[=[ @within C @@ -279,35 +425,6 @@ function c.struct(fields: { CTypes }): CStructInfo return nil :: any end ---[=[ - @class FFI - - Built-in library for foreign function interface - - ### Example usage - - ```lua - ``` -]=] -local ffi = {} - -ffi.c = c - -ffi.u8 = {} :: u8 -ffi.u16 = {} :: u16 -ffi.u32 = {} :: u32 -ffi.u64 = {} :: u64 -ffi.u128 = {} :: u128 -ffi.i8 = {} :: i8 -ffi.i16 = {} :: i16 -ffi.i32 = {} :: i32 -ffi.i64 = {} :: i64 -ffi.i128 = {} :: i128 -ffi.f32 = {} :: f32 -ffi.f64 = {} :: f64 -ffi.usize = {} :: usize -ffi.isize = {} :: isize - --[=[ @within FFI @@ -317,7 +434,7 @@ ffi.isize = {} :: isize @return A zero initialized Ref ]=] -function ffi.nullRef(): Ref +function ffi.nullRef(): RefData return nil :: any end @@ -329,7 +446,7 @@ end @param size The size of the new box @return A allocated box ]=] -function ffi.box(size: number): Box +function ffi.box(size: number): BoxData return nil :: any end @@ -341,7 +458,7 @@ end @param name The name of the target library @return A dynamic library handle ]=] -function ffi.open(name: string): Lib +function ffi.open(name: string): LibData return nil :: any end @@ -357,5 +474,4 @@ function ffi.isInteger(val: T): boolean return nil :: any end - return ffi From d42bfc9f63a781ddcd449cb8c485c2d49a28dda4 Mon Sep 17 00:00:00 2001 From: qwreey Date: Tue, 22 Oct 2024 02:18:15 +0000 Subject: [PATCH 41/79] Add benchmark tests/ffi/benchmark/external_call (#243) --- crates/lune-std-ffi/README.md | 2 + crates/lune-std-ffi/src/data/box_data/mod.rs | 5 ++ .../lune-std-ffi/src/data/ref_data/bounds.rs | 4 ++ crates/lune-std-ffi/src/data/ref_data/mod.rs | 4 ++ tests/ffi/README.md | 50 +++++++++++++++++-- tests/ffi/benchmark/external_call/deno.ts | 23 +++++++++ tests/ffi/benchmark/external_call/init.luau | 35 +++++++++++++ tests/ffi/benchmark/external_call/lib.c | 4 ++ tests/ffi/benchmark/external_call/luajit.lua | 27 ++++++++++ tests/ffi/external_closure/init.luau | 17 +++---- tests/ffi/utility/deno.ts | 12 +++++ tests/ffi/utility/proc_clock/deno.ts | 25 ++++++++++ tests/ffi/utility/proc_clock/init.luau | 37 ++++++++++++++ tests/ffi/utility/proc_clock/lib.c | 12 +++++ types/ffi.luau | 9 ++++ 15 files changed, 253 insertions(+), 13 deletions(-) create mode 100644 tests/ffi/benchmark/external_call/deno.ts create mode 100644 tests/ffi/benchmark/external_call/init.luau create mode 100644 tests/ffi/benchmark/external_call/lib.c create mode 100644 tests/ffi/benchmark/external_call/luajit.lua create mode 100644 tests/ffi/utility/deno.ts create mode 100644 tests/ffi/utility/proc_clock/deno.ts create mode 100644 tests/ffi/utility/proc_clock/init.luau create mode 100644 tests/ffi/utility/proc_clock/lib.c diff --git a/crates/lune-std-ffi/README.md b/crates/lune-std-ffi/README.md index 546cc596..a2ac1729 100644 --- a/crates/lune-std-ffi/README.md +++ b/crates/lune-std-ffi/README.md @@ -23,6 +23,8 @@ See [tests/ffi](../../tests/ffi/README.md) > For windows API +- Add varargs support + ## Code structure ### /c diff --git a/crates/lune-std-ffi/src/data/box_data/mod.rs b/crates/lune-std-ffi/src/data/box_data/mod.rs index 1ca07704..f92473b6 100644 --- a/crates/lune-std-ffi/src/data/box_data/mod.rs +++ b/crates/lune-std-ffi/src/data/box_data/mod.rs @@ -107,6 +107,7 @@ impl BoxData { } // Get size of box + #[inline] pub fn size(&self) -> usize { self.data.len() } @@ -121,18 +122,22 @@ impl Drop for BoxData { } impl FfiData for BoxData { + #[inline] fn check_inner_boundary(&self, offset: isize, size: usize) -> bool { if offset < 0 { return false; } self.size() - (offset as usize) >= size } + #[inline] unsafe fn get_inner_pointer(&self) -> *mut () { self.data.as_ptr().cast_mut().cast::<()>() } + #[inline] fn is_readable(&self) -> bool { true } + #[inline] fn is_writable(&self) -> bool { true } diff --git a/crates/lune-std-ffi/src/data/ref_data/bounds.rs b/crates/lune-std-ffi/src/data/ref_data/bounds.rs index 6d43491d..0a702e1f 100644 --- a/crates/lune-std-ffi/src/data/ref_data/bounds.rs +++ b/crates/lune-std-ffi/src/data/ref_data/bounds.rs @@ -16,11 +16,13 @@ impl RefBounds { Self { above, below } } + #[inline] pub fn is_unsized(&self) -> bool { self.above == usize::MAX && self.below == usize::MAX } // Check boundary + #[inline] pub fn check_boundary(&self, offset: isize) -> bool { if self.is_unsized() { return true; @@ -39,6 +41,7 @@ impl RefBounds { // Check boundary // Check required here + #[inline] pub fn check_sized(&self, offset: isize, size: usize) -> bool { if self.is_unsized() { return true; @@ -61,6 +64,7 @@ impl RefBounds { // Calculate new bounds from bounds and offset // No boundary checking in here + #[inline] pub fn offset(&self, offset: isize) -> Self { let sign = offset.signum(); let offset_abs = offset.unsigned_abs(); diff --git a/crates/lune-std-ffi/src/data/ref_data/mod.rs b/crates/lune-std-ffi/src/data/ref_data/mod.rs index 22a123ce..81f1a586 100644 --- a/crates/lune-std-ffi/src/data/ref_data/mod.rs +++ b/crates/lune-std-ffi/src/data/ref_data/mod.rs @@ -127,15 +127,19 @@ impl Drop for RefData { } impl FfiData for RefData { + #[inline] fn check_inner_boundary(&self, offset: isize, size: usize) -> bool { self.boundary.check_sized(offset, size) } + #[inline] unsafe fn get_inner_pointer(&self) -> *mut () { **self.ptr } + #[inline] fn is_readable(&self) -> bool { u8_test(self.flags, RefFlag::Readable.value()) } + #[inline] fn is_writable(&self) -> bool { u8_test(self.flags, RefFlag::Writable.value()) } diff --git a/tests/ffi/README.md b/tests/ffi/README.md index 4d093cc4..3317f29e 100644 --- a/tests/ffi/README.md +++ b/tests/ffi/README.md @@ -4,7 +4,7 @@ gcc for library compiling (for external-\*) -## Results +## Test Results **External tests** @@ -12,9 +12,7 @@ gcc for library compiling (for external-\*) - [x] [external_pointer](./external_pointer/init.luau) - [x] [external_print](./external_print/init.luau) - [x] [external_struct](./external_struct/init.luau) -- [ ] [external_closure](./external_closure/init.luau) - - > failed (segfault) +- [x] [external_closure](./external_closure/init.luau) **Luau-side** @@ -34,3 +32,47 @@ gcc for library compiling (for external-\*) - [ ] [cast](./cast) > need assertion + +## Benchmark Results + +> Note: LuaJit's os.clock function returns process CPU time (used) which much smaller then Luau's os.clock output. In this benchmark, luau uses 'time.h' instead of os.clock. See [utility/proc_clock](./utility/proc_clock/init.luau) + +### [benchmark/external_call](./benchmark/external_call/init.luau) + +**Target external c function** + +```c +int add(int a, int b) { + return a + b; +} +``` + +bench_scale = 1000000 + +**Lune ffi call function** + +> cargo run run tests/ffi/benchmark/external_call +> cargo run --profile=release run tests/ffi/benchmark/external_call + +Lune release target: 0.205127 (sec) +Lune dev target: 1.556489 (sec) + +**LuaJit ffi call function** + +> luajit tests/ffi/benchmark/external_call/luajit.lua + +LuaJIT 2.1.1727870382: 0.001682 (sec) +flags = JIT ON SSE3 SSE4.1 BMI2 fold cse dce fwd dse narrow loop abc sink fuse + +**Deno ffi call function** + +> deno run --unstable-ffi --allow-ffi ./tests/ffi/benchmark/external_call/deno.ts + +Deno 1.46.3: 0.006384 (sec) +v8 = 12.9.202.5-rusty + +**Sysinformation** + +> CPU: AMD Ryzen 5 7600 (12) @ 5.1 +> MEM: 61898MiB 5600 MT/s +> KERNEL: 6.8.12-2-pve (Proxmox VE 8.2.7 x86_64) diff --git a/tests/ffi/benchmark/external_call/deno.ts b/tests/ffi/benchmark/external_call/deno.ts new file mode 100644 index 00000000..f1b7df08 --- /dev/null +++ b/tests/ffi/benchmark/external_call/deno.ts @@ -0,0 +1,23 @@ +import { libSuffix } from "../../utility/deno.ts"; +import { get_clock, get_offset } from "../../utility/proc_clock/deno.ts"; + +const library_file = "./tests/ffi/benchmark/external_call/lib."+libSuffix; +let library = Deno.dlopen(library_file, { + add: { + parameters: ["i32", "i32"], + result: "i32", + }, +}); + +function bench_add(bench_size: number) { + let add = library.symbols.add; + let value = 0; + const before = get_clock(); + for (let i=0; i +clock_t get_clock() { + return clock(); +} + +int sizeof_clock() { + return sizeof(clock_t); +} + +double get_offset(clock_t before, clock_t after) { + return (double)(after - before) / CLOCKS_PER_SEC; +} diff --git a/types/ffi.luau b/types/ffi.luau index 8cbabbbc..656ec83b 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -119,6 +119,15 @@ export type CallableData = (ret: (RefData|BoxData)?, ...RefData)->() & { A lua function wrapper for function pointer ]=] export type ClosureData = { + --[=[ + @within ClosureData + @tag Method + @method ref + + Create a reference of the closure. usually can be used for passing function pointer as argument + + @return A reference of the closure + ]=] ref: (self: ClosureData)->RefData, } From ddf0c4c2dc67f9662e5cccfff49b27340557918b Mon Sep 17 00:00:00 2001 From: qwreey Date: Tue, 22 Oct 2024 02:22:48 +0000 Subject: [PATCH 42/79] Typescript lint error fix (#243) --- crates/lune-std-ffi/README.md | 2 +- tests/ffi/benchmark/external_call/deno.ts | 1 + tests/ffi/utility/deno.ts | 1 + tests/ffi/utility/proc_clock/deno.ts | 2 ++ 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/lune-std-ffi/README.md b/crates/lune-std-ffi/README.md index a2ac1729..8f0ace1e 100644 --- a/crates/lune-std-ffi/README.md +++ b/crates/lune-std-ffi/README.md @@ -1,6 +1,6 @@ # `lune-std-ffi` -## Tests +## Tests & Benchmarks See [tests/ffi](../../tests/ffi/README.md) diff --git a/tests/ffi/benchmark/external_call/deno.ts b/tests/ffi/benchmark/external_call/deno.ts index f1b7df08..46b56e0c 100644 --- a/tests/ffi/benchmark/external_call/deno.ts +++ b/tests/ffi/benchmark/external_call/deno.ts @@ -2,6 +2,7 @@ import { libSuffix } from "../../utility/deno.ts"; import { get_clock, get_offset } from "../../utility/proc_clock/deno.ts"; const library_file = "./tests/ffi/benchmark/external_call/lib."+libSuffix; +// @ts-ignore let library = Deno.dlopen(library_file, { add: { parameters: ["i32", "i32"], diff --git a/tests/ffi/utility/deno.ts b/tests/ffi/utility/deno.ts index ec6c9dde..41dc2818 100644 --- a/tests/ffi/utility/deno.ts +++ b/tests/ffi/utility/deno.ts @@ -1,4 +1,5 @@ export let libSuffix = ""; +// @ts-ignore switch (Deno.build.os) { case "windows": libSuffix = "dll"; diff --git a/tests/ffi/utility/proc_clock/deno.ts b/tests/ffi/utility/proc_clock/deno.ts index 4fd9177a..d5c8d140 100644 --- a/tests/ffi/utility/proc_clock/deno.ts +++ b/tests/ffi/utility/proc_clock/deno.ts @@ -1,6 +1,7 @@ import { libSuffix } from "../deno.ts"; const library_file = "./tests/ffi/utility/proc_clock/lib."+libSuffix; +// @ts-ignore let library = Deno.dlopen(library_file, { sizeof_clock: { parameters: [], @@ -10,6 +11,7 @@ let library = Deno.dlopen(library_file, { const sizeof_clock = library.symbols.sizeof_clock(); const type_clock_t = "u" + (sizeof_clock * 8); library.close(); +// @ts-ignore library = Deno.dlopen(library_file, { get_clock: { parameters: [], From 886d555ab82428175927fdf99909dca0cb82a8bd Mon Sep 17 00:00:00 2001 From: qwreey Date: Tue, 22 Oct 2024 04:44:48 +0000 Subject: [PATCH 43/79] Fix assertion (#243) --- tests/ffi/README.md | 36 ++++++++++++++++++-------------- tests/ffi/external_pointer/lib.c | 2 +- tests/ffi/pretty_print.luau | 2 +- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/tests/ffi/README.md b/tests/ffi/README.md index 3317f29e..f988a7b3 100644 --- a/tests/ffi/README.md +++ b/tests/ffi/README.md @@ -49,30 +49,34 @@ int add(int a, int b) { bench_scale = 1000000 -**Lune ffi call function** +**Lune ffi** -> cargo run run tests/ffi/benchmark/external_call -> cargo run --profile=release run tests/ffi/benchmark/external_call +Command: `cargo run run tests/ffi/benchmark/external_call` +Command: `cargo run --profile=release run tests/ffi/benchmark/external_call` -Lune release target: 0.205127 (sec) -Lune dev target: 1.556489 (sec) +- Device1 + Lune release target: 0.205127 (sec) + Lune dev target: 1.556489 (sec) + > Commit: ddf0c4c -**LuaJit ffi call function** +**LuaJit ffi** -> luajit tests/ffi/benchmark/external_call/luajit.lua +Command: `luajit tests/ffi/benchmark/external_call/luajit.lua` -LuaJIT 2.1.1727870382: 0.001682 (sec) -flags = JIT ON SSE3 SSE4.1 BMI2 fold cse dce fwd dse narrow loop abc sink fuse +- Device1: 0.001682 (sec) + > LuaJIT 2.1.1727870382 + > (flags = JIT ON SSE3 SSE4.1 BMI2 fold cse dce fwd dse narrow loop abc sink fuse) -**Deno ffi call function** +**Deno ffi** -> deno run --unstable-ffi --allow-ffi ./tests/ffi/benchmark/external_call/deno.ts +Command: `deno run --unstable-ffi --allow-ffi ./tests/ffi/benchmark/external_call/deno.ts` -Deno 1.46.3: 0.006384 (sec) -v8 = 12.9.202.5-rusty +- Device1: 0.006384 (sec) + > Deno 1.46.3 (v8 = 12.9.202.5-rusty) **Sysinformation** -> CPU: AMD Ryzen 5 7600 (12) @ 5.1 -> MEM: 61898MiB 5600 MT/s -> KERNEL: 6.8.12-2-pve (Proxmox VE 8.2.7 x86_64) +- Device1 + > CPU: AMD Ryzen 5 7600 (12) @ 5.1 + > MEM: 61898MiB 5600 MT/s + > KERNEL: 6.8.12-2-pve (Proxmox VE 8.2.7 x86_64) diff --git a/tests/ffi/external_pointer/lib.c b/tests/ffi/external_pointer/lib.c index 07146224..697fd090 100644 --- a/tests/ffi/external_pointer/lib.c +++ b/tests/ffi/external_pointer/lib.c @@ -1,3 +1,3 @@ -void pointer(int *a) { +void pointer_write(int *a) { *a = 123; } diff --git a/tests/ffi/pretty_print.luau b/tests/ffi/pretty_print.luau index bac478b6..815c2614 100644 --- a/tests/ffi/pretty_print.luau +++ b/tests/ffi/pretty_print.luau @@ -14,7 +14,7 @@ assert(tostring(c.int:ptr():arr(5)) == " , length = 5 ") assert(typeof(c.fn({ c.int }, c.int)) :: string == "CFn") assert(tostring(c.fn({ c.int }, c.int)) == " (int) -> int ") -assert(tostring(c.fn({ c.int, c.double }, c.int)) == " (int, double) -> int ") +assert(tostring(c.fn({ c.int, ffi.f32 }, c.int)) == " (int, f32) -> int ") assert(tostring(c.fn({ c.int:ptr() }, c.int)) == " () -> int ") assert(tostring(c.fn({ c.int }, c.int:ptr())) == " (int) -> ") assert(tostring(c.fn({ c.int:ptr() }, c.int:ptr())) == " () -> ") From b442ba7985999706432962411e911d7e8a5b6d5c Mon Sep 17 00:00:00 2001 From: qwreey Date: Tue, 22 Oct 2024 07:01:35 +0000 Subject: [PATCH 44/79] Add windows benchmark result (#243) --- tests/ffi/README.md | 23 +++++++++++++++++---- tests/ffi/utility/proc_clock/init.luau | 28 ++++++++++++++++++-------- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/tests/ffi/README.md b/tests/ffi/README.md index f988a7b3..b1e5e5b6 100644 --- a/tests/ffi/README.md +++ b/tests/ffi/README.md @@ -54,16 +54,23 @@ bench_scale = 1000000 Command: `cargo run run tests/ffi/benchmark/external_call` Command: `cargo run --profile=release run tests/ffi/benchmark/external_call` -- Device1 +- Device1-Linux-PVE Lune release target: 0.205127 (sec) Lune dev target: 1.556489 (sec) + + > Commit: ddf0c4c + +- Device2-Windows-11 + Lune release target: 0.1875 (sec) + Lune dev target: ? SEGFUALT (sec) + > Commit: ddf0c4c **LuaJit ffi** Command: `luajit tests/ffi/benchmark/external_call/luajit.lua` -- Device1: 0.001682 (sec) +- Device1-Linux-PVE: 0.001682 (sec) > LuaJIT 2.1.1727870382 > (flags = JIT ON SSE3 SSE4.1 BMI2 fold cse dce fwd dse narrow loop abc sink fuse) @@ -71,12 +78,20 @@ Command: `luajit tests/ffi/benchmark/external_call/luajit.lua` Command: `deno run --unstable-ffi --allow-ffi ./tests/ffi/benchmark/external_call/deno.ts` -- Device1: 0.006384 (sec) +- Device1-Linux-PVE: 0.006384 (sec) > Deno 1.46.3 (v8 = 12.9.202.5-rusty) **Sysinformation** -- Device1 +- Device1-Linux-PVE + > CPU: AMD Ryzen 5 7600 (12) @ 5.1 > MEM: 61898MiB 5600 MT/s > KERNEL: 6.8.12-2-pve (Proxmox VE 8.2.7 x86_64) + +- Device2-Windows-11 + + > CPU: AMD Ryzen 5 7600 (4) @ 3.800GHz + > MEM: 12250MiB 5600 MT/s + > KERNEL: 10.0.22631 (Windows 11 x86_64) + > HOST: QEMU Standard PC (Q35 + ICH9, 2009) diff --git a/tests/ffi/utility/proc_clock/init.luau b/tests/ffi/utility/proc_clock/init.luau index 0462fb8f..40744667 100644 --- a/tests/ffi/utility/proc_clock/init.luau +++ b/tests/ffi/utility/proc_clock/init.luau @@ -1,4 +1,8 @@ +-- FIXME: in windows, we need another library to get process cpu time + local ffi = require("@lune/ffi") +local process = require("@lune/process") +local is_windows = process.os == "windows" local c = ffi.c local proc_clock = {} @@ -10,27 +14,35 @@ local lib = ffi.open(`{libdir}/lib.so`) -- sizeof_clock local sizeof_clock = c.fn({}, c.int):callable(lib:find("sizeof_clock")) -function proc_clock.sizeof_clock() +function proc_clock.sizeof_clock(): number local result = ffi.box(c.int.size) sizeof_clock(result) return c.int:readData(result) end - -- get_clock -local clock_t = ffi["u" .. (proc_clock.sizeof_clock() * 8)] +local clock_t = if is_windows then ffi.f32 else ffi["u" .. (proc_clock.sizeof_clock() * 8)] assert(clock_t, "clock_t is unknown type") -local get_clock = c.fn({}, clock_t):callable(lib:find("get_clock")) -proc_clock.get_clock = get_clock +proc_clock.get_clock = ( + if is_windows + then function(clock: ffi.BoxData | ffi.RefData) + ffi.f32:writeData(clock, os.clock()) + end + else c.fn({}, clock_t):callable(lib:find("get_clock")) +) :: (ffi.BoxData | ffi.RefData) -> () -- get_offset -local get_offset = c.fn({ clock_t, clock_t }, ffi.f64):callable(lib:find("get_offset")) -function proc_clock.get_offset(before, after) +local get_offset: (ffi.BoxData, ffi.RefData, ffi.RefData) -> () = if is_windows + then function(result: ffi.BoxData, before: ffi.RefData, after: ffi.RefData) + ffi.f64:writeData(result, (ffi.f32:readData(after) - ffi.f32:readData(before))) + end + else c.fn({ clock_t, clock_t }, ffi.f64):callable(lib:find("get_offset")) +function proc_clock.get_offset(before: ffi.BoxData, after: ffi.BoxData): number local result = ffi.box(ffi.f64.size) get_offset(result, before:ref(), after:ref()) return ffi.f64:readData(result) end -function proc_clock.new_box() +function proc_clock.new_box(): (ffi.BoxData, ffi.BoxData) return ffi.box(clock_t.size), ffi.box(clock_t.size) end From 83be2bc96a1b504463632f992311debe62d39103 Mon Sep 17 00:00:00 2001 From: qwreey Date: Wed, 23 Oct 2024 04:29:32 +0000 Subject: [PATCH 45/79] Remove callable boundary check (#243) --- crates/lune-std-ffi/README.md | 2 +- crates/lune-std-ffi/src/c/arr_info.rs | 1 - crates/lune-std-ffi/src/c/fn_info.rs | 3 - crates/lune-std-ffi/src/c/helper.rs | 12 ++-- crates/lune-std-ffi/src/c/mod.rs | 3 + crates/lune-std-ffi/src/c/ptr_info.rs | 1 - crates/lune-std-ffi/src/c/string_info.rs | 10 ++++ crates/lune-std-ffi/src/c/struct_info.rs | 1 - crates/lune-std-ffi/src/c/type_info.rs | 3 +- crates/lune-std-ffi/src/c/void_info.rs | 3 - crates/lune-std-ffi/src/data/callable_data.rs | 59 +++++++++---------- tests/ffi/pretty_print.luau | 24 ++++---- 12 files changed, 61 insertions(+), 61 deletions(-) diff --git a/crates/lune-std-ffi/README.md b/crates/lune-std-ffi/README.md index 8f0ace1e..83d1abfd 100644 --- a/crates/lune-std-ffi/README.md +++ b/crates/lune-std-ffi/README.md @@ -12,7 +12,7 @@ See [tests/ffi](../../tests/ffi/README.md) - Add math operation. - > `CTypeInfo:add(target, from1, from2, ...)` and `:sub` `:mul` `:div` `:mod` `:pow` + > Provide related methods: `CTypeInfo:add(target, from1, from2, ...)` and `:sub` `:mul` `:div` `:mod` `:pow` `:max` `:min` `:gt` `:lt` > Luau cannot handle f64, i64 or i128, so we should provide math operation for it - Add bit operation diff --git a/crates/lune-std-ffi/src/c/arr_info.rs b/crates/lune-std-ffi/src/c/arr_info.rs index cfd72590..4a109ff3 100644 --- a/crates/lune-std-ffi/src/c/arr_info.rs +++ b/crates/lune-std-ffi/src/c/arr_info.rs @@ -150,7 +150,6 @@ impl FfiConvert for CArrInfo { impl LuaUserData for CArrInfo { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_meta_field(LuaMetaMethod::Type, "CArr"); 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| { diff --git a/crates/lune-std-ffi/src/c/fn_info.rs b/crates/lune-std-ffi/src/c/fn_info.rs index ca787401..43b7f543 100644 --- a/crates/lune-std-ffi/src/c/fn_info.rs +++ b/crates/lune-std-ffi/src/c/fn_info.rs @@ -203,9 +203,6 @@ impl CFnInfo { } impl LuaUserData for CFnInfo { - fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_meta_field(LuaMetaMethod::Type, "CFn"); - } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { // Subtype method_provider::provide_ptr(methods); diff --git a/crates/lune-std-ffi/src/c/helper.rs b/crates/lune-std-ffi/src/c/helper.rs index 8a54fdc8..760e5824 100644 --- a/crates/lune-std-ffi/src/c/helper.rs +++ b/crates/lune-std-ffi/src/c/helper.rs @@ -314,17 +314,17 @@ pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { // get name tag for any c-type userdata pub fn get_tag_name(userdata: &LuaAnyUserData) -> LuaResult { Ok(if userdata.is::() { - String::from("CStruct") + String::from("CStructInfo") } else if userdata.is::() { - String::from("CArr") + String::from("CArrInfo") } else if userdata.is::() { - String::from("CPtr") + String::from("CPtrInfo") } else if userdata.is::() { - String::from("CFn") + String::from("CFnInfo") } else if userdata.is::() { - String::from("CVoid") + String::from("CVoidInfo") } else if ctype_helper::is_ctype(userdata) { - String::from("CType") + String::from("CTypeInfo") } else { String::from("Unknown") }) diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index 6db6a698..911cdb6f 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -5,6 +5,7 @@ mod arr_info; mod fn_info; pub mod helper; mod ptr_info; +mod string_info; mod struct_info; mod type_info; mod types; @@ -15,6 +16,7 @@ pub use self::{ fn_info::CFnInfo, helper::method_provider, ptr_info::CPtrInfo, + string_info::CStringInfo, struct_info::CStructInfo, type_info::{CTypeCast, CTypeInfo}, types::{ctype_helper, export_c_types, export_fixed_types}, @@ -44,5 +46,6 @@ pub fn export_c(lua: &Lua) -> LuaResult { .with_function("fn", |lua, (args, ret): (LuaTable, LuaAnyUserData)| { CFnInfo::from_table(lua, args, ret) })? + .with_value("string", CStringInfo::new())? .build_readonly() } diff --git a/crates/lune-std-ffi/src/c/ptr_info.rs b/crates/lune-std-ffi/src/c/ptr_info.rs index d66c394c..f39b4251 100644 --- a/crates/lune-std-ffi/src/c/ptr_info.rs +++ b/crates/lune-std-ffi/src/c/ptr_info.rs @@ -124,7 +124,6 @@ impl CPtrInfo { impl LuaUserData for CPtrInfo { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_meta_field(LuaMetaMethod::Type, "CPtr"); fields.add_field_method_get("size", |_, _| Ok(size_of::())); fields.add_field_function_get("inner", |lua, this| { let inner = association::get(lua, CPTR_INNER, this)? diff --git a/crates/lune-std-ffi/src/c/string_info.rs b/crates/lune-std-ffi/src/c/string_info.rs index 8b137891..2a4da645 100644 --- a/crates/lune-std-ffi/src/c/string_info.rs +++ b/crates/lune-std-ffi/src/c/string_info.rs @@ -1 +1,11 @@ +use mlua::prelude::*; +pub struct CStringInfo(); + +impl CStringInfo { + pub fn new() -> Self { + Self() + } +} + +impl LuaUserData for CStringInfo {} diff --git a/crates/lune-std-ffi/src/c/struct_info.rs b/crates/lune-std-ffi/src/c/struct_info.rs index 8917eb5f..3abbe73f 100644 --- a/crates/lune-std-ffi/src/c/struct_info.rs +++ b/crates/lune-std-ffi/src/c/struct_info.rs @@ -182,7 +182,6 @@ impl FfiConvert for CStructInfo { impl LuaUserData for CStructInfo { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_meta_field(LuaMetaMethod::Type, "CStruct"); fields.add_field_method_get("size", |_, this| Ok(this.get_size())); } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { diff --git a/crates/lune-std-ffi/src/c/type_info.rs b/crates/lune-std-ffi/src/c/type_info.rs index b12eebfe..374f09b6 100644 --- a/crates/lune-std-ffi/src/c/type_info.rs +++ b/crates/lune-std-ffi/src/c/type_info.rs @@ -91,9 +91,8 @@ where Self: CTypeCast + FfiSignedness + FfiConvert + FfiSize, { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_meta_field(LuaMetaMethod::Type, "CType"); + fields.add_meta_field(LuaMetaMethod::Type, "CTypeInfo"); 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())); } diff --git a/crates/lune-std-ffi/src/c/void_info.rs b/crates/lune-std-ffi/src/c/void_info.rs index b0008e2b..05ad57d6 100644 --- a/crates/lune-std-ffi/src/c/void_info.rs +++ b/crates/lune-std-ffi/src/c/void_info.rs @@ -31,9 +31,6 @@ impl CVoidInfo { } impl LuaUserData for CVoidInfo { - fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_meta_field(LuaMetaMethod::Type, "CVoid"); - } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { method_provider::provide_to_string(methods); method_provider::provide_ptr(methods); diff --git a/crates/lune-std-ffi/src/data/callable_data.rs b/crates/lune-std-ffi/src/data/callable_data.rs index f94d420d..fab6c7e8 100644 --- a/crates/lune-std-ffi/src/data/callable_data.rs +++ b/crates/lune-std-ffi/src/data/callable_data.rs @@ -23,32 +23,32 @@ pub struct CallableData { const VOID_RESULT_PTR: *mut () = ptr::null_mut(); const ZERO_SIZE_ARG_PTR: *mut *mut c_void = ptr::null_mut(); +// Use known size array in stack instead of creating new Vec on heap macro_rules! create_caller { ($len:expr) => { |callable: &CallableData, result: LuaValue, args: LuaMultiValue| unsafe { - let mut arg_list: [MaybeUninit<*mut c_void>; $len] = [MaybeUninit::uninit(); $len]; - + // Get `rvalue: *mut c_void` result pointer let result_pointer = if callable.result_info.size == 0 { VOID_RESULT_PTR } else { - let result_data = result.get_ffi_data()?; - if !result_data.check_inner_boundary(0, callable.result_info.size) { - return Err(LuaError::external("Result boundary check failed")); - } - result_data.get_inner_pointer() + result.get_ffi_data()?.get_inner_pointer() } .cast::(); + // Create `avalue: *mut *mut c_void` argument list + let mut arg_list: [MaybeUninit<*mut c_void>; $len] = [MaybeUninit::uninit(); $len]; for (index, arg) in arg_list.iter_mut().enumerate() { let arg_value = args .get(index) - .ok_or_else(|| LuaError::external(format!("argument {index} required")))? + .ok_or_else(|| LuaError::external(format!("Argument {index} required")))? .as_userdata() - .ok_or_else(|| LuaError::external("argument should be Ref"))?; + .ok_or_else(|| LuaError::external("Argument should be a RefData"))?; - let arg_ref = arg_value.borrow::()?; - - arg.write(arg_ref.get_inner_pointer().cast::()); + if let Ok(arg_ref) = arg_value.borrow::() { + arg.write(arg_ref.get_inner_pointer().cast::()); + } else { + return Err(LuaError::external("Argument should be a RefData")); + } } ffi_call( @@ -65,6 +65,7 @@ macro_rules! create_caller { }; } +// Call without arguments unsafe fn zero_size_caller( callable: &CallableData, result: LuaValue, @@ -73,11 +74,7 @@ unsafe fn zero_size_caller( let result_pointer = if callable.result_info.size == 0 { VOID_RESULT_PTR } else { - let result_data = result.get_ffi_data()?; - if !result_data.check_inner_boundary(0, callable.result_info.size) { - return Err(LuaError::external("Result boundary check failed")); - } - result_data.get_inner_pointer() + result.get_ffi_data()?.get_inner_pointer() } .cast::(); @@ -130,31 +127,31 @@ impl CallableData { return SIZED_CALLERS[arg_len](self, result, args); } - let mut arg_list = Vec::<*mut c_void>::with_capacity(arg_len); - + // Get `rvalue: *mut c_void` result pointer let result_pointer = if self.result_info.size == 0 { VOID_RESULT_PTR } else { - let result_data = result.get_ffi_data()?; - if !result_data.check_inner_boundary(0, self.result_info.size) { - return Err(LuaError::external("Result boundary check failed")); - } - result_data.get_inner_pointer() + result.get_ffi_data()?.get_inner_pointer() } .cast::(); - for index in 0..self.arg_info_list.len() { + // Create `avalue: *mut *mut c_void` argument list + let mut arg_list = Vec::<*mut c_void>::with_capacity(arg_len); + for index in 0..arg_len { let arg_value = args .get(index) - .ok_or_else(|| LuaError::external(format!("argument {index} required")))? + .ok_or_else(|| LuaError::external(format!("Argument {index} required")))? .as_userdata() - .ok_or_else(|| LuaError::external("argument should be Ref"))?; + .ok_or_else(|| LuaError::external("Argument should be a RefData"))?; - let arg_ref = arg_value.borrow::()?; - - arg_list.push(arg_ref.get_inner_pointer().cast::()); + if let Ok(arg_ref) = arg_value.borrow::() { + arg_list.push(arg_ref.get_inner_pointer().cast::()); + } else { + return Err(LuaError::external("Argument should be a RefData")); + } } + // Call libffi::raw::ffi_call ffi_call( self.cif, Some(*self.code.as_safe_fun()), @@ -172,7 +169,7 @@ impl LuaUserData for CallableData { LuaMetaMethod::Call, |_lua, this: &CallableData, mut args: LuaMultiValue| { let result = args.pop_front().ok_or_else(|| { - LuaError::external("First argument must be result data handle or nil") + LuaError::external("First argument 'result' must be a RefData, BoxData or nil") })?; unsafe { this.call(result, args) } }, diff --git a/tests/ffi/pretty_print.luau b/tests/ffi/pretty_print.luau index 815c2614..6019089e 100644 --- a/tests/ffi/pretty_print.luau +++ b/tests/ffi/pretty_print.luau @@ -1,32 +1,32 @@ local ffi = require("@lune/ffi") local c = ffi.c -assert(typeof(c.int) :: string == "CType") +assert(typeof(c.int) :: string == "CTypeInfo") assert(tostring(c.int) == "int") -assert(typeof(c.int:ptr()) :: string == "CPtr") +assert(typeof(c.int:ptr()) :: string == "CPtrInfo") assert(tostring(c.int:ptr()) == "int") -assert(tostring(c.int:arr(5):ptr()) == " ") +assert(tostring(c.int:arr(5):ptr()) == " ") -assert(typeof(c.int:arr(5)) :: string == "CArr") +assert(typeof(c.int:arr(5)) :: string == "CArrInfo") assert(tostring(c.int:arr(5)) == " int, length = 5 ") -assert(tostring(c.int:ptr():arr(5)) == " , length = 5 ") +assert(tostring(c.int:ptr():arr(5)) == " , length = 5 ") -assert(typeof(c.fn({ c.int }, c.int)) :: string == "CFn") +assert(typeof(c.fn({ c.int }, c.int)) :: string == "CFnInfo") assert(tostring(c.fn({ c.int }, c.int)) == " (int) -> int ") assert(tostring(c.fn({ c.int, ffi.f32 }, c.int)) == " (int, f32) -> int ") -assert(tostring(c.fn({ c.int:ptr() }, c.int)) == " () -> int ") -assert(tostring(c.fn({ c.int }, c.int:ptr())) == " (int) -> ") -assert(tostring(c.fn({ c.int:ptr() }, c.int:ptr())) == " () -> ") +assert(tostring(c.fn({ c.int:ptr() }, c.int)) == " () -> int ") +assert(tostring(c.fn({ c.int }, c.int:ptr())) == " (int) -> ") +assert(tostring(c.fn({ c.int:ptr() }, c.int:ptr())) == " () -> ") assert( tostring(c.fn({ c.int:ptr(), c.int:ptr() }, c.int:ptr())) - == " (, ) -> " + == " (, ) -> " ) -assert(typeof(c.struct({ c.int, c.char })) :: string == "CStruct") +assert(typeof(c.struct({ c.int, c.char })) :: string == "CStructInfo") assert( tostring(c.struct({ c.int, c.char:ptr() })) - == ` int, , size = {c.struct({ c.int, c.char:ptr() }).size} ` + == ` int, , size = {c.struct({ c.int, c.char:ptr() }).size} ` ) -- FIXME: add box, ref pretty-print test From 34a5b3927729e2e3fba4e43f1a15eb8ca0e358fd Mon Sep 17 00:00:00 2001 From: qwreey Date: Wed, 23 Oct 2024 05:04:21 +0000 Subject: [PATCH 46/79] Add linguist ignore for tests/ffi (#243) --- .gitattributes | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitattributes b/.gitattributes index 3cb3e3eb..db1a5e97 100644 --- a/.gitattributes +++ b/.gitattributes @@ -6,3 +6,7 @@ # Ensure all txt files within tests use LF tests/**/*.txt eol=lf + +# Remove test c, typescript from language list +tests/ffi/**/*.c linguist-vendored +tests/ffi/**/*.ts linguist-vendored From 154c68a64e8639f26979c9c71d534dde32b87a1e Mon Sep 17 00:00:00 2001 From: qwreey Date: Thu, 24 Oct 2024 00:26:43 +0000 Subject: [PATCH 47/79] Add Data:copyFrom, tests and annotation (#243) --- .gitattributes | 2 +- crates/lune-std-ffi/README.md | 6 + crates/lune-std-ffi/src/data/box_data/mod.rs | 9 +- crates/lune-std-ffi/src/data/helper.rs | 41 +++ crates/lune-std-ffi/src/data/mod.rs | 1 + crates/lune-std-ffi/src/data/ref_data/mod.rs | 15 +- crates/lune-std-ffi/src/ffi/mod.rs | 11 + tests/ffi/from_boundary.luau | 0 tests/ffi/into_boundary.luau | 0 tests/ffi/read_boundary.luau | 53 +++ tests/ffi/write_boundary.luau | 46 +++ types/ffi.luau | 365 +++++++++++++++++-- 12 files changed, 514 insertions(+), 35 deletions(-) create mode 100644 crates/lune-std-ffi/src/data/helper.rs delete mode 100644 tests/ffi/from_boundary.luau delete mode 100644 tests/ffi/into_boundary.luau create mode 100644 tests/ffi/read_boundary.luau create mode 100644 tests/ffi/write_boundary.luau diff --git a/.gitattributes b/.gitattributes index db1a5e97..38d1ab4f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,6 +7,6 @@ # Ensure all txt files within tests use LF tests/**/*.txt eol=lf -# Remove test c, typescript from language list +# Remove test c and typescript from language list tests/ffi/**/*.c linguist-vendored tests/ffi/**/*.ts linguist-vendored diff --git a/crates/lune-std-ffi/README.md b/crates/lune-std-ffi/README.md index 83d1abfd..f842af6f 100644 --- a/crates/lune-std-ffi/README.md +++ b/crates/lune-std-ffi/README.md @@ -6,6 +6,10 @@ See [tests/ffi](../../tests/ffi/README.md) ## TODO +- Deref + +- Big endianness / Little endianness variable (On process.endianness) + - CString - Add buffer for owned data support @@ -25,6 +29,8 @@ See [tests/ffi](../../tests/ffi/README.md) - Add varargs support +- Array argument in cfn + ## Code structure ### /c diff --git a/crates/lune-std-ffi/src/data/box_data/mod.rs b/crates/lune-std-ffi/src/data/box_data/mod.rs index f92473b6..4e75b10d 100644 --- a/crates/lune-std-ffi/src/data/box_data/mod.rs +++ b/crates/lune-std-ffi/src/data/box_data/mod.rs @@ -1,7 +1,13 @@ -use std::{alloc, alloc::Layout, boxed::Box, mem::ManuallyDrop, ptr}; +use std::{ + alloc::{self, Layout}, + boxed::Box, + mem::ManuallyDrop, + ptr, +}; use mlua::prelude::*; +use super::helper::method_provider; use crate::{ data::{association_names::REF_INNER, RefBounds, RefData, RefFlag}, ffi::{association, bit_mask::*, FfiData}, @@ -148,6 +154,7 @@ impl LuaUserData for BoxData { fields.add_field_method_get("size", |_, this| Ok(this.size())); } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + method_provider::provide_copy_from(methods); // For convenience, :zero returns self. methods.add_function_mut("zero", |_, this: LuaAnyUserData| { this.borrow_mut::()?.zero(); diff --git a/crates/lune-std-ffi/src/data/helper.rs b/crates/lune-std-ffi/src/data/helper.rs new file mode 100644 index 00000000..a1aebd44 --- /dev/null +++ b/crates/lune-std-ffi/src/data/helper.rs @@ -0,0 +1,41 @@ +use mlua::prelude::*; + +use super::{FfiData, GetFfiData}; + +pub mod method_provider { + + use super::*; + + pub fn provide_copy_from<'lua, Target, M>(methods: &mut M) + where + Target: FfiData, + M: LuaUserDataMethods<'lua, Target>, + { + methods.add_method( + "copyFrom", + |_lua, + this, + (src, length, dst_offset, src_offset): ( + LuaAnyUserData, + usize, + Option, + Option, + )| unsafe { + let dst_offset = dst_offset.unwrap_or(0); + let src_offset = src_offset.unwrap_or(0); + let src = src.get_ffi_data()?; + + if !src.check_inner_boundary(src_offset, length) { + return Err(LuaError::external("Source boundary check failed")); + } + if !this.check_inner_boundary(dst_offset, length) { + return Err(LuaError::external("Self boundary check failed")); + } + + this.copy_from(&src, length, dst_offset, src_offset); + + Ok(()) + }, + ); + } +} diff --git a/crates/lune-std-ffi/src/data/mod.rs b/crates/lune-std-ffi/src/data/mod.rs index 27d3f945..2c4a68f4 100644 --- a/crates/lune-std-ffi/src/data/mod.rs +++ b/crates/lune-std-ffi/src/data/mod.rs @@ -6,6 +6,7 @@ use mlua::prelude::*; mod box_data; mod callable_data; mod closure_data; +mod helper; mod lib_data; mod ref_data; diff --git a/crates/lune-std-ffi/src/data/ref_data/mod.rs b/crates/lune-std-ffi/src/data/ref_data/mod.rs index 81f1a586..26de8269 100644 --- a/crates/lune-std-ffi/src/data/ref_data/mod.rs +++ b/crates/lune-std-ffi/src/data/ref_data/mod.rs @@ -2,6 +2,7 @@ use std::{mem::ManuallyDrop, ptr}; use mlua::prelude::*; +use super::helper::method_provider; use crate::{ data::association_names::REF_INNER, ffi::{association, bit_mask::*, FfiData}, @@ -91,6 +92,10 @@ impl RefData { (**self.ptr) as usize == 0 } + pub fn leak(&mut self) { + self.flags = u8_set(self.flags, RefFlag::Leaked.value(), true); + } + pub unsafe fn offset(&self, offset: isize) -> LuaResult { u8_test(self.flags, RefFlag::Offsetable.value()) .then_some(()) @@ -147,6 +152,8 @@ impl FfiData for RefData { impl LuaUserData for RefData { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + method_provider::provide_copy_from(methods); + // FIXME: methods.add_function("deref", |lua, this: LuaAnyUserData| { let inner = association::get(lua, REF_INNER, &this)?; @@ -171,10 +178,12 @@ impl LuaUserData for RefData { Ok(userdata) }); - // FIXME: + methods.add_function_mut("leak", |lua, this: LuaAnyUserData| { + this.borrow_mut::()?.leak(); + RefData::luaref(lua, this) + }); methods.add_function("ref", |lua, this: LuaAnyUserData| { - let ffiref = RefData::luaref(lua, this)?; - Ok(ffiref) + RefData::luaref(lua, this) }); methods.add_method("isNull", |_, this, ()| Ok(this.is_nullptr())); } diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index 66a11da3..c4fa7d08 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -62,6 +62,17 @@ pub trait FfiData { unsafe fn get_inner_pointer(&self) -> *mut (); fn is_writable(&self) -> bool; fn is_readable(&self) -> bool; + unsafe fn copy_from( + &self, + src: &Ref, + length: usize, + dst_offset: isize, + src_offset: isize, + ) { + self.get_inner_pointer() + .byte_offset(dst_offset) + .copy_from(src.get_inner_pointer().byte_offset(src_offset), length); + } } pub struct FfiArg { diff --git a/tests/ffi/from_boundary.luau b/tests/ffi/from_boundary.luau deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/ffi/into_boundary.luau b/tests/ffi/into_boundary.luau deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/ffi/read_boundary.luau b/tests/ffi/read_boundary.luau new file mode 100644 index 00000000..bc573579 --- /dev/null +++ b/tests/ffi/read_boundary.luau @@ -0,0 +1,53 @@ +local ffi = require("@lune/ffi") + +local ok + +-- Case1: Success +ok = pcall(function() + local box = ffi.u8:box(1) + ffi.u8:readData(box) +end) +assert(ok, "assersion failed, Case1 should success") + +-- Case2: Fail +ok = pcall(function() + local box = ffi.u8:box(1) + ffi.u16:readData(box) +end) +assert(not ok, "assersion failed, Case2 should fail") + +-- Case3: Success +ok = pcall(function() + local box = ffi.box(ffi.u8.size * 2) + ffi.u16:readData(box) +end) +assert(ok, "assersion failed, Case3 should success") + +-- Case4: Success + +ok = pcall(function() + local box = ffi.box(ffi.u8.size * 2) + ffi.u8:readData(box, ffi.u8.size) +end) +assert(ok, "assersion failed, Case4 should success") + +-- Case5: Fail +ok = pcall(function() + local box = ffi.u8:box(1):ref() + ffi.u16:readData(box) +end) +assert(not ok, "assersion failed, Case5 should fail") + +-- Case6: Success +ok = pcall(function() + local box = ffi.box(ffi.u8.size * 2):ref() + ffi.u16:readData(box) +end) +assert(ok, "assersion failed, Case6 should success") + +-- Case7: Fail +ok = pcall(function() + local box = ffi.box(ffi.u8.size * 2):ref(ffi.u16.size) + ffi.u16:readData(box) +end) +assert(ok, "assersion failed, Case7 should fail") diff --git a/tests/ffi/write_boundary.luau b/tests/ffi/write_boundary.luau new file mode 100644 index 00000000..53291d6e --- /dev/null +++ b/tests/ffi/write_boundary.luau @@ -0,0 +1,46 @@ +local ffi = require("@lune/ffi") +local c = ffi.c + +local ok + +-- Case1: Fail +ok = pcall(function() + local box = ffi.box(c.int.size - 1) + c.int:writeData(box, 10) +end) +assert(not ok, "assersion failed, Case1 should fail") + +-- Case2: Success +ok = pcall(function() + local box = ffi.box(c.int.size) + c.int:writeData(box, 10) +end) +assert(ok, "assersion failed, Case2 should success") + +-- Case3: Success +ok = pcall(function() + local box = ffi.box(c.int.size * 2) + c.int:writeData(box, 10, c.int.size) +end) +assert(ok, "assersion failed, Case3 should success") + +-- Case4: Fail +ok = pcall(function() + local box = ffi.box(c.int.size * 2) + c.int:writeData(box, 10, c.int.size * 2) +end) +assert(not ok, "assersion failed, Case4 should fail") + +-- Case5: Success +ok = pcall(function() + local box = ffi.box(c.int.size * 2):ref() + c.int:writeData(box, 10, c.int.size) +end) +assert(ok, "assersion failed, Case5 should success") + +-- Case6: Fail +ok = pcall(function() + local box = ffi.box(c.int.size * 2):ref() + c.int:writeData(box, 10, c.int.size * 2) +end) +assert(not ok, "assersion failed, Case6 should fail") diff --git a/types/ffi.luau b/types/ffi.luau index 656ec83b..f21b4bf5 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -1,11 +1,41 @@ --[=[ @class FFI - Built-in library for foreign function interface + Built-in library for foreign function interface. ### Example usage - + lib.c: + ```c + int add(int a, int b) { + return a + b; + } + ``` + init.luau: ```lua + local ffi = require("@lune/ffi") + + -- Create function signature + local addSignature = ffi.c.fn({ ffi.c.int, ffi.c.int }, ffi.c.int) + + -- Load library + local lib = ffi.open("./lib.so") + + -- Get symbol from library + local addSymbol = lib:find("add") + + -- Create CallableData + local add = addSignature:callable(addSymbol) + + -- Create result box and arguments + local result = ffi.box(ffi.c.int.size) + local a = ffi.c.int:box(1) + local b = ffi.c.int:box(2) + + -- Call external function + add(result, a:ref(), b:ref()) + + -- Get number from result + print(ffi.c.int:readData(result)) ``` ]=] local ffi = {} @@ -24,19 +54,83 @@ ffi.c = c --[=[ @class RefData - A user manageable memory reference + A user manageable memory reference. ]=] export type RefData = { + --[=[ + @within RefData + @tag Method + @method deref + + Get a RefData by dereference this reference. + + @return A dereferenced `RefData` + ]=] deref: (self: RefData) -> RefData, + --[=[ + @within RefData + @tag Method + @method offset + + Create a reference with specific offset from this reference. + + @param offset Create a reference at the given offset + @return A offseted reference + ]=] offset: (self: RefData, offset: number) -> RefData, + --[=[ + @within RefData + @tag Method + @method ref + + Create a reference of this reference. + + The created reference keeps the box from being garbage collected until the reference itself is collected. + + @return A reference of this reference + ]=] ref: (self: RefData) -> RefData, + --[=[ + @within RefData + @tag Method + @method leak + + Create a reference of this reference after leaking it. + + GC doesn't manage destruction after this action. You must free it later. + + @return A reference of this reference + ]=] + leak: (self: RefData) -> RefData, + --[=[ + @within RefData + @tag Method + @method isNull + + Check reference is null or not. + + @return Whether reference is null or not + ]=] isNull: (self: RefData) -> boolean, + --[=[ + @within RefData + @tag Method + @method copyFrom + + Copy content from another data. + + @param src The source data + @param len The amount of data to copy, in bytes + @param dst_offset The offset in the destination where the data will be pasted + @param src_offset The offset in the source data from where the data will be copied + ]=] + copyFrom: (self: RefData, src: (BoxData|RefData), length: number, dst_offset: number, src_offset: number)->(); } --[=[ @class BoxData - A user manageable heap memory + A user manageable heap memory. ]=] export type BoxData = { --[=[ @@ -44,7 +138,7 @@ export type BoxData = { @tag Field @field size - Size of the box. + The size of the box. ]=] size: number, @@ -65,8 +159,9 @@ export type BoxData = { Create a reference of the box after leaking it. - GC doesn't manage destruction after this action. You must free it later + GC doesn't manage destruction after this action. You must free it later. + @param offset Create a reference at the given offset @return A reference of the box ]=] leak: (self: BoxData, offset: number?) -> RefData, @@ -77,15 +172,31 @@ export type BoxData = { Create a reference of the box. + The created reference keeps the box from being garbage collected until the reference itself is collected. + + @param offset Create a reference at the given offset @return A reference of the box ]=] ref: (self: BoxData, offset: number?) -> RefData, + --[=[ + @within BoxData + @tag Method + @method copyFrom + + Copy content from another data. + + @param src The source data + @param len The amount of data to copy, in bytes + @param dst_offset The offset in the destination where the data will be pasted + @param src_offset The offset in the source data from where the data will be copied + ]=] + copyFrom: (self: BoxData, src: (BoxData|RefData), length: number, dst_offset: number, src_offset: number)->(); } --[=[ @class LibData - - A dynamic opened library handle + + A dynamic opened library handle. ]=] export type LibData = { --[=[ @@ -105,9 +216,12 @@ export type LibData = { --[=[ @class CallableData - @tag unsafe - A callable external function + A callable external function. + + To call external function, you should provide memory for the return value and references for the arguments. + + If return type is `void`, pass `nil`. ]=] export type CallableData = (ret: (RefData|BoxData)?, ...RefData)->() & { -- apply: (self: Callable, args: Args)->AppliedCallable, @@ -116,7 +230,9 @@ export type CallableData = (ret: (RefData|BoxData)?, ...RefData)->() & { --[=[ @class ClosureData - A lua function wrapper for function pointer + A lua function wrapper for the function pointer. + + To return some data, write value into ret reference. ]=] export type ClosureData = { --[=[ @@ -124,7 +240,9 @@ export type ClosureData = { @tag Method @method ref - Create a reference of the closure. usually can be used for passing function pointer as argument + Create a reference of the closure. usually can be used for passing function pointer as argument. + + The created reference keeps the closure from being garbage collected until the reference itself is collected. @return A reference of the closure ]=] @@ -137,7 +255,21 @@ export type ClosureData = { -- NOTE: T is a unique identifier for the `CType` and R is the closest Lua type. export type CTypeInfo = { + --[=[ + @within CTypeInfo + @tag Field + @field size + + The size of the type in bytes. + ]=] size: number, + --[=[ + @within CTypeInfo + @tag Field + @field signedness + + The signedness of the type. + ]=] signedness: boolean, -- subtype @@ -156,7 +288,23 @@ export type CTypeInfo = { type NumCType = CTypeInfo export type CPtrInfo = { + --[=[ + @within CPtrInfo + @tag Field + @field size + + The size of a pointer. should be the same for all pointers. + + Equivalent to `ffi.c.usize.size`. + ]=] size: number, + --[=[ + @within CPtrInfo + @tag Field + @field inner + + The inner type of the pointer. + ]=] inner: T, -- subtype @@ -169,9 +317,35 @@ export type CPtrInfo = { writeRef: (self: CPtrInfo, target: (RefData|BoxData), value: (RefData|BoxData), offset: number?) -> (), } +--[=[ + @class CArrInfo + + A c sized array type information. +]=] export type CArrInfo = { + --[=[ + @within CArrInfo + @tag Field + @field size + + The total size of the array in bytes. + ]=] size: number, + --[=[ + @within CArrInfo + @tag Field + @field length + + The length of the array. + ]=] length: number, + --[=[ + @within CArrInfo + @tag Field + @field inner + + The inner element type of the array. + ]=] inner: T, -- subtype @@ -186,15 +360,62 @@ export type CArrInfo = { offset: (self: CArrInfo, index: number) -> number, } +--[=[ + @class CFnInfo + + A c function signature type information. +]=] export type CFnInfo = { + --[=[ + @within CFnInfo + @tag Method + @method callable + + Create a callable from reference. + + @return Struct array type + ]=] callable: (self: CFnInfo, functionRef: RefData) -> CallableData, + --[=[ + @within CFnInfo + @tag Method + @method closure + + Create a closure from lua function. + + @return A closure. + ]=] closure: (self: CFnInfo, (ret: RefData, ...RefData)->()) -> ClosureData, } +--[=[ + @class CStructInfo + + A c struct type information. +]=] export type CStructInfo = { size: number, + --[=[ + @within CSturctInfo + @tag Method + @method arr + + Create a struct array type. + + @param len The length of the array + @return A struct array type + ]=] arr: (self: CStructInfo, len: number) -> CArrInfo, + --[=[ + @within CSturctInfo + @tag Method + @method ptr + + Create a struct pointer type. + + @return A struct pointer type + ]=] ptr: (self: CStructInfo) -> CPtrInfo, box: (self: CStructInfo, table: { any }) -> BoxData, @@ -217,9 +438,9 @@ export type CVoidInfo = { @tag Method @method ptr - Create a generic pointer type + Create a generic pointer type. - @return Generic pointer type + @return Generic pointer type, equivalent to `*void` in C. ]=] ptr: (self: CVoidInfo) -> CPtrInfo, } @@ -233,7 +454,7 @@ c.void = {} :: CVoidInfo @class u8 @within FFI - A 8-bit sized unsigned integer, Equivalent to `uint8_t` in `stdint` + A 8-bit sized unsigned integer, Equivalent to `uint8_t` in `stdint`. ]=] ffi.u8 = {} :: u8 export type u8 = NumCType<"u8"> @@ -241,7 +462,7 @@ export type u8 = NumCType<"u8"> @class u16 @within FFI - A 16-bit sized unsigned integer, Equivalent to `uint16_t` in `stdint` + A 16-bit sized unsigned integer, Equivalent to `uint16_t` in `stdint`. ]=] ffi.u16 = {} :: u16 export type u16 = NumCType<"u16"> @@ -249,7 +470,7 @@ export type u16 = NumCType<"u16"> @class u32 @within FFI - A 32-bit sized unsigned integer, Equivalent to `uint32_t` in `stdint` + A 32-bit sized unsigned integer, Equivalent to `uint32_t` in `stdint`. ]=] ffi.u32 = {} :: u32 export type u32 = NumCType<"u32"> @@ -257,7 +478,7 @@ export type u32 = NumCType<"u32"> @class u64 @within FFI - A 64-bit sized unsigned integer, Equivalent to `uint64_t` in `stdint` + A 64-bit sized unsigned integer, Equivalent to `uint64_t` in `stdint`. ]=] ffi.u64 = {} :: u64 export type u64 = NumCType<"u64"> @@ -265,7 +486,7 @@ export type u64 = NumCType<"u64"> @class u128 @within FFI - A 128-bit sized unsigned integer, Equivalent to `uint128_t` in `stdint` + A 128-bit sized unsigned integer, Equivalent to `uint128_t` in `stdint`. ]=] ffi.u128 = {} :: u128 export type u128 = NumCType<"u128"> @@ -273,7 +494,7 @@ export type u128 = NumCType<"u128"> @class i8 @within FFI - A 8-bit sized signed integer, Equivalent to `int8_t` in `stdint` + A 8-bit sized signed integer, Equivalent to `int8_t` in `stdint`. ]=] ffi.i8 = {} :: i8 export type i8 = NumCType<"i8"> @@ -281,7 +502,7 @@ export type i8 = NumCType<"i8"> @class i16 @within FFI - A 16-bit sized signed integer, Equivalent to `int16_t` in `stdint` + A 16-bit sized signed integer, Equivalent to `int16_t` in `stdint`. ]=] ffi.i16 = {} :: i16 export type i16 = NumCType<"i16"> @@ -289,7 +510,7 @@ export type i16 = NumCType<"i16"> @class i32 @within FFI - A 32-bit sized signed integer, Equivalent to `int32_t` in `stdint` + A 32-bit sized signed integer, Equivalent to `int32_t` in `stdint`. ]=] ffi.i32 = {} :: i32 export type i32 = NumCType<"i32"> @@ -297,7 +518,7 @@ export type i32 = NumCType<"i32"> @class i64 @within FFI - A 64-bit sized signed integer, Equivalent to `int64_t` in `stdint` + A 64-bit sized signed integer, Equivalent to `int64_t` in `stdint`. ]=] ffi.i64 = {} :: i64 export type i64 = NumCType<"i64"> @@ -305,7 +526,7 @@ export type i64 = NumCType<"i64"> @class i128 @within FFI - A 128-bit sized signed integer, Equivalent to `int128_t` in `stdint` + A 128-bit sized signed integer, Equivalent to `int128_t` in `stdint`. ]=] ffi.i128 = {} :: i128 export type i128 = NumCType<"i128"> @@ -313,7 +534,7 @@ export type i128 = NumCType<"i128"> @class f32 @within FFI - A single-precision 32-bit sized floating-point, Almost always equivalent to `float` in C + A single-precision 32-bit sized floating-point, Almost always equivalent to `float` in C. ]=] ffi.f32 = {} :: f32 export type f32 = NumCType<"f32"> @@ -321,7 +542,7 @@ export type f32 = NumCType<"f32"> @class f64 @within FFI - A double-precision 64-bit sized floating-point, Almost always equivalent to `double` in C + A double-precision 64-bit sized floating-point, Almost always equivalent to `double` in C. ]=] ffi.f64 = {} :: f64 export type f64 = NumCType<"f64"> @@ -329,7 +550,7 @@ export type f64 = NumCType<"f64"> @class usize @within FFI - A machine specific pointer sized unsigned integer, + A machine specific pointer sized unsigned integer. ]=] ffi.usize = {} :: usize export type usize = NumCType<"usize"> @@ -337,7 +558,7 @@ export type usize = NumCType<"usize"> @class isize @within FFI - A machine specific pointer sized signed integer, + A machine specific pointer sized signed integer. ]=] ffi.isize = {} :: isize export type isize = NumCType<"isize"> @@ -345,36 +566,120 @@ export type isize = NumCType<"isize"> --#endregion Fixed size Rust-style types -- --#region Variable size C-style types -- +--[=[ + @class char + @within C + + Compiler defined C `char` type. + + The signedness may differ depending on the compiler and platform. + You can get signedness by `signedness` field. +]=] c.char = {} :: char export type char = NumCType<"char"> -- c.float = {} :: float -- export type float = NumCType<"float"> -- c.double = {} :: double -- export type double = NumCType<"double"> +--[=[ + @class uchar + @within C + + Compiler defined C `unsigned char` type. + + Mostly equivalent to `u8`. +]=] c.uchar = {} :: uchar export type uchar = NumCType<"uchar"> +--[=[ + @class schar + @within C + + Compiler defined C `signed char` type. +]=] c.schar = {} :: schar export type schar = NumCType<"schar"> +--[=[ + @class short + @within C + + Compiler defined C `short` type. +]=] c.short = {} :: short export type short = NumCType<"short"> +--[=[ + @class ushort + @within C + + Compiler defined C `unsigned short` type. +]=] c.ushort = {} :: ushort export type ushort = NumCType<"ushort"> +--[=[ + @class int + @within C + + Compiler defined C `int` type. + + The side may differ depending on the compiler and platform. +]=] c.int = {} :: int export type int = NumCType<"int"> +--[=[ + @class uint + @within C + + Compiler defined C `unsigned int` type. + + The side may differ depending on the compiler and platform. +]=] c.uint = {} :: uint export type uint = NumCType<"uint"> +--[=[ + @class long + @within C + + Compiler defined C `long` type. + + The side may differ depending on the compiler and platform. +]=] c.long = {} :: long export type long = NumCType<"long"> +--[=[ + @class ulong + @within C + + Compiler defined C `unsigned long` type. + + The side may differ depending on the compiler and platform. +]=] c.ulong = {} :: ulong export type ulong = NumCType<"ulong"> +--[=[ + @class longlong + @within C + + Compiler defined C `unsigned longlong` type. +]=] c.longlong = {} :: longlong export type longlong = NumCType<"longlong"> +--[=[ + @class longlong + @within C + + Compiler defined C `unsigned longlong` type. +]=] c.ulonglong = {} :: ulonglong export type ulonglong = NumCType<"ulonglong"> --#endregion Variable size C-style types -- +--[=[ + @class CTypes + + All possible C types. +]=] export type CTypes = | u8 | u16 @@ -427,7 +732,7 @@ end Create a struct type information. - @param fields An array of CTypes represents the fields of the struct + @param fields An array of CTypes represents the fields of the struct @return A struct type information ]=] function c.struct(fields: { CTypes }): CStructInfo @@ -474,7 +779,7 @@ end --[=[ @within FFI - Return `true` if the second argument is an integer (i32) + Return `true` if the second argument is an integer (i32). @param val A lua value to check @return Whether val is an integer or not From 14d2b60f431d6f4e1375bde9ca90dd52c3a706a5 Mon Sep 17 00:00:00 2001 From: qwreey Date: Thu, 24 Oct 2024 01:01:49 +0000 Subject: [PATCH 48/79] Fix casting and add casting test (#243) --- crates/lune-std-ffi/README.md | 22 ++++++++++++++++------ crates/lune-std-ffi/src/c/types/mod.rs | 2 +- tests/ffi/README.md | 16 +++++++--------- tests/ffi/cast.luau | 13 +++++++++++++ tests/ffi/isInteger.luau | 7 ++----- 5 files changed, 39 insertions(+), 21 deletions(-) diff --git a/crates/lune-std-ffi/README.md b/crates/lune-std-ffi/README.md index f842af6f..4470901c 100644 --- a/crates/lune-std-ffi/README.md +++ b/crates/lune-std-ffi/README.md @@ -31,6 +31,8 @@ See [tests/ffi](../../tests/ffi/README.md) - Array argument in cfn +- Ref boundary fix + ## Code structure ### /c @@ -84,12 +86,11 @@ Implememt type-casting for all CTypes - **Trait `FfiSize`** - **Trait `FfiSignedness`** -- **Trait `FfiConvert`:** Provide read LuaValue from FfiData or write LuaValue into FfiData -**Traits:** Provide call information trait +**Structs:** Provide call information trait -- **Trait `FfiArg`:** Used for argument boundary checking and callback argument ref flag -- **Trait `FfiResult`:** Used for result boundary checking +- **Struct `FfiArg`:** Used for argument boundary checking and callback argument ref flag +- **Struct `FfiResult`:** Used for result boundary checking **Trait `FfiData`:** Provide common data handle, including methods below @@ -97,6 +98,14 @@ Implememt type-casting for all CTypes - **Method `get_inner_pointer`:** returns raw pointer `*mut ()` - **Method `is_writable`** - **Method `is_readable`** +- **Method `copy_from`** copy data from another data + +- **Trait `FfiConvert`:** Provide methods for read LuaValue from FfiData or write LuaValue into FfiData + +- **Method `value_into_data`:** set data with lua value +- **Method `value_from_data`:** get lua value from data +- **Method `copy_data`:** copy sized data into another data +- **Method `stringify_data`:** stringify data with specific type > Note: `GetFfiData` trait in `data/mod.rs` provides `AnyUserData.get_data_handle() -> FfiData` method @@ -108,6 +117,7 @@ Implememt type-casting for all CTypes - **Function `num_cast(from: FfiData, from: FfiData)`:** Cast number type value inno another number type - [**Mod `libffi_helper.rs`:**](./src/ffi/libffi_helper.rs) - - **Const `FFI_STATUS_NAMES`:** Used for ffi_status stringify - - **Function `get_ensured_size`:** Returns ensured ffi_type size + - **Const `FFI_STATUS_NAMES`:** Used for `ffi_status` stringify + - **Function `get_ensured_size`:** Returns ensured `ffi_type` size - **Const `SIZE_OF_POINTER`:** Platform specific pointer size (Compile time known) + - **Function `ffi_status_assert`:** Convert `ffi_status` to `LuaResult<()>` diff --git a/crates/lune-std-ffi/src/c/types/mod.rs b/crates/lune-std-ffi/src/c/types/mod.rs index d778874a..672279e4 100644 --- a/crates/lune-std-ffi/src/c/types/mod.rs +++ b/crates/lune-std-ffi/src/c/types/mod.rs @@ -115,7 +115,7 @@ where into: &Ref, ) -> LuaResult<()> { define_cast_num!( - From, self, into_info, from_info, from, into, + From, self, from_info, into_info, from, into, u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize ) } diff --git a/tests/ffi/README.md b/tests/ffi/README.md index b1e5e5b6..8f911d31 100644 --- a/tests/ffi/README.md +++ b/tests/ffi/README.md @@ -16,22 +16,20 @@ gcc for library compiling (for external-\*) **Luau-side** +- [x] [isInteger](./isInteger) +- [x] [cast](./cast.luau) + - [ ] [pretty_print](./pretty_print) > need box, ref test -- [x] [isInteger](./isInteger) -- [ ] [into_boundary](./into_boundary) - - > need assertion - -- [ ] [from_boundary](./from_boundary) +- [ ] [write_boundary](./write_boundary.luau) - > need assertion + > Failed, need fix -- [ ] [cast](./cast) +- [ ] [read_boundary](./read_boundary.luau) - > need assertion + > Failed, need fix ## Benchmark Results diff --git a/tests/ffi/cast.luau b/tests/ffi/cast.luau index e69de29b..9c4d5361 100644 --- a/tests/ffi/cast.luau +++ b/tests/ffi/cast.luau @@ -0,0 +1,13 @@ +local ffi = require("@lune/ffi") + +local floatBox = ffi.f32:box(1.2) +local intBox = ffi.box(ffi.i32.size) + +ffi.f32:cast(ffi.i32, floatBox, intBox) + +local castedInt = ffi.i32:readData(intBox) + +assert( + castedInt == 1 and ffi.isInteger(castedInt), + "castedInt == 1 and ffi.isInteger(castedInt) assersion failed" +) diff --git a/tests/ffi/isInteger.luau b/tests/ffi/isInteger.luau index 1084b8f0..a856df0c 100644 --- a/tests/ffi/isInteger.luau +++ b/tests/ffi/isInteger.luau @@ -1,10 +1,7 @@ ---!nocheck ---!nolint - local ffi = require("@lune/ffi") local int = 0b1 local float = 0.5 -assert(ffi.isInteger(int) == true, "ffi.isInteger(int) == true failed") -assert(ffi.isInteger(float) == false, "ffi.isInteger(float) == false failed") +assert(ffi.isInteger(int) == true, "ffi.isInteger(int) == true assersion failed") +assert(ffi.isInteger(float) == false, "ffi.isInteger(float) == false assersion failed") From 00319f03e3eed5a4faee5e948887bbe738cced9a Mon Sep 17 00:00:00 2001 From: qwreey Date: Thu, 24 Oct 2024 04:52:11 +0000 Subject: [PATCH 49/79] Use camel case naming on ffi test (#243) --- crates/lune-std-ffi/README.md | 8 +--- tests/ffi/benchmark/external_call/init.luau | 6 +-- tests/ffi/external_closure/init.luau | 48 +++++++++++++-------- tests/ffi/external_closure/lib.c | 15 ++++--- tests/ffi/external_math/init.luau | 28 ++++++------ tests/ffi/external_pointer/init.luau | 15 +++---- tests/ffi/external_struct/init.luau | 14 +++--- tests/ffi/external_struct/lib.c | 2 +- tests/ffi/utility/proc_clock/init.luau | 26 +++++------ 9 files changed, 83 insertions(+), 79 deletions(-) diff --git a/crates/lune-std-ffi/README.md b/crates/lune-std-ffi/README.md index 4470901c..c5fa3c8a 100644 --- a/crates/lune-std-ffi/README.md +++ b/crates/lune-std-ffi/README.md @@ -6,14 +6,10 @@ See [tests/ffi](../../tests/ffi/README.md) ## TODO +- Rewrite error messages - Deref - -- Big endianness / Little endianness variable (On process.endianness) - - CString - - Add buffer for owned data support - - Add math operation. > Provide related methods: `CTypeInfo:add(target, from1, from2, ...)` and `:sub` `:mul` `:div` `:mod` `:pow` `:max` `:min` `:gt` `:lt` @@ -28,9 +24,7 @@ See [tests/ffi](../../tests/ffi/README.md) > For windows API - Add varargs support - - Array argument in cfn - - Ref boundary fix ## Code structure diff --git a/tests/ffi/benchmark/external_call/init.luau b/tests/ffi/benchmark/external_call/init.luau index 64e86001..3c4eef6c 100644 --- a/tests/ffi/benchmark/external_call/init.luau +++ b/tests/ffi/benchmark/external_call/init.luau @@ -2,8 +2,8 @@ local ffi = require("@lune/ffi") local c = ffi.c local proc_clock = require("../../utility/proc_clock") -local before, after = proc_clock.new_box() -local get_clock = proc_clock.get_clock +local before, after = proc_clock.newBox() +local get_clock = proc_clock.getClock local testdir = "./tests/ffi/benchmark/external_call" local compile = require("../../utility/compile") @@ -26,7 +26,7 @@ local function bench_add(bench_scale: number) add_callable(a, a_ref, delta_ref) end get_clock(after) - print(proc_clock.get_offset(before, after)) + print(proc_clock.getOffset(before, after)) local result = c.int:readData(a) assert(result == bench_scale, `bench_add failed. result expected {bench_scale}, got {result}`) diff --git a/tests/ffi/external_closure/init.luau b/tests/ffi/external_closure/init.luau index f36b0340..f442b9e4 100644 --- a/tests/ffi/external_closure/init.luau +++ b/tests/ffi/external_closure/init.luau @@ -6,35 +6,47 @@ local compile = require("../utility/compile") compile(`{testdir}/lib.c`, `{testdir}/lib.so`) local lib = ffi.open(`{testdir}/lib.so`) -local function test_closure() - local callback_info = c.fn({ c.int, c.int }, c.int) - local callback_closure = callback_info:closure(function(ret, a, b) +local function test_callClosure() + local closureInfo = c.fn({ c.int, c.int }, c.int) + local closure = closureInfo:closure(function(ret, a, b) c.int:writeData(ret, c.int:readData(a) + c.int:readData(b)) end) - local closure_test_info = c.fn({ callback_info }, c.int) + local callClosure = c.fn({ closureInfo }, c.int):callable(lib:find("call_closure")) - local closure_test_callable = closure_test_info:callable(lib:find("closure")) - - local result_box = ffi.box(c.int.size) - closure_test_callable(result_box, callback_closure:ref()) - local result = c.int:readData(result_box) - assert(result == 72, `test_closure failed. result expected 20000, got {result}`) + local resultBox = ffi.box(c.int.size) + callClosure(resultBox, closure:ref()) + local result = c.int:readData(resultBox) + assert(result == 72, `test_callClosure failed. result expected 20000, got {result}`) end -test_closure() +test_callClosure() -local function test_hello_world() - local callback_info = c.fn({}, c.void) - local callback_closure = callback_info:closure(function() +local function test_helloWorld() + local helloWorldInfo = c.fn({}, c.void) + local helloWorld = helloWorldInfo:closure(function() print("Hello world in lua closure!") end) - local closure_test_info = c.fn({ callback_info }, c.void) + local callHelloWorld = c.fn({ helloWorldInfo }, c.void):callable(lib:find("call_hello_world")) + callHelloWorld(nil, helloWorld:ref()) +end + +test_helloWorld() + +local function test_closureWithPointer() + local closureWithPointerInfo = c.fn({ c.int, c.int:ptr() }, c.int) + local closureWithPointer = closureWithPointerInfo:closure(function(returnRef, aRef, bRef) + c.int:writeData(returnRef, c.int:readData(aRef) + c.int:readData(bRef:deref())) + end) - local closure_test_callable = closure_test_info:callable(lib:find("hello_world")) + local callClosureWithPointer = c.fn({ closureWithPointerInfo }, c.int) + :callable(lib:find("call_closure_with_pointer")) - closure_test_callable(nil, callback_closure:ref()) + local resultBox = ffi.box(c.int.size) + callClosureWithPointer(resultBox, closureWithPointer:ref()) + local result = c.int:readData(resultBox) + assert(result == 72, `test_closureWithPointer failed. result expected 20000, got {result}`) end -test_hello_world() +test_closureWithPointer() diff --git a/tests/ffi/external_closure/lib.c b/tests/ffi/external_closure/lib.c index f14f1002..a5e7a775 100644 --- a/tests/ffi/external_closure/lib.c +++ b/tests/ffi/external_closure/lib.c @@ -1,12 +1,17 @@ #include -typedef int (*lua_callback_t)(int, int); -typedef void (*lua_hello_world_callback_t)(); - -int closure(lua_callback_t lua_closure) { +typedef int (*lua_closure_t)(int, int); +int call_closure(lua_closure_t lua_closure) { return lua_closure(12, 24) * 2; } -void hello_world(lua_hello_world_callback_t lua_closure) { +typedef void (*lua_hello_world_t)(); +void call_hello_world(lua_hello_world_t lua_closure) { lua_closure(); } + +typedef int (*lua_closure_with_pointer_t)(int, int*); +int call_closure_with_pointer(lua_closure_with_pointer_t lua_closure) { + int b = 24; + return lua_closure(12, &b) * 2; +} diff --git a/tests/ffi/external_math/init.luau b/tests/ffi/external_math/init.luau index fe486b91..f4ce95ff 100644 --- a/tests/ffi/external_math/init.luau +++ b/tests/ffi/external_math/init.luau @@ -6,36 +6,32 @@ local compile = require("../utility/compile") compile(`{testdir}/lib.c`, `{testdir}/lib.so`) local lib = ffi.open(`{testdir}/lib.so`) -local function test_add_int() - local add_int_info = c.fn({ c.int, c.int }, c.int) +local function test_addInt() + local addInt = c.fn({ c.int, c.int }, c.int):callable(lib:find("add_int")) - local add_int_callable = add_int_info:callable(lib:find("add_int")) - - local result_box = ffi.box(c.int.size) + local resultBox = ffi.box(c.int.size) local arg1 = c.int:box(100) local arg2 = c.int:box(200) - add_int_callable(result_box, arg1:ref(), arg2:ref()) - local result = c.int:readData(result_box) + addInt(resultBox, arg1:ref(), arg2:ref()) + local result = c.int:readData(resultBox) - assert(result == 300, `add_int failed. result expected 300, got {result}`) + assert(result == 300, `test_addInt failed. result expected 300, got {result}`) end -test_add_int() - -local function test_mul_int() - local mul_int = c.fn({ c.int, c.int }, c.int) +test_addInt() - local mul_int_caller = mul_int:callable(lib:find("mul_int")) +local function test_mulInt() + local mulInt = c.fn({ c.int, c.int }, c.int):callable(lib:find("mul_int")) local resultBox = ffi.box(c.int.size) local arg1 = c.int:box(100) local arg2 = c.int:box(200) - mul_int_caller(resultBox, arg1:ref(), arg2:ref()) + mulInt(resultBox, arg1:ref(), arg2:ref()) local result = c.int:readData(resultBox) - assert(result == 20000, `mul_int failed. result expected 20000, got {result}`) + assert(result == 20000, `test_mulInt failed. result expected 20000, got {result}`) end -test_mul_int() +test_mulInt() diff --git a/tests/ffi/external_pointer/init.luau b/tests/ffi/external_pointer/init.luau index a78f7676..8e0e988f 100644 --- a/tests/ffi/external_pointer/init.luau +++ b/tests/ffi/external_pointer/init.luau @@ -6,18 +6,15 @@ local compile = require("../utility/compile") compile(`{testdir}/lib.c`, `{testdir}/lib.so`) local lib = ffi.open(`{testdir}/lib.so`) -local function test_pointer_write() - local pointer_write_info = c.fn({ c.int:ptr() }, c.void) +local function test_pointerWrite() + local pointerWrite = c.fn({ c.int:ptr() }, c.void):callable(lib:find("pointer_write")) - local pointer_write_callable = pointer_write_info:callable(lib:find("pointer_write")) + local aBox = ffi.box(c.int.size) + pointerWrite(nil, aBox:ref():ref()) - local a = ffi.box(c.int.size) - - pointer_write_callable(nil, a:ref():ref()) - - local result = c.int:readData(a) + local result = c.int:readData(aBox) assert(result == 123, `pointer failed. result expected 123, got {result}`) end -test_pointer_write() +test_pointerWrite() diff --git a/tests/ffi/external_struct/init.luau b/tests/ffi/external_struct/init.luau index d3ae98ab..109ff491 100644 --- a/tests/ffi/external_struct/init.luau +++ b/tests/ffi/external_struct/init.luau @@ -7,19 +7,19 @@ compile(`{testdir}/lib.c`, `{testdir}/lib.so`) local lib = ffi.open(`{testdir}/lib.so`) local function test_AB() - local ArgStruct = c.struct({ c.int, c.int:ptr() }) - local ResultStruct = c.struct({ c.int, c.int }) + local argStructInfo = c.struct({ c.int, c.int:ptr() }) + local resultStructInfo = c.struct({ c.int, c.int }) - local AB = c.fn({ ArgStruct }, ResultStruct) + local AB = c.fn({ argStructInfo }, resultStructInfo) local AB_callable = AB:callable(lib:find("AB")) - local resultBox = ffi.box(ResultStruct.size) + local resultBox = ffi.box(resultStructInfo.size) local b = c.int:box(200) - local arg = ArgStruct:box({ 100, b:ref() }) + local argStruct = argStructInfo:box({ 100, b:ref() }) - AB_callable(resultBox, arg:ref()) - local result = ResultStruct:readData(resultBox) + AB_callable(resultBox, argStruct:ref()) + local result = resultStructInfo:readData(resultBox) assert(result[1] == 300, `AB failed. result expected 300, got {result[1]}`) assert(result[2] == 20000, `AB failed. result expected 300, got {result[2]}`) diff --git a/tests/ffi/external_struct/lib.c b/tests/ffi/external_struct/lib.c index a9e076b9..b542d5d3 100644 --- a/tests/ffi/external_struct/lib.c +++ b/tests/ffi/external_struct/lib.c @@ -9,6 +9,6 @@ typedef struct { } ResultStruct; ResultStruct AB(ArgStruct t) { - ResultStruct result = { t.a+*t.b, t.a**t.b }; + ResultStruct result = { t.a+ * t.b, t.a * (*t.b) }; return result; } diff --git a/tests/ffi/utility/proc_clock/init.luau b/tests/ffi/utility/proc_clock/init.luau index 40744667..720cbd6a 100644 --- a/tests/ffi/utility/proc_clock/init.luau +++ b/tests/ffi/utility/proc_clock/init.luau @@ -2,10 +2,10 @@ local ffi = require("@lune/ffi") local process = require("@lune/process") -local is_windows = process.os == "windows" +local isWindows = process.os == "windows" local c = ffi.c -local proc_clock = {} +local procClock = {} local libdir = "./tests/ffi/utility/proc_clock" local compile = require("../compile") @@ -13,17 +13,17 @@ compile(`{libdir}/lib.c`, `{libdir}/lib.so`) local lib = ffi.open(`{libdir}/lib.so`) -- sizeof_clock -local sizeof_clock = c.fn({}, c.int):callable(lib:find("sizeof_clock")) -function proc_clock.sizeof_clock(): number +local sizeofClock = c.fn({}, c.int):callable(lib:find("sizeof_clock")) +function procClock.sizeofClock(): number local result = ffi.box(c.int.size) - sizeof_clock(result) + sizeofClock(result) return c.int:readData(result) end -- get_clock -local clock_t = if is_windows then ffi.f32 else ffi["u" .. (proc_clock.sizeof_clock() * 8)] +local clock_t = if isWindows then ffi.f32 else ffi["u" .. (procClock.sizeofClock() * 8)] assert(clock_t, "clock_t is unknown type") -proc_clock.get_clock = ( - if is_windows +procClock.getClock = ( + if isWindows then function(clock: ffi.BoxData | ffi.RefData) ffi.f32:writeData(clock, os.clock()) end @@ -31,19 +31,19 @@ proc_clock.get_clock = ( ) :: (ffi.BoxData | ffi.RefData) -> () -- get_offset -local get_offset: (ffi.BoxData, ffi.RefData, ffi.RefData) -> () = if is_windows +local getOffset: (ffi.BoxData, ffi.RefData, ffi.RefData) -> () = if isWindows then function(result: ffi.BoxData, before: ffi.RefData, after: ffi.RefData) ffi.f64:writeData(result, (ffi.f32:readData(after) - ffi.f32:readData(before))) end else c.fn({ clock_t, clock_t }, ffi.f64):callable(lib:find("get_offset")) -function proc_clock.get_offset(before: ffi.BoxData, after: ffi.BoxData): number +function procClock.getOffset(before: ffi.BoxData, after: ffi.BoxData): number local result = ffi.box(ffi.f64.size) - get_offset(result, before:ref(), after:ref()) + getOffset(result, before:ref(), after:ref()) return ffi.f64:readData(result) end -function proc_clock.new_box(): (ffi.BoxData, ffi.BoxData) +function procClock.newBox(): (ffi.BoxData, ffi.BoxData) return ffi.box(clock_t.size), ffi.box(clock_t.size) end -return proc_clock +return procClock From 90c0987754208488db0479aa16b2d7cfe935a49a Mon Sep 17 00:00:00 2001 From: qwreey Date: Thu, 24 Oct 2024 08:34:35 +0000 Subject: [PATCH 50/79] Restruct tests/ffi and add std-ffi tests (#243) --- crates/lune-std-ffi/src/c/fn_info.rs | 4 +- crates/lune-std-ffi/src/c/ptr_info.rs | 2 +- crates/lune-std-ffi/src/c/void_info.rs | 3 + crates/lune/src/tests.rs | 18 ++ print-ignore-me.luau | 12 -- tests/ffi/benchmark/external_call/deno.ts | 4 +- tests/ffi/benchmark/external_call/init.luau | 46 ++--- tests/ffi/benchmark/external_call/luajit.lua | 35 ++-- tests/ffi/external_closure/callClosure.luau | 14 ++ .../callClosureWithPointer.luau | 15 ++ .../ffi/external_closure/callHelloWorld.luau | 12 ++ tests/ffi/external_closure/init.luau | 52 ----- tests/ffi/external_math/addInt.luau | 9 + tests/ffi/external_math/init.luau | 37 ---- tests/ffi/external_math/mulInt.luau | 8 + tests/ffi/external_pointer/init.luau | 20 -- tests/ffi/external_pointer/lib.c | 4 + tests/ffi/external_pointer/pointerRead.luau | 8 + tests/ffi/external_pointer/pointerWrite.luau | 9 + tests/ffi/external_print/helloWorld.luau | 5 + tests/ffi/external_print/init.luau | 17 -- tests/ffi/external_struct/ab.luau | 12 ++ tests/ffi/external_struct/init.luau | 28 --- tests/ffi/external_struct/lib.c | 2 +- .../{pretty_print.luau => prettyPrint.luau} | 0 .../{read_boundary.luau => readBoundary.luau} | 2 - tests/ffi/utility/compile.luau | 9 - tests/ffi/utils/callableWrapper.luau | 38 ++++ tests/ffi/utils/compile.luau | 25 +++ .../{utility/deno.ts => utils/libSuffix.ts} | 0 .../ffi/{utility => utils}/proc_clock/deno.ts | 4 +- .../{utility => utils}/proc_clock/init.luau | 5 +- tests/ffi/{utility => utils}/proc_clock/lib.c | 0 ...write_boundary.luau => writeBoundary.luau} | 1 - types/ffi.luau | 192 ++++++++++++------ 35 files changed, 350 insertions(+), 302 deletions(-) delete mode 100644 print-ignore-me.luau create mode 100644 tests/ffi/external_closure/callClosure.luau create mode 100644 tests/ffi/external_closure/callClosureWithPointer.luau create mode 100644 tests/ffi/external_closure/callHelloWorld.luau delete mode 100644 tests/ffi/external_closure/init.luau create mode 100644 tests/ffi/external_math/addInt.luau delete mode 100644 tests/ffi/external_math/init.luau create mode 100644 tests/ffi/external_math/mulInt.luau delete mode 100644 tests/ffi/external_pointer/init.luau create mode 100644 tests/ffi/external_pointer/pointerRead.luau create mode 100644 tests/ffi/external_pointer/pointerWrite.luau create mode 100644 tests/ffi/external_print/helloWorld.luau delete mode 100644 tests/ffi/external_print/init.luau create mode 100644 tests/ffi/external_struct/ab.luau delete mode 100644 tests/ffi/external_struct/init.luau rename tests/ffi/{pretty_print.luau => prettyPrint.luau} (100%) rename tests/ffi/{read_boundary.luau => readBoundary.luau} (99%) delete mode 100644 tests/ffi/utility/compile.luau create mode 100644 tests/ffi/utils/callableWrapper.luau create mode 100644 tests/ffi/utils/compile.luau rename tests/ffi/{utility/deno.ts => utils/libSuffix.ts} (100%) rename tests/ffi/{utility => utils}/proc_clock/deno.ts (83%) rename tests/ffi/{utility => utils}/proc_clock/init.luau (89%) rename tests/ffi/{utility => utils}/proc_clock/lib.c (100%) rename tests/ffi/{write_boundary.luau => writeBoundary.luau} (99%) diff --git a/crates/lune-std-ffi/src/c/fn_info.rs b/crates/lune-std-ffi/src/c/fn_info.rs index 43b7f543..29944991 100644 --- a/crates/lune-std-ffi/src/c/fn_info.rs +++ b/crates/lune-std-ffi/src/c/fn_info.rs @@ -43,7 +43,6 @@ impl FfiSignedness for CFnInfo { false } } - impl FfiSize for CFnInfo { fn get_size(&self) -> usize { SIZE_OF_POINTER @@ -203,6 +202,9 @@ impl CFnInfo { } impl LuaUserData for CFnInfo { + fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("size", |_, _| Ok(SIZE_OF_POINTER)); + } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { // Subtype method_provider::provide_ptr(methods); diff --git a/crates/lune-std-ffi/src/c/ptr_info.rs b/crates/lune-std-ffi/src/c/ptr_info.rs index f39b4251..0758ba82 100644 --- a/crates/lune-std-ffi/src/c/ptr_info.rs +++ b/crates/lune-std-ffi/src/c/ptr_info.rs @@ -124,7 +124,7 @@ impl CPtrInfo { impl LuaUserData for CPtrInfo { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("size", |_, _| Ok(size_of::())); + fields.add_field_method_get("size", |_, _| Ok(SIZE_OF_POINTER)); fields.add_field_function_get("inner", |lua, this| { let inner = association::get(lua, CPTR_INNER, this)? .ok_or_else(|| LuaError::external("inner type not found"))?; diff --git a/crates/lune-std-ffi/src/c/void_info.rs b/crates/lune-std-ffi/src/c/void_info.rs index 05ad57d6..97a2fa28 100644 --- a/crates/lune-std-ffi/src/c/void_info.rs +++ b/crates/lune-std-ffi/src/c/void_info.rs @@ -31,6 +31,9 @@ impl CVoidInfo { } impl LuaUserData for CVoidInfo { + fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("size", |_, _| Ok(0)); + } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { method_provider::provide_to_string(methods); method_provider::provide_ptr(methods); diff --git a/crates/lune/src/tests.rs b/crates/lune/src/tests.rs index d5f56404..acce10ec 100644 --- a/crates/lune/src/tests.rs +++ b/crates/lune/src/tests.rs @@ -99,6 +99,24 @@ create_tests! { datetime_to_universal_time: "datetime/toUniversalTime", } +#[cfg(feature = "std-ffi")] +create_tests! { + ffi_external_closure_call_closure: "ffi/external_closure/callClosure", + ffi_external_closure_call_closure_with_pointer: "ffi/external_closure/callClosureWithPointer", + ffi_external_closure_call_hello_world: "ffi/external_closure/callHelloWorld", + ffi_external_math_add_int: "ffi/external_math/addInt", + ffi_external_math_mul_int: "ffi/external_math/mulInt", + ffi_external_pointer_pointer_read: "ffi/external_pointer/pointerRead", + ffi_external_pointer_pointer_write: "ffi/external_pointer/pointerWrite", + ffi_external_print_hello_world: "ffi/external_print/helloWorld", + ffi_external_struct_ab: "ffi/external_struct/ab", + ffi_cast: "ffi/cast", + ffi_is_integer: "ffi/isInteger", + ffi_pretty_print: "ffi/prettyPrint", + ffi_read_boundary: "ffi/readBoundary", + ffi_write_boundary: "ffi/writeBoundary", +} + #[cfg(feature = "std-fs")] create_tests! { fs_files: "fs/files", diff --git a/print-ignore-me.luau b/print-ignore-me.luau deleted file mode 100644 index 3686c9ea..00000000 --- a/print-ignore-me.luau +++ /dev/null @@ -1,12 +0,0 @@ -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/benchmark/external_call/deno.ts b/tests/ffi/benchmark/external_call/deno.ts index 46b56e0c..7332ae18 100644 --- a/tests/ffi/benchmark/external_call/deno.ts +++ b/tests/ffi/benchmark/external_call/deno.ts @@ -1,5 +1,5 @@ -import { libSuffix } from "../../utility/deno.ts"; -import { get_clock, get_offset } from "../../utility/proc_clock/deno.ts"; +import { libSuffix } from "../../utils/libSuffix.ts"; +import { get_clock, get_offset } from "../../utils/proc_clock/deno.ts"; const library_file = "./tests/ffi/benchmark/external_call/lib."+libSuffix; // @ts-ignore diff --git a/tests/ffi/benchmark/external_call/init.luau b/tests/ffi/benchmark/external_call/init.luau index 3c4eef6c..6df592be 100644 --- a/tests/ffi/benchmark/external_call/init.luau +++ b/tests/ffi/benchmark/external_call/init.luau @@ -1,35 +1,27 @@ local ffi = require("@lune/ffi") +local lib = require("../../utility/compile")("./tests/ffi/benchmark/external_call/lib.c") +local process = require("@lune/process") local c = ffi.c +local BENCH_SCALE: number = tonumber(process.env.BENCH_SCALE) or 1000000 -local proc_clock = require("../../utility/proc_clock") -local before, after = proc_clock.newBox() -local get_clock = proc_clock.getClock +-- Get clock provider +local procClock = require("../../utility/proc_clock") +local before, after = procClock.newBox() +local getClock = procClock.getClock -local testdir = "./tests/ffi/benchmark/external_call" -local compile = require("../../utility/compile") -compile(`{testdir}/lib.c`, `{testdir}/lib.so`) -local lib = ffi.open(`{testdir}/lib.so`) +local add = c.fn({ c.int, c.int }, c.int):callable(lib:find("add")) -local function bench_add(bench_scale: number) - local add_info = c.fn({ c.int, c.int }, c.int) +local a = c.int:box(0) +local delta = c.int:box(1) +local a_ref = a:ref() +local delta_ref = delta:ref() - local add_callable = add_info:callable(lib:find("add")) - - local a = c.int:box(0) - local delta = c.int:box(1) - - local a_ref = a:ref() - local delta_ref = delta:ref() - - get_clock(before) - for i = 1, bench_scale do - add_callable(a, a_ref, delta_ref) - end - get_clock(after) - print(proc_clock.getOffset(before, after)) - - local result = c.int:readData(a) - assert(result == bench_scale, `bench_add failed. result expected {bench_scale}, got {result}`) +getClock(before) +for i = 1, BENCH_SCALE do + add(a, a_ref, delta_ref) end +getClock(after) -bench_add(1000000) +print(procClock.getOffset(before, after)) +local result = c.int:readData(a) +assert(result == BENCH_SCALE, `bench_add failed. result expected {BENCH_SCALE}, got {result}`) diff --git a/tests/ffi/benchmark/external_call/luajit.lua b/tests/ffi/benchmark/external_call/luajit.lua index e5dc41a8..b1eb6f43 100644 --- a/tests/ffi/benchmark/external_call/luajit.lua +++ b/tests/ffi/benchmark/external_call/luajit.lua @@ -2,26 +2,23 @@ --!nocheck local ffi = require("ffi") +local BENCH_SCALE = 1000000 -local function bench_add(bench_scale) - ffi.cdef([[ - int add(int a, int b); - ]]) - local lib = ffi.load("./tests/ffi/benchmark/external_call/lib.so") - local add = lib.add - local a = 0 +ffi.cdef([[ + int add(int a, int b); +]]) +local lib = ffi.load("./tests/ffi/benchmark/external_call/lib.so") +local add = lib.add +local a = 0 - local before = os.clock() - for i = 1, bench_scale do - a = add(a, 1) - end - local after = os.clock() - - print(after - before) - assert( - a == bench_scale, - string.format("bench_add failed. result expected %d, got %d", bench_scale, a) - ) +local before = os.clock() +for i = 1, BENCH_SCALE do + a = add(a, 1) end +local after = os.clock() -bench_add(1000000) +print(after - before) +assert( + a == BENCH_SCALE, + string.format("bench_add failed. result expected %d, got %d", BENCH_SCALE, a) +) diff --git a/tests/ffi/external_closure/callClosure.luau b/tests/ffi/external_closure/callClosure.luau new file mode 100644 index 00000000..b73fe6c7 --- /dev/null +++ b/tests/ffi/external_closure/callClosure.luau @@ -0,0 +1,14 @@ +local callableWrapper = require("../utils/callableWrapper") +local ffi = require("@lune/ffi") +local lib = require("../utils/compile")("./tests/ffi/external_closure/lib.c") +local c = ffi.c + +-- Create closure +local closureInfo = c.fn({ c.int, c.int }, c.int) +local closure = closureInfo:closure(function(ret, a, b) + c.int:writeData(ret, c.int:readData(a) + c.int:readData(b)) +end) + +local callClosure = callableWrapper(lib:find("call_closure"), { closureInfo }, c.int) +local result = callClosure(closure:ref()) +assert(result == 72, `callClosure failed. result expected 20000, got {result}`) diff --git a/tests/ffi/external_closure/callClosureWithPointer.luau b/tests/ffi/external_closure/callClosureWithPointer.luau new file mode 100644 index 00000000..5fd47b91 --- /dev/null +++ b/tests/ffi/external_closure/callClosureWithPointer.luau @@ -0,0 +1,15 @@ +local callableWrapper = require("../utils/callableWrapper") +local ffi = require("@lune/ffi") +local lib = require("../utils/compile")("./tests/ffi/external_closure/lib.c") +local c = ffi.c + +-- Create closure +local closureWithPointerInfo = c.fn({ c.int, c.int:ptr() }, c.int) +local closureWithPointer = closureWithPointerInfo:closure(function(returnRef, aRef, bRef) + c.int:writeData(returnRef, c.int:readData(aRef) + c.int:readData(bRef:deref())) +end) + +local callClosureWithPointer = + callableWrapper(lib:find("call_closure_with_pointer"), { closureWithPointerInfo }, c.int) +local result = callClosureWithPointer(closureWithPointer:ref()) +assert(result == 72, `closureWithPointer failed. result expected 20000, got {result}`) diff --git a/tests/ffi/external_closure/callHelloWorld.luau b/tests/ffi/external_closure/callHelloWorld.luau new file mode 100644 index 00000000..811601d1 --- /dev/null +++ b/tests/ffi/external_closure/callHelloWorld.luau @@ -0,0 +1,12 @@ +local ffi = require("@lune/ffi") +local lib = require("../utils/compile")("./tests/ffi/external_closure/lib.c") +local c = ffi.c + +-- Create closure +local helloWorldInfo = c.fn({}, c.void) +local helloWorld = helloWorldInfo:closure(function() + print("Hello world in lua closure!") +end) + +local callHelloWorld = c.fn({ helloWorldInfo }, c.void):callable(lib:find("call_hello_world")) +callHelloWorld(nil, helloWorld:ref()) diff --git a/tests/ffi/external_closure/init.luau b/tests/ffi/external_closure/init.luau deleted file mode 100644 index f442b9e4..00000000 --- a/tests/ffi/external_closure/init.luau +++ /dev/null @@ -1,52 +0,0 @@ -local ffi = require("@lune/ffi") -local c = ffi.c - -local testdir = "./tests/ffi/external_closure" -local compile = require("../utility/compile") -compile(`{testdir}/lib.c`, `{testdir}/lib.so`) -local lib = ffi.open(`{testdir}/lib.so`) - -local function test_callClosure() - local closureInfo = c.fn({ c.int, c.int }, c.int) - local closure = closureInfo:closure(function(ret, a, b) - c.int:writeData(ret, c.int:readData(a) + c.int:readData(b)) - end) - - local callClosure = c.fn({ closureInfo }, c.int):callable(lib:find("call_closure")) - - local resultBox = ffi.box(c.int.size) - callClosure(resultBox, closure:ref()) - local result = c.int:readData(resultBox) - assert(result == 72, `test_callClosure failed. result expected 20000, got {result}`) -end - -test_callClosure() - -local function test_helloWorld() - local helloWorldInfo = c.fn({}, c.void) - local helloWorld = helloWorldInfo:closure(function() - print("Hello world in lua closure!") - end) - - local callHelloWorld = c.fn({ helloWorldInfo }, c.void):callable(lib:find("call_hello_world")) - callHelloWorld(nil, helloWorld:ref()) -end - -test_helloWorld() - -local function test_closureWithPointer() - local closureWithPointerInfo = c.fn({ c.int, c.int:ptr() }, c.int) - local closureWithPointer = closureWithPointerInfo:closure(function(returnRef, aRef, bRef) - c.int:writeData(returnRef, c.int:readData(aRef) + c.int:readData(bRef:deref())) - end) - - local callClosureWithPointer = c.fn({ closureWithPointerInfo }, c.int) - :callable(lib:find("call_closure_with_pointer")) - - local resultBox = ffi.box(c.int.size) - callClosureWithPointer(resultBox, closureWithPointer:ref()) - local result = c.int:readData(resultBox) - assert(result == 72, `test_closureWithPointer failed. result expected 20000, got {result}`) -end - -test_closureWithPointer() diff --git a/tests/ffi/external_math/addInt.luau b/tests/ffi/external_math/addInt.luau new file mode 100644 index 00000000..d63f3132 --- /dev/null +++ b/tests/ffi/external_math/addInt.luau @@ -0,0 +1,9 @@ +local callableWrapper = require("../utils/callableWrapper") +local ffi = require("@lune/ffi") +local lib = require("../utils/compile")("./tests/ffi/external_math/lib.c") +local c = ffi.c + +local addInt = callableWrapper(lib:find("add_int"), { c.int, c.int }, c.int) +local result = addInt(100, 200) + +assert(result == 300, `test_addInt failed. result expected 300, got {result}`) diff --git a/tests/ffi/external_math/init.luau b/tests/ffi/external_math/init.luau deleted file mode 100644 index f4ce95ff..00000000 --- a/tests/ffi/external_math/init.luau +++ /dev/null @@ -1,37 +0,0 @@ -local ffi = require("@lune/ffi") -local c = ffi.c - -local testdir = "./tests/ffi/external_math" -local compile = require("../utility/compile") -compile(`{testdir}/lib.c`, `{testdir}/lib.so`) -local lib = ffi.open(`{testdir}/lib.so`) - -local function test_addInt() - local addInt = c.fn({ c.int, c.int }, c.int):callable(lib:find("add_int")) - - local resultBox = ffi.box(c.int.size) - local arg1 = c.int:box(100) - local arg2 = c.int:box(200) - - addInt(resultBox, arg1:ref(), arg2:ref()) - local result = c.int:readData(resultBox) - - assert(result == 300, `test_addInt failed. result expected 300, got {result}`) -end - -test_addInt() - -local function test_mulInt() - local mulInt = c.fn({ c.int, c.int }, c.int):callable(lib:find("mul_int")) - - local resultBox = ffi.box(c.int.size) - local arg1 = c.int:box(100) - local arg2 = c.int:box(200) - - mulInt(resultBox, arg1:ref(), arg2:ref()) - local result = c.int:readData(resultBox) - - assert(result == 20000, `test_mulInt failed. result expected 20000, got {result}`) -end - -test_mulInt() diff --git a/tests/ffi/external_math/mulInt.luau b/tests/ffi/external_math/mulInt.luau new file mode 100644 index 00000000..e14a86bb --- /dev/null +++ b/tests/ffi/external_math/mulInt.luau @@ -0,0 +1,8 @@ +local callableWrapper = require("../utils/callableWrapper") +local ffi = require("@lune/ffi") +local lib = require("../utils/compile")("./tests/ffi/external_math/lib.c") +local c = ffi.c + +local mulInt = callableWrapper(lib:find("mul_int"), { c.int, c.int }, c.int) +local result = mulInt(100, 200) +assert(result == 20000, `test_mulInt failed. result expected 20000, got {result}`) diff --git a/tests/ffi/external_pointer/init.luau b/tests/ffi/external_pointer/init.luau deleted file mode 100644 index 8e0e988f..00000000 --- a/tests/ffi/external_pointer/init.luau +++ /dev/null @@ -1,20 +0,0 @@ -local ffi = require("@lune/ffi") -local c = ffi.c - -local testdir = "./tests/ffi/external_pointer" -local compile = require("../utility/compile") -compile(`{testdir}/lib.c`, `{testdir}/lib.so`) -local lib = ffi.open(`{testdir}/lib.so`) - -local function test_pointerWrite() - local pointerWrite = c.fn({ c.int:ptr() }, c.void):callable(lib:find("pointer_write")) - - local aBox = ffi.box(c.int.size) - pointerWrite(nil, aBox:ref():ref()) - - local result = c.int:readData(aBox) - - assert(result == 123, `pointer failed. result expected 123, got {result}`) -end - -test_pointerWrite() diff --git a/tests/ffi/external_pointer/lib.c b/tests/ffi/external_pointer/lib.c index 697fd090..7d7440a8 100644 --- a/tests/ffi/external_pointer/lib.c +++ b/tests/ffi/external_pointer/lib.c @@ -1,3 +1,7 @@ void pointer_write(int *a) { *a = 123; } + +int pointer_read(int *a) { + return *a; +} diff --git a/tests/ffi/external_pointer/pointerRead.luau b/tests/ffi/external_pointer/pointerRead.luau new file mode 100644 index 00000000..e2490a3f --- /dev/null +++ b/tests/ffi/external_pointer/pointerRead.luau @@ -0,0 +1,8 @@ +local callableWrapper = require("../utils/callableWrapper") +local ffi = require("@lune/ffi") +local lib = require("../utils/compile")("./tests/ffi/external_pointer/lib.c") +local c = ffi.c + +local pointerRead = callableWrapper(lib:find("pointer_read"), { c.int:ptr() }, c.int) +local result = pointerRead(c.int:box(123):ref():ref()) +assert(result == 123, `pointerRead failed. result expected 123, got {result}`) diff --git a/tests/ffi/external_pointer/pointerWrite.luau b/tests/ffi/external_pointer/pointerWrite.luau new file mode 100644 index 00000000..72a9b40b --- /dev/null +++ b/tests/ffi/external_pointer/pointerWrite.luau @@ -0,0 +1,9 @@ +local ffi = require("@lune/ffi") +local lib = require("../utils/compile")("./tests/ffi/external_pointer/lib.c") +local c = ffi.c + +local pointerWrite = c.fn({ c.int:ptr() }, c.void):callable(lib:find("pointer_write")) +local aBox = ffi.box(c.int.size) +pointerWrite(nil, aBox:ref():ref()) +local result = c.int:readData(aBox) +assert(result == 123, `pointerWrite failed. result expected 123, got {result}`) diff --git a/tests/ffi/external_print/helloWorld.luau b/tests/ffi/external_print/helloWorld.luau new file mode 100644 index 00000000..665283b1 --- /dev/null +++ b/tests/ffi/external_print/helloWorld.luau @@ -0,0 +1,5 @@ +local ffi = require("@lune/ffi") +local lib = require("../utils/compile")("./tests/ffi/external_print/lib.c") +local c = ffi.c + +c.fn({}, c.void):callable(lib:find("hello_world"))(nil) diff --git a/tests/ffi/external_print/init.luau b/tests/ffi/external_print/init.luau deleted file mode 100644 index 174fdc2c..00000000 --- a/tests/ffi/external_print/init.luau +++ /dev/null @@ -1,17 +0,0 @@ -local ffi = require("@lune/ffi") -local c = ffi.c - -local testdir = "./tests/ffi/external_print" -local compile = require("../utility/compile") -compile(`{testdir}/lib.c`, `{testdir}/lib.so`) -local lib = ffi.open(`{testdir}/lib.so`) - -local function test_hello_world() - local hello_world_info = c.fn({}, c.void) - - local hello_world_callable = hello_world_info:callable(lib:find("hello_world")) - - hello_world_callable(nil) -end - -test_hello_world() diff --git a/tests/ffi/external_struct/ab.luau b/tests/ffi/external_struct/ab.luau new file mode 100644 index 00000000..114b74c3 --- /dev/null +++ b/tests/ffi/external_struct/ab.luau @@ -0,0 +1,12 @@ +local callableWrapper = require("../utils/callableWrapper") +local ffi = require("@lune/ffi") +local lib = require("../utils/compile")("./tests/ffi/external_struct/lib.c") +local c = ffi.c + +local argStructInfo = c.struct({ c.int, c.int:ptr() }) +local resultStructInfo = c.struct({ c.int, c.int }) + +local ab = callableWrapper(lib:find("ab"), { argStructInfo }, resultStructInfo) +local result = ab({ 100, c.int:box(200):ref() } :: { any }) +assert(result[1] == 300, `ab failed. result expected 300, got {result[1]}`) +assert(result[2] == 20000, `ab failed. result expected 300, got {result[2]}`) diff --git a/tests/ffi/external_struct/init.luau b/tests/ffi/external_struct/init.luau deleted file mode 100644 index 109ff491..00000000 --- a/tests/ffi/external_struct/init.luau +++ /dev/null @@ -1,28 +0,0 @@ -local ffi = require("@lune/ffi") -local c = ffi.c - -local testdir = "./tests/ffi/external_struct" -local compile = require("../utility/compile") -compile(`{testdir}/lib.c`, `{testdir}/lib.so`) -local lib = ffi.open(`{testdir}/lib.so`) - -local function test_AB() - local argStructInfo = c.struct({ c.int, c.int:ptr() }) - local resultStructInfo = c.struct({ c.int, c.int }) - - local AB = c.fn({ argStructInfo }, resultStructInfo) - - local AB_callable = AB:callable(lib:find("AB")) - - local resultBox = ffi.box(resultStructInfo.size) - local b = c.int:box(200) - local argStruct = argStructInfo:box({ 100, b:ref() }) - - AB_callable(resultBox, argStruct:ref()) - local result = resultStructInfo:readData(resultBox) - - assert(result[1] == 300, `AB failed. result expected 300, got {result[1]}`) - assert(result[2] == 20000, `AB failed. result expected 300, got {result[2]}`) -end - -test_AB() diff --git a/tests/ffi/external_struct/lib.c b/tests/ffi/external_struct/lib.c index b542d5d3..f68a0674 100644 --- a/tests/ffi/external_struct/lib.c +++ b/tests/ffi/external_struct/lib.c @@ -8,7 +8,7 @@ typedef struct { int mul; } ResultStruct; -ResultStruct AB(ArgStruct t) { +ResultStruct ab(ArgStruct t) { ResultStruct result = { t.a+ * t.b, t.a * (*t.b) }; return result; } diff --git a/tests/ffi/pretty_print.luau b/tests/ffi/prettyPrint.luau similarity index 100% rename from tests/ffi/pretty_print.luau rename to tests/ffi/prettyPrint.luau diff --git a/tests/ffi/read_boundary.luau b/tests/ffi/readBoundary.luau similarity index 99% rename from tests/ffi/read_boundary.luau rename to tests/ffi/readBoundary.luau index bc573579..dd8e3d25 100644 --- a/tests/ffi/read_boundary.luau +++ b/tests/ffi/readBoundary.luau @@ -1,5 +1,4 @@ local ffi = require("@lune/ffi") - local ok -- Case1: Success @@ -24,7 +23,6 @@ end) assert(ok, "assersion failed, Case3 should success") -- Case4: Success - ok = pcall(function() local box = ffi.box(ffi.u8.size * 2) ffi.u8:readData(box, ffi.u8.size) diff --git a/tests/ffi/utility/compile.luau b/tests/ffi/utility/compile.luau deleted file mode 100644 index 5cb24347..00000000 --- a/tests/ffi/utility/compile.luau +++ /dev/null @@ -1,9 +0,0 @@ -local process = require("@lune/process") -local function compile(file, out) - local gcc = process.exec("gcc", { "-shared", "-o", out, "-fPIC", file }) - if not gcc.ok then - error("Failed to execute gcc command\n" .. gcc.stdout .. gcc.stderr) - end -end - -return compile diff --git a/tests/ffi/utils/callableWrapper.luau b/tests/ffi/utils/callableWrapper.luau new file mode 100644 index 00000000..ffa9597c --- /dev/null +++ b/tests/ffi/utils/callableWrapper.luau @@ -0,0 +1,38 @@ +--!nocheck +local ffi = require("@lune/ffi") + +local function callableWrapper( + functionRef: ffi.RefData, + argTypeList: { ffi.CTypes }, + retType: ffi.CTypes +): (...any) -> any + local callable = ffi.c.fn(argTypeList, retType):callable(functionRef) + + return function(...) + local argValues = table.create(#argTypeList + 1) + + local resultBox + if retType ~= ffi.c.void then + resultBox = ffi.box(retType.size) + end + argValues[1] = resultBox + + for index, argType in argTypeList do + local arg = select(index, ...) + if type(arg) == "userdata" then + argValues[index + 1] = arg + else + argValues[index + 1] = argType:box(arg):ref() + end + end + + callable(table.unpack(argValues, 1, #argTypeList + 1)) + + if retType == ffi.c.void then + return nil + end + return retType:readData(resultBox) + end +end + +return callableWrapper diff --git a/tests/ffi/utils/compile.luau b/tests/ffi/utils/compile.luau new file mode 100644 index 00000000..624ddaf0 --- /dev/null +++ b/tests/ffi/utils/compile.luau @@ -0,0 +1,25 @@ +local ffi = require("@lune/ffi") +local process = require("@lune/process") + +local function getLibSuffix(): string + if process.os == "linux" then + return "so" + elseif process.os == "windows" then + return "dll" + elseif process.os == "macos" then + return "dylib" + end + error("Unknown OS") +end + +local function compile(file: string): ffi.LibData + local out = file:gsub("%.c$", "." .. getLibSuffix()) + local gcc = process.exec("gcc", { "-shared", "-o", out, "-fPIC", file }) + if not gcc.ok then + error("Failed to execute gcc command\n" .. gcc.stdout .. gcc.stderr) + end + + return ffi.open(out) +end + +return compile diff --git a/tests/ffi/utility/deno.ts b/tests/ffi/utils/libSuffix.ts similarity index 100% rename from tests/ffi/utility/deno.ts rename to tests/ffi/utils/libSuffix.ts diff --git a/tests/ffi/utility/proc_clock/deno.ts b/tests/ffi/utils/proc_clock/deno.ts similarity index 83% rename from tests/ffi/utility/proc_clock/deno.ts rename to tests/ffi/utils/proc_clock/deno.ts index d5c8d140..23ea8d4a 100644 --- a/tests/ffi/utility/proc_clock/deno.ts +++ b/tests/ffi/utils/proc_clock/deno.ts @@ -1,6 +1,6 @@ -import { libSuffix } from "../deno.ts"; +import { libSuffix } from "../libSuffix.ts"; -const library_file = "./tests/ffi/utility/proc_clock/lib."+libSuffix; +const library_file = "./tests/ffi/utils/proc_clock/lib."+libSuffix; // @ts-ignore let library = Deno.dlopen(library_file, { sizeof_clock: { diff --git a/tests/ffi/utility/proc_clock/init.luau b/tests/ffi/utils/proc_clock/init.luau similarity index 89% rename from tests/ffi/utility/proc_clock/init.luau rename to tests/ffi/utils/proc_clock/init.luau index 720cbd6a..8877a4c5 100644 --- a/tests/ffi/utility/proc_clock/init.luau +++ b/tests/ffi/utils/proc_clock/init.luau @@ -7,10 +7,7 @@ local c = ffi.c local procClock = {} -local libdir = "./tests/ffi/utility/proc_clock" -local compile = require("../compile") -compile(`{libdir}/lib.c`, `{libdir}/lib.so`) -local lib = ffi.open(`{libdir}/lib.so`) +local lib = require("../compile")("./tests/ffi/utils/proc_clock/lib.c") -- sizeof_clock local sizeofClock = c.fn({}, c.int):callable(lib:find("sizeof_clock")) diff --git a/tests/ffi/utility/proc_clock/lib.c b/tests/ffi/utils/proc_clock/lib.c similarity index 100% rename from tests/ffi/utility/proc_clock/lib.c rename to tests/ffi/utils/proc_clock/lib.c diff --git a/tests/ffi/write_boundary.luau b/tests/ffi/writeBoundary.luau similarity index 99% rename from tests/ffi/write_boundary.luau rename to tests/ffi/writeBoundary.luau index 53291d6e..afb2b162 100644 --- a/tests/ffi/write_boundary.luau +++ b/tests/ffi/writeBoundary.luau @@ -1,6 +1,5 @@ local ffi = require("@lune/ffi") local c = ffi.c - local ok -- Case1: Fail diff --git a/types/ffi.luau b/types/ffi.luau index f21b4bf5..a60c6ee4 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -42,15 +42,13 @@ local ffi = {} --[=[ @class C - @within FFI Namespace for compile time sized c types. ]=] local c = {} ffi.c = c ---#region Data -- - +--#region Data --[=[ @class RefData @@ -124,7 +122,13 @@ export type RefData = { @param dst_offset The offset in the destination where the data will be pasted @param src_offset The offset in the source data from where the data will be copied ]=] - copyFrom: (self: RefData, src: (BoxData|RefData), length: number, dst_offset: number, src_offset: number)->(); + copyFrom: ( + self: RefData, + src: BoxData | RefData, + length: number, + dst_offset: number, + src_offset: number + ) -> (), } --[=[ @@ -190,7 +194,13 @@ export type BoxData = { @param dst_offset The offset in the destination where the data will be pasted @param src_offset The offset in the source data from where the data will be copied ]=] - copyFrom: (self: BoxData, src: (BoxData|RefData), length: number, dst_offset: number, src_offset: number)->(); + copyFrom: ( + self: BoxData, + src: BoxData | RefData, + length: number, + dst_offset: number, + src_offset: number + ) -> (), } --[=[ @@ -223,7 +233,10 @@ export type LibData = { If return type is `void`, pass `nil`. ]=] -export type CallableData = (ret: (RefData|BoxData)?, ...RefData)->() & { +export type CallableData = ( + ret: (RefData | BoxData)?, + ...RefData +) -> () & { -- apply: (self: Callable, args: Args)->AppliedCallable, } @@ -246,13 +259,11 @@ export type ClosureData = { @return A reference of the closure ]=] - ref: (self: ClosureData)->RefData, + ref: (self: ClosureData) -> RefData, } +--#endregion Data ---#endregion Data -- - ---#region C ABI Type Infos -- - +--#region C ABI Type Infos -- NOTE: T is a unique identifier for the `CType` and R is the closest Lua type. export type CTypeInfo = { --[=[ @@ -278,14 +289,19 @@ export type CTypeInfo = { -- realize box: (self: CTypeInfo, val: R) -> BoxData, - readData: (self: CTypeInfo, target: (RefData|BoxData), offset: number?) -> R, - writeData: (self: CTypeInfo, target: (RefData|BoxData), value: R, offset: number?) -> (), - stringifyData: (self: CTypeInfo, target: (RefData|BoxData), offset: number?) -> string, + readData: (self: CTypeInfo, target: RefData | BoxData, offset: number?) -> R, + writeData: (self: CTypeInfo, target: RefData | BoxData, value: R, offset: number?) -> (), + stringifyData: (self: CTypeInfo, target: RefData | BoxData, offset: number?) -> string, -- FIXME: recursive types; 'intoType' should be CTypes - cast: (self: CTypeInfo, intoType: any, fromData: (RefData|BoxData), intoData: (RefData|BoxData)) -> (), + cast: ( + self: CTypeInfo, + intoType: any, + fromData: RefData | BoxData, + intoData: RefData | BoxData + ) -> (), } & { ["__phantom"]: T } -type NumCType = CTypeInfo +type NumCType = CTypeInfo export type CPtrInfo = { --[=[ @@ -313,8 +329,13 @@ export type CPtrInfo = { -- FIXME: recursive types; result 'any' should be CPtrInfo> ptr: (self: CPtrInfo) -> any, - readRef: (self: CPtrInfo, target: (RefData|BoxData), offset: number?) -> RefData, - writeRef: (self: CPtrInfo, target: (RefData|BoxData), value: (RefData|BoxData), offset: number?) -> (), + readRef: (self: CPtrInfo, target: RefData | BoxData, offset: number?) -> RefData, + writeRef: ( + self: CPtrInfo, + target: RefData | BoxData, + value: RefData | BoxData, + offset: number? + ) -> (), } --[=[ @@ -353,9 +374,20 @@ export type CArrInfo = { -- realize box: (self: CArrInfo, table: { T }) -> BoxData, - readData: (self: CArrInfo, target: (RefData|BoxData), offset: number?) -> { T }, - writeData: (self: CArrInfo, target: (RefData|BoxData), value: { R }, target_offset: number?) -> (), - copyData: (self: CArrInfo, dst: (RefData|BoxData), src: (RefData|BoxData), dst_offset: number?, src_offset: number?) -> (), + readData: (self: CArrInfo, target: RefData | BoxData, offset: number?) -> { T }, + writeData: ( + self: CArrInfo, + target: RefData | BoxData, + value: { R }, + target_offset: number? + ) -> (), + copyData: ( + self: CArrInfo, + dst: RefData | BoxData, + src: RefData | BoxData, + dst_offset: number?, + src_offset: number? + ) -> (), offset: (self: CArrInfo, index: number) -> number, } @@ -366,6 +398,16 @@ export type CArrInfo = { A c function signature type information. ]=] export type CFnInfo = { + --[=[ + @within CFnInfo + @tag Field + @field size + + The size of a function pointer. + + Equivalent to `ffi.c.usize.size`. + ]=] + size: number, --[=[ @within CFnInfo @tag Method @@ -385,7 +427,7 @@ export type CFnInfo = { @return A closure. ]=] - closure: (self: CFnInfo, (ret: RefData, ...RefData)->()) -> ClosureData, + closure: (self: CFnInfo, (ret: RefData, ...RefData) -> ()) -> ClosureData, } --[=[ @@ -394,6 +436,13 @@ export type CFnInfo = { A c struct type information. ]=] export type CStructInfo = { + --[=[ + @within CStructInfo + @tag Field + @field size + + The size of a struct, including padding. + ]=] size: number, --[=[ @@ -406,7 +455,7 @@ export type CStructInfo = { @param len The length of the array @return A struct array type ]=] - arr: (self: CStructInfo, len: number) -> CArrInfo, + arr: (self: CStructInfo, len: number) -> CArrInfo, --[=[ @within CSturctInfo @tag Method @@ -419,9 +468,20 @@ export type CStructInfo = { ptr: (self: CStructInfo) -> CPtrInfo, box: (self: CStructInfo, table: { any }) -> BoxData, - readData: (self: CStructInfo, target: (RefData|BoxData), offset: number?) -> { any }, - writeData: (self: CStructInfo, target: (RefData|BoxData), table: { any }, offset: number?) -> (), - copyData: (self: CStructInfo, dst: (RefData|BoxData), src: (RefData|BoxData), dst_offset: number?, src_offset: number?) -> (), + readData: (self: CStructInfo, target: RefData | BoxData, offset: number?) -> { any }, + writeData: ( + self: CStructInfo, + target: RefData | BoxData, + table: { any }, + offset: number? + ) -> (), + copyData: ( + self: CStructInfo, + dst: RefData | BoxData, + src: RefData | BoxData, + dst_offset: number?, + src_offset: number? + ) -> (), offset: (self: CStructInfo, index: number) -> number, field: (self: CStructInfo, index: number) -> CTypes, @@ -433,6 +493,14 @@ export type CStructInfo = { A type that represents c void. can only be used for the function return type. ]=] export type CVoidInfo = { + --[=[ + @within CVoidInfo + @tag Field + @field size + + The size of the void type. It is always 0. + ]=] + size: number, --[=[ @within CVoidInfo @tag Method @@ -445,13 +513,11 @@ export type CVoidInfo = { ptr: (self: CVoidInfo) -> CPtrInfo, } c.void = {} :: CVoidInfo +--#endregion C ABI Type Infos ---#endregion C ABI Type Infos -- - ---#region Fixed size Rust-style types -- - +--#region Fixed size Rust-style types --[=[ - @class u8 + @prop u8 NumCType @within FFI A 8-bit sized unsigned integer, Equivalent to `uint8_t` in `stdint`. @@ -459,7 +525,7 @@ c.void = {} :: CVoidInfo ffi.u8 = {} :: u8 export type u8 = NumCType<"u8"> --[=[ - @class u16 + @prop u16 NumCType @within FFI A 16-bit sized unsigned integer, Equivalent to `uint16_t` in `stdint`. @@ -467,7 +533,7 @@ export type u8 = NumCType<"u8"> ffi.u16 = {} :: u16 export type u16 = NumCType<"u16"> --[=[ - @class u32 + @prop u32 NumCType @within FFI A 32-bit sized unsigned integer, Equivalent to `uint32_t` in `stdint`. @@ -475,7 +541,7 @@ export type u16 = NumCType<"u16"> ffi.u32 = {} :: u32 export type u32 = NumCType<"u32"> --[=[ - @class u64 + @prop u64 NumCType @within FFI A 64-bit sized unsigned integer, Equivalent to `uint64_t` in `stdint`. @@ -483,7 +549,7 @@ export type u32 = NumCType<"u32"> ffi.u64 = {} :: u64 export type u64 = NumCType<"u64"> --[=[ - @class u128 + @prop u128 NumCType @within FFI A 128-bit sized unsigned integer, Equivalent to `uint128_t` in `stdint`. @@ -491,7 +557,7 @@ export type u64 = NumCType<"u64"> ffi.u128 = {} :: u128 export type u128 = NumCType<"u128"> --[=[ - @class i8 + @prop i8 NumCType @within FFI A 8-bit sized signed integer, Equivalent to `int8_t` in `stdint`. @@ -499,7 +565,7 @@ export type u128 = NumCType<"u128"> ffi.i8 = {} :: i8 export type i8 = NumCType<"i8"> --[=[ - @class i16 + @prop i16 NumCType @within FFI A 16-bit sized signed integer, Equivalent to `int16_t` in `stdint`. @@ -507,7 +573,7 @@ export type i8 = NumCType<"i8"> ffi.i16 = {} :: i16 export type i16 = NumCType<"i16"> --[=[ - @class i32 + @prop i32 NumCType @within FFI A 32-bit sized signed integer, Equivalent to `int32_t` in `stdint`. @@ -515,7 +581,7 @@ export type i16 = NumCType<"i16"> ffi.i32 = {} :: i32 export type i32 = NumCType<"i32"> --[=[ - @class i64 + @prop i64 NumCType @within FFI A 64-bit sized signed integer, Equivalent to `int64_t` in `stdint`. @@ -523,7 +589,7 @@ export type i32 = NumCType<"i32"> ffi.i64 = {} :: i64 export type i64 = NumCType<"i64"> --[=[ - @class i128 + @prop i128 NumCType @within FFI A 128-bit sized signed integer, Equivalent to `int128_t` in `stdint`. @@ -531,7 +597,7 @@ export type i64 = NumCType<"i64"> ffi.i128 = {} :: i128 export type i128 = NumCType<"i128"> --[=[ - @class f32 + @prop f32 NumCType @within FFI A single-precision 32-bit sized floating-point, Almost always equivalent to `float` in C. @@ -539,7 +605,7 @@ export type i128 = NumCType<"i128"> ffi.f32 = {} :: f32 export type f32 = NumCType<"f32"> --[=[ - @class f64 + @prop f64 NumCType @within FFI A double-precision 64-bit sized floating-point, Almost always equivalent to `double` in C. @@ -547,7 +613,7 @@ export type f32 = NumCType<"f32"> ffi.f64 = {} :: f64 export type f64 = NumCType<"f64"> --[=[ - @class usize + @prop usize NumCType @within FFI A machine specific pointer sized unsigned integer. @@ -555,19 +621,18 @@ export type f64 = NumCType<"f64"> ffi.usize = {} :: usize export type usize = NumCType<"usize"> --[=[ - @class isize + @prop isize NumCType @within FFI A machine specific pointer sized signed integer. ]=] ffi.isize = {} :: isize export type isize = NumCType<"isize"> +--#endregion Fixed size Rust-style types ---#endregion Fixed size Rust-style types -- - ---#region Variable size C-style types -- +--#region Variable size C-style types --[=[ - @class char + @prop char NumCType @within C Compiler defined C `char` type. @@ -578,12 +643,8 @@ export type isize = NumCType<"isize"> ]=] c.char = {} :: char export type char = NumCType<"char"> --- c.float = {} :: float --- export type float = NumCType<"float"> --- c.double = {} :: double --- export type double = NumCType<"double"> --[=[ - @class uchar + @prop uchar NumCType @within C Compiler defined C `unsigned char` type. @@ -593,7 +654,7 @@ export type char = NumCType<"char"> c.uchar = {} :: uchar export type uchar = NumCType<"uchar"> --[=[ - @class schar + @prop schar NumCType @within C Compiler defined C `signed char` type. @@ -601,7 +662,7 @@ export type uchar = NumCType<"uchar"> c.schar = {} :: schar export type schar = NumCType<"schar"> --[=[ - @class short + @prop short NumCType @within C Compiler defined C `short` type. @@ -609,7 +670,7 @@ export type schar = NumCType<"schar"> c.short = {} :: short export type short = NumCType<"short"> --[=[ - @class ushort + @prop ushort NumCType @within C Compiler defined C `unsigned short` type. @@ -617,7 +678,7 @@ export type short = NumCType<"short"> c.ushort = {} :: ushort export type ushort = NumCType<"ushort"> --[=[ - @class int + @prop int NumCType @within C Compiler defined C `int` type. @@ -627,7 +688,7 @@ export type ushort = NumCType<"ushort"> c.int = {} :: int export type int = NumCType<"int"> --[=[ - @class uint + @prop uint NumCType @within C Compiler defined C `unsigned int` type. @@ -637,7 +698,7 @@ export type int = NumCType<"int"> c.uint = {} :: uint export type uint = NumCType<"uint"> --[=[ - @class long + @prop long NumCType @within C Compiler defined C `long` type. @@ -647,7 +708,7 @@ export type uint = NumCType<"uint"> c.long = {} :: long export type long = NumCType<"long"> --[=[ - @class ulong + @prop ulong NumCType @within C Compiler defined C `unsigned long` type. @@ -657,7 +718,7 @@ export type long = NumCType<"long"> c.ulong = {} :: ulong export type ulong = NumCType<"ulong"> --[=[ - @class longlong + @prop longlong NumCType @within C Compiler defined C `unsigned longlong` type. @@ -665,15 +726,14 @@ export type ulong = NumCType<"ulong"> c.longlong = {} :: longlong export type longlong = NumCType<"longlong"> --[=[ - @class longlong + @prop longlong NumCType @within C Compiler defined C `unsigned longlong` type. ]=] c.ulonglong = {} :: ulonglong export type ulonglong = NumCType<"ulonglong"> - ---#endregion Variable size C-style types -- +--#endregion Variable size C-style types --[=[ @class CTypes @@ -681,7 +741,7 @@ export type ulonglong = NumCType<"ulonglong"> All possible C types. ]=] export type CTypes = - | u8 + u8 | u16 | u32 | u64 @@ -696,8 +756,6 @@ export type CTypes = | usize | isize | char - -- | float - -- | double | uchar | schar | short From 80a74975831595bc32f2094142a9c9890887117a Mon Sep 17 00:00:00 2001 From: qwreey Date: Thu, 24 Oct 2024 17:07:49 +0000 Subject: [PATCH 51/79] Fix benchmark code and add C level result (#243) --- tests/ffi/README.md | 5 +++++ tests/ffi/benchmark/external_call/init.luau | 10 +++++++--- tests/ffi/benchmark/external_call/lib.c | 14 ++++++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/tests/ffi/README.md b/tests/ffi/README.md index 8f911d31..de366fad 100644 --- a/tests/ffi/README.md +++ b/tests/ffi/README.md @@ -64,6 +64,11 @@ Command: `cargo run --profile=release run tests/ffi/benchmark/external_call` > Commit: ddf0c4c +**C** + +- Device1-Linux-PVE: 0.001949 (sec) + > gcc (GCC) 14.2.1 20240910 + **LuaJit ffi** Command: `luajit tests/ffi/benchmark/external_call/luajit.lua` diff --git a/tests/ffi/benchmark/external_call/init.luau b/tests/ffi/benchmark/external_call/init.luau index 6df592be..14c6389d 100644 --- a/tests/ffi/benchmark/external_call/init.luau +++ b/tests/ffi/benchmark/external_call/init.luau @@ -1,11 +1,11 @@ local ffi = require("@lune/ffi") -local lib = require("../../utility/compile")("./tests/ffi/benchmark/external_call/lib.c") +local lib = require("../../utils/compile")("./tests/ffi/benchmark/external_call/lib.c") local process = require("@lune/process") local c = ffi.c local BENCH_SCALE: number = tonumber(process.env.BENCH_SCALE) or 1000000 -- Get clock provider -local procClock = require("../../utility/proc_clock") +local procClock = require("../../utils/proc_clock") local before, after = procClock.newBox() local getClock = procClock.getClock @@ -22,6 +22,10 @@ for i = 1, BENCH_SCALE do end getClock(after) -print(procClock.getOffset(before, after)) +print("lune-std-ffi: " .. procClock.getOffset(before, after)) local result = c.int:readData(a) assert(result == BENCH_SCALE, `bench_add failed. result expected {BENCH_SCALE}, got {result}`) + +local cSideTime = ffi.box(ffi.f64.size) +c.fn({}, ffi.f64):callable(lib:find("c_test"))(cSideTime) +print("C level: " .. ffi.f64:readData(cSideTime)) diff --git a/tests/ffi/benchmark/external_call/lib.c b/tests/ffi/benchmark/external_call/lib.c index 36b7e3be..7d74114c 100644 --- a/tests/ffi/benchmark/external_call/lib.c +++ b/tests/ffi/benchmark/external_call/lib.c @@ -1,4 +1,18 @@ +#include int add(int a, int b) { return a + b; } + +double c_test() { + clock_t before = clock(); + + int a = 0; + for (int i=0; i<1000000; i++) { + a = add(a, 1); + } + + clock_t after = clock(); + + return (double)(after - before) / CLOCKS_PER_SEC; +} From 2a9664a90fecd242d8f3a46e6d97e0d57d39c0a5 Mon Sep 17 00:00:00 2001 From: qwreey Date: Thu, 31 Oct 2024 06:32:19 +0000 Subject: [PATCH 52/79] Add runtime flag for allowing unsafe libraries (#243) --- crates/lune-std/src/lib.rs | 2 ++ crates/lune-std/src/library.rs | 32 ++++++++++++++++++++++++++- crates/lune-std/src/unsafe_library.rs | 22 ++++++++++++++++++ crates/lune/src/cli/run.rs | 7 +++++- crates/lune/src/rt/runtime.rs | 11 +++++++++ 5 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 crates/lune-std/src/unsafe_library.rs diff --git a/crates/lune-std/src/lib.rs b/crates/lune-std/src/lib.rs index a29bef03..98089127 100644 --- a/crates/lune-std/src/lib.rs +++ b/crates/lune-std/src/lib.rs @@ -6,10 +6,12 @@ mod global; mod globals; mod library; mod luaurc; +mod unsafe_library; pub use self::global::LuneStandardGlobal; pub use self::globals::version::set_global_version; pub use self::library::LuneStandardLibrary; +pub use self::unsafe_library::{get_unsafe_library_enabled, set_unsafe_library_enabled}; /** Injects all standard globals into the given Lua state / VM. diff --git a/crates/lune-std/src/library.rs b/crates/lune-std/src/library.rs index 2ac783e0..80e2b5cc 100644 --- a/crates/lune-std/src/library.rs +++ b/crates/lune-std/src/library.rs @@ -2,6 +2,8 @@ use std::str::FromStr; use mlua::prelude::*; +use crate::get_unsafe_library_enabled; + /** A standard library probloxrovided by Lune. */ @@ -64,16 +66,44 @@ impl LuneStandardLibrary { } } + /** + Gets whether the library is unsafe. + */ + #[must_use] + #[rustfmt::skip] + #[allow(unreachable_patterns)] + pub fn is_unsafe(&self) -> bool { + match self { + #[cfg(feature = "datetime")] Self::DateTime => false, + #[cfg(feature = "fs")] Self::Fs => false, + #[cfg(feature = "luau")] Self::Luau => false, + #[cfg(feature = "net")] Self::Net => false, + #[cfg(feature = "task")] Self::Task => false, + #[cfg(feature = "process")] Self::Process => false, + #[cfg(feature = "regex")] Self::Regex => false, + #[cfg(feature = "serde")] Self::Serde => false, + #[cfg(feature = "stdio")] Self::Stdio => false, + #[cfg(feature = "roblox")] Self::Roblox => false, + #[cfg(feature = "ffi")] Self::Ffi => true, + + _ => unreachable!("no standard library enabled"), + } + } + /** Creates the Lua module for the library. # Errors - If the library could not be created. + If the library could not be created, or if requiring an unsafe library without enabling the unsafe library. */ #[rustfmt::skip] #[allow(unreachable_patterns)] pub fn module<'lua>(&self, lua: &'lua Lua) -> LuaResult> { + if self.is_unsafe() && !get_unsafe_library_enabled(lua) { + return Err(LuaError::external(format!("Standard library '{}' requires unsafe library enabled", self.name()))); + } + let res: LuaResult = match self { #[cfg(feature = "datetime")] Self::DateTime => lune_std_datetime::module(lua), #[cfg(feature = "fs")] Self::Fs => lune_std_fs::module(lua), diff --git a/crates/lune-std/src/unsafe_library.rs b/crates/lune-std/src/unsafe_library.rs new file mode 100644 index 00000000..3c0cbf41 --- /dev/null +++ b/crates/lune-std/src/unsafe_library.rs @@ -0,0 +1,22 @@ +use mlua::prelude::*; + +struct UnsafeLibrary(bool); + +/** + Override unsafe library allowance +*/ +pub fn set_unsafe_library_enabled(lua: &Lua, enabled: bool) { + lua.set_app_data(UnsafeLibrary(enabled)); +} + +/** + Returns whether unsafe libraries are allowed + + # Panics + + Panic if `UnsafeLib` app data doesn't exist. +*/ +#[must_use] +pub fn get_unsafe_library_enabled(lua: &Lua) -> bool { + lua.app_data_ref::().unwrap().0 +} diff --git a/crates/lune/src/cli/run.rs b/crates/lune/src/cli/run.rs index 6267ed7d..19eab0bc 100644 --- a/crates/lune/src/cli/run.rs +++ b/crates/lune/src/cli/run.rs @@ -14,6 +14,9 @@ use super::utils::files::{discover_script_path_including_lune_dirs, strip_sheban /// Run a script #[derive(Debug, Clone, Parser)] pub struct RunCommand { + /// Allow unsafe libraries + #[clap(long, action)] + r#unsafe: bool, /// Script name or full path to the file to run script_path: String, /// Arguments to pass to the script, stored in process.args @@ -41,7 +44,9 @@ impl RunCommand { }; // Create a new lune runtime with all globals & run the script - let mut rt = Runtime::new().with_args(self.script_args); + let mut rt = Runtime::new() + .with_args(self.script_args) + .set_unsafe_lib_enabled(self.r#unsafe); let result = rt .run(&script_display_name, strip_shebang(script_contents)) diff --git a/crates/lune/src/rt/runtime.rs b/crates/lune/src/rt/runtime.rs index 31e5b039..b6028dda 100644 --- a/crates/lune/src/rt/runtime.rs +++ b/crates/lune/src/rt/runtime.rs @@ -54,6 +54,7 @@ impl RuntimeInner { feature = "std-serde", feature = "std-stdio", feature = "std-task", + feature = "std-ffi", ))] { lune_std::set_global_version(lua, env!("CARGO_PKG_VERSION")); @@ -76,6 +77,7 @@ impl RuntimeInner { feature = "std-serde", feature = "std-stdio", feature = "std-task", + feature = "std-ffi", ))] { let g_table = lune_std::LuneStandardGlobal::GTable; @@ -130,6 +132,15 @@ impl Runtime { self } + /** + Sets arguments to give in `process.args` for Lune scripts. + */ + #[must_use] + pub fn set_unsafe_lib_enabled(self, enabled: bool) -> Self { + lune_std::set_unsafe_library_enabled(self.inner.lua(), enabled); + self + } + /** Runs a Lune script inside of the current runtime. From de7029aa193fcbcbf90cdb79611a8e14a3921066 Mon Sep 17 00:00:00 2001 From: qwreey Date: Sat, 2 Nov 2024 14:17:00 +0000 Subject: [PATCH 53/79] Remove debug exports (#243) --- crates/lune-std-ffi/src/ffi/association.rs | 13 ----------- crates/lune-std-ffi/src/lib.rs | 8 +------ crates/lune/src/cli/run.rs | 2 +- crates/lune/src/rt/runtime.rs | 2 +- types/ffi.luau | 25 ++++++++++++++++++++-- 5 files changed, 26 insertions(+), 24 deletions(-) diff --git a/crates/lune-std-ffi/src/ffi/association.rs b/crates/lune-std-ffi/src/ffi/association.rs index b5c6265f..19382306 100644 --- a/crates/lune-std-ffi/src/ffi/association.rs +++ b/crates/lune-std-ffi/src/ffi/association.rs @@ -66,16 +66,3 @@ where _ => panic!(), } } - -// 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 debug build. -#[cfg(debug_assertions)] -pub fn get_table<'lua>(lua: &'lua Lua, regname: &str) -> LuaResult>> { - match lua.named_registry_value::(regname)? { - LuaValue::Nil => Ok(None), - LuaValue::Table(t) => Ok(Some(t)), - _ => panic!(), - } -} diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs index f85a1bb9..35a2450f 100644 --- a/crates/lune-std-ffi/src/lib.rs +++ b/crates/lune-std-ffi/src/lib.rs @@ -21,18 +21,12 @@ use crate::{ */ pub fn module(lua: &Lua) -> LuaResult { let result = TableBuilder::new(lua)? - .with_values(export_fixed_types(lua)?)? .with_function("nullRef", |lua, ()| create_nullref(lua))? .with_function("box", |_lua, size: usize| Ok(BoxData::new(size)))? .with_function("open", |_lua, name: String| LibData::new(name))? .with_function("isInteger", |_lua, num: LuaValue| Ok(num.is_integer()))? + .with_values(export_fixed_types(lua)?)? .with_value("c", export_c(lua)?)?; - #[cfg(debug_assertions)] - let result = result.with_function("debugAssociation", |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."); - ffi::association::get_table(lua, str.as_ref()) - })?; - result.build_readonly() } diff --git a/crates/lune/src/cli/run.rs b/crates/lune/src/cli/run.rs index 19eab0bc..8f198c48 100644 --- a/crates/lune/src/cli/run.rs +++ b/crates/lune/src/cli/run.rs @@ -46,7 +46,7 @@ impl RunCommand { // Create a new lune runtime with all globals & run the script let mut rt = Runtime::new() .with_args(self.script_args) - .set_unsafe_lib_enabled(self.r#unsafe); + .set_unsafe_library_enabled(self.r#unsafe); let result = rt .run(&script_display_name, strip_shebang(script_contents)) diff --git a/crates/lune/src/rt/runtime.rs b/crates/lune/src/rt/runtime.rs index b6028dda..daeb0fd7 100644 --- a/crates/lune/src/rt/runtime.rs +++ b/crates/lune/src/rt/runtime.rs @@ -136,7 +136,7 @@ impl Runtime { Sets arguments to give in `process.args` for Lune scripts. */ #[must_use] - pub fn set_unsafe_lib_enabled(self, enabled: bool) -> Self { + pub fn set_unsafe_library_enabled(self, enabled: bool) -> Self { lune_std::set_unsafe_library_enabled(self.inner.lua(), enabled); self } diff --git a/types/ffi.luau b/types/ffi.luau index a60c6ee4..e524b203 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -415,7 +415,7 @@ export type CFnInfo = { Create a callable from reference. - @return Struct array type + @return A callable ]=] callable: (self: CFnInfo, functionRef: RefData) -> CallableData, --[=[ @@ -425,7 +425,7 @@ export type CFnInfo = { Create a closure from lua function. - @return A closure. + @return A closure ]=] closure: (self: CFnInfo, (ret: RefData, ...RefData) -> ()) -> ClosureData, } @@ -467,7 +467,28 @@ export type CStructInfo = { ]=] ptr: (self: CStructInfo) -> CPtrInfo, + --[=[ + @within CSturctInfo + @tag Method + @method box + + Create a box with initial value. + + @param table The array of field values + @return A box + ]=] box: (self: CStructInfo, table: { any }) -> BoxData, + --[=[ + @within CSturctInfo + @tag Method + @method readData + + Read a lua table from reference or box. + + @param target Target to read data from + @param offset Offset to read data from + @return A table + ]=] readData: (self: CStructInfo, target: RefData | BoxData, offset: number?) -> { any }, writeData: ( self: CStructInfo, From 37b55576caed4e6b7d6adcecbf57adac67ad7fa0 Mon Sep 17 00:00:00 2001 From: qwreey Date: Sat, 2 Nov 2024 14:31:00 +0000 Subject: [PATCH 54/79] Add missing types (#243) --- types/ffi.luau | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/types/ffi.luau b/types/ffi.luau index e524b203..b41875fa 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -119,15 +119,15 @@ export type RefData = { @param src The source data @param len The amount of data to copy, in bytes - @param dst_offset The offset in the destination where the data will be pasted - @param src_offset The offset in the source data from where the data will be copied + @param dstOffset The offset in the destination where the data will be pasted + @param srcOffset The offset in the source data from where the data will be copied ]=] copyFrom: ( self: RefData, src: BoxData | RefData, length: number, - dst_offset: number, - src_offset: number + dstOffset: number, + srcOffset: number ) -> (), } @@ -191,15 +191,15 @@ export type BoxData = { @param src The source data @param len The amount of data to copy, in bytes - @param dst_offset The offset in the destination where the data will be pasted - @param src_offset The offset in the source data from where the data will be copied + @param dstOffset The offset in the destination where the data will be pasted + @param srcOffset The offset in the source data from where the data will be copied ]=] copyFrom: ( self: BoxData, src: BoxData | RefData, length: number, - dst_offset: number, - src_offset: number + dstOffset: number, + srcOffset: number ) -> (), } @@ -291,6 +291,13 @@ export type CTypeInfo = { box: (self: CTypeInfo, val: R) -> BoxData, readData: (self: CTypeInfo, target: RefData | BoxData, offset: number?) -> R, writeData: (self: CTypeInfo, target: RefData | BoxData, value: R, offset: number?) -> (), + copyData: ( + self: CTypeInfo, + dst: RefData | BoxData, + src: RefData | BoxData, + dstOffset: number?, + srcOffset: number? + ) -> (), stringifyData: (self: CTypeInfo, target: RefData | BoxData, offset: number?) -> string, -- FIXME: recursive types; 'intoType' should be CTypes @@ -298,7 +305,9 @@ export type CTypeInfo = { self: CTypeInfo, intoType: any, fromData: RefData | BoxData, - intoData: RefData | BoxData + intoData: RefData | BoxData, + fromOffset: number?, + intoOffset: number? ) -> (), } & { ["__phantom"]: T } type NumCType = CTypeInfo @@ -385,8 +394,8 @@ export type CArrInfo = { self: CArrInfo, dst: RefData | BoxData, src: RefData | BoxData, - dst_offset: number?, - src_offset: number? + dstOffset: number?, + srcOffset: number? ) -> (), offset: (self: CArrInfo, index: number) -> number, @@ -490,6 +499,17 @@ export type CStructInfo = { @return A table ]=] readData: (self: CStructInfo, target: RefData | BoxData, offset: number?) -> { any }, + --[=[ + @within CSturctInfo + @tag Method + @method writeData + + Write a lua table into reference or box. + + @param target Target to write data into + @param table Lua data to write + @param offset Offset to write data into + ]=] writeData: ( self: CStructInfo, target: RefData | BoxData, @@ -500,8 +520,8 @@ export type CStructInfo = { self: CStructInfo, dst: RefData | BoxData, src: RefData | BoxData, - dst_offset: number?, - src_offset: number? + dstOffset: number?, + srcOffset: number? ) -> (), offset: (self: CStructInfo, index: number) -> number, From 4cc2698e30ca62fc4144417c674c07d3c7a09a44 Mon Sep 17 00:00:00 2001 From: qwreey Date: Sat, 2 Nov 2024 14:39:11 +0000 Subject: [PATCH 55/79] Add offset option in cast method (#243) --- crates/lune-std-ffi/src/c/type_info.rs | 8 +++++++- crates/lune-std-ffi/src/c/types/mod.rs | 10 ++++++---- crates/lune-std-ffi/src/ffi/cast.rs | 19 ++++++++++++++++--- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/crates/lune-std-ffi/src/c/type_info.rs b/crates/lune-std-ffi/src/c/type_info.rs index 374f09b6..96c989c6 100644 --- a/crates/lune-std-ffi/src/c/type_info.rs +++ b/crates/lune-std-ffi/src/c/type_info.rs @@ -21,6 +21,8 @@ pub trait CTypeCast { into_ctype: &LuaAnyUserData, _from: &Ref, _into: &Ref, + _from_offset: isize, + _into_offset: isize, ) -> LuaResult<()> { // Show error if have no cast implement Err(Self::cast_failed_with(self, from_ctype, into_ctype)) @@ -114,17 +116,21 @@ where methods.add_function( "cast", |_, - (from_type, into_type, from, into): ( + (from_type, into_type, from, into, from_offset, into_offset): ( LuaAnyUserData, LuaAnyUserData, LuaAnyUserData, LuaAnyUserData, + Option, + Option, )| { from_type.borrow::()?.cast( &from_type, &into_type, &from.get_ffi_data()?, &into.get_ffi_data()?, + from_offset.unwrap_or(0), + into_offset.unwrap_or(0), ) }, ); diff --git a/crates/lune-std-ffi/src/c/types/mod.rs b/crates/lune-std-ffi/src/c/types/mod.rs index 672279e4..2de89bb9 100644 --- a/crates/lune-std-ffi/src/c/types/mod.rs +++ b/crates/lune-std-ffi/src/c/types/mod.rs @@ -25,7 +25,7 @@ pub mod u64; pub mod u8; pub mod usize; -// create CType userdata and export +// CType userdata export macro_rules! create_ctypes { ($lua:ident, $(( $name:expr, $rust_type:ty, $libffi_type:expr ),)* ) => { Ok(vec![$(( @@ -82,9 +82,9 @@ pub fn export_fixed_types(lua: &Lua) -> LuaResult { + ($from_rust_type:ident, $self:ident, $from_ctype:ident, $into_ctype:ident, $from:ident, $into:ident, $fromOffset:ident, $intoOffset:ident, $($into_rust_type:ty)*) => { $( if $into_ctype.is::>() { - num_cast::<$from_rust_type, $into_rust_type>($from, $into) + num_cast::<$from_rust_type, $into_rust_type>($from, $into, $fromOffset, $intoOffset) } else )* { Err($self.cast_failed_with($from_ctype, $into_ctype)) } @@ -113,9 +113,11 @@ where into_info: &LuaAnyUserData, from: &Ref, into: &Ref, + from_offset: isize, + into_offset: isize, ) -> LuaResult<()> { define_cast_num!( - From, self, from_info, into_info, from, into, + From, self, from_info, into_info, from, into, from_offset, into_offset, u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize ) } diff --git a/crates/lune-std-ffi/src/ffi/cast.rs b/crates/lune-std-ffi/src/ffi/cast.rs index f0dc7bae..1cd6c3f2 100644 --- a/crates/lune-std-ffi/src/ffi/cast.rs +++ b/crates/lune-std-ffi/src/ffi/cast.rs @@ -6,13 +6,26 @@ use num::cast::AsPrimitive; use super::FfiData; #[inline] -pub fn num_cast(from: &Ref, into: &Ref) -> LuaResult<()> +pub fn num_cast( + from: &Ref, + into: &Ref, + from_offset: isize, + into_offset: isize, +) -> LuaResult<()> where From: AsPrimitive, Into: 'static + Copy, { - let from_ptr = unsafe { from.get_inner_pointer().cast::() }; - let into_ptr = unsafe { into.get_inner_pointer().cast::() }; + let from_ptr = unsafe { + from.get_inner_pointer() + .byte_offset(from_offset) + .cast::() + }; + let into_ptr = unsafe { + into.get_inner_pointer() + .byte_offset(into_offset) + .cast::() + }; unsafe { *into_ptr = (*from_ptr).as_(); From b95266ef3c69a093ecd3b3fd18016801107bfab9 Mon Sep 17 00:00:00 2001 From: kimpure Date: Sun, 3 Nov 2024 01:07:10 +0900 Subject: [PATCH 56/79] type plus --- types/ffi.luau | 239 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) diff --git a/types/ffi.luau b/types/ffi.luau index b41875fa..91dcdb11 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -284,13 +284,80 @@ export type CTypeInfo = { signedness: boolean, -- subtype + --[=[ + @within CTypeInfo + @tag Method + @Method ptr + + create a pointer subtype. + + @return pointer subtype + ]=] ptr: (self: CTypeInfo) -> CPtrInfo>, + + --[=[ + @within CTypeInfo + @tag Method + @Method arr + + create an array subtype. + + @param len The length of the array + @return array subtype + ]=] arr: (self: CTypeInfo, len: number) -> CArrInfo, R>, -- realize + --[=[ + @within CTypeInfo + @tag Method + @Method box + + create a box with initial values + + @param table The array of field values + @return A box + ]=] box: (self: CTypeInfo, val: R) -> BoxData, + + --[=[ + @within CTypeInfo + @tag Method + @method readData + + Read a lua table from reference or box. + + @param target Target to read data from + @param offset Offset to read data from + @return A table + ]=] readData: (self: CTypeInfo, target: RefData | BoxData, offset: number?) -> R, + + --[=[ + @within CTypeInfo + @tag Method + @method writeData + + Write a lua table into reference or box. + + @param target Target to write data into + @param table Lua data to write + @param offset Offset to write data into + ]=] writeData: (self: CTypeInfo, target: RefData | BoxData, value: R, offset: number?) -> (), + + --[=[ + @within CTypeInfo + @tag Method + @Method copyData + + copy values ​​from the source and paste them into the target. + + @param destination where the data will be pasted + @param src The source data + @param dstOffset The offset in the destination where the data will be pasted + @param srcOffset The offset in the source data from where the data will be copied + ]=] copyData: ( self: CTypeInfo, dst: RefData | BoxData, @@ -298,9 +365,37 @@ export type CTypeInfo = { dstOffset: number?, srcOffset: number? ) -> (), + + --[=[ + @within CTypeInfo + @tag Method + @Method stringifyData + + stringify data. Useful when you need to output numbers that Lua can't handle. + + @param memory to output + @param memory byte offset + ]=] stringifyData: (self: CTypeInfo, target: RefData | BoxData, offset: number?) -> string, -- FIXME: recursive types; 'intoType' should be CTypes + --[=[ + @within CTypeInfo + @tag Method + @Method cast + + casting a value to a different type. + + may result in loss of precision. + + FIXME: recursive types; 'intoType' should be CTypes + + @param type to convert + @param memory to read the value to be converted + @param memory to use the converted value + @param memory byte offset to read + @param memory byte offset to write + ]=] cast: ( self: CTypeInfo, intoType: any, @@ -334,11 +429,55 @@ export type CPtrInfo = { -- subtype -- FIXME: recursive types; result 'any' should be CArrInfo> + --[=[ + @within CPtrInfo + @tag Method + @Method arr + + create an array subtype. + FIXME: recursive types; result 'any' should be CArrInfo> + + @param len The length of the array + @return array subtype + ]=] arr: (self: CPtrInfo, len: number) -> any, + -- FIXME: recursive types; result 'any' should be CPtrInfo> + --[=[ + @within CPtrInfo + @tag Method + @Method ptr + + create a pointer subtype. + FIXME: recursive types; result 'any' should be CPtrInfo> + + @return pointer subtype + ]=] ptr: (self: CPtrInfo) -> any, + --[=[ + @within CPtrInfo + @tag Method + @Method readData + + similar to readData . Reads data in the reference (the memory space pointed to by reference). + + @param Reference to read + @param byte offset + ]=] readRef: (self: CPtrInfo, target: RefData | BoxData, offset: number?) -> RefData, + + --[=[ + @within CPtrInfo + @tag Method + @Method writeData + + similar to writeData. Writes data in the reference (in the memory space pointed to by). + + @param reference to use + @param lua value to use + @param byte offset + ]=] writeRef: ( self: CPtrInfo, target: RefData | BoxData, @@ -379,17 +518,74 @@ export type CArrInfo = { inner: T, -- subtype + --[=[ + @within CArrInfo + @tag Method + @Method ptr + + create a pointer subtype. + FIXME: recursive types; result 'any' should be CPtrInfo> + + @return pointer subtype + ]=] ptr: (self: CArrInfo) -> CPtrInfo>, -- realize + --[=[ + @within CArrInfo + @tag Method + @Method box + + create a box with initial values + + @param table The array of field values + @return A box + ]=] box: (self: CArrInfo, table: { T }) -> BoxData, + + --[=[ + @within CArrInfo + @tag Method + @method readData + + Read a lua table from reference or box. + + @param target Target to read data from + @param offset Offset to read data from + @return A table + ]=] readData: (self: CArrInfo, target: RefData | BoxData, offset: number?) -> { T }, + + --[=[ + @within CArrInfo + @tag Method + @method writeData + + Write a lua table into reference or box. + + @param target Target to write data into + @param table Lua data to write + @param offset Offset to write data into + ]=] writeData: ( self: CArrInfo, target: RefData | BoxData, value: { R }, target_offset: number? ) -> (), + + --[=[ + @within CArrInfo + @tag Method + @Method copyData + + copy values ​​from the source and paste them into the target. + + @param destination where the data will be pasted + @param src The source data + @param dstOffset The offset in the destination where the data will be pasted + @param srcOffset The offset in the source data from where the data will be copied + ]=] copyData: ( self: CArrInfo, dst: RefData | BoxData, @@ -398,6 +594,16 @@ export type CArrInfo = { srcOffset: number? ) -> (), + --[=[ + @within CArrInfo + @tag Method + @method copyData + + returns the byte offset of the field. + + @param field index + @return byte offset + ]=] offset: (self: CArrInfo, index: number) -> number, } @@ -516,6 +722,18 @@ export type CStructInfo = { table: { any }, offset: number? ) -> (), + --[=[ + @within CSturctInfo + @tag Method + @method copyData + + Copy values from the source and paste them into the target. + + @param destination where the data will be pasted + @param src The source data + @param dstOffset The offset in the destination where the data will be pasted + @param srcOffset The offset in the source data from where the data will be copied + ]=] copyData: ( self: CStructInfo, dst: RefData | BoxData, @@ -524,7 +742,28 @@ export type CStructInfo = { srcOffset: number? ) -> (), + --[=[ + @within CSturctInfo + @tag Method + @method copyData + + returns the byte offset of the field. + + @param field index + @return byte offset + ]=] offset: (self: CStructInfo, index: number) -> number, + + --[=[ + @within CSturctInfo + @tag Method + @method copyData + + returns the field type + + @param field index + @return field type + ]=] field: (self: CStructInfo, index: number) -> CTypes, } From 7856764fd4630e8f3ecf9d3d5a4d89dc6b8d04d1 Mon Sep 17 00:00:00 2001 From: kimpure Date: Tue, 5 Nov 2024 22:02:29 +0900 Subject: [PATCH 57/79] fix --- types/ffi.luau | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/types/ffi.luau b/types/ffi.luau index 91dcdb11..daca4c4c 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -289,7 +289,7 @@ export type CTypeInfo = { @tag Method @Method ptr - create a pointer subtype. + Create a pointer subtype. @return pointer subtype ]=] @@ -300,10 +300,10 @@ export type CTypeInfo = { @tag Method @Method arr - create an array subtype. + Create an array subtype. @param len The length of the array - @return array subtype + @return An array subtype ]=] arr: (self: CTypeInfo, len: number) -> CArrInfo, R>, @@ -435,10 +435,9 @@ export type CPtrInfo = { @Method arr create an array subtype. - FIXME: recursive types; result 'any' should be CArrInfo> @param len The length of the array - @return array subtype + @return An array subtype ]=] arr: (self: CPtrInfo, len: number) -> any, @@ -748,21 +747,21 @@ export type CStructInfo = { @method copyData returns the byte offset of the field. - + @param field index - @return byte offset + @return the byte offset ]=] offset: (self: CStructInfo, index: number) -> number, --[=[ @within CSturctInfo @tag Method - @method copyData + @method field - returns the field type + Get the field type. - @param field index - @return field type + @param index The field index + @return The field type ]=] field: (self: CStructInfo, index: number) -> CTypes, } From c20ef95d6d97800d91cabb32277eeee747cb5f6c Mon Sep 17 00:00:00 2001 From: kimpure Date: Tue, 5 Nov 2024 22:03:49 +0900 Subject: [PATCH 58/79] fix --- types/ffi.luau | 2 -- 1 file changed, 2 deletions(-) diff --git a/types/ffi.luau b/types/ffi.luau index daca4c4c..dcff859f 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -387,8 +387,6 @@ export type CTypeInfo = { casting a value to a different type. may result in loss of precision. - - FIXME: recursive types; 'intoType' should be CTypes @param type to convert @param memory to read the value to be converted From 208bfa1bc729669e0319e6c02690dbbb94997a70 Mon Sep 17 00:00:00 2001 From: kimpure Date: Tue, 5 Nov 2024 22:05:43 +0900 Subject: [PATCH 59/79] fix --- types/ffi.luau | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/ffi.luau b/types/ffi.luau index dcff859f..088952d3 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -313,7 +313,7 @@ export type CTypeInfo = { @tag Method @Method box - create a box with initial values + Create a box with initial values @param table The array of field values @return A box @@ -351,7 +351,7 @@ export type CTypeInfo = { @tag Method @Method copyData - copy values ​​from the source and paste them into the target. + Copy values ​​from the source and paste them into the target. @param destination where the data will be pasted @param src The source data From 8b2fdbc81091e767457a2a96022b2e7c6bfed646 Mon Sep 17 00:00:00 2001 From: kimpure Date: Tue, 5 Nov 2024 22:06:52 +0900 Subject: [PATCH 60/79] move fixme --- types/ffi.luau | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/types/ffi.luau b/types/ffi.luau index 088952d3..2eae29f8 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -446,7 +446,6 @@ export type CPtrInfo = { @Method ptr create a pointer subtype. - FIXME: recursive types; result 'any' should be CPtrInfo> @return pointer subtype ]=] @@ -457,7 +456,7 @@ export type CPtrInfo = { @tag Method @Method readData - similar to readData . Reads data in the reference (the memory space pointed to by reference). + Similar to readData. Reads data in the reference (the memory space pointed to by reference). @param Reference to read @param byte offset @@ -469,7 +468,7 @@ export type CPtrInfo = { @tag Method @Method writeData - similar to writeData. Writes data in the reference (in the memory space pointed to by). + Similar to writeData. Writes data in the reference (in the memory space pointed to by). @param reference to use @param lua value to use @@ -521,7 +520,6 @@ export type CArrInfo = { @Method ptr create a pointer subtype. - FIXME: recursive types; result 'any' should be CPtrInfo> @return pointer subtype ]=] @@ -533,7 +531,7 @@ export type CArrInfo = { @tag Method @Method box - create a box with initial values + Create a box with initial values @param table The array of field values @return A box @@ -576,7 +574,7 @@ export type CArrInfo = { @tag Method @Method copyData - copy values ​​from the source and paste them into the target. + Copy values ​​from the source and paste them into the target. @param destination where the data will be pasted @param src The source data @@ -596,7 +594,7 @@ export type CArrInfo = { @tag Method @method copyData - returns the byte offset of the field. + Get the byte offset of the field. @param field index @return byte offset From a05c598dc3b92098880ddbd0fd6229ec80803490 Mon Sep 17 00:00:00 2001 From: kimpure Date: Wed, 6 Nov 2024 16:17:01 +0900 Subject: [PATCH 61/79] moonwave annotation fix --- types/ffi.luau | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/types/ffi.luau b/types/ffi.luau index 2eae29f8..06bbb30c 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -291,7 +291,7 @@ export type CTypeInfo = { Create a pointer subtype. - @return pointer subtype + @return A pointer subtype ]=] ptr: (self: CTypeInfo) -> CPtrInfo>, @@ -432,7 +432,7 @@ export type CPtrInfo = { @tag Method @Method arr - create an array subtype. + Create an array subtype. @param len The length of the array @return An array subtype @@ -445,34 +445,35 @@ export type CPtrInfo = { @tag Method @Method ptr - create a pointer subtype. + Create a pointer subtype. - @return pointer subtype + @return A pointer subtype ]=] ptr: (self: CPtrInfo) -> any, --[=[ @within CPtrInfo @tag Method - @Method readData + @Method readRef - Similar to readData. Reads data in the reference (the memory space pointed to by reference). + Similar to readData, read a lua value from reference. - @param Reference to read - @param byte offset + @param target Target reference to read data from + @param offset Offset to read data from + @return A lua value ]=] - readRef: (self: CPtrInfo, target: RefData | BoxData, offset: number?) -> RefData, + readRef: (self: CPtrInfo, target: RefData | BoxData, offset: number?) -> any, --[=[ @within CPtrInfo @tag Method - @Method writeData - - Similar to writeData. Writes data in the reference (in the memory space pointed to by). + @Method writeRef + + Similar to writeData, write a lua value into reference. - @param reference to use - @param lua value to use - @param byte offset + @param target Target reference to write data into + @param value Lua data to write + @param offset Offset to write data into ]=] writeRef: ( self: CPtrInfo, @@ -519,9 +520,9 @@ export type CArrInfo = { @tag Method @Method ptr - create a pointer subtype. + Create a pointer subtype. - @return pointer subtype + @return A pointer subtype ]=] ptr: (self: CArrInfo) -> CPtrInfo>, @@ -531,7 +532,7 @@ export type CArrInfo = { @tag Method @Method box - Create a box with initial values + Create a box with initial values. @param table The array of field values @return A box @@ -576,9 +577,9 @@ export type CArrInfo = { Copy values ​​from the source and paste them into the target. - @param destination where the data will be pasted + @param dst where the data will be pasted @param src The source data - @param dstOffset The offset in the destination where the data will be pasted + @param dstOffset The offset in the dst where the data will be pasted @param srcOffset The offset in the source data from where the data will be copied ]=] copyData: ( @@ -592,7 +593,7 @@ export type CArrInfo = { --[=[ @within CArrInfo @tag Method - @method copyData + @method offset Get the byte offset of the field. From a525faabb4aad0a5af12f9bc5865771a52ccbadf Mon Sep 17 00:00:00 2001 From: kimpure Date: Wed, 6 Nov 2024 16:20:08 +0900 Subject: [PATCH 62/79] moonwave annotation fix --- types/ffi.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/ffi.luau b/types/ffi.luau index 06bbb30c..206d26b9 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -597,7 +597,7 @@ export type CArrInfo = { Get the byte offset of the field. - @param field index + @param The element index @return byte offset ]=] offset: (self: CArrInfo, index: number) -> number, From 9bca7b80f50dd42fa8b9c95e73f6bc6c86aa24a1 Mon Sep 17 00:00:00 2001 From: qwreey Date: Thu, 7 Nov 2024 08:00:17 +0000 Subject: [PATCH 63/79] Fix annotation (#243) --- types/ffi.luau | 57 +++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/types/ffi.luau b/types/ffi.luau index 206d26b9..c6e32ded 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -115,7 +115,7 @@ export type RefData = { @tag Method @method copyFrom - Copy content from another data. + Copy content from another data with specific length. @param src The source data @param len The amount of data to copy, in bytes @@ -187,7 +187,7 @@ export type BoxData = { @tag Method @method copyFrom - Copy content from another data. + Copy content from another data with specific length. @param src The source data @param len The amount of data to copy, in bytes @@ -300,7 +300,7 @@ export type CTypeInfo = { @tag Method @Method arr - Create an array subtype. + Create an array subtype with specific length. @param len The length of the array @return An array subtype @@ -313,9 +313,9 @@ export type CTypeInfo = { @tag Method @Method box - Create a box with initial values + Create a box with initial values. - @param table The array of field values + @param table The array of element values @return A box ]=] box: (self: CTypeInfo, val: R) -> BoxData, @@ -345,15 +345,15 @@ export type CTypeInfo = { @param offset Offset to write data into ]=] writeData: (self: CTypeInfo, target: RefData | BoxData, value: R, offset: number?) -> (), - + --[=[ @within CTypeInfo @tag Method @Method copyData Copy values ​​from the source and paste them into the target. - - @param destination where the data will be pasted + + @param dst Where the data will be pasted @param src The source data @param dstOffset The offset in the destination where the data will be pasted @param srcOffset The offset in the source data from where the data will be copied @@ -370,11 +370,11 @@ export type CTypeInfo = { @within CTypeInfo @tag Method @Method stringifyData + + Stringify data. Useful when output numbers, which Luau can't handle. - stringify data. Useful when you need to output numbers that Lua can't handle. - - @param memory to output - @param memory byte offset + @param target The target data + @param offset Offset to stringify data from ]=] stringifyData: (self: CTypeInfo, target: RefData | BoxData, offset: number?) -> string, @@ -384,15 +384,15 @@ export type CTypeInfo = { @tag Method @Method cast - casting a value to a different type. + Casting data to different type. - may result in loss of precision. + May result in loss of precision. - @param type to convert - @param memory to read the value to be converted - @param memory to use the converted value - @param memory byte offset to read - @param memory byte offset to write + @param intoType The target type to convert to + @param fromData Source data to be converted + @param intoData Target to write converted data into + @param fromOffset The offset in the source data + @param intoOffset The offset in the destination ]=] cast: ( self: CTypeInfo, @@ -432,13 +432,12 @@ export type CPtrInfo = { @tag Method @Method arr - Create an array subtype. + Create an array subtype with specific length. @param len The length of the array @return An array subtype ]=] arr: (self: CPtrInfo, len: number) -> any, - -- FIXME: recursive types; result 'any' should be CPtrInfo> --[=[ @within CPtrInfo @@ -577,7 +576,7 @@ export type CArrInfo = { Copy values ​​from the source and paste them into the target. - @param dst where the data will be pasted + @param dst Where the data will be pasted @param src The source data @param dstOffset The offset in the dst where the data will be pasted @param srcOffset The offset in the source data from where the data will be copied @@ -597,8 +596,8 @@ export type CArrInfo = { Get the byte offset of the field. - @param The element index - @return byte offset + @param index The element index + @return The byte offset ]=] offset: (self: CArrInfo, index: number) -> number, } @@ -725,7 +724,7 @@ export type CStructInfo = { Copy values from the source and paste them into the target. - @param destination where the data will be pasted + @param dst Where the data will be pasted @param src The source data @param dstOffset The offset in the destination where the data will be pasted @param srcOffset The offset in the source data from where the data will be copied @@ -741,12 +740,12 @@ export type CStructInfo = { --[=[ @within CSturctInfo @tag Method - @method copyData + @method offset - returns the byte offset of the field. + Get the field offset. - @param field index - @return the byte offset + @param index The field index + @return The byte offset ]=] offset: (self: CStructInfo, index: number) -> number, From 4b2277fec31825399f574865da9bdf5ebb7c53bd Mon Sep 17 00:00:00 2001 From: qwreey Date: Fri, 8 Nov 2024 06:31:06 +0000 Subject: [PATCH 64/79] Fix error messages (#243) --- crates/lune-std-ffi/src/c/struct_info.rs | 4 ++-- crates/lune-std-ffi/src/data/box_data/mod.rs | 2 +- crates/lune-std-ffi/src/data/ref_data/mod.rs | 8 ++++---- crates/lune-std-ffi/src/ffi/libffi_helper.rs | 7 +------ crates/lune-std-ffi/src/ffi/mod.rs | 2 +- 5 files changed, 9 insertions(+), 14 deletions(-) diff --git a/crates/lune-std-ffi/src/c/struct_info.rs b/crates/lune-std-ffi/src/c/struct_info.rs index 3abbe73f..9f5b1c98 100644 --- a/crates/lune-std-ffi/src/c/struct_info.rs +++ b/crates/lune-std-ffi/src/c/struct_info.rs @@ -20,12 +20,12 @@ fn get_field_table<'lua>( userdata: &LuaAnyUserData<'lua>, ) -> LuaResult> { let value = association::get(lua, CSTRUCT_INNER, userdata)? - .ok_or_else(|| LuaError::external("Failed to get inner field table. not found"))?; + .ok_or_else(|| LuaError::external("Failed to retrieve inner field table: not found"))?; if let LuaValue::Table(table) = value { Ok(table) } else { Err(LuaError::external( - "Failed to get inner field table. not a table", + "Failed to retrieve inner field: not a table", )) } } diff --git a/crates/lune-std-ffi/src/data/box_data/mod.rs b/crates/lune-std-ffi/src/data/box_data/mod.rs index 4e75b10d..9585a57d 100644 --- a/crates/lune-std-ffi/src/data/box_data/mod.rs +++ b/crates/lune-std-ffi/src/data/box_data/mod.rs @@ -86,7 +86,7 @@ impl BoxData { if let Some(t) = offset { if !bounds.check_boundary(t) { return Err(LuaError::external(format!( - "Offset is out of bounds. box.size: {}. offset got {}", + "Offset out of bounds (box.size: {}, got {})", target.size(), t ))); diff --git a/crates/lune-std-ffi/src/data/ref_data/mod.rs b/crates/lune-std-ffi/src/data/ref_data/mod.rs index 26de8269..d54ab4ba 100644 --- a/crates/lune-std-ffi/src/data/ref_data/mod.rs +++ b/crates/lune-std-ffi/src/data/ref_data/mod.rs @@ -69,12 +69,12 @@ impl RefData { pub unsafe fn deref(&self) -> LuaResult { if !u8_test(self.flags, RefFlag::Dereferenceable.value()) { - return Err(LuaError::external("This pointer is not dereferenceable.")); + return Err(LuaError::external("Reference is not dereferenceable")); } if !self.boundary.check_sized(0, size_of::()) { return Err(LuaError::external( - "Offset is out of bounds. Dereferencing pointer requires size of usize", + "Offset out of bounds", )); } @@ -99,7 +99,7 @@ impl RefData { pub unsafe fn offset(&self, offset: isize) -> LuaResult { u8_test(self.flags, RefFlag::Offsetable.value()) .then_some(()) - .ok_or_else(|| LuaError::external("This pointer is not offsetable."))?; + .ok_or_else(|| LuaError::external("Reference is not offsetable"))?; // Check boundary, if exceed, return error self.boundary @@ -107,7 +107,7 @@ impl RefData { .then_some(()) .ok_or_else(|| { LuaError::external(format!( - "Offset is out of bounds. high: {}, low: {}. offset got {}", + "Offset out of bounds (high: {}, low: {}, got {})", self.boundary.above, self.boundary.below, offset )) })?; diff --git a/crates/lune-std-ffi/src/ffi/libffi_helper.rs b/crates/lune-std-ffi/src/ffi/libffi_helper.rs index 04d764db..c91d2d5f 100644 --- a/crates/lune-std-ffi/src/ffi/libffi_helper.rs +++ b/crates/lune-std-ffi/src/ffi/libffi_helper.rs @@ -17,12 +17,7 @@ pub fn get_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult { ) }; - if result != raw::ffi_status_FFI_OK { - return Err(LuaError::external(format!( - "ffi_prep_cif failed. expected result {}, got {}", - FFI_STATUS_NAMES[0], FFI_STATUS_NAMES[result as usize] - ))); - } + ffi_status_assert(result)?; unsafe { Ok((*ffi_type).size) } } diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index c4fa7d08..7e65f5e2 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -53,7 +53,7 @@ pub trait FfiConvert { _offset: isize, _data_handle: &Ref, ) -> LuaResult { - Err(LuaError::external("stringify not implemented")) + Err(LuaError::external("Stringify method not implemented")) } } From a655a4dad0f5cc718b44e163f116a2aed35309c5 Mon Sep 17 00:00:00 2001 From: qwreey Date: Fri, 8 Nov 2024 14:57:19 +0000 Subject: [PATCH 65/79] Improve code quality (#243) --- crates/lune-std-ffi/README.md | 1 - crates/lune-std-ffi/src/c/arr_info.rs | 23 ++--- crates/lune-std-ffi/src/c/fn_info.rs | 16 ++-- crates/lune-std-ffi/src/c/helper.rs | 81 ++++++++--------- crates/lune-std-ffi/src/c/mod.rs | 1 + crates/lune-std-ffi/src/c/ptr_info.rs | 27 +++--- crates/lune-std-ffi/src/c/string_info.rs | 2 + crates/lune-std-ffi/src/c/struct_info.rs | 30 +++---- crates/lune-std-ffi/src/c/type_info.rs | 10 +-- crates/lune-std-ffi/src/c/types/f32.rs | 3 +- crates/lune-std-ffi/src/c/types/f64.rs | 3 +- crates/lune-std-ffi/src/c/types/i128.rs | 3 +- crates/lune-std-ffi/src/c/types/i16.rs | 3 +- crates/lune-std-ffi/src/c/types/i32.rs | 3 +- crates/lune-std-ffi/src/c/types/i64.rs | 3 +- crates/lune-std-ffi/src/c/types/i8.rs | 3 +- crates/lune-std-ffi/src/c/types/isize.rs | 3 +- crates/lune-std-ffi/src/c/types/mod.rs | 5 +- crates/lune-std-ffi/src/c/types/u128.rs | 3 +- crates/lune-std-ffi/src/c/types/u16.rs | 3 +- crates/lune-std-ffi/src/c/types/u32.rs | 3 +- crates/lune-std-ffi/src/c/types/u64.rs | 3 +- crates/lune-std-ffi/src/c/types/u8.rs | 3 +- crates/lune-std-ffi/src/c/types/usize.rs | 3 +- crates/lune-std-ffi/src/c/void_info.rs | 2 +- crates/lune-std-ffi/src/data/box_data/mod.rs | 47 ++++------ crates/lune-std-ffi/src/data/callable_data.rs | 14 +-- crates/lune-std-ffi/src/data/closure_data.rs | 5 +- crates/lune-std-ffi/src/data/helper.rs | 2 +- crates/lune-std-ffi/src/data/lib_data.rs | 13 +-- crates/lune-std-ffi/src/data/mod.rs | 3 +- .../lune-std-ffi/src/data/ref_data/bounds.rs | 11 ++- crates/lune-std-ffi/src/data/ref_data/mod.rs | 89 ++++++++----------- crates/lune-std-ffi/src/ffi/association.rs | 24 +---- crates/lune-std-ffi/src/ffi/cast.rs | 1 + crates/lune-std-ffi/src/ffi/libffi_helper.rs | 10 +-- crates/lune-std-ffi/src/ffi/mod.rs | 9 +- types/ffi.luau | 16 +++- 38 files changed, 218 insertions(+), 266 deletions(-) diff --git a/crates/lune-std-ffi/README.md b/crates/lune-std-ffi/README.md index c5fa3c8a..e7b3fbcd 100644 --- a/crates/lune-std-ffi/README.md +++ b/crates/lune-std-ffi/README.md @@ -7,7 +7,6 @@ See [tests/ffi](../../tests/ffi/README.md) ## TODO - Rewrite error messages -- Deref - CString - Add buffer for owned data support - Add math operation. diff --git a/crates/lune-std-ffi/src/c/arr_info.rs b/crates/lune-std-ffi/src/c/arr_info.rs index 4a109ff3..0362f264 100644 --- a/crates/lune-std-ffi/src/c/arr_info.rs +++ b/crates/lune-std-ffi/src/c/arr_info.rs @@ -9,12 +9,10 @@ use crate::ffi::{association, libffi_helper::get_ensured_size, FfiConvert, FfiDa // 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. -// However, multidimensional arrays are not impossible to implement +// Multidimensional arrays can be implemented // because they are a series of transcribed one-dimensional arrays. (flatten) - // We can simply provide array type with struct. // See: https://stackoverflow.com/a/43525176 - pub struct CArrInfo { struct_type: Type, length: usize, @@ -33,7 +31,6 @@ impl CArrInfo { let struct_type = Type::structure(vec![element_type.clone(); length]); Ok(Self { - // element_type, struct_type, length, size: inner_size * length, @@ -63,8 +60,8 @@ impl CArrInfo { self.struct_type.clone() } - // Stringify for pretty printing like: - // + // Stringify for pretty-print + // ex: pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { let this = userdata.borrow::()?; if let Some(LuaValue::UserData(inner_userdata)) = @@ -76,7 +73,7 @@ impl CArrInfo { this.length, )) } else { - Err(LuaError::external("failed to get inner type userdata.")) + Err(LuaError::external("Failed to retrieve inner type")) } } } @@ -150,13 +147,11 @@ impl FfiConvert for CArrInfo { impl LuaUserData for CArrInfo { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("size", |_, this| Ok(this.get_size())); - fields.add_field_method_get("length", |_, this| Ok(this.get_length())); + fields.add_field_method_get("size", |_lua, this| Ok(this.get_size())); + fields.add_field_method_get("length", |_lua, this| Ok(this.get_length())); fields.add_field_function_get("inner", |lua, this: LuaAnyUserData| { - let inner: LuaValue = association::get(lua, CARR_INNER, this)? - // It shouldn't happen. - .ok_or_else(|| LuaError::external("inner field not found"))?; - Ok(inner) + association::get(lua, CARR_INNER, this)? + .ok_or_else(|| LuaError::external("Failed to retrieve inner field")) }); } @@ -173,7 +168,7 @@ impl LuaUserData for CArrInfo { method_provider::provide_write_data(methods); method_provider::provide_copy_data(methods); - methods.add_method("offset", |_, this, offset: isize| { + methods.add_method("offset", |_lua, this, offset: isize| { if this.length > (offset as usize) && offset >= 0 { Ok(this.inner_size * (offset as usize)) } else { diff --git a/crates/lune-std-ffi/src/c/fn_info.rs b/crates/lune-std-ffi/src/c/fn_info.rs index 29944991..21ce3f0d 100644 --- a/crates/lune-std-ffi/src/c/fn_info.rs +++ b/crates/lune-std-ffi/src/c/fn_info.rs @@ -67,7 +67,7 @@ fn create_arg_info(userdata: &LuaAnyUserData) -> LuaResult { } else if userdata.is::() { CALLBACK_ARG_REF_FLAG_CFN } else { - return Err(LuaError::external("unexpected type userdata")); + return Err(LuaError::external("Unexpected argument type")); }; Ok(FfiArg { size: helper::get_size(userdata)?, @@ -116,8 +116,8 @@ impl CFnInfo { Ok(cfn) } - // Stringify for pretty printing like: - // u8 )> + // Stringify for pretty-print + // ex: 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))) = ( @@ -142,7 +142,7 @@ impl CFnInfo { ); Ok(result) } else { - Err(LuaError::external("failed to get inner type userdata.")) + Err(LuaError::external("Failed to retrieve inner type")) } } @@ -173,12 +173,14 @@ impl CFnInfo { target_ref: &LuaAnyUserData, ) -> LuaResult> { if !target_ref.is::() { - return Err(LuaError::external("argument 0 must be ffiref")); + return Err(LuaError::external("Argument 'functionRef' must be RefData")); } let ffi_ref = target_ref.borrow::()?; if u8_test_not(ffi_ref.flags, RefFlag::Function.value()) { - return Err(LuaError::external("not a function ref")); + return Err(LuaError::external( + "Argument 'functionRef' is not a valid function reference", + )); } let callable = lua.create_userdata(unsafe { @@ -203,7 +205,7 @@ impl CFnInfo { impl LuaUserData for CFnInfo { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("size", |_, _| Ok(SIZE_OF_POINTER)); + fields.add_field_method_get("size", |_lua, _this| Ok(SIZE_OF_POINTER)); } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { // Subtype diff --git a/crates/lune-std-ffi/src/c/helper.rs b/crates/lune-std-ffi/src/c/helper.rs index 760e5824..68f7183e 100644 --- a/crates/lune-std-ffi/src/c/helper.rs +++ b/crates/lune-std-ffi/src/c/helper.rs @@ -53,7 +53,7 @@ pub mod method_provider { return Err(LuaError::external("Out of bounds")); } if !data_handle.is_readable() { - return Err(LuaError::external("Unreadable data handle")); + return Err(LuaError::external("Unreadable data")); } unsafe { this.value_from_data(lua, offset, data_handle) } @@ -77,7 +77,7 @@ pub mod method_provider { return Err(LuaError::external("Out of bounds")); } if !data_handle.is_writable() { - return Err(LuaError::external("Unwritable data handle")); + return Err(LuaError::external("Unwritable data")); } unsafe { this.value_into_data(lua, offset, data_handle, value) } @@ -106,18 +106,18 @@ pub mod method_provider { let dst = &dst.get_ffi_data()?; // use or functions if !dst.check_inner_boundary(dst_offset, this.get_size()) { - return Err(LuaError::external("Out of bounds")); + return Err(LuaError::external("Destination out of bounds")); } if !dst.is_writable() { - return Err(LuaError::external("Unwritable data handle")); + return Err(LuaError::external("Destination is unwritable")); } let src = &src.get_ffi_data()?; if !src.check_inner_boundary(dst_offset, this.get_size()) { - return Err(LuaError::external("Out of bounds")); + return Err(LuaError::external("Source out of bounds")); } if !src.is_readable() { - return Err(LuaError::external("Unreadable value data handle")); + return Err(LuaError::external("Source is unreadable")); } unsafe { this.copy_data(lua, dst_offset, src_offset, dst, src) } @@ -196,22 +196,6 @@ pub fn get_userdata(value: LuaValue) -> LuaResult { } } -// Get the NativeConvert handle from the type UserData -// this is intended to avoid lookup userdata and lua table every time. (eg: struct) -// userdata must live longer than the NativeConvert handle. -// However, c_struct is a strong reference to each field, so this is not a problem. -pub unsafe fn get_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn FfiConvert> { - if userdata.is::() { - Ok(userdata.to_pointer().cast::() as *const dyn FfiConvert) - } else if userdata.is::() { - Ok(userdata.to_pointer().cast::() as *const dyn FfiConvert) - } else if userdata.is::() { - Ok(userdata.to_pointer().cast::() as *const dyn FfiConvert) - } else { - ctype_helper::get_conv(userdata) - } -} - // Create vec from table with (userdata)->T pub fn create_list( table: &LuaTable, @@ -228,27 +212,23 @@ pub fn create_list( Ok(list) } -//Get -pub unsafe fn get_conv_list(table: &LuaTable) -> LuaResult> { - create_list(table, |userdata| get_conv(userdata)) -} - -// Get type size from ctype userdata -pub fn get_size(userdata: &LuaAnyUserData) -> LuaResult { +// Get the NativeConvert handle from the ctype userData +// This is intended to avoid lookup userdata and lua table every time. (eg: struct) +// The userdata must live longer than the NativeConvert handle +pub unsafe fn get_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn FfiConvert> { if userdata.is::() { - Ok(userdata.borrow::()?.get_size()) + Ok(userdata.to_pointer().cast::() as *const dyn FfiConvert) } else if userdata.is::() { - Ok(userdata.borrow::()?.get_size()) + Ok(userdata.to_pointer().cast::() as *const dyn FfiConvert) } else if userdata.is::() { - Ok(userdata.borrow::()?.get_size()) - } else if userdata.is::() { - Ok(userdata.borrow::()?.get_size()) - } else if userdata.is::() { - Ok(userdata.borrow::()?.get_size()) + Ok(userdata.to_pointer().cast::() as *const dyn FfiConvert) } else { - ctype_helper::get_size(userdata) + ctype_helper::get_conv(userdata) } } +pub unsafe fn get_conv_list(table: &LuaTable) -> LuaResult> { + create_list(table, |userdata| get_conv(userdata)) +} // Get libffi_type from ctype userdata pub fn get_middle_type(userdata: &LuaAnyUserData) -> LuaResult { @@ -276,12 +256,28 @@ pub fn get_middle_type(userdata: &LuaAnyUserData) -> LuaResult { ))) } } - -// get Vec from table(array) of c-type userdata pub fn get_middle_type_list(table: &LuaTable) -> LuaResult> { create_list(table, get_middle_type) } +// Get type size from ctype userdata +pub fn get_size(userdata: &LuaAnyUserData) -> LuaResult { + if userdata.is::() { + Ok(userdata.borrow::()?.get_size()) + } else if userdata.is::() { + Ok(userdata.borrow::()?.get_size()) + } else if userdata.is::() { + Ok(userdata.borrow::()?.get_size()) + } else if userdata.is::() { + Ok(userdata.borrow::()?.get_size()) + } else if userdata.is::() { + Ok(userdata.borrow::()?.get_size()) + } else { + ctype_helper::get_size(userdata) + } +} + +// Check lua table has void ctype userdata pub fn has_void(table: &LuaTable) -> LuaResult { for i in 0..table.raw_len() { let value: LuaValue = table.raw_get(i + 1)?; @@ -292,7 +288,7 @@ pub fn has_void(table: &LuaTable) -> LuaResult { Ok(false) } -// stringify any c-type userdata (for recursive) +// Stringify any c-type userdata recursively pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { if userdata.is::() { CStructInfo::stringify(lua, userdata) @@ -311,7 +307,7 @@ pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { } } -// get name tag for any c-type userdata +// Get name tag from ctype userdata pub fn get_tag_name(userdata: &LuaAnyUserData) -> LuaResult { Ok(if userdata.is::() { String::from("CStructInfo") @@ -330,7 +326,8 @@ pub fn get_tag_name(userdata: &LuaAnyUserData) -> LuaResult { }) } -// emulate 'print' for ctype userdata, but ctype is simplified +// Emulate 'print' for ctype userdata, but simplified +// Used for print struct field, cfn arguments, etc... pub fn pretty_format(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { if ctype_helper::is_ctype(userdata) { stringify(lua, userdata) diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index 911cdb6f..5f9293a2 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -36,6 +36,7 @@ mod association_names { pub const CLOSURE_CFN: &str = "__closure_cfn"; } +// Export c namespace pub fn export_c(lua: &Lua) -> LuaResult { TableBuilder::new(lua)? .with_value("void", CVoidInfo::new())? diff --git a/crates/lune-std-ffi/src/c/ptr_info.rs b/crates/lune-std-ffi/src/c/ptr_info.rs index 0758ba82..12ad7b37 100644 --- a/crates/lune-std-ffi/src/c/ptr_info.rs +++ b/crates/lune-std-ffi/src/c/ptr_info.rs @@ -11,12 +11,9 @@ use crate::{ }, }; -const READ_CPTR_REF_FLAGS: u8 = - RefFlag::Dereferenceable.value() | RefFlag::Offsetable.value() | RefFlag::Leaked.value(); -const READ_REF_FLAGS: u8 = RefFlag::Offsetable.value() - | RefFlag::Leaked.value() - | RefFlag::Readable.value() - | RefFlag::Writable.value(); +const READ_CPTR_REF_FLAGS: u8 = RefFlag::Dereferenceable.value() | RefFlag::Offsetable.value(); +const READ_REF_FLAGS: u8 = + RefFlag::Offsetable.value() | RefFlag::Readable.value() | RefFlag::Writable.value(); pub struct CPtrInfo { inner_size: usize, @@ -42,9 +39,12 @@ impl FfiConvert for CPtrInfo { data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { - let value_userdata = value - .as_userdata() - .ok_or_else(|| LuaError::external("CPtrInfo:writeRef only allows data"))?; + let value_userdata = value.as_userdata().ok_or_else(|| { + LuaError::external(format!( + "Value must be a RefData, BoxData or ClosureData, got {}", + value.type_name() + )) + })?; *data_handle .get_inner_pointer() .byte_offset(offset) @@ -112,7 +112,7 @@ impl CPtrInfo { format!(" {pretty_formatted} ") }) } else { - Err(LuaError::external("failed to get inner type userdata.")) + Err(LuaError::external("Failed to retrieve inner type")) } } @@ -124,11 +124,10 @@ impl CPtrInfo { impl LuaUserData for CPtrInfo { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("size", |_, _| Ok(SIZE_OF_POINTER)); + fields.add_field_method_get("size", |_lua, _this| Ok(SIZE_OF_POINTER)); fields.add_field_function_get("inner", |lua, this| { - let inner = association::get(lua, CPTR_INNER, this)? - .ok_or_else(|| LuaError::external("inner type not found"))?; - Ok(inner) + association::get(lua, CPTR_INNER, this)? + .ok_or_else(|| LuaError::external("Failed to retrieve inner type")) }); } diff --git a/crates/lune-std-ffi/src/c/string_info.rs b/crates/lune-std-ffi/src/c/string_info.rs index 2a4da645..7fe35684 100644 --- a/crates/lune-std-ffi/src/c/string_info.rs +++ b/crates/lune-std-ffi/src/c/string_info.rs @@ -1,3 +1,5 @@ +// TODO: + use mlua::prelude::*; pub struct CStringInfo(); diff --git a/crates/lune-std-ffi/src/c/struct_info.rs b/crates/lune-std-ffi/src/c/struct_info.rs index 9f5b1c98..55b8a429 100644 --- a/crates/lune-std-ffi/src/c/struct_info.rs +++ b/crates/lune-std-ffi/src/c/struct_info.rs @@ -46,9 +46,7 @@ impl CStructInfo { 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 not required + // Get tailing padded size of struct (get_ensured_size not required) let size = unsafe { (*middle_type.as_raw_ptr()).size }; Ok(Self { @@ -59,8 +57,8 @@ impl CStructInfo { }) } - // Create new CStruct UserData from LuaTable. - // Lock and hold table for .inner ref + // Create new CStruct from LuaTable. + // Freeze and hold table pub fn from_table<'lua>( lua: &'lua Lua, table: LuaTable<'lua>, @@ -73,25 +71,27 @@ impl CStructInfo { .create_userdata(Self::new(helper::get_middle_type_list(&table)?, unsafe { helper::get_conv_list(&table)? })?)?; + + // Save field table table.set_readonly(true); association::set(lua, CSTRUCT_INNER, &cstruct, table)?; Ok(cstruct) } - // Stringify cstruct for pretty printing like: - // + // Stringify cstruct for pretty printing + // ex: pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { let fields = get_field_table(lua, userdata)?; let mut stringified = String::from(" "); - // children + // Children for i in 0..fields.raw_len() { let child: LuaAnyUserData = fields.raw_get(i + 1)?; let pretty_formatted = helper::pretty_format(lua, &child)?; stringified.push_str(format!("{pretty_formatted}, ").as_str()); } - // size of + // Size stringified .push_str(format!("size = {} ", userdata.borrow::()?.get_size()).as_str()); Ok(stringified) @@ -99,12 +99,11 @@ impl CStructInfo { // Get byte offset of nth field pub fn offset(&self, index: usize) -> LuaResult { - let offset = self + Ok(self .inner_offset_list .get(index) .ok_or_else(|| LuaError::external("Out of index"))? - .to_owned(); - Ok(offset) + .to_owned()) } pub fn get_middle_type(&self) -> Type { @@ -182,7 +181,7 @@ impl FfiConvert for CStructInfo { impl LuaUserData for CStructInfo { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("size", |_, this| Ok(this.get_size())); + fields.add_field_method_get("size", |_lua, this| Ok(this.get_size())); } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { // Subtype @@ -198,8 +197,9 @@ impl LuaUserData for CStructInfo { method_provider::provide_write_data(methods); method_provider::provide_copy_data(methods); - methods.add_method("offset", |_, this, index: usize| this.offset(index)); - // Get nth field type userdata + // Get nth field offset + methods.add_method("offset", |_lua, this, index: usize| this.offset(index)); + // Get nth field type methods.add_function( "field", |lua, (this, field_index): (LuaAnyUserData, usize)| { diff --git a/crates/lune-std-ffi/src/c/type_info.rs b/crates/lune-std-ffi/src/c/type_info.rs index 96c989c6..fa606fd5 100644 --- a/crates/lune-std-ffi/src/c/type_info.rs +++ b/crates/lune-std-ffi/src/c/type_info.rs @@ -24,7 +24,7 @@ pub trait CTypeCast { _from_offset: isize, _into_offset: isize, ) -> LuaResult<()> { - // Show error if have no cast implement + // Error if have no cast implement Err(Self::cast_failed_with(self, from_ctype, into_ctype)) } @@ -35,7 +35,7 @@ pub trait CTypeCast { ) -> LuaError { let config = ValueFormatConfig::new(); LuaError::external(format!( - "Cannot cast {} to {}", + "Failed to cast {} into {}", pretty_format_value(&LuaValue::UserData(from_ctype.to_owned()), &config), pretty_format_value(&LuaValue::UserData(into_ctype.to_owned()), &config), )) @@ -94,8 +94,8 @@ where { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { fields.add_meta_field(LuaMetaMethod::Type, "CTypeInfo"); - fields.add_field_method_get("size", |_, this| Ok(this.get_size())); - fields.add_field_method_get("signedness", |_, this| Ok(this.get_signedness())); + fields.add_field_method_get("size", |_lua, this| Ok(this.get_size())); + fields.add_field_method_get("signedness", |_lua, this| Ok(this.get_signedness())); } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { @@ -115,7 +115,7 @@ where methods.add_function( "cast", - |_, + |_lua, (from_type, into_type, from, into, from_offset, into_offset): ( LuaAnyUserData, LuaAnyUserData, diff --git a/crates/lune-std-ffi/src/c/types/f32.rs b/crates/lune-std-ffi/src/c/types/f32.rs index 6352e5b2..b13fb4af 100644 --- a/crates/lune-std-ffi/src/c/types/f32.rs +++ b/crates/lune-std-ffi/src/c/types/f32.rs @@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo { .map_err(LuaError::external)?, _ => { return Err(LuaError::external(format!( - "Argument LuaValue expected a Integer, Number or String, got {}", + "Value must be a Integer, Number or String, got {}", value.type_name() ))) } @@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/f64.rs b/crates/lune-std-ffi/src/c/types/f64.rs index 8657052a..1747e39e 100644 --- a/crates/lune-std-ffi/src/c/types/f64.rs +++ b/crates/lune-std-ffi/src/c/types/f64.rs @@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo { .map_err(LuaError::external)?, _ => { return Err(LuaError::external(format!( - "Argument LuaValue expected a Integer, Number or String, got {}", + "Value must be a Integer, Number or String, got {}", value.type_name() ))) } @@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/i128.rs b/crates/lune-std-ffi/src/c/types/i128.rs index 17eb8884..e60b1305 100644 --- a/crates/lune-std-ffi/src/c/types/i128.rs +++ b/crates/lune-std-ffi/src/c/types/i128.rs @@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo { .map_err(LuaError::external)?, _ => { return Err(LuaError::external(format!( - "Argument LuaValue expected a Integer, Number or String, got {}", + "Value must be a Integer, Number or String, got {}", value.type_name() ))) } @@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/i16.rs b/crates/lune-std-ffi/src/c/types/i16.rs index 39035b52..e82920fa 100644 --- a/crates/lune-std-ffi/src/c/types/i16.rs +++ b/crates/lune-std-ffi/src/c/types/i16.rs @@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo { .map_err(LuaError::external)?, _ => { return Err(LuaError::external(format!( - "Argument LuaValue expected a Integer, Number or String, got {}", + "Value must be a Integer, Number or String, got {}", value.type_name() ))) } @@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/i32.rs b/crates/lune-std-ffi/src/c/types/i32.rs index 4dae14ac..b25515a9 100644 --- a/crates/lune-std-ffi/src/c/types/i32.rs +++ b/crates/lune-std-ffi/src/c/types/i32.rs @@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo { .map_err(LuaError::external)?, _ => { return Err(LuaError::external(format!( - "Argument LuaValue expected a Integer, Number or String, got {}", + "Value must be a Integer, Number or String, got {}", value.type_name() ))) } @@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/i64.rs b/crates/lune-std-ffi/src/c/types/i64.rs index 3e353101..db4e5673 100644 --- a/crates/lune-std-ffi/src/c/types/i64.rs +++ b/crates/lune-std-ffi/src/c/types/i64.rs @@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo { .map_err(LuaError::external)?, _ => { return Err(LuaError::external(format!( - "Argument LuaValue expected a Integer, Number or String, got {}", + "Value must be a Integer, Number or String, got {}", value.type_name() ))) } @@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/i8.rs b/crates/lune-std-ffi/src/c/types/i8.rs index ea778e2c..4384f747 100644 --- a/crates/lune-std-ffi/src/c/types/i8.rs +++ b/crates/lune-std-ffi/src/c/types/i8.rs @@ -27,7 +27,7 @@ impl FfiConvert for CTypeInfo { LuaValue::String(t) => t.as_bytes().first().map_or(0, u8::to_owned).as_(), _ => { return Err(LuaError::external(format!( - "Argument LuaValue expected a Integer or String, got {}", + "Value must be a Integer or String, got {}", value.type_name() ))) } @@ -43,7 +43,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/isize.rs b/crates/lune-std-ffi/src/c/types/isize.rs index 9c363eaa..bee4db62 100644 --- a/crates/lune-std-ffi/src/c/types/isize.rs +++ b/crates/lune-std-ffi/src/c/types/isize.rs @@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo { .map_err(LuaError::external)?, _ => { return Err(LuaError::external(format!( - "Argument LuaValue expected a Integer, Number or String, got {}", + "Value must be a Integer, Number or String, got {}", value.type_name() ))) } @@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/mod.rs b/crates/lune-std-ffi/src/c/types/mod.rs index 2de89bb9..cfbd6175 100644 --- a/crates/lune-std-ffi/src/c/types/mod.rs +++ b/crates/lune-std-ffi/src/c/types/mod.rs @@ -126,7 +126,7 @@ where pub mod ctype_helper { use super::*; - // To prevent drop NativeConvert, we must use ffi_association to ensure children keep alive + // To prevent droping NativeConvert, need to ensure userdata keep alive macro_rules! define_get_conv { ($userdata:ident, $( $rust_type:ty )*) => { $( if $userdata.is::>() { @@ -141,7 +141,7 @@ pub mod ctype_helper { define_get_conv!(userdata, u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize) } - // Get size of ctype (not includes struct, arr, ... only CType<*>) + // Get size of ctype (not including struct, arr, ... only CType<*>) macro_rules! define_get_size { ($userdata:ident, $( $rust_type:ty )*) => { $( if $userdata.is::>() { @@ -186,6 +186,7 @@ pub mod ctype_helper { define_get_middle_type!(userdata, u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize) } + // Check whether userdata is ctype or not macro_rules! define_is_ctype { ($userdata:ident, $( $rust_type:ty )*) => { $( if $userdata.is::>() { diff --git a/crates/lune-std-ffi/src/c/types/u128.rs b/crates/lune-std-ffi/src/c/types/u128.rs index 78851f0a..3bb8443b 100644 --- a/crates/lune-std-ffi/src/c/types/u128.rs +++ b/crates/lune-std-ffi/src/c/types/u128.rs @@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo { .map_err(LuaError::external)?, _ => { return Err(LuaError::external(format!( - "Argument LuaValue expected a Integer, Number or String, got {}", + "Value must be a Integer, Number or String, got {}", value.type_name() ))) } @@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/u16.rs b/crates/lune-std-ffi/src/c/types/u16.rs index 2a9dc044..ec1d0721 100644 --- a/crates/lune-std-ffi/src/c/types/u16.rs +++ b/crates/lune-std-ffi/src/c/types/u16.rs @@ -32,7 +32,7 @@ impl FfiConvert for CTypeInfo { .map_err(LuaError::external)?, _ => { return Err(LuaError::external(format!( - "Argument LuaValue expected a Integer, Number or String, got {}", + "Value must be a Integer, Number or String, got {}", value.type_name() ))) } @@ -48,7 +48,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/u32.rs b/crates/lune-std-ffi/src/c/types/u32.rs index 04e95483..25942e0b 100644 --- a/crates/lune-std-ffi/src/c/types/u32.rs +++ b/crates/lune-std-ffi/src/c/types/u32.rs @@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo { .map_err(LuaError::external)?, _ => { return Err(LuaError::external(format!( - "Argument LuaValue expected a Integer, Number or String, got {}", + "Value must be a Integer, Number or String, got {}", value.type_name() ))) } @@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/u64.rs b/crates/lune-std-ffi/src/c/types/u64.rs index 07911b5f..33d9785d 100644 --- a/crates/lune-std-ffi/src/c/types/u64.rs +++ b/crates/lune-std-ffi/src/c/types/u64.rs @@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo { .map_err(LuaError::external)?, _ => { return Err(LuaError::external(format!( - "Argument LuaValue expected a Integer, Number or String, got {}", + "Value must be a Integer, Number or String, got {}", value.type_name() ))) } @@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/u8.rs b/crates/lune-std-ffi/src/c/types/u8.rs index a9d575b3..8764bfc3 100644 --- a/crates/lune-std-ffi/src/c/types/u8.rs +++ b/crates/lune-std-ffi/src/c/types/u8.rs @@ -28,7 +28,7 @@ impl FfiConvert for CTypeInfo { LuaValue::String(t) => t.as_bytes().first().map_or(0, u8::to_owned).as_(), _ => { return Err(LuaError::external(format!( - "Argument LuaValue expected a Integer or String, got {}", + "Value must be a Integer or String, got {}", value.type_name() ))) } @@ -46,7 +46,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/types/usize.rs b/crates/lune-std-ffi/src/c/types/usize.rs index ab97d232..a7902ed1 100644 --- a/crates/lune-std-ffi/src/c/types/usize.rs +++ b/crates/lune-std-ffi/src/c/types/usize.rs @@ -31,7 +31,7 @@ impl FfiConvert for CTypeInfo { .map_err(LuaError::external)?, _ => { return Err(LuaError::external(format!( - "Argument LuaValue expected a Integer, Number or String, got {}", + "Value must be a Integer, Number or String, got {}", value.type_name() ))) } @@ -47,7 +47,6 @@ impl FfiConvert for CTypeInfo { unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, - // _type_userdata: &LuaAnyUserData<'lua>, offset: isize, data_handle: &Ref, ) -> LuaResult> { diff --git a/crates/lune-std-ffi/src/c/void_info.rs b/crates/lune-std-ffi/src/c/void_info.rs index 97a2fa28..3c0ed880 100644 --- a/crates/lune-std-ffi/src/c/void_info.rs +++ b/crates/lune-std-ffi/src/c/void_info.rs @@ -32,7 +32,7 @@ impl CVoidInfo { impl LuaUserData for CVoidInfo { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("size", |_, _| Ok(0)); + fields.add_field_method_get("size", |_lua, _this| Ok(0)); } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { method_provider::provide_to_string(methods); diff --git a/crates/lune-std-ffi/src/data/box_data/mod.rs b/crates/lune-std-ffi/src/data/box_data/mod.rs index 9585a57d..dd6cc958 100644 --- a/crates/lune-std-ffi/src/data/box_data/mod.rs +++ b/crates/lune-std-ffi/src/data/box_data/mod.rs @@ -17,28 +17,20 @@ mod flag; pub use self::flag::BoxFlag; -// Ref which created by lua should not be dereferenceable, +const FFI_BOX_PRINT_MAX_LENGTH: usize = 1024; + +// Reference which created by lua should not be dereferenceable const BOX_REF_FLAGS: u8 = RefFlag::Readable.value() | RefFlag::Writable.value() | RefFlag::Offsetable.value(); -// It is an untyped, sized memory area that Lua can manage. -// This area is safe within Lua. Operations have their boundaries checked. -// It is basically intended to implement passing a pointed space to the outside. -// It also helps you handle data that Lua cannot handle. -// Depending on the type, operations such as sum, mul, and mod may be implemented. -// There is no need to enclose all data in a box; -// rather, it creates more heap space, so it should be used appropriately -// where necessary. - +// Untyped runtime sized memory for luau. +// This operations are safe, have boundaries check. pub struct BoxData { flags: u8, data: ManuallyDrop>, } -const FFI_BOX_PRINT_MAX_LENGTH: usize = 1024; - impl BoxData { - // For efficiency, it is initialized non-zeroed. pub fn new(size: usize) -> Self { let slice = unsafe { Box::from_raw(ptr::slice_from_raw_parts_mut( @@ -53,13 +45,10 @@ impl BoxData { } } - // pub fn copy(&self, target: &mut FfiBox) {} - + // Stringify for pretty-print, with hex format content pub fn stringify(&self) -> String { if self.size() > FFI_BOX_PRINT_MAX_LENGTH * 2 { - // FIXME - // Todo: if too big, print as another format - return String::from("exceed"); + return String::from("length limit exceed"); } let mut buff: String = String::with_capacity(self.size() * 2); for value in self.data.iter() { @@ -72,7 +61,7 @@ impl BoxData { self.flags = u8_set(self.flags, BoxFlag::Leaked.value(), true); } - // Make FfiRef from box, with boundary checking + // Make FfiRef from box, with boundary check pub fn luaref<'lua>( lua: &'lua Lua, this: LuaAnyUserData<'lua>, @@ -97,17 +86,13 @@ impl BoxData { let luaref = lua.create_userdata(RefData::new(ptr.cast(), BOX_REF_FLAGS, bounds))?; - // Makes box alive longer then ref + // Make box live longer then ref association::set(lua, REF_INNER, &luaref, &this)?; Ok(luaref) } - pub unsafe fn drop(&mut self) { - ManuallyDrop::drop(&mut self.data); - } - - // Fill every field with 0 + // Fill with zero pub fn zero(&mut self) { self.data.fill(0); } @@ -122,7 +107,7 @@ impl BoxData { impl Drop for BoxData { fn drop(&mut self) { if u8_test_not(self.flags, BoxFlag::Leaked.value()) { - unsafe { self.drop() }; + unsafe { ManuallyDrop::drop(&mut self.data) }; } } } @@ -151,12 +136,12 @@ impl FfiData for BoxData { impl LuaUserData for BoxData { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("size", |_, this| Ok(this.size())); + fields.add_field_method_get("size", |_lua, this| Ok(this.size())); } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { method_provider::provide_copy_from(methods); - // For convenience, :zero returns self. - methods.add_function_mut("zero", |_, this: LuaAnyUserData| { + // For convenience, :zero returns box itself. + methods.add_function_mut("zero", |_lua, this: LuaAnyUserData| { this.borrow_mut::()?.zero(); Ok(this) }); @@ -173,6 +158,8 @@ impl LuaUserData for BoxData { BoxData::luaref(lua, this, offset) }, ); - methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| Ok(this.stringify())); + methods.add_meta_method(LuaMetaMethod::ToString, |_lua, this, ()| { + Ok(this.stringify()) + }); } } diff --git a/crates/lune-std-ffi/src/data/callable_data.rs b/crates/lune-std-ffi/src/data/callable_data.rs index fab6c7e8..2e95a27b 100644 --- a/crates/lune-std-ffi/src/data/callable_data.rs +++ b/crates/lune-std-ffi/src/data/callable_data.rs @@ -23,7 +23,8 @@ pub struct CallableData { const VOID_RESULT_PTR: *mut () = ptr::null_mut(); const ZERO_SIZE_ARG_PTR: *mut *mut c_void = ptr::null_mut(); -// Use known size array in stack instead of creating new Vec on heap +// Optimization: +// Use known size array in stack instead of creating new Vec to eliminate heap allocation macro_rules! create_caller { ($len:expr) => { |callable: &CallableData, result: LuaValue, args: LuaMultiValue| unsafe { @@ -42,12 +43,12 @@ macro_rules! create_caller { .get(index) .ok_or_else(|| LuaError::external(format!("Argument {index} required")))? .as_userdata() - .ok_or_else(|| LuaError::external("Argument should be a RefData"))?; + .ok_or_else(|| LuaError::external("Argument must be a RefData"))?; if let Ok(arg_ref) = arg_value.borrow::() { arg.write(arg_ref.get_inner_pointer().cast::()); } else { - return Err(LuaError::external("Argument should be a RefData")); + return Err(LuaError::external("Argument must be a RefData")); } } @@ -65,6 +66,7 @@ macro_rules! create_caller { }; } +// Optimization: // Call without arguments unsafe fn zero_size_caller( callable: &CallableData, @@ -88,6 +90,7 @@ unsafe fn zero_size_caller( Ok(()) } +// Optimization: sized callers type Caller = unsafe fn(callable: &CallableData, result: LuaValue, args: LuaMultiValue) -> LuaResult<()>; const SIZED_CALLERS: [Caller; 13] = [ @@ -123,6 +126,7 @@ impl CallableData { pub unsafe fn call(&self, result: LuaValue, args: LuaMultiValue) -> LuaResult<()> { let arg_len = self.arg_info_list.len(); + // Optimization: use sized caller when possible if arg_len < SIZED_CALLERS.len() { return SIZED_CALLERS[arg_len](self, result, args); } @@ -142,12 +146,12 @@ impl CallableData { .get(index) .ok_or_else(|| LuaError::external(format!("Argument {index} required")))? .as_userdata() - .ok_or_else(|| LuaError::external("Argument should be a RefData"))?; + .ok_or_else(|| LuaError::external("Argument must be a RefData"))?; if let Ok(arg_ref) = arg_value.borrow::() { arg_list.push(arg_ref.get_inner_pointer().cast::()); } else { - return Err(LuaError::external("Argument should be a RefData")); + return Err(LuaError::external("Argument must be a RefData")); } } diff --git a/crates/lune-std-ffi/src/data/closure_data.rs b/crates/lune-std-ffi/src/data/closure_data.rs index bd4256f2..bc6c0784 100644 --- a/crates/lune-std-ffi/src/data/closure_data.rs +++ b/crates/lune-std-ffi/src/data/closure_data.rs @@ -34,10 +34,10 @@ impl Drop for ClosureData { } } -const RESULT_REF_FLAGS: u8 = - RefFlag::Leaked.value() | RefFlag::Writable.value() | RefFlag::Offsetable.value(); +const RESULT_REF_FLAGS: u8 = RefFlag::Writable.value() | RefFlag::Offsetable.value(); const CLOSURE_REF_FLAGS: u8 = RefFlag::Function.value(); +// Process C -> Lua function call unsafe extern "C" fn callback( cif: *mut ffi_cif, result_pointer: *mut c_void, @@ -84,6 +84,7 @@ unsafe extern "C" fn callback( } impl ClosureData { + // Allocate new ffi closure with lua function pub fn alloc( lua: &Lua, cif: *mut ffi_cif, diff --git a/crates/lune-std-ffi/src/data/helper.rs b/crates/lune-std-ffi/src/data/helper.rs index a1aebd44..812e7f5a 100644 --- a/crates/lune-std-ffi/src/data/helper.rs +++ b/crates/lune-std-ffi/src/data/helper.rs @@ -3,9 +3,9 @@ use mlua::prelude::*; use super::{FfiData, GetFfiData}; pub mod method_provider { - use super::*; + // Implement copyFrom method pub fn provide_copy_from<'lua, Target, M>(methods: &mut M) where Target: FfiData, diff --git a/crates/lune-std-ffi/src/data/lib_data.rs b/crates/lune-std-ffi/src/data/lib_data.rs index a7d38a45..9c92ce59 100644 --- a/crates/lune-std-ffi/src/data/lib_data.rs +++ b/crates/lune-std-ffi/src/data/lib_data.rs @@ -12,17 +12,20 @@ const LIB_REF_FLAGS: u8 = RefFlag::Offsetable.value() | RefFlag::Dereferenceable.value() | RefFlag::Function.value(); +// Runtime dynamic loaded libraries pub struct LibData(Library); impl LibData { + // Open library then return library handle pub fn new(libname: String) -> LuaResult { match Library::open(libname) { Ok(t) => Ok(Self(t)), - Err(err) => Err(LuaError::external(format!("{err}"))), + Err(err) => Err(err.into_lua_err()), } } - pub fn get_sym<'lua>( + // Get named symbol from library + pub fn find_symbol<'lua>( lua: &'lua Lua, this: LuaAnyUserData<'lua>, name: String, @@ -31,12 +34,12 @@ impl LibData { let sym = unsafe { lib.0 .symbol::<*const ()>(name.as_str()) - .map_err(|err| LuaError::external(format!("{err}")))? + .map_err(LuaError::external)? }; - let ffi_ref = lua.create_userdata(RefData::new(sym.cast_mut(), LIB_REF_FLAGS, UNSIZED_BOUNDS))?; + // Library handle should live longer than retrieved symbol association::set(lua, SYM_INNER, &ffi_ref, &this)?; Ok(ffi_ref) @@ -46,7 +49,7 @@ impl LibData { impl LuaUserData for LibData { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { methods.add_function("find", |lua, (this, name): (LuaAnyUserData, String)| { - LibData::get_sym(lua, this, name) + LibData::find_symbol(lua, this, name) }); } } diff --git a/crates/lune-std-ffi/src/data/mod.rs b/crates/lune-std-ffi/src/data/mod.rs index 2c4a68f4..558873fd 100644 --- a/crates/lune-std-ffi/src/data/mod.rs +++ b/crates/lune-std-ffi/src/data/mod.rs @@ -26,11 +26,11 @@ mod association_names { pub const CLSOURE_REF_INNER: &str = "__closure_ref_inner"; } +// Get dynamic FfiData handle from LuaValue and LuaAnyUserData pub trait GetFfiData { fn get_ffi_data(&self) -> LuaResult>; fn is_ffi_data(&self) -> bool; } - impl GetFfiData for LuaAnyUserData<'_> { fn get_ffi_data(&self) -> LuaResult> { if self.is::() { @@ -51,7 +51,6 @@ impl GetFfiData for LuaAnyUserData<'_> { self.is::() | self.is::() | self.is::() } } - impl GetFfiData for LuaValue<'_> { fn get_ffi_data(&self) -> LuaResult> { self.as_userdata() diff --git a/crates/lune-std-ffi/src/data/ref_data/bounds.rs b/crates/lune-std-ffi/src/data/ref_data/bounds.rs index 0a702e1f..be3e288e 100644 --- a/crates/lune-std-ffi/src/data/ref_data/bounds.rs +++ b/crates/lune-std-ffi/src/data/ref_data/bounds.rs @@ -1,8 +1,8 @@ -// Memory range for ref or box data. For boundary checking +// Memory boundaries pub struct RefBounds { - // Indicates how much data is above the pointer + // How much data available above pub(crate) above: usize, - // Indicates how much data is below the pointer + // How much data available below pub(crate) below: usize, } @@ -39,8 +39,7 @@ impl RefBounds { } } - // Check boundary - // Check required here + // Check boundary with specific size #[inline] pub fn check_sized(&self, offset: isize, size: usize) -> bool { if self.is_unsized() { @@ -62,7 +61,7 @@ impl RefBounds { } } - // Calculate new bounds from bounds and offset + // Calculate new boundaries from bounds and offset // No boundary checking in here #[inline] pub fn offset(&self, offset: isize) -> Self { diff --git a/crates/lune-std-ffi/src/data/ref_data/mod.rs b/crates/lune-std-ffi/src/data/ref_data/mod.rs index d54ab4ba..86ad176c 100644 --- a/crates/lune-std-ffi/src/data/ref_data/mod.rs +++ b/crates/lune-std-ffi/src/data/ref_data/mod.rs @@ -18,22 +18,12 @@ pub use self::{ // Box:ref():ref() should not be able to modify, Only for external const BOX_REF_REF_FLAGS: u8 = 0; -// | FfiRefFlag::Writable.value() -// | FfiRefFlag::Readable.value() -// | FfiRefFlag::Dereferenceable.value() -// | FfiRefFlag::Offsetable.value() -// | FfiRefFlag::Function.value(); - -// A referenced space. It is possible to read and write through types. -// This operation is not safe. This may cause a memory error in Lua -// if use it incorrectly. -// If it references an area managed by Lua, -// the box will remain as long as this reference is alive. +// A referenced memory address box. Possible to read and write through types. pub struct RefData { ptr: ManuallyDrop>, - pub flags: u8, - pub boundary: RefBounds, + pub(crate) flags: u8, + boundary: RefBounds, } impl RefData { @@ -45,7 +35,7 @@ impl RefData { } } - // Make FfiRef from ref + // Create reference of this reference box pub fn luaref<'lua>( lua: &'lua Lua, this: LuaAnyUserData<'lua>, @@ -61,32 +51,32 @@ impl RefData { }, ))?; - // If the ref holds a box, make sure the new ref also holds the box by holding ref + // Make new reference live longer then this reference association::set(lua, REF_INNER, &luaref, &this)?; Ok(luaref) } + // Dereference this reference pub unsafe fn deref(&self) -> LuaResult { + // Check dereferenceable if !u8_test(self.flags, RefFlag::Dereferenceable.value()) { return Err(LuaError::external("Reference is not dereferenceable")); } + // Check boundary if !self.boundary.check_sized(0, size_of::()) { - return Err(LuaError::external( - "Offset out of bounds", - )); + return Err(LuaError::external("Out of bounds")); } - // FIXME flags Ok(Self::new( *self.ptr.cast::<*mut ()>(), - self.flags, + u8_set(self.flags, RefFlag::Leaked.value(), false), UNSIZED_BOUNDS, )) } - pub fn is_nullptr(&self) -> bool { + pub fn is_null(&self) -> bool { // * ManuallyDrop wrapper // * Box wrapper (**self.ptr) as usize == 0 @@ -96,31 +86,33 @@ impl RefData { self.flags = u8_set(self.flags, RefFlag::Leaked.value(), true); } + // Create new reference with specific offset from this reference pub unsafe fn offset(&self, offset: isize) -> LuaResult { - u8_test(self.flags, RefFlag::Offsetable.value()) - .then_some(()) - .ok_or_else(|| LuaError::external("Reference is not offsetable"))?; - - // Check boundary, if exceed, return error - self.boundary - .check_boundary(offset) - .then_some(()) - .ok_or_else(|| { - LuaError::external(format!( - "Offset out of bounds (high: {}, low: {}, got {})", - self.boundary.above, self.boundary.below, offset - )) - })?; + // Check offsetable + if u8_test_not(self.flags, RefFlag::Offsetable.value()) { + return Err(LuaError::external("Reference is not offsetable")); + } - let boundary = self.boundary.offset(offset); + // Check boundary + if !self.boundary.check_boundary(offset) { + return Err(LuaError::external(format!( + "Offset out of bounds (high: {}, low: {}, got {})", + self.boundary.above, self.boundary.below, offset + ))); + } - // TODO + let boundary = self.boundary.offset(offset); Ok(Self::new( self.ptr.byte_offset(offset), - self.flags, + u8_set(self.flags, RefFlag::Leaked.value(), false), boundary, )) } + + // Stringify for pretty-print, with hex format address + pub fn stringify(&self) -> String { + format!("{:x}", **self.ptr as usize) + } } impl Drop for RefData { @@ -154,24 +146,12 @@ impl LuaUserData for RefData { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { method_provider::provide_copy_from(methods); - // FIXME: - methods.add_function("deref", |lua, this: LuaAnyUserData| { - let inner = association::get(lua, REF_INNER, &this)?; - let ffiref = this.borrow::()?; - let result = lua.create_userdata(unsafe { ffiref.deref()? })?; - - if let Some(t) = inner { - // if let Some(u) = association::get(lua, regname, value) {} - association::set(lua, REF_INNER, &result, &t)?; - } - - Ok(result) - }); + methods.add_method("deref", |_lua, this, ()| unsafe { this.deref() }); methods.add_function("offset", |lua, (this, offset): (LuaAnyUserData, isize)| { let ffiref = unsafe { this.borrow::()?.offset(offset)? }; let userdata = lua.create_userdata(ffiref)?; - // If the ref holds a box, make sure the new ref also holds the box + // If the ref holds a box or reference, make sure the new ref also holds it if let Some(t) = association::get(lua, REF_INNER, &this)? { association::set(lua, REF_INNER, &userdata, t)?; } @@ -185,7 +165,10 @@ impl LuaUserData for RefData { methods.add_function("ref", |lua, this: LuaAnyUserData| { RefData::luaref(lua, this) }); - methods.add_method("isNull", |_, this, ()| Ok(this.is_nullptr())); + methods.add_method("isNull", |_lua, this, ()| Ok(this.is_null())); + methods.add_meta_method(LuaMetaMethod::ToString, |_lua, this, ()| { + Ok(this.stringify()) + }); } } diff --git a/crates/lune-std-ffi/src/ffi/association.rs b/crates/lune-std-ffi/src/ffi/association.rs index 19382306..f9a68c83 100644 --- a/crates/lune-std-ffi/src/ffi/association.rs +++ b/crates/lune-std-ffi/src/ffi/association.rs @@ -4,30 +4,14 @@ use mlua::prelude::*; // In FFI, there is often data that is dependent on other data. // However, if you use user_value to inform Lua of the dependency, // a table will be created for each userdata. -// To prevent this, we place a weak reference table in the registry +// To prevent this, we place a weak reference table in the named registry // and simulate what mlua does. -// Since mlua does not provide Lua state (private), -// uservalue operations cannot be performed directly, -// so this is the best solution for now. + // If the dependency is deep, the value may be completely destroyed when -// gc is performed multiple times. To prevent this situation, FFI 'copies' +// gc is performed multiple times. To prevent this situation, FFI should copy // dependency if possible. -// -// ffi.i32:ptr():ptr() -// Something like this, every pointer type will have various inner field. -// -// box:ref():ref() -// But, in this case, -// -// Since the outermost pointer holds the definition for the pointer -// type inside it, only the outermost type will be removed on the first gc. -// It doesn't matter much. But if there is a cleaner way, we should choose it -// Forces 'associated' to persist as long as 'value' is alive. -// 'value' can only hold one value. If you want to keep something else, -// use a table with a different name. // You can delete the relationship by changing 'associated' to nil - #[inline] pub fn set<'lua, T, U>(lua: &'lua Lua, regname: &str, value: T, associated: U) -> LuaResult<()> where @@ -52,7 +36,7 @@ where Ok(()) } -// returns the Lua value that 'value' keeps. +// Returns the Lua value that 'value' keeps. // If there is no table in registry, it returns None. // If there is no value in table, it returns LuaNil. #[inline] diff --git a/crates/lune-std-ffi/src/ffi/cast.rs b/crates/lune-std-ffi/src/ffi/cast.rs index 1cd6c3f2..bbbe5804 100644 --- a/crates/lune-std-ffi/src/ffi/cast.rs +++ b/crates/lune-std-ffi/src/ffi/cast.rs @@ -5,6 +5,7 @@ use num::cast::AsPrimitive; use super::FfiData; +// Cast number type to another number type, with num::cast library #[inline] pub fn num_cast( from: &Ref, diff --git a/crates/lune-std-ffi/src/ffi/libffi_helper.rs b/crates/lune-std-ffi/src/ffi/libffi_helper.rs index c91d2d5f..df0e28fd 100644 --- a/crates/lune-std-ffi/src/ffi/libffi_helper.rs +++ b/crates/lune-std-ffi/src/ffi/libffi_helper.rs @@ -3,8 +3,9 @@ use std::ptr::{self, null_mut}; use libffi::{low, raw}; use mlua::prelude::*; -// Get ensured size of c-type (raw::libffi_type) -// See: http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html +pub const SIZE_OF_POINTER: usize = size_of::<*mut ()>(); + +// Get ensured size of ctype (raw::libffi_type) pub fn get_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult { let mut cif = low::ffi_cif::default(); let result = unsafe { @@ -21,9 +22,7 @@ pub fn get_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult { unsafe { Ok((*ffi_type).size) } } -pub const SIZE_OF_POINTER: usize = size_of::<*mut ()>(); - -// Converts ffi status into &str +// Converts ffi status into &str for formatting pub const FFI_STATUS_NAMES: [&str; 4] = [ "ffi_status_FFI_OK", "ffi_status_FFI_BAD_TYPEDEF", @@ -31,6 +30,7 @@ pub const FFI_STATUS_NAMES: [&str; 4] = [ "ffi_status_FFI_BAD_ARGTYPE", ]; +// Check ffi_result is OK pub fn ffi_status_assert(result: raw::ffi_status) -> LuaResult<()> { if result == raw::ffi_status_FFI_OK { Ok(()) diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index 7e65f5e2..5131b968 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -9,17 +9,17 @@ pub mod libffi_helper; pub use self::cast::num_cast; +// Common type information pub trait FfiSize { fn get_size(&self) -> usize; } - pub trait FfiSignedness { fn get_signedness(&self) -> bool { false } } -// Provide type conversion between luavalue and ffidata types +// Provide conversion between luau value and ffi types pub trait FfiConvert { // Write LuaValue into FfiData unsafe fn value_into_data<'lua>( @@ -57,6 +57,7 @@ pub trait FfiConvert { } } +// Provide read, write, boundary check methods for datas pub trait FfiData { fn check_inner_boundary(&self, offset: isize, size: usize) -> bool; unsafe fn get_inner_pointer(&self) -> *mut (); @@ -75,11 +76,11 @@ pub trait FfiData { } } +// Function argument informations pub struct FfiArg { pub size: usize, pub callback_ref_flag: u8, } - impl Clone for FfiArg { fn clone(&self) -> Self { Self { @@ -89,10 +90,10 @@ impl Clone for FfiArg { } } +// Function result information pub struct FfiResult { pub size: usize, } - impl Clone for FfiResult { fn clone(&self) -> Self { Self { size: self.size } diff --git a/types/ffi.luau b/types/ffi.luau index c6e32ded..b6ec423e 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -52,7 +52,9 @@ ffi.c = c --[=[ @class RefData - A user manageable memory reference. + A user manageable memory reference box. + + It can be GCed, But it doesn't free the referenced memory. ]=] export type RefData = { --[=[ @@ -60,7 +62,10 @@ export type RefData = { @tag Method @method deref - Get a RefData by dereference this reference. + Create a RefData by dereference this reference. + The created reference has no boundaries and has no restrictions. + + This method is unsafe. @return A dereferenced `RefData` ]=] @@ -71,7 +76,9 @@ export type RefData = { @method offset Create a reference with specific offset from this reference. - + + The created reference can be GCed and holds same data. + @param offset Create a reference at the given offset @return A offseted reference ]=] @@ -83,7 +90,7 @@ export type RefData = { Create a reference of this reference. - The created reference keeps the box from being garbage collected until the reference itself is collected. + The created reference keeps the target reference from being garbage collected until created reference itself is collected. @return A reference of this reference ]=] @@ -1089,6 +1096,7 @@ end @within FFI Create a `Box` with specific size. + The created box is not filed with zero. @param size The size of the new box @return A allocated box From 3a6f3bd016ac480f5a869623802936288190a904 Mon Sep 17 00:00:00 2001 From: qwreey Date: Fri, 8 Nov 2024 15:20:09 +0000 Subject: [PATCH 66/79] Add free function (#243) --- Cargo.lock | 27 +++++++++++++-------------- crates/lune-std-ffi/Cargo.toml | 5 +++-- crates/lune-std-ffi/src/lib.rs | 9 ++++++++- types/ffi.luau | 11 +++++++++++ 4 files changed, 35 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 95fb7fc4..4ec79331 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -789,9 +789,9 @@ dependencies = [ [[package]] name = "dlopen2" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bc2c7ed06fd72a8513ded8d0d2f6fd2655a85d6885c48cae8625d80faf28c03" +checksum = "9e1297103d2bbaea85724fcee6294c2d50b1081f9ad47d0f6f6f61eda65315a6" dependencies = [ "dlopen2_derive", "libc", @@ -1445,9 +1445,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.160" +version = "0.2.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0b21006cd1874ae9e650973c565615676dc4a274c965bb0a73796dac838ce4f" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" [[package]] name = "libffi" @@ -1633,6 +1633,7 @@ name = "lune-std-ffi" version = "0.1.1" dependencies = [ "dlopen2", + "libc", "libffi", "lune-utils", "mlua", @@ -1937,9 +1938,9 @@ dependencies = [ [[package]] name = "num" -version = "0.3.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ "num-bigint", "num-complex", @@ -1951,20 +1952,19 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.3.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "autocfg", "num-integer", "num-traits", ] [[package]] name = "num-complex" -version = "0.3.1" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ "num-traits", ] @@ -1997,11 +1997,10 @@ dependencies = [ [[package]] name = "num-rational" -version = "0.3.2" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "autocfg", "num-bigint", "num-integer", "num-traits", diff --git a/crates/lune-std-ffi/Cargo.toml b/crates/lune-std-ffi/Cargo.toml index 0420f1dc..78eebda6 100644 --- a/crates/lune-std-ffi/Cargo.toml +++ b/crates/lune-std-ffi/Cargo.toml @@ -15,8 +15,9 @@ workspace = true [dependencies] mlua = { version = "0.9.9", features = ["luau"] } mlua-sys = { version = "0.6.2", features = ["luau"] } -num = "0.3.1" -dlopen2 = "0.6" +num = "0.4.3" +dlopen2 = "0.7.0" +libc = "0.2.162" libffi = "3.2.0" diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs index 35a2450f..62b2572d 100644 --- a/crates/lune-std-ffi/src/lib.rs +++ b/crates/lune-std-ffi/src/lib.rs @@ -1,5 +1,8 @@ #![allow(clippy::cargo_common_metadata)] +use std::ffi::c_void; + +use libc::free; use lune_utils::TableBuilder; use mlua::prelude::*; @@ -9,7 +12,7 @@ mod ffi; use crate::{ c::{export_c, export_fixed_types}, - data::{create_nullref, BoxData, LibData}, + data::{create_nullref, BoxData, GetFfiData, LibData}, }; /** @@ -25,6 +28,10 @@ pub fn module(lua: &Lua) -> LuaResult { .with_function("box", |_lua, size: usize| Ok(BoxData::new(size)))? .with_function("open", |_lua, name: String| LibData::new(name))? .with_function("isInteger", |_lua, num: LuaValue| Ok(num.is_integer()))? + .with_function("free", |_lua, data: LuaAnyUserData| { + unsafe { free(data.get_ffi_data()?.get_inner_pointer().cast::()) }; + Ok(()) + })? .with_values(export_fixed_types(lua)?)? .with_value("c", export_c(lua)?)?; diff --git a/types/ffi.luau b/types/ffi.luau index b6ec423e..bfc465e0 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -1129,4 +1129,15 @@ function ffi.isInteger(val: T): boolean return nil :: any end +--[=[ + @within FFI + + Free referenced memory. + + @param data Target memory to free +]=] +function ffi.free(data: RefData | BoxData) + return nil :: any +end + return ffi From c45773770a7a8ddce81693ee468ebe6f59b879c5 Mon Sep 17 00:00:00 2001 From: qwreey Date: Fri, 8 Nov 2024 15:31:23 +0000 Subject: [PATCH 67/79] Fix dereference ref flags (#243) --- crates/lune-std-ffi/src/data/ref_data/mod.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/crates/lune-std-ffi/src/data/ref_data/mod.rs b/crates/lune-std-ffi/src/data/ref_data/mod.rs index 86ad176c..15ea044c 100644 --- a/crates/lune-std-ffi/src/data/ref_data/mod.rs +++ b/crates/lune-std-ffi/src/data/ref_data/mod.rs @@ -17,7 +17,13 @@ pub use self::{ }; // Box:ref():ref() should not be able to modify, Only for external -const BOX_REF_REF_FLAGS: u8 = 0; +const REF_REF_FLAGS: u8 = 0; + +const DEREF_REF_FLAG: u8 = RefFlag::Dereferenceable.value() + | RefFlag::Function.value() + | RefFlag::Offsetable.value() + | RefFlag::Readable.value() + | RefFlag::Writable.value(); // A referenced memory address box. Possible to read and write through types. pub struct RefData { @@ -44,7 +50,7 @@ impl RefData { let luaref = lua.create_userdata(RefData::new( ptr::from_ref(&**target.ptr) as *mut (), - BOX_REF_REF_FLAGS, + REF_REF_FLAGS, RefBounds { below: 0, above: size_of::(), @@ -58,7 +64,7 @@ impl RefData { } // Dereference this reference - pub unsafe fn deref(&self) -> LuaResult { + pub unsafe fn dereference(&self) -> LuaResult { // Check dereferenceable if !u8_test(self.flags, RefFlag::Dereferenceable.value()) { return Err(LuaError::external("Reference is not dereferenceable")); @@ -71,7 +77,7 @@ impl RefData { Ok(Self::new( *self.ptr.cast::<*mut ()>(), - u8_set(self.flags, RefFlag::Leaked.value(), false), + DEREF_REF_FLAG, UNSIZED_BOUNDS, )) } @@ -146,7 +152,7 @@ impl LuaUserData for RefData { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { method_provider::provide_copy_from(methods); - methods.add_method("deref", |_lua, this, ()| unsafe { this.deref() }); + methods.add_method("deref", |_lua, this, ()| unsafe { this.dereference() }); methods.add_function("offset", |lua, (this, offset): (LuaAnyUserData, isize)| { let ffiref = unsafe { this.borrow::()?.offset(offset)? }; let userdata = lua.create_userdata(ffiref)?; From 809fd566a15dad579a08d8d2f46fdc2557978a3e Mon Sep 17 00:00:00 2001 From: qwreey Date: Sat, 9 Nov 2024 10:07:26 +0000 Subject: [PATCH 68/79] Add free test (#243) --- crates/lune-std-ffi/README.md | 3 +-- crates/lune-std-ffi/src/c/arr_info.rs | 1 + crates/lune-std-ffi/src/c/fn_info.rs | 1 + crates/lune-std-ffi/src/c/ptr_info.rs | 2 ++ crates/lune-std-ffi/src/c/struct_info.rs | 2 ++ crates/lune-std-ffi/src/c/void_info.rs | 1 + crates/lune/src/tests.rs | 3 ++- tests/ffi/free.luau | 18 ++++++++++++++++++ 8 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 tests/ffi/free.luau diff --git a/crates/lune-std-ffi/README.md b/crates/lune-std-ffi/README.md index e7b3fbcd..1140c04a 100644 --- a/crates/lune-std-ffi/README.md +++ b/crates/lune-std-ffi/README.md @@ -24,7 +24,6 @@ See [tests/ffi](../../tests/ffi/README.md) - Add varargs support - Array argument in cfn -- Ref boundary fix ## Code structure @@ -35,7 +34,7 @@ Define C-ABI type information and provide conversion and casting - [**Struct ` CArrInfo`:**](./src/c/struct_info.rs) Represents C Array type - [**Struct ` CPtrInfo`:**](./src/c/ptr_info.rs) Represents C Pointer type - [**Struct ` CFnInfo`:**](./src/c/fn_info.rs) Represents C Function signature - > provide CallableData and ClosureData creation + > provide `CallableData` and `ClosureData` creator - [**Struct ` CStructInfo`:**](./src/c/struct_info.rs) Represents C Struct type - [**Struct ` CTypeInfo`:**](./src/c/type_info.rs) Represents C type, extended in `/c/types` diff --git a/crates/lune-std-ffi/src/c/arr_info.rs b/crates/lune-std-ffi/src/c/arr_info.rs index 0362f264..fd76dce1 100644 --- a/crates/lune-std-ffi/src/c/arr_info.rs +++ b/crates/lune-std-ffi/src/c/arr_info.rs @@ -83,6 +83,7 @@ impl FfiSize for CArrInfo { self.size } } + impl FfiConvert for CArrInfo { unsafe fn value_into_data<'lua>( &self, diff --git a/crates/lune-std-ffi/src/c/fn_info.rs b/crates/lune-std-ffi/src/c/fn_info.rs index 21ce3f0d..eaf566e6 100644 --- a/crates/lune-std-ffi/src/c/fn_info.rs +++ b/crates/lune-std-ffi/src/c/fn_info.rs @@ -43,6 +43,7 @@ impl FfiSignedness for CFnInfo { false } } + impl FfiSize for CFnInfo { fn get_size(&self) -> usize { SIZE_OF_POINTER diff --git a/crates/lune-std-ffi/src/c/ptr_info.rs b/crates/lune-std-ffi/src/c/ptr_info.rs index 12ad7b37..f1efc9e3 100644 --- a/crates/lune-std-ffi/src/c/ptr_info.rs +++ b/crates/lune-std-ffi/src/c/ptr_info.rs @@ -25,11 +25,13 @@ impl FfiSignedness for CPtrInfo { false } } + impl FfiSize for CPtrInfo { fn get_size(&self) -> usize { SIZE_OF_POINTER } } + impl FfiConvert for CPtrInfo { // Convert luavalue into data, then write into ptr unsafe fn value_into_data<'lua>( diff --git a/crates/lune-std-ffi/src/c/struct_info.rs b/crates/lune-std-ffi/src/c/struct_info.rs index 55b8a429..f97f89a0 100644 --- a/crates/lune-std-ffi/src/c/struct_info.rs +++ b/crates/lune-std-ffi/src/c/struct_info.rs @@ -116,11 +116,13 @@ impl FfiSize for CStructInfo { self.size } } + impl FfiSignedness for CStructInfo { fn get_signedness(&self) -> bool { false } } + impl FfiConvert for CStructInfo { unsafe fn value_into_data<'lua>( &self, diff --git a/crates/lune-std-ffi/src/c/void_info.rs b/crates/lune-std-ffi/src/c/void_info.rs index 3c0ed880..9fd1968e 100644 --- a/crates/lune-std-ffi/src/c/void_info.rs +++ b/crates/lune-std-ffi/src/c/void_info.rs @@ -12,6 +12,7 @@ impl FfiSignedness for CVoidInfo { false } } + impl FfiSize for CVoidInfo { fn get_size(&self) -> usize { 0 diff --git a/crates/lune/src/tests.rs b/crates/lune/src/tests.rs index acce10ec..0599f4a3 100644 --- a/crates/lune/src/tests.rs +++ b/crates/lune/src/tests.rs @@ -31,7 +31,7 @@ macro_rules! create_tests { // The rest of the test logic can continue as normal let full_name = format!("{}/tests/{}.luau", workspace_dir.display(), $value); let script = read_to_string(&full_name).await?; - let mut lune = Runtime::new().with_args( + let mut lune = Runtime::new().set_unsafe_library_enabled(true).with_args( ARGS .clone() .iter() @@ -111,6 +111,7 @@ create_tests! { ffi_external_print_hello_world: "ffi/external_print/helloWorld", ffi_external_struct_ab: "ffi/external_struct/ab", ffi_cast: "ffi/cast", + ffi_free: "ffi/free", ffi_is_integer: "ffi/isInteger", ffi_pretty_print: "ffi/prettyPrint", ffi_read_boundary: "ffi/readBoundary", diff --git a/tests/ffi/free.luau b/tests/ffi/free.luau new file mode 100644 index 00000000..5ab91da0 --- /dev/null +++ b/tests/ffi/free.luau @@ -0,0 +1,18 @@ +--!nocheck +--!nolint +local ffi = require("@lune/ffi") + +local box = ffi.box(ffi.i32.size) +local ref = box:leak() + +box = nil + +collectgarbage("collect") +collectgarbage("collect") +collectgarbage("collect") + +ffi.free(ref) + +collectgarbage("collect") +collectgarbage("collect") +collectgarbage("collect") From 230632b1ca7c6e5bdf101757f2792334e8a89ad6 Mon Sep 17 00:00:00 2001 From: qwreey Date: Sat, 9 Nov 2024 10:27:48 +0000 Subject: [PATCH 69/79] Fix unsafe library error, add --unsafe repl option (#243) --- crates/lune-std/src/unsafe_library.rs | 6 +++++- crates/lune/src/cli/repl.rs | 8 ++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/crates/lune-std/src/unsafe_library.rs b/crates/lune-std/src/unsafe_library.rs index 3c0cbf41..31660506 100644 --- a/crates/lune-std/src/unsafe_library.rs +++ b/crates/lune-std/src/unsafe_library.rs @@ -18,5 +18,9 @@ pub fn set_unsafe_library_enabled(lua: &Lua, enabled: bool) { */ #[must_use] pub fn get_unsafe_library_enabled(lua: &Lua) -> bool { - lua.app_data_ref::().unwrap().0 + if let Some(app_data) = lua.app_data_ref::() { + app_data.0 + } else { + false + } } diff --git a/crates/lune/src/cli/repl.rs b/crates/lune/src/cli/repl.rs index 78a6bd74..faeff737 100644 --- a/crates/lune/src/cli/repl.rs +++ b/crates/lune/src/cli/repl.rs @@ -17,7 +17,11 @@ enum PromptState { /// Launch an interactive REPL (default) #[derive(Debug, Clone, Default, Parser)] -pub struct ReplCommand {} +pub struct ReplCommand { + /// Allow unsafe libraries + #[clap(long, action)] + r#unsafe: bool, +} impl ReplCommand { pub async fn run(self) -> Result { @@ -38,7 +42,7 @@ impl ReplCommand { let mut prompt_state = PromptState::Regular; let mut source_code = String::new(); - let mut lune_instance = Runtime::new(); + let mut lune_instance = Runtime::new().set_unsafe_library_enabled(self.r#unsafe); loop { let prompt = match prompt_state { From b191218993900eb95aba1062c07e1b93d1373ebe Mon Sep 17 00:00:00 2001 From: qwreey Date: Sat, 9 Nov 2024 12:44:55 +0000 Subject: [PATCH 70/79] Throw out of index error in struct:field method (#243) --- crates/lune-std-ffi/src/c/struct_info.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/lune-std-ffi/src/c/struct_info.rs b/crates/lune-std-ffi/src/c/struct_info.rs index f97f89a0..b175a07e 100644 --- a/crates/lune-std-ffi/src/c/struct_info.rs +++ b/crates/lune-std-ffi/src/c/struct_info.rs @@ -206,7 +206,9 @@ impl LuaUserData for CStructInfo { "field", |lua, (this, field_index): (LuaAnyUserData, usize)| { let field_table = get_field_table(lua, &this)?; - field_table.raw_get::<_, LuaAnyUserData>(field_index + 1) + field_table + .raw_get::<_, Option>(field_index + 1)? + .ok_or_else(|| LuaError::external("Out of index")) }, ); } From 902f5f960b99f85061e9ecbc4647996501a667fc Mon Sep 17 00:00:00 2001 From: qwreey Date: Sat, 9 Nov 2024 12:46:20 +0000 Subject: [PATCH 71/79] Add and organize ffi tests (#243) --- crates/lune/src/tests.rs | 10 +++++++++- tests/ffi/README.md | 17 ++++++---------- tests/ffi/prettyPrint.luau | 32 ------------------------------ tests/ffi/pretty_print/arr.luau | 6 ++++++ tests/ffi/pretty_print/box.luau | 4 ++++ tests/ffi/pretty_print/fn.luau | 13 ++++++++++++ tests/ffi/pretty_print/ptr.luau | 6 ++++++ tests/ffi/pretty_print/struct.luau | 8 ++++++++ tests/ffi/pretty_print/type.luau | 6 ++++++ tests/ffi/types/arr.luau | 19 ++++++++++++++++++ tests/ffi/types/fn.luau | 0 tests/ffi/types/ptr.luau | 17 ++++++++-------- tests/ffi/types/struct.luau | 16 +++++++++++---- 13 files changed, 97 insertions(+), 57 deletions(-) delete mode 100644 tests/ffi/prettyPrint.luau create mode 100644 tests/ffi/pretty_print/arr.luau create mode 100644 tests/ffi/pretty_print/box.luau create mode 100644 tests/ffi/pretty_print/fn.luau create mode 100644 tests/ffi/pretty_print/ptr.luau create mode 100644 tests/ffi/pretty_print/struct.luau create mode 100644 tests/ffi/pretty_print/type.luau delete mode 100644 tests/ffi/types/fn.luau diff --git a/crates/lune/src/tests.rs b/crates/lune/src/tests.rs index 0599f4a3..4d06e1b1 100644 --- a/crates/lune/src/tests.rs +++ b/crates/lune/src/tests.rs @@ -110,10 +110,18 @@ create_tests! { ffi_external_pointer_pointer_write: "ffi/external_pointer/pointerWrite", ffi_external_print_hello_world: "ffi/external_print/helloWorld", ffi_external_struct_ab: "ffi/external_struct/ab", + ffi_pretty_print_arr: "ffi/pretty_print/arr", + ffi_pretty_print_box: "ffi/pretty_print/box", + ffi_pretty_print_fn: "ffi/pretty_print/fn", + ffi_pretty_print_ptr: "ffi/pretty_print/ptr", + ffi_pretty_print_struct: "ffi/pretty_print/struct", + ffi_pretty_print_type: "ffi/pretty_print/type", + ffi_types_arr: "ffi/types/arr", + ffi_types_ptr: "ffi/types/ptr", + ffi_types_struct: "ffi/types/struct", ffi_cast: "ffi/cast", ffi_free: "ffi/free", ffi_is_integer: "ffi/isInteger", - ffi_pretty_print: "ffi/prettyPrint", ffi_read_boundary: "ffi/readBoundary", ffi_write_boundary: "ffi/writeBoundary", } diff --git a/tests/ffi/README.md b/tests/ffi/README.md index de366fad..77ed2693 100644 --- a/tests/ffi/README.md +++ b/tests/ffi/README.md @@ -16,20 +16,15 @@ gcc for library compiling (for external-\*) **Luau-side** -- [x] [isInteger](./isInteger) +- [x] [isInteger](./isInteger.luau) - [x] [cast](./cast.luau) +- [x] [write_boundary](./write_boundary.luau) +- [x] [read_boundary](./read_boundary.luau) +- [x] [free](./free.luau) -- [ ] [pretty_print](./pretty_print) - - > need box, ref test - -- [ ] [write_boundary](./write_boundary.luau) +**Pretty Print** - > Failed, need fix - -- [ ] [read_boundary](./read_boundary.luau) - - > Failed, need fix +- [ ] [pretty_print](./pretty_print) ## Benchmark Results diff --git a/tests/ffi/prettyPrint.luau b/tests/ffi/prettyPrint.luau deleted file mode 100644 index 6019089e..00000000 --- a/tests/ffi/prettyPrint.luau +++ /dev/null @@ -1,32 +0,0 @@ -local ffi = require("@lune/ffi") -local c = ffi.c - -assert(typeof(c.int) :: string == "CTypeInfo") -assert(tostring(c.int) == "int") - -assert(typeof(c.int:ptr()) :: string == "CPtrInfo") -assert(tostring(c.int:ptr()) == "int") -assert(tostring(c.int:arr(5):ptr()) == " ") - -assert(typeof(c.int:arr(5)) :: string == "CArrInfo") -assert(tostring(c.int:arr(5)) == " int, length = 5 ") -assert(tostring(c.int:ptr():arr(5)) == " , length = 5 ") - -assert(typeof(c.fn({ c.int }, c.int)) :: string == "CFnInfo") -assert(tostring(c.fn({ c.int }, c.int)) == " (int) -> int ") -assert(tostring(c.fn({ c.int, ffi.f32 }, c.int)) == " (int, f32) -> int ") -assert(tostring(c.fn({ c.int:ptr() }, c.int)) == " () -> int ") -assert(tostring(c.fn({ c.int }, c.int:ptr())) == " (int) -> ") -assert(tostring(c.fn({ c.int:ptr() }, c.int:ptr())) == " () -> ") -assert( - tostring(c.fn({ c.int:ptr(), c.int:ptr() }, c.int:ptr())) - == " (, ) -> " -) - -assert(typeof(c.struct({ c.int, c.char })) :: string == "CStructInfo") -assert( - tostring(c.struct({ c.int, c.char:ptr() })) - == ` int, , size = {c.struct({ c.int, c.char:ptr() }).size} ` -) - --- FIXME: add box, ref pretty-print test diff --git a/tests/ffi/pretty_print/arr.luau b/tests/ffi/pretty_print/arr.luau new file mode 100644 index 00000000..4b78d5e8 --- /dev/null +++ b/tests/ffi/pretty_print/arr.luau @@ -0,0 +1,6 @@ +local ffi = require("@lune/ffi") +local c = ffi.c + +assert(typeof(c.int:arr(5)) :: string == "CArrInfo") +assert(tostring(c.int:arr(5)) == " int, length = 5 ") +assert(tostring(c.int:ptr():arr(5)) == " , length = 5 ") diff --git a/tests/ffi/pretty_print/box.luau b/tests/ffi/pretty_print/box.luau new file mode 100644 index 00000000..e9714343 --- /dev/null +++ b/tests/ffi/pretty_print/box.luau @@ -0,0 +1,4 @@ +local ffi = require("@lune/ffi") +local half_back = 0b_0000_0000_0000_0000_0000_0000_1111_1111 + +print(ffi.i32:box(half_back)) diff --git a/tests/ffi/pretty_print/fn.luau b/tests/ffi/pretty_print/fn.luau new file mode 100644 index 00000000..d20326d7 --- /dev/null +++ b/tests/ffi/pretty_print/fn.luau @@ -0,0 +1,13 @@ +local ffi = require("@lune/ffi") +local c = ffi.c + +assert(typeof(c.fn({ c.int }, c.int)) :: string == "CFnInfo") +assert(tostring(c.fn({ c.int }, c.int)) == " (int) -> int ") +assert(tostring(c.fn({ c.int, ffi.f32 }, c.int)) == " (int, f32) -> int ") +assert(tostring(c.fn({ c.int:ptr() }, c.int)) == " () -> int ") +assert(tostring(c.fn({ c.int }, c.int:ptr())) == " (int) -> ") +assert(tostring(c.fn({ c.int:ptr() }, c.int:ptr())) == " () -> ") +assert( + tostring(c.fn({ c.int:ptr(), c.int:ptr() }, c.int:ptr())) + == " (, ) -> " +) diff --git a/tests/ffi/pretty_print/ptr.luau b/tests/ffi/pretty_print/ptr.luau new file mode 100644 index 00000000..fd3da1d0 --- /dev/null +++ b/tests/ffi/pretty_print/ptr.luau @@ -0,0 +1,6 @@ +local ffi = require("@lune/ffi") +local c = ffi.c + +assert(typeof(c.int:ptr()) :: string == "CPtrInfo") +assert(tostring(c.int:ptr()) == "int") +assert(tostring(c.int:arr(5):ptr()) == " ") diff --git a/tests/ffi/pretty_print/struct.luau b/tests/ffi/pretty_print/struct.luau new file mode 100644 index 00000000..124d4127 --- /dev/null +++ b/tests/ffi/pretty_print/struct.luau @@ -0,0 +1,8 @@ +local ffi = require("@lune/ffi") +local c = ffi.c + +assert(typeof(c.struct({ c.int, c.char })) :: string == "CStructInfo") +assert( + tostring(c.struct({ c.int, c.char:ptr() })) + == ` int, , size = {c.struct({ c.int, c.char:ptr() }).size} ` +) diff --git a/tests/ffi/pretty_print/type.luau b/tests/ffi/pretty_print/type.luau new file mode 100644 index 00000000..af86dcc8 --- /dev/null +++ b/tests/ffi/pretty_print/type.luau @@ -0,0 +1,6 @@ +local ffi = require("@lune/ffi") +local c = ffi.c + +assert(typeof(c.int) :: string == "CTypeInfo") +assert(tostring(c.int) == "int") +assert(tostring(ffi.i32) == "i32") diff --git a/tests/ffi/types/arr.luau b/tests/ffi/types/arr.luau index e69de29b..448fff34 100644 --- a/tests/ffi/types/arr.luau +++ b/tests/ffi/types/arr.luau @@ -0,0 +1,19 @@ +local ffi = require("@lune/ffi") +local ok + +local arr = ffi.i32:arr(4) + +assert(rawequal(arr.length, 4), "length assersion failed, arr.length should be 4") +assert(rawequal(arr.inner, ffi.i32), "inner assersion failed, arr.inner should be ffi.i32") + +-- offset(2) success +ok = pcall(function() + arr:offset(2) +end) +assert(ok, "assersion failed, arr:offset(2) should success") + +-- offset(4) success +ok = pcall(function() + arr:offset(4) +end) +assert(not ok, "assersion failed, arr:offset(4) should fail") diff --git a/tests/ffi/types/fn.luau b/tests/ffi/types/fn.luau deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/ffi/types/ptr.luau b/tests/ffi/types/ptr.luau index cdbc2fe7..05cdf136 100644 --- a/tests/ffi/types/ptr.luau +++ b/tests/ffi/types/ptr.luau @@ -1,32 +1,31 @@ ---!nocheck ---!nolint - local ffi = require("@lune/ffi") -- ptr size test assert( ffi.i32:ptr().size == ffi.i64:ptr().size, - "All of Ptr.size must be same.\n" .. "ffi.i32:ptr().size == ffi.i64:ptr().size failed" + "size assersion failed, size of pointer should be same with each other (ffi.i32:ptr().size == ffi.i64:ptr().size)" ) -- inner test local i32ptr = ffi.i32:ptr() assert( rawequal(ffi.i32, i32ptr.inner), - "Ptr.inner must be same with their parent\n" .. "raweq ffi.i32 == ffi.i32:ptr().inner failed" + "inner assersion failed, inner field must be same with their parent" + .. " (ffi.i32 == ffi.i32:ptr().inner)" ) assert( rawequal(i32ptr, i32ptr:ptr().inner), - "Ptr.inner must be same with their parent\n" .. "raweq i32ptr == i32ptr:ptr().inner failed" + "inner assersion failed, inner field must be same with their parent" + .. " (i32ptr == i32ptr:ptr().inner)" ) assert( rawequal(i32ptr, i32ptr:ptr().inner:ptr().inner:ptr().inner), - "Ptr.inner must be same with their parent\n" - .. "raweq i32ptr == i32ptr:ptr().inner:ptr().inner:ptr().inner failed" + "inner assersion failed, inner field must be same with their parent" + .. " (i32ptr == i32ptr:ptr().inner:ptr().inner:ptr().inner)" ) -- deep ptr test local ok, err = pcall(function() i32ptr:ptr():ptr():ptr():ptr():ptr():ptr():ptr() end) -assert(ok, `Deep ptr test failed.\n{err}`) +assert(ok, "deep ptr assersion failed\n" .. (err or "")) diff --git a/tests/ffi/types/struct.luau b/tests/ffi/types/struct.luau index a955e718..10edd4a3 100644 --- a/tests/ffi/types/struct.luau +++ b/tests/ffi/types/struct.luau @@ -1,12 +1,20 @@ ---!nocheck ---!nolint - local ffi = require("@lune/ffi") +local ok local i32ptr = ffi.i32:ptr() -local struct = ffi.struct({ i32ptr, ffi.i32 }) +local struct = ffi.c.struct({ i32ptr, ffi.i32 }) assert(rawequal(struct:field(0), i32ptr), "Struct get field failed") assert(rawequal(struct:field(1), ffi.i32), "Struct get field failed") -- offset(2) should fail +ok = pcall(function() + struct:offset(2) +end) +assert(not ok, "assersion failed, struct:offset(2) should fail") + +-- field(2) should fail +ok = pcall(function() + struct:field(2) +end) +assert(not ok, "assersion failed, struct:field(2) should fail") From b503cc9f5b017ae040655a7fef17ba43dd29c513 Mon Sep 17 00:00:00 2001 From: qwreey Date: Sat, 9 Nov 2024 12:56:01 +0000 Subject: [PATCH 72/79] Fix boundary check logic (#243) --- crates/lune-std-ffi/README.md | 14 +-- .../lune-std-ffi/src/data/ref_data/bounds.rs | 85 ++++++++----------- tests/ffi/README.md | 15 ++-- tests/ffi/readBoundary.luau | 2 +- 4 files changed, 55 insertions(+), 61 deletions(-) diff --git a/crates/lune-std-ffi/README.md b/crates/lune-std-ffi/README.md index 1140c04a..352cb609 100644 --- a/crates/lune-std-ffi/README.md +++ b/crates/lune-std-ffi/README.md @@ -6,24 +6,28 @@ See [tests/ffi](../../tests/ffi/README.md) ## TODO -- Rewrite error messages - CString -- Add buffer for owned data support -- Add math operation. +- Add buffer as owned data support +- Add math operation for numeric types > Provide related methods: `CTypeInfo:add(target, from1, from2, ...)` and `:sub` `:mul` `:div` `:mod` `:pow` `:max` `:min` `:gt` `:lt` > Luau cannot handle f64, i64 or i128, so we should provide math operation for it -- Add bit operation +- Add bit operation for box/ref > Luau only supports 32bit bit operations - Add wchar and wstring support - > For windows API + > For windows API support - Add varargs support - Array argument in cfn +- More box/ref methods + - writeString + - readString + - writeBase64 + - readBase64 ## Code structure diff --git a/crates/lune-std-ffi/src/data/ref_data/bounds.rs b/crates/lune-std-ffi/src/data/ref_data/bounds.rs index be3e288e..4b715f92 100644 --- a/crates/lune-std-ffi/src/data/ref_data/bounds.rs +++ b/crates/lune-std-ffi/src/data/ref_data/bounds.rs @@ -16,77 +16,62 @@ impl RefBounds { Self { above, below } } - #[inline] - pub fn is_unsized(&self) -> bool { - self.above == usize::MAX && self.below == usize::MAX - } - // Check boundary #[inline] pub fn check_boundary(&self, offset: isize) -> bool { - if self.is_unsized() { - return true; - } - let sign = offset.signum(); let offset_abs = offset.unsigned_abs(); - if sign == -1 { - self.above >= offset_abs - } else if sign == 1 { - self.below >= offset_abs - } else { - // sign == 0 - true + match offset.signum() { + -1 => self.above >= offset_abs, + 1 => self.below >= offset_abs, + 0 => true, + _ => unreachable!(), } } // Check boundary with specific size + // + // -4 ∧ ────── Above = 4 + // -3 │ (Case1) + // -2 │ ┌──── Offset = -2 : offset >= 0 || abs(offset) <= above + // -1 │ │ + // 0 │ │ Size = 4 + // 1 │ │ (Case2) + // 2 │ ∨ ─── End = 2 : end = offset + size; + // 3 │ end <= 0 || end <= below + // 4 ∨ ────── Below = 4 + // #[inline] pub fn check_sized(&self, offset: isize, size: usize) -> bool { - if self.is_unsized() { - return true; - } + // (Case1) offset over above if offset < 0 && self.above < offset.unsigned_abs() { - return true; - } - let end = offset + (size as isize) - 1; - let end_sign = end.signum(); - let end_abs = end.unsigned_abs(); - if end_sign == -1 { - self.above >= end_abs - } else if end_sign == 1 { - self.below >= end_abs - } else { - // sign == 0 - true + return false; } + + // (Case2) end over below + let end = offset + (size as isize); + end <= 0 || self.below >= end.unsigned_abs() } - // Calculate new boundaries from bounds and offset + // Calculate new boundaries with bounds and offset // No boundary checking in here #[inline] pub fn offset(&self, offset: isize) -> Self { let sign = offset.signum(); let offset_abs = offset.unsigned_abs(); - let high: usize = if sign == -1 { - self.above - offset_abs - } else if sign == 1 { - self.above + offset_abs - } else { - self.above - }; - - let low: usize = if sign == -1 { - self.below + offset_abs - } else if sign == 1 { - self.below - offset_abs - } else { - self.below - }; - Self { - above: high, - below: low, + above: match sign { + -1 => self.above - offset_abs, + 1 => self.above + offset_abs, + 0 => self.above, + _ => unreachable!(), + }, + below: match sign { + -1 => self.below + offset_abs, + 1 => self.below - offset_abs, + 0 => self.below, + _ => unreachable!(), + }, } } } diff --git a/tests/ffi/README.md b/tests/ffi/README.md index 77ed2693..f42576b6 100644 --- a/tests/ffi/README.md +++ b/tests/ffi/README.md @@ -8,23 +8,28 @@ gcc for library compiling (for external-\*) **External tests** +- [x] [external_closure](./external_closure/init.luau) - [x] [external_math](./external_math/init.luau) - [x] [external_pointer](./external_pointer/init.luau) - [x] [external_print](./external_print/init.luau) - [x] [external_struct](./external_struct/init.luau) -- [x] [external_closure](./external_closure/init.luau) **Luau-side** -- [x] [isInteger](./isInteger.luau) - [x] [cast](./cast.luau) -- [x] [write_boundary](./write_boundary.luau) -- [x] [read_boundary](./read_boundary.luau) - [x] [free](./free.luau) +- [x] [isInteger](./isInteger.luau) +- [x] [read_boundary](./read_boundary.luau) +- [x] [write_boundary](./write_boundary.luau) **Pretty Print** -- [ ] [pretty_print](./pretty_print) +- [x] [arr](./pretty_print/arr.luau) +- [ ] [box](./pretty_print/box.luau) +- [x] [fn](./pretty_print/fn.luau) +- [x] [ptr](./pretty_print/ptr.luau) +- [x] [struct](./pretty_print/struct.luau) +- [x] [type](./pretty_print/type.luau) ## Benchmark Results diff --git a/tests/ffi/readBoundary.luau b/tests/ffi/readBoundary.luau index dd8e3d25..94c4ff35 100644 --- a/tests/ffi/readBoundary.luau +++ b/tests/ffi/readBoundary.luau @@ -48,4 +48,4 @@ ok = pcall(function() local box = ffi.box(ffi.u8.size * 2):ref(ffi.u16.size) ffi.u16:readData(box) end) -assert(ok, "assersion failed, Case7 should fail") +assert(not ok, "assersion failed, Case7 should fail") From c3f255db7a5ea37fc0b34fb576b878074f4d273e Mon Sep 17 00:00:00 2001 From: qwreey Date: Sat, 9 Nov 2024 15:43:15 +0000 Subject: [PATCH 73/79] Improve code quality (#243) --- crates/lune-std-ffi/README.md | 97 ++++++++++++------- crates/lune-std-ffi/src/c/helper.rs | 48 +++------ crates/lune-std-ffi/src/c/mod.rs | 2 +- crates/lune-std-ffi/src/c/type_info.rs | 8 +- crates/lune-std-ffi/src/c/types/mod.rs | 90 ++++++++--------- crates/lune-std-ffi/src/data/box_data/flag.rs | 2 +- crates/lune-std-ffi/src/data/box_data/mod.rs | 5 +- crates/lune-std-ffi/src/data/closure_data.rs | 4 +- crates/lune-std-ffi/src/data/helper.rs | 3 + crates/lune-std-ffi/src/data/mod.rs | 3 +- .../lune-std-ffi/src/data/ref_data/bounds.rs | 23 ++++- crates/lune-std-ffi/src/data/ref_data/flag.rs | 1 + crates/lune-std-ffi/src/data/ref_data/mod.rs | 9 +- crates/lune-std-ffi/src/ffi/libffi_helper.rs | 2 +- 14 files changed, 156 insertions(+), 141 deletions(-) diff --git a/crates/lune-std-ffi/README.md b/crates/lune-std-ffi/README.md index 352cb609..3f35d4eb 100644 --- a/crates/lune-std-ffi/README.md +++ b/crates/lune-std-ffi/README.md @@ -1,3 +1,5 @@ + + # `lune-std-ffi` ## Tests & Benchmarks @@ -6,24 +8,18 @@ See [tests/ffi](../../tests/ffi/README.md) ## TODO -- CString +- [CString](./src/c/string_info.rs) - Add buffer as owned data support - Add math operation for numeric types - > Provide related methods: `CTypeInfo:add(target, from1, from2, ...)` and `:sub` `:mul` `:div` `:mod` `:pow` `:max` `:min` `:gt` `:lt` > Luau cannot handle f64, i64 or i128, so we should provide math operation for it - - Add bit operation for box/ref - > Luau only supports 32bit bit operations - - Add wchar and wstring support - > For windows API support - - Add varargs support - Array argument in cfn -- More box/ref methods +- [More box/ref methods](./src/data/helper.rs) - writeString - readString - writeBase64 @@ -35,30 +31,53 @@ See [tests/ffi](../../tests/ffi/README.md) Define C-ABI type information and provide conversion and casting -- [**Struct ` CArrInfo`:**](./src/c/struct_info.rs) Represents C Array type -- [**Struct ` CPtrInfo`:**](./src/c/ptr_info.rs) Represents C Pointer type -- [**Struct ` CFnInfo`:**](./src/c/fn_info.rs) Represents C Function signature +**Structs:** C ABI type informations + +- [**Struct `CArrInfo`:**](./src/c/arr_info.rs) Represents C Array type +- [**Struct `CPtrInfo`:**](./src/c/ptr_info.rs) Represents C Pointer type +- [**Struct `CFnInfo`:**](./src/c/fn_info.rs) Represents C Function signature > provide `CallableData` and `ClosureData` creator -- [**Struct ` CStructInfo`:**](./src/c/struct_info.rs) Represents C Struct type -- [**Struct ` CTypeInfo`:**](./src/c/type_info.rs) Represents C type, extended in `/c/types` +- [**Struct `CStructInfo`:**](./src/c/struct_info.rs) Represents C Struct type +- [**Struct `CTypeInfo`:**](./src/c/type_info.rs) Represents C type, extended in `/c/types` + +
Mod helper.rs: C ABI type helper + +- **Function `get_conv`, `get_conv_list`:** + get `FfiConvert` from userdata (CStruct, CArr, CPtr, CTypes) +- **Function `get_middle_type`, `get_middle_type_list`:** + get **`libffi::middle::Type`:** from userdata (CFn, CStruct, CArr, CPtr, CTypes) +- **Function `get_size`:** + get size from userdata +- **Function `has_void`:** + check table has void type +- **Function `stringify`:** + stringify any type userdata +- **Function `get_name`:** + get type name from ctype userdata, used for pretty-print +- **Function `is_ctype`:** check userdata is ctype +- **Mod `method_provider`:** provide common userdata method implements + +
#### /c/types Export fixed-size source time known types and non-fixed compile time known types -Implememt type-casting for all CTypes +mod.rs implememts type-casting for all CTypes -**Mod `ctype_helper`:** +
Mod ctype_helper: c type helper - **Function `get_conv`:** - get _FfiConvert_ from some ctype userdata, used for struct and array conversion + get `FfiConvert` from ctype userdata, used for struct and array conversion +- **Function `get_middle_type`:** + get **`libffi::middle::Type`:** from ctype userdata - **Function `get_size`:** - get size from some ctype userdata, used for call return and arguments boundary checking + get size from ctype userdata - **Function `get_name`:** - get type name from some ctype userdata, used for pretty-print -- **Function `get_middle_type`:** - get **`libffi::middle::Type`:** from some ctype userdata + get type name from ctype userdata, used for pretty-print - **Function `is_ctype`:** check userdata is ctype +
+ --- ### /data @@ -83,12 +102,21 @@ Implememt type-casting for all CTypes - **Trait `FfiSize`** - **Trait `FfiSignedness`** -**Structs:** Provide call information trait +
  • Trait FfiConvert: Provide methods for read LuaValue from FfiData or write LuaValue into FfiData + +- **Method `value_into_data`:** set data with lua value +- **Method `value_from_data`:** get lua value from data +- **Method `copy_data`:** copy sized data into another data +- **Method `stringify_data`:** stringify data with specific type + +
+ +**Structs:** Provide call information - **Struct `FfiArg`:** Used for argument boundary checking and callback argument ref flag - **Struct `FfiResult`:** Used for result boundary checking -**Trait `FfiData`:** Provide common data handle, including methods below +
Trait FfiData: Provide common data handle, including methods below - **Method `check_inner_boundary`:** check boundary with offset and size - **Method `get_inner_pointer`:** returns raw pointer `*mut ()` @@ -96,24 +124,23 @@ Implememt type-casting for all CTypes - **Method `is_readable`** - **Method `copy_from`** copy data from another data -- **Trait `FfiConvert`:** Provide methods for read LuaValue from FfiData or write LuaValue into FfiData +
-- **Method `value_into_data`:** set data with lua value -- **Method `value_from_data`:** get lua value from data -- **Method `copy_data`:** copy sized data into another data -- **Method `stringify_data`:** stringify data with specific type - -> Note: `GetFfiData` trait in `data/mod.rs` provides `AnyUserData.get_data_handle() -> FfiData` method +> Note: `GetFfiData` trait in `data/mod.rs` provides `(LuaValue | LuaAnyUserData).get_data_handle() -> FfiData` method **Mods:** Provide common helper functions - [**Mod `association.rs`:**](./src/ffi/association.rs) GC utility, used for inner, ret and arg type holding in subtype - [**Mod `bit_mask.rs`:**](./src/ffi/bit_mask.rs) u8 bitfield helper -- [**Mod `cast.rs`:**](./src/ffi/cast.rs) library +- [**Mod `cast.rs`:**](./src/ffi/cast.rs) num cast library wrapper - **Function `num_cast(from: FfiData, from: FfiData)`:** Cast number type value inno another number type -- [**Mod `libffi_helper.rs`:**](./src/ffi/libffi_helper.rs) - - **Const `FFI_STATUS_NAMES`:** Used for `ffi_status` stringify - - **Function `get_ensured_size`:** Returns ensured `ffi_type` size - - **Const `SIZE_OF_POINTER`:** Platform specific pointer size (Compile time known) - - **Function `ffi_status_assert`:** Convert `ffi_status` to `LuaResult<()>` + +
  • Mod libffi_helper.rs: libffi library helper + +- **Const `FFI_STATUS_NAMES`:** Stringify `ffi_status` +- **Function `get_ensured_size`:** Returns ensured size of `ffi_type` +- **Const `SIZE_OF_POINTER`:** Platform specific pointer size (Compile time known) +- **Function `ffi_status_assert`:** Convert `ffi_status` to `LuaResult<()>` + +
diff --git a/crates/lune-std-ffi/src/c/helper.rs b/crates/lune-std-ffi/src/c/helper.rs index 68f7183e..1e246531 100644 --- a/crates/lune-std-ffi/src/c/helper.rs +++ b/crates/lune-std-ffi/src/c/helper.rs @@ -11,6 +11,7 @@ use crate::{ pub mod method_provider { use super::*; + // Implement tostring pub fn provide_to_string<'lua, Target, M>(methods: &mut M) where M: LuaUserDataMethods<'lua, Target>, @@ -20,6 +21,7 @@ pub mod method_provider { }); } + // Implement ptr method pub fn provide_ptr<'lua, Target, M>(methods: &mut M) where M: LuaUserDataMethods<'lua, Target>, @@ -29,6 +31,7 @@ pub mod method_provider { }); } + // Implement arr method pub fn provide_arr<'lua, Target, M>(methods: &mut M) where M: LuaUserDataMethods<'lua, Target>, @@ -38,6 +41,7 @@ pub mod method_provider { }); } + // Implement readData method pub fn provide_read_data<'lua, Target, M>(methods: &mut M) where Target: FfiSize + FfiConvert, @@ -61,6 +65,7 @@ pub mod method_provider { ); } + // Implement writeData method pub fn provide_write_data<'lua, Target, M>(methods: &mut M) where Target: FfiSize + FfiConvert, @@ -85,6 +90,7 @@ pub mod method_provider { ); } + // Implement copyData method pub fn provide_copy_data<'lua, Target, M>(methods: &mut M) where Target: FfiSize + FfiConvert, @@ -125,6 +131,7 @@ pub mod method_provider { ); } + // Implement stringifyData method pub fn provide_stringify_data<'lua, Target, M>(methods: &mut M) where Target: FfiSize + FfiConvert, @@ -138,6 +145,7 @@ pub mod method_provider { ); } + // Implement box method pub fn provide_box<'lua, Target, M>(methods: &mut M) where Target: FfiSize + FfiConvert, @@ -149,43 +157,9 @@ pub mod method_provider { Ok(result) }); } - - // FIXME: Buffer support should be part of another PR - // pub fn provide_write_buffer<'lua, Target, M>(methods: &mut M) - // where - // Target: FfiSize + FfiConvert, - // M: LuaUserDataMethods<'lua, Target>, - // { - // methods.add_method( - // "writeBuffer", - // |lua, this, (target, value, offset): (LuaValue, LuaValue, Option)| { - // if !target.is_buffer() { - // return Err(LuaError::external(format!( - // "Argument target must be a buffer, got {}", - // target.type_name() - // ))); - // } - - // target.to_pointer() - // target.as_userdata().unwrap().to_pointer() - // let offset = offset.unwrap_or(0); - - // let data_handle = &target.get_ffi_data()?; - // // use or functions - // 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.value_into_data(lua, offset, data_handle, value) } - // }, - // ); - // } } -pub fn get_userdata(value: LuaValue) -> LuaResult { +fn get_userdata(value: LuaValue) -> LuaResult { if let LuaValue::UserData(field_type) = value { Ok(field_type) } else { @@ -212,9 +186,9 @@ pub fn create_list( Ok(list) } -// Get the NativeConvert handle from the ctype userData +// Get the dynamic FfiConvert handle from the userData // This is intended to avoid lookup userdata and lua table every time. (eg: struct) -// The userdata must live longer than the NativeConvert handle +// The userdata must live longer than the FfiConvert handle pub unsafe fn get_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn FfiConvert> { if userdata.is::() { Ok(userdata.to_pointer().cast::() as *const dyn FfiConvert) diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index 5f9293a2..5bd9c1dd 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -23,7 +23,7 @@ pub use self::{ void_info::CVoidInfo, }; -// Named registry table names +// Named registry keys mod association_names { pub const CPTR_INNER: &str = "__cptr_inner"; pub const CARR_INNER: &str = "__carr_inner"; diff --git a/crates/lune-std-ffi/src/c/type_info.rs b/crates/lune-std-ffi/src/c/type_info.rs index fa606fd5..5da8f60d 100644 --- a/crates/lune-std-ffi/src/c/type_info.rs +++ b/crates/lune-std-ffi/src/c/type_info.rs @@ -12,7 +12,8 @@ use crate::{ ffi::{libffi_helper::get_ensured_size, FfiConvert, FfiData, FfiSignedness, FfiSize}, }; -// Cast native data +// Provide type casting +// This trait should be implemented for each types pub trait CTypeCast { #[inline(always)] fn cast( @@ -82,7 +83,7 @@ where self.name } - pub fn get_type(&self) -> Type { + pub fn get_middle_type(&self) -> Type { self.middle_type.clone() } } @@ -113,6 +114,9 @@ where method_provider::provide_copy_data(methods); method_provider::provide_stringify_data(methods); + // Math + // TODO: Math support for numeric types + methods.add_function( "cast", |_lua, diff --git a/crates/lune-std-ffi/src/c/types/mod.rs b/crates/lune-std-ffi/src/c/types/mod.rs index cfbd6175..caa2a620 100644 --- a/crates/lune-std-ffi/src/c/types/mod.rs +++ b/crates/lune-std-ffi/src/c/types/mod.rs @@ -10,20 +10,20 @@ use num::cast::AsPrimitive; use super::{CTypeCast, CTypeInfo}; use crate::ffi::{num_cast, FfiConvert, FfiData, FfiSize}; -pub mod f32; -pub mod f64; -pub mod i128; -pub mod i16; -pub mod i32; -pub mod i64; -pub mod i8; -pub mod isize; -pub mod u128; -pub mod u16; -pub mod u32; -pub mod u64; -pub mod u8; -pub mod usize; +mod f32; +mod f64; +mod i128; +mod i16; +mod i32; +mod i64; +mod i8; +mod isize; +mod u128; +mod u16; +mod u32; +mod u64; +mod u8; +mod usize; // CType userdata export macro_rules! create_ctypes { @@ -92,20 +92,20 @@ macro_rules! define_cast_num { } impl CTypeCast for CTypeInfo where - From: AsPrimitive - + AsPrimitive - + AsPrimitive - + AsPrimitive - + AsPrimitive - + AsPrimitive + From: AsPrimitive + + AsPrimitive + + AsPrimitive + AsPrimitive + AsPrimitive + AsPrimitive - + AsPrimitive - + AsPrimitive - + AsPrimitive - + AsPrimitive - + AsPrimitive, + + AsPrimitive + + AsPrimitive + + AsPrimitive + + AsPrimitive + + AsPrimitive + + AsPrimitive + + AsPrimitive + + AsPrimitive, { fn cast( &self, @@ -118,7 +118,7 @@ where ) -> LuaResult<()> { define_cast_num!( From, self, from_info, into_info, from, into, from_offset, into_offset, - u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize + f32 f64 i128 i16 i32 i64 i8 isize u128 u16 u32 u64 u8 usize ) } } @@ -138,52 +138,52 @@ pub mod ctype_helper { } #[inline] pub fn get_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn FfiConvert> { - define_get_conv!(userdata, u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 usize isize) + define_get_conv!(userdata, f32 f64 i128 i16 i32 i64 i8 isize u128 u16 u32 u64 u8 usize) } - // Get size of ctype (not including struct, arr, ... only CType<*>) - macro_rules! define_get_size { + // Get libffi_type of ctype + macro_rules! define_get_middle_type { ($userdata:ident, $( $rust_type:ty )*) => { $( if $userdata.is::>() { - Ok($userdata.borrow::>()?.get_size()) + Ok(Some($userdata.borrow::>()?.get_middle_type())) } else )* { - Err(LuaError::external("Unexpected type")) + Ok(None) } }; } #[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) + pub fn get_middle_type(userdata: &LuaAnyUserData) -> LuaResult> { + define_get_middle_type!(userdata, f32 f64 i128 i16 i32 i64 i8 isize u128 u16 u32 u64 u8 usize) } - // Get name of ctype - macro_rules! define_get_name { + // Get size of ctype (not including struct, arr, ... only CType<*>) + macro_rules! define_get_size { ($userdata:ident, $( $rust_type:ty )*) => { $( if $userdata.is::>() { - Ok(Some($userdata.borrow::>()?.get_name())) + Ok($userdata.borrow::>()?.get_size()) } else )* { - Ok(None) + Err(LuaError::external("Unexpected type")) } }; } #[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) + pub fn get_size(userdata: &LuaAnyUserData) -> LuaResult { + define_get_size!(userdata, f32 f64 i128 i16 i32 i64 i8 isize u128 u16 u32 u64 u8 usize) } - // Get libffi_type of ctype - macro_rules! define_get_middle_type { + // Get name of ctype + macro_rules! define_get_name { ($userdata:ident, $( $rust_type:ty )*) => { $( if $userdata.is::>() { - Ok(Some($userdata.borrow::>()?.get_type())) + Ok(Some($userdata.borrow::>()?.get_name())) } 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) + pub fn get_name(userdata: &LuaAnyUserData) -> LuaResult> { + define_get_name!(userdata, f32 f64 i128 i16 i32 i64 i8 isize u128 u16 u32 u64 u8 usize) } // Check whether userdata is ctype or not @@ -198,6 +198,6 @@ pub mod ctype_helper { } #[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) + define_is_ctype!(userdata, f32 f64 i128 i16 i32 i64 i8 isize u128 u16 u32 u64 u8 usize) } } diff --git a/crates/lune-std-ffi/src/data/box_data/flag.rs b/crates/lune-std-ffi/src/data/box_data/flag.rs index 181326cf..445a3b3f 100644 --- a/crates/lune-std-ffi/src/data/box_data/flag.rs +++ b/crates/lune-std-ffi/src/data/box_data/flag.rs @@ -7,7 +7,7 @@ pub enum BoxFlag { impl BoxFlag { pub const fn value(&self) -> u8 { match self { - Self::Leaked => U8_MASK2, + Self::Leaked => U8_MASK1, } } } diff --git a/crates/lune-std-ffi/src/data/box_data/mod.rs b/crates/lune-std-ffi/src/data/box_data/mod.rs index dd6cc958..88ab7bae 100644 --- a/crates/lune-std-ffi/src/data/box_data/mod.rs +++ b/crates/lune-std-ffi/src/data/box_data/mod.rs @@ -73,7 +73,7 @@ impl BoxData { // Calculate offset if let Some(t) = offset { - if !bounds.check_boundary(t) { + if !bounds.check_offset(t) { return Err(LuaError::external(format!( "Offset out of bounds (box.size: {}, got {})", target.size(), @@ -113,7 +113,6 @@ impl Drop for BoxData { } impl FfiData for BoxData { - #[inline] fn check_inner_boundary(&self, offset: isize, size: usize) -> bool { if offset < 0 { return false; @@ -124,11 +123,9 @@ impl FfiData for BoxData { unsafe fn get_inner_pointer(&self) -> *mut () { self.data.as_ptr().cast_mut().cast::<()>() } - #[inline] fn is_readable(&self) -> bool { true } - #[inline] fn is_writable(&self) -> bool { true } diff --git a/crates/lune-std-ffi/src/data/closure_data.rs b/crates/lune-std-ffi/src/data/closure_data.rs index bc6c0784..1a5dfca6 100644 --- a/crates/lune-std-ffi/src/data/closure_data.rs +++ b/crates/lune-std-ffi/src/data/closure_data.rs @@ -8,7 +8,7 @@ use libffi::{ use mlua::prelude::*; use super::{ - association_names::CLSOURE_REF_INNER, + association_names::REF_INNER, ref_data::{RefBounds, RefData, RefFlag, UNSIZED_BOUNDS}, }; use crate::ffi::{ @@ -145,7 +145,7 @@ impl LuaUserData for ClosureData { CLOSURE_REF_FLAGS, UNSIZED_BOUNDS, ))?; - association::set(lua, CLSOURE_REF_INNER, &ref_data, &this)?; + association::set(lua, REF_INNER, &ref_data, &this)?; Ok(ref_data) }); } diff --git a/crates/lune-std-ffi/src/data/helper.rs b/crates/lune-std-ffi/src/data/helper.rs index 812e7f5a..cfd304cc 100644 --- a/crates/lune-std-ffi/src/data/helper.rs +++ b/crates/lune-std-ffi/src/data/helper.rs @@ -38,4 +38,7 @@ pub mod method_provider { }, ); } + + // TODO: writeString, readString, writeBase64 and readBase64 methods + // TODO: Bit operation support } diff --git a/crates/lune-std-ffi/src/data/mod.rs b/crates/lune-std-ffi/src/data/mod.rs index 558873fd..ceda5881 100644 --- a/crates/lune-std-ffi/src/data/mod.rs +++ b/crates/lune-std-ffi/src/data/mod.rs @@ -19,11 +19,10 @@ pub use self::{ }; use crate::ffi::FfiData; -// Named registry table names +// Named registry keys mod association_names { pub const REF_INNER: &str = "__ref_inner"; pub const SYM_INNER: &str = "__syn_inner"; - pub const CLSOURE_REF_INNER: &str = "__closure_ref_inner"; } // Get dynamic FfiData handle from LuaValue and LuaAnyUserData diff --git a/crates/lune-std-ffi/src/data/ref_data/bounds.rs b/crates/lune-std-ffi/src/data/ref_data/bounds.rs index 4b715f92..4bdec8b4 100644 --- a/crates/lune-std-ffi/src/data/ref_data/bounds.rs +++ b/crates/lune-std-ffi/src/data/ref_data/bounds.rs @@ -1,8 +1,8 @@ // Memory boundaries pub struct RefBounds { - // How much data available above + // How much bytes available above pub(crate) above: usize, - // How much data available below + // How much bytes available below pub(crate) below: usize, } @@ -16,9 +16,9 @@ impl RefBounds { Self { above, below } } - // Check boundary + // Check offset is in boundary #[inline] - pub fn check_boundary(&self, offset: isize) -> bool { + pub fn check_offset(&self, offset: isize) -> bool { let offset_abs = offset.unsigned_abs(); match offset.signum() { -1 => self.above >= offset_abs, @@ -52,8 +52,21 @@ impl RefBounds { end <= 0 || self.below >= end.unsigned_abs() } - // Calculate new boundaries with bounds and offset + // Calculate new boundaries with offset // No boundary checking in here + // + // Above = 3 + // ∧ ───∧─── + // -3│ │ New above = 2 + // -2│ │ + // -1│ <────── Offset = -1 + // 0│ │ + // 1│ │ + // 2│ │ + // 3│ │ New below = 4 + // ∨ ───∨─── + // Below = 3 + // #[inline] pub fn offset(&self, offset: isize) -> Self { let sign = offset.signum(); diff --git a/crates/lune-std-ffi/src/data/ref_data/flag.rs b/crates/lune-std-ffi/src/data/ref_data/flag.rs index e607e714..36a24a00 100644 --- a/crates/lune-std-ffi/src/data/ref_data/flag.rs +++ b/crates/lune-std-ffi/src/data/ref_data/flag.rs @@ -8,6 +8,7 @@ pub enum RefFlag { Offsetable, Function, } + impl RefFlag { pub const fn value(&self) -> u8 { match self { diff --git a/crates/lune-std-ffi/src/data/ref_data/mod.rs b/crates/lune-std-ffi/src/data/ref_data/mod.rs index 15ea044c..2c15d5ec 100644 --- a/crates/lune-std-ffi/src/data/ref_data/mod.rs +++ b/crates/lune-std-ffi/src/data/ref_data/mod.rs @@ -41,7 +41,7 @@ impl RefData { } } - // Create reference of this reference box + // Create reference of this reference pub fn luaref<'lua>( lua: &'lua Lua, this: LuaAnyUserData<'lua>, @@ -57,7 +57,7 @@ impl RefData { }, ))?; - // Make new reference live longer then this reference + // Make sure new reference live longer then this reference association::set(lua, REF_INNER, &luaref, &this)?; Ok(luaref) @@ -100,7 +100,7 @@ impl RefData { } // Check boundary - if !self.boundary.check_boundary(offset) { + if !self.boundary.check_offset(offset) { return Err(LuaError::external(format!( "Offset out of bounds (high: {}, low: {}, got {})", self.boundary.above, self.boundary.below, offset @@ -130,7 +130,6 @@ impl Drop for RefData { } impl FfiData for RefData { - #[inline] fn check_inner_boundary(&self, offset: isize, size: usize) -> bool { self.boundary.check_sized(offset, size) } @@ -138,11 +137,9 @@ impl FfiData for RefData { unsafe fn get_inner_pointer(&self) -> *mut () { **self.ptr } - #[inline] fn is_readable(&self) -> bool { u8_test(self.flags, RefFlag::Readable.value()) } - #[inline] fn is_writable(&self) -> bool { u8_test(self.flags, RefFlag::Writable.value()) } diff --git a/crates/lune-std-ffi/src/ffi/libffi_helper.rs b/crates/lune-std-ffi/src/ffi/libffi_helper.rs index df0e28fd..bfb73a51 100644 --- a/crates/lune-std-ffi/src/ffi/libffi_helper.rs +++ b/crates/lune-std-ffi/src/ffi/libffi_helper.rs @@ -23,7 +23,7 @@ pub fn get_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult { } // Converts ffi status into &str for formatting -pub const FFI_STATUS_NAMES: [&str; 4] = [ +const FFI_STATUS_NAMES: [&str; 4] = [ "ffi_status_FFI_OK", "ffi_status_FFI_BAD_TYPEDEF", "ffi_status_FFI_BAD_ABI", From 7a7ccf7d8599df6460a6a287a1756b7e4e76e2a0 Mon Sep 17 00:00:00 2001 From: qwreey Date: Sat, 9 Nov 2024 16:00:09 +0000 Subject: [PATCH 74/79] More pretty-prints (#243) --- crates/lune-std-ffi/src/data/box_data/mod.rs | 3 ++- crates/lune-std-ffi/src/data/callable_data.rs | 8 +++++++ crates/lune-std-ffi/src/data/closure_data.rs | 8 +++++++ crates/lune-std-ffi/src/data/lib_data.rs | 21 +++++++++++++++---- crates/lune-std-ffi/src/data/ref_data/mod.rs | 2 +- tests/ffi/README.md | 8 +++++-- 6 files changed, 42 insertions(+), 8 deletions(-) diff --git a/crates/lune-std-ffi/src/data/box_data/mod.rs b/crates/lune-std-ffi/src/data/box_data/mod.rs index 88ab7bae..70ce3b38 100644 --- a/crates/lune-std-ffi/src/data/box_data/mod.rs +++ b/crates/lune-std-ffi/src/data/box_data/mod.rs @@ -50,7 +50,8 @@ impl BoxData { if self.size() > FFI_BOX_PRINT_MAX_LENGTH * 2 { return String::from("length limit exceed"); } - let mut buff: String = String::with_capacity(self.size() * 2); + let mut buff: String = String::with_capacity(self.size() * 2 + 2); + buff.push_str("0x"); for value in self.data.iter() { buff.push_str(format!("{:x}", value.to_be()).as_str()); } diff --git a/crates/lune-std-ffi/src/data/callable_data.rs b/crates/lune-std-ffi/src/data/callable_data.rs index 2e95a27b..47f47953 100644 --- a/crates/lune-std-ffi/src/data/callable_data.rs +++ b/crates/lune-std-ffi/src/data/callable_data.rs @@ -124,6 +124,11 @@ impl CallableData { } } + // Stringify for pretty-print, with hex format address + pub fn stringify(&self) -> String { + format!("0x{:x}", self.code.as_ptr() as usize) + } + pub unsafe fn call(&self, result: LuaValue, args: LuaMultiValue) -> LuaResult<()> { let arg_len = self.arg_info_list.len(); // Optimization: use sized caller when possible @@ -178,5 +183,8 @@ impl LuaUserData for CallableData { unsafe { this.call(result, args) } }, ); + methods.add_meta_method(LuaMetaMethod::ToString, |_lua, this, ()| { + Ok(this.stringify()) + }); } } diff --git a/crates/lune-std-ffi/src/data/closure_data.rs b/crates/lune-std-ffi/src/data/closure_data.rs index 1a5dfca6..26595d1c 100644 --- a/crates/lune-std-ffi/src/data/closure_data.rs +++ b/crates/lune-std-ffi/src/data/closure_data.rs @@ -118,6 +118,11 @@ impl ClosureData { Ok(closure_data) } + + // Stringify for pretty-print, with hex format address + pub fn stringify(&self) -> String { + format!("0x{:x}", unsafe { self.get_inner_pointer() } as usize) + } } impl FfiData for ClosureData { @@ -148,5 +153,8 @@ impl LuaUserData for ClosureData { association::set(lua, REF_INNER, &ref_data, &this)?; Ok(ref_data) }); + methods.add_meta_method(LuaMetaMethod::ToString, |_lua, this, ()| { + Ok(this.stringify()) + }); } } diff --git a/crates/lune-std-ffi/src/data/lib_data.rs b/crates/lune-std-ffi/src/data/lib_data.rs index 9c92ce59..b8819f9b 100644 --- a/crates/lune-std-ffi/src/data/lib_data.rs +++ b/crates/lune-std-ffi/src/data/lib_data.rs @@ -13,13 +13,19 @@ const LIB_REF_FLAGS: u8 = RefFlag::Offsetable.value() | RefFlag::Function.value(); // Runtime dynamic loaded libraries -pub struct LibData(Library); +pub struct LibData { + name: String, + lib: Library, +} impl LibData { // Open library then return library handle pub fn new(libname: String) -> LuaResult { - match Library::open(libname) { - Ok(t) => Ok(Self(t)), + match Library::open(&libname) { + Ok(t) => Ok(Self { + lib: t, + name: libname.clone(), + }), Err(err) => Err(err.into_lua_err()), } } @@ -32,7 +38,7 @@ impl LibData { ) -> LuaResult> { let lib = this.borrow::()?; let sym = unsafe { - lib.0 + lib.lib .symbol::<*const ()>(name.as_str()) .map_err(LuaError::external)? }; @@ -44,6 +50,10 @@ impl LibData { Ok(ffi_ref) } + + pub fn stringify(&self) -> String { + self.name.clone() + } } impl LuaUserData for LibData { @@ -51,5 +61,8 @@ impl LuaUserData for LibData { methods.add_function("find", |lua, (this, name): (LuaAnyUserData, String)| { LibData::find_symbol(lua, this, name) }); + methods.add_meta_method(LuaMetaMethod::ToString, |_lua, this, ()| { + Ok(this.stringify()) + }); } } diff --git a/crates/lune-std-ffi/src/data/ref_data/mod.rs b/crates/lune-std-ffi/src/data/ref_data/mod.rs index 2c15d5ec..3de26137 100644 --- a/crates/lune-std-ffi/src/data/ref_data/mod.rs +++ b/crates/lune-std-ffi/src/data/ref_data/mod.rs @@ -117,7 +117,7 @@ impl RefData { // Stringify for pretty-print, with hex format address pub fn stringify(&self) -> String { - format!("{:x}", **self.ptr as usize) + format!("0x{:x}", **self.ptr as usize) } } diff --git a/tests/ffi/README.md b/tests/ffi/README.md index f42576b6..47d2779f 100644 --- a/tests/ffi/README.md +++ b/tests/ffi/README.md @@ -1,4 +1,6 @@ -# tests/ffi + + +# `tests/ffi` ## Requirements @@ -25,7 +27,9 @@ gcc for library compiling (for external-\*) **Pretty Print** - [x] [arr](./pretty_print/arr.luau) -- [ ] [box](./pretty_print/box.luau) +- [ ] [box](./pretty_print/box.luau) Need assertion +- [ ] [ref](./pretty_print/ref.luau) Need assertion +- [ ] [lib](./pretty_print/lib.luau) Need assertion - [x] [fn](./pretty_print/fn.luau) - [x] [ptr](./pretty_print/ptr.luau) - [x] [struct](./pretty_print/struct.luau) From 461ab26dea1231ca53b0437618ff17c1369802cb Mon Sep 17 00:00:00 2001 From: qwreey Date: Sat, 9 Nov 2024 16:14:17 +0000 Subject: [PATCH 75/79] Update ffi README files (#243) --- crates/lune-std-ffi/README.md | 4 ++-- tests/ffi/README.md | 11 ++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/crates/lune-std-ffi/README.md b/crates/lune-std-ffi/README.md index 3f35d4eb..a6ad488e 100644 --- a/crates/lune-std-ffi/README.md +++ b/crates/lune-std-ffi/README.md @@ -40,7 +40,7 @@ Define C-ABI type information and provide conversion and casting - [**Struct `CStructInfo`:**](./src/c/struct_info.rs) Represents C Struct type - [**Struct `CTypeInfo`:**](./src/c/type_info.rs) Represents C type, extended in `/c/types` -
Mod helper.rs: C ABI type helper +
Mod helper.rs: C ABI type helper - **Function `get_conv`, `get_conv_list`:** get `FfiConvert` from userdata (CStruct, CArr, CPtr, CTypes) @@ -64,7 +64,7 @@ Define C-ABI type information and provide conversion and casting Export fixed-size source time known types and non-fixed compile time known types mod.rs implememts type-casting for all CTypes -
Mod ctype_helper: c type helper +
Mod ctype_helper: CTypeInfo helper - **Function `get_conv`:** get `FfiConvert` from ctype userdata, used for struct and array conversion diff --git a/tests/ffi/README.md b/tests/ffi/README.md index 47d2779f..3298b749 100644 --- a/tests/ffi/README.md +++ b/tests/ffi/README.md @@ -1,4 +1,5 @@ + # `tests/ffi` @@ -24,6 +25,12 @@ gcc for library compiling (for external-\*) - [x] [read_boundary](./read_boundary.luau) - [x] [write_boundary](./write_boundary.luau) +**Types** + +- [x] [arr](./types/arr.luau) +- [x] [ptr](./types/ptr.luau) +- [x] [struct](./types/struct.luau) + **Pretty Print** - [x] [arr](./pretty_print/arr.luau) @@ -39,7 +46,7 @@ gcc for library compiling (for external-\*) > Note: LuaJit's os.clock function returns process CPU time (used) which much smaller then Luau's os.clock output. In this benchmark, luau uses 'time.h' instead of os.clock. See [utility/proc_clock](./utility/proc_clock/init.luau) -### [benchmark/external_call](./benchmark/external_call/init.luau) +

benchmark/external_call

**Target external c function** @@ -102,3 +109,5 @@ Command: `deno run --unstable-ffi --allow-ffi ./tests/ffi/benchmark/external_cal > MEM: 12250MiB 5600 MT/s > KERNEL: 10.0.22631 (Windows 11 x86_64) > HOST: QEMU Standard PC (Q35 + ICH9, 2009) + +
From 627c2c9afbd8489ec50514417c4971abf542e10a Mon Sep 17 00:00:00 2001 From: qwreey Date: Tue, 12 Nov 2024 03:05:55 +0000 Subject: [PATCH 76/79] Update readRef method to allow reuse RefData (#243) --- crates/lune-std-ffi/src/c/arr_info.rs | 2 +- crates/lune-std-ffi/src/c/fn_info.rs | 23 +---- crates/lune-std-ffi/src/c/ptr_info.rs | 77 +++++++++++----- crates/lune-std-ffi/src/data/mod.rs | 2 +- crates/lune-std-ffi/src/data/ref_data/mod.rs | 17 ++++ types/ffi.luau | 97 +++++++++++--------- 6 files changed, 132 insertions(+), 86 deletions(-) diff --git a/crates/lune-std-ffi/src/c/arr_info.rs b/crates/lune-std-ffi/src/c/arr_info.rs index fd76dce1..1668bd65 100644 --- a/crates/lune-std-ffi/src/c/arr_info.rs +++ b/crates/lune-std-ffi/src/c/arr_info.rs @@ -6,7 +6,7 @@ use mlua::prelude::*; use super::{association_names::CARR_INNER, helper, method_provider}; use crate::ffi::{association, libffi_helper::get_ensured_size, FfiConvert, FfiData, FfiSize}; -// This is a series of some type. +// 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. // Multidimensional arrays can be implemented diff --git a/crates/lune-std-ffi/src/c/fn_info.rs b/crates/lune-std-ffi/src/c/fn_info.rs index eaf566e6..fb5b8bcc 100644 --- a/crates/lune-std-ffi/src/c/fn_info.rs +++ b/crates/lune-std-ffi/src/c/fn_info.rs @@ -16,22 +16,7 @@ use crate::{ }, }; -// cfn is a type declaration for a function. -// Basically, when calling an external function, this type declaration -// is referred to and type conversion is automatically assisted. - -// However, in order to save on type conversion costs, -// users keep values ​​they will use continuously in a box and use them multiple times. -// Alternatively, if the types are the same,you can save the cost of creating -// a new space by directly passing FfiRaw, -// the result value of another function or the argument value of the callback. - -// Defining cfn simply lists the function's actual argument positions and conversions. -// You must decide how to process the data in Lua. - -// The name cfn is intentional. This is because any *c_void is -// moved to a Lua function or vice versa. - +// Function pointer type pub struct CFnInfo { cif: Cif, arg_info_list: Vec, @@ -147,6 +132,7 @@ impl CFnInfo { } } + // Create ClosureData with lua function pub fn create_closure<'lua>( &self, lua: &'lua Lua, @@ -167,6 +153,7 @@ impl CFnInfo { Ok(closure_data) } + // Create CallableData from RefData pub fn create_callable<'lua>( &self, lua: &'lua Lua, @@ -209,10 +196,6 @@ impl LuaUserData for CFnInfo { fields.add_field_method_get("size", |_lua, _this| Ok(SIZE_OF_POINTER)); } 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); diff --git a/crates/lune-std-ffi/src/c/ptr_info.rs b/crates/lune-std-ffi/src/c/ptr_info.rs index f1efc9e3..aa774ecd 100644 --- a/crates/lune-std-ffi/src/c/ptr_info.rs +++ b/crates/lune-std-ffi/src/c/ptr_info.rs @@ -5,7 +5,7 @@ use mlua::prelude::*; use super::{association_names::CPTR_INNER, ctype_helper, helper, method_provider}; use crate::{ - data::{GetFfiData, RefBounds, RefData, RefFlag}, + data::{GetFfiData, RefData, RefFlag, UNSIZED_BOUNDS}, ffi::{ association, libffi_helper::SIZE_OF_POINTER, FfiConvert, FfiData, FfiSignedness, FfiSize, }, @@ -16,7 +16,6 @@ const READ_REF_FLAGS: u8 = RefFlag::Offsetable.value() | RefFlag::Readable.value() | RefFlag::Writable.value(); pub struct CPtrInfo { - inner_size: usize, inner_is_cptr: bool, } @@ -33,7 +32,7 @@ impl FfiSize for CPtrInfo { } impl FfiConvert for CPtrInfo { - // Convert luavalue into data, then write into ptr + // Write address of RefData unsafe fn value_into_data<'lua>( &self, _lua: &'lua Lua, @@ -41,12 +40,12 @@ impl FfiConvert for CPtrInfo { data_handle: &Ref, value: LuaValue<'lua>, ) -> LuaResult<()> { - let value_userdata = value.as_userdata().ok_or_else(|| { - LuaError::external(format!( + let LuaValue::UserData(value_userdata) = value else { + return Err(LuaError::external(format!( "Value must be a RefData, BoxData or ClosureData, got {}", value.type_name() - )) - })?; + ))); + }; *data_handle .get_inner_pointer() .byte_offset(offset) @@ -54,24 +53,30 @@ impl FfiConvert for CPtrInfo { Ok(()) } - // Read data from ptr, then convert into luavalue + // Read address, create RefData unsafe fn value_from_data<'lua>( &self, lua: &'lua Lua, offset: isize, data_handle: &Ref, ) -> LuaResult> { - Ok(LuaValue::UserData(lua.create_userdata(RefData::new( - unsafe { data_handle.get_inner_pointer().byte_offset(offset) }, - if self.inner_is_cptr { - READ_CPTR_REF_FLAGS - } else { - READ_REF_FLAGS - }, - RefBounds::new(0, self.inner_size), - ))?)) + Ok(LuaValue::UserData( + lua.create_userdata(RefData::new( + *data_handle + .get_inner_pointer() + .byte_offset(offset) + .cast::<*mut ()>(), + if self.inner_is_cptr { + READ_CPTR_REF_FLAGS + } else { + READ_REF_FLAGS + }, + UNSIZED_BOUNDS, + ))?, + )) } + // Copy Address unsafe fn copy_data( &self, _lua: &Lua, @@ -82,7 +87,10 @@ impl FfiConvert for CPtrInfo { ) -> LuaResult<()> { *dst.get_inner_pointer() .byte_offset(dst_offset) - .cast::<*mut ()>() = src.get_inner_pointer().byte_offset(src_offset); + .cast::<*mut ()>() = *src + .get_inner_pointer() + .byte_offset(src_offset) + .cast::<*mut ()>(); Ok(()) } } @@ -95,7 +103,6 @@ impl CPtrInfo { inner: &LuaAnyUserData, ) -> LuaResult> { let value = lua.create_userdata(Self { - inner_size: helper::get_size(inner)?, inner_is_cptr: inner.is::(), })?; @@ -143,8 +150,36 @@ impl LuaUserData for CPtrInfo { methods.add_method( "readRef", - |lua, this, (target, offset): (LuaAnyUserData, Option)| unsafe { - this.value_from_data(lua, offset.unwrap_or(0), &target.get_ffi_data()?) + |lua, + this, + (target, offset, ref_data): ( + LuaAnyUserData, + Option, + Option, + )| unsafe { + if let Some(ref_userdata) = ref_data { + if !ref_userdata.is::() { + return Err(LuaError::external("")); + } + RefData::update( + lua, + ref_userdata.clone(), + *target + .get_ffi_data()? + .get_inner_pointer() + .byte_offset(offset.unwrap_or(0)) + .cast::<*mut ()>(), + if this.inner_is_cptr { + READ_CPTR_REF_FLAGS + } else { + READ_REF_FLAGS + }, + UNSIZED_BOUNDS, + )?; + Ok(LuaValue::UserData(ref_userdata)) + } else { + this.value_from_data(lua, offset.unwrap_or(0), &target.get_ffi_data()?) + } }, ); methods.add_method( diff --git a/crates/lune-std-ffi/src/data/mod.rs b/crates/lune-std-ffi/src/data/mod.rs index ceda5881..8294f214 100644 --- a/crates/lune-std-ffi/src/data/mod.rs +++ b/crates/lune-std-ffi/src/data/mod.rs @@ -15,7 +15,7 @@ pub use self::{ callable_data::CallableData, closure_data::ClosureData, lib_data::LibData, - ref_data::{create_nullref, RefBounds, RefData, RefFlag}, + ref_data::{create_nullref, RefBounds, RefData, RefFlag, UNSIZED_BOUNDS}, }; use crate::ffi::FfiData; diff --git a/crates/lune-std-ffi/src/data/ref_data/mod.rs b/crates/lune-std-ffi/src/data/ref_data/mod.rs index 3de26137..55090155 100644 --- a/crates/lune-std-ffi/src/data/ref_data/mod.rs +++ b/crates/lune-std-ffi/src/data/ref_data/mod.rs @@ -41,6 +41,23 @@ impl RefData { } } + pub fn update<'lua>( + lua: &'lua Lua, + this: LuaAnyUserData<'lua>, + ptr: *mut (), + flags: u8, + boundary: RefBounds, + ) -> LuaResult<()> { + let mut target = this.borrow_mut::()?; + association::set(lua, REF_INNER, &this, LuaNil)?; + + **target.ptr = ptr; + target.flags = flags; + target.boundary = boundary; + + Ok(()) + } + // Create reference of this reference pub fn luaref<'lua>( lua: &'lua Lua, diff --git a/types/ffi.luau b/types/ffi.luau index bfc465e0..d17d053d 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -1,6 +1,6 @@ --[=[ @class FFI - + Built-in library for foreign function interface. ### Example usage @@ -30,7 +30,7 @@ local result = ffi.box(ffi.c.int.size) local a = ffi.c.int:box(1) local b = ffi.c.int:box(2) - + -- Call external function add(result, a:ref(), b:ref()) @@ -51,8 +51,8 @@ ffi.c = c --#region Data --[=[ @class RefData - - A user manageable memory reference box. + + A user manageable memory reference. It can be GCed, But it doesn't free the referenced memory. ]=] @@ -140,7 +140,7 @@ export type RefData = { --[=[ @class BoxData - + A user manageable heap memory. ]=] export type BoxData = { @@ -229,14 +229,12 @@ export type LibData = { find: (self: LibData, sym: string) -> RefData, } --- export type AppliedCallable = ()->() - --[=[ @class CallableData - + A callable external function. - To call external function, you should provide memory for the return value and references for the arguments. + To call external function, provide memory for save the return value and references for the arguments. If return type is `void`, pass `nil`. ]=] @@ -246,13 +244,12 @@ export type CallableData = ( ) -> () & { -- apply: (self: Callable, args: Args)->AppliedCallable, } +-- export type AppliedCallable = ()->() --[=[ @class ClosureData - - A lua function wrapper for the function pointer. - To return some data, write value into ret reference. + A reference that holds lua function. ]=] export type ClosureData = { --[=[ @@ -290,7 +287,7 @@ export type CTypeInfo = { ]=] signedness: boolean, - -- subtype + -- Subtype --[=[ @within CTypeInfo @tag Method @@ -301,7 +298,6 @@ export type CTypeInfo = { @return A pointer subtype ]=] ptr: (self: CTypeInfo) -> CPtrInfo>, - --[=[ @within CTypeInfo @tag Method @@ -314,7 +310,7 @@ export type CTypeInfo = { ]=] arr: (self: CTypeInfo, len: number) -> CArrInfo, R>, - -- realize + -- Create/Read/Write/Copy --[=[ @within CTypeInfo @tag Method @@ -326,33 +322,30 @@ export type CTypeInfo = { @return A box ]=] box: (self: CTypeInfo, val: R) -> BoxData, - --[=[ @within CTypeInfo @tag Method @method readData - Read a lua table from reference or box. + Read a lua value from reference or box. @param target Target to read data from @param offset Offset to read data from - @return A table + @return A lua value ]=] readData: (self: CTypeInfo, target: RefData | BoxData, offset: number?) -> R, - --[=[ @within CTypeInfo @tag Method @method writeData - Write a lua table into reference or box. + Write a lua value into reference or box. @param target Target to write data into - @param table Lua data to write + @param value Lua data to write @param offset Offset to write data into ]=] writeData: (self: CTypeInfo, target: RefData | BoxData, value: R, offset: number?) -> (), - --[=[ @within CTypeInfo @tag Method @@ -372,7 +365,6 @@ export type CTypeInfo = { dstOffset: number?, srcOffset: number? ) -> (), - --[=[ @within CTypeInfo @tag Method @@ -385,6 +377,7 @@ export type CTypeInfo = { ]=] stringifyData: (self: CTypeInfo, target: RefData | BoxData, offset: number?) -> string, + -- ETC -- FIXME: recursive types; 'intoType' should be CTypes --[=[ @within CTypeInfo @@ -432,7 +425,7 @@ export type CPtrInfo = { ]=] inner: T, - -- subtype + -- Subtype -- FIXME: recursive types; result 'any' should be CArrInfo> --[=[ @within CPtrInfo @@ -457,34 +450,46 @@ export type CPtrInfo = { ]=] ptr: (self: CPtrInfo) -> any, + -- Address --[=[ @within CPtrInfo @tag Method @Method readRef - - Similar to readData, read a lua value from reference. - - @param target Target reference to read data from - @param offset Offset to read data from + + Read address from data, then return RefData. + + Useful when reading pointer fields of structures. + + If the `ref` argument is given, rather than create new RefData, update it. + + @param target Target data to read address from + @param offset Offset to read address from + @param ref RefData to update @return A lua value ]=] - readRef: (self: CPtrInfo, target: RefData | BoxData, offset: number?) -> any, - + readRef: ( + self: CPtrInfo, + target: RefData | BoxData, + offset: number?, + ref: RefData? + ) -> RefData, --[=[ @within CPtrInfo @tag Method @Method writeRef - Similar to writeData, write a lua value into reference. + Write address to data. - @param target Target reference to write data into - @param value Lua data to write - @param offset Offset to write data into + Useful when writing pointer fields of structures. + + @param target Target data to write address into + @param ref Memory address to write + @param offset Offset to write address into ]=] writeRef: ( self: CPtrInfo, target: RefData | BoxData, - value: RefData | BoxData, + ref: RefData | BoxData | ClosureData, offset: number? ) -> (), } @@ -520,7 +525,7 @@ export type CArrInfo = { ]=] inner: T, - -- subtype + -- Subtype --[=[ @within CArrInfo @tag Method @@ -532,7 +537,7 @@ export type CArrInfo = { ]=] ptr: (self: CArrInfo) -> CPtrInfo>, - -- realize + -- Create/Read/Write/Copy --[=[ @within CArrInfo @tag Method @@ -544,7 +549,6 @@ export type CArrInfo = { @return A box ]=] box: (self: CArrInfo, table: { T }) -> BoxData, - --[=[ @within CArrInfo @tag Method @@ -557,7 +561,6 @@ export type CArrInfo = { @return A table ]=] readData: (self: CArrInfo, target: RefData | BoxData, offset: number?) -> { T }, - --[=[ @within CArrInfo @tag Method @@ -575,7 +578,6 @@ export type CArrInfo = { value: { R }, target_offset: number? ) -> (), - --[=[ @within CArrInfo @tag Method @@ -596,6 +598,7 @@ export type CArrInfo = { srcOffset: number? ) -> (), + -- ETC --[=[ @within CArrInfo @tag Method @@ -612,7 +615,7 @@ export type CArrInfo = { --[=[ @class CFnInfo - A c function signature type information. + A C function pointer type information, with function signature. ]=] export type CFnInfo = { --[=[ @@ -625,6 +628,8 @@ export type CFnInfo = { Equivalent to `ffi.c.usize.size`. ]=] size: number, + + -- Function --[=[ @within CFnInfo @tag Method @@ -642,6 +647,8 @@ export type CFnInfo = { Create a closure from lua function. + To return some data, lua function should write value into ret reference. + @return A closure ]=] closure: (self: CFnInfo, (ret: RefData, ...RefData) -> ()) -> ClosureData, @@ -662,6 +669,7 @@ export type CStructInfo = { ]=] size: number, + -- Subtype --[=[ @within CSturctInfo @tag Method @@ -684,6 +692,7 @@ export type CStructInfo = { ]=] ptr: (self: CStructInfo) -> CPtrInfo, + -- Create/Read/Write/Copy --[=[ @within CSturctInfo @tag Method @@ -744,6 +753,7 @@ export type CStructInfo = { srcOffset: number? ) -> (), + -- ETC --[=[ @within CSturctInfo @tag Method @@ -755,7 +765,6 @@ export type CStructInfo = { @return The byte offset ]=] offset: (self: CStructInfo, index: number) -> number, - --[=[ @within CSturctInfo @tag Method @@ -783,6 +792,8 @@ export type CVoidInfo = { The size of the void type. It is always 0. ]=] size: number, + + -- Subtype --[=[ @within CVoidInfo @tag Method From e8cc2dcda38f2f6c9f9e15e39f43f505b9477f2a Mon Sep 17 00:00:00 2001 From: qwreey Date: Tue, 12 Nov 2024 05:40:32 +0000 Subject: [PATCH 77/79] Add readString, writeString method (#243) --- crates/lune-std-ffi/src/data/box_data/mod.rs | 3 + crates/lune-std-ffi/src/data/helper.rs | 61 ++++++++++- crates/lune-std-ffi/src/data/ref_data/mod.rs | 2 + crates/lune-std-ffi/src/ffi/mod.rs | 27 ++++- types/ffi.luau | 104 +++++++++++++++---- 5 files changed, 172 insertions(+), 25 deletions(-) diff --git a/crates/lune-std-ffi/src/data/box_data/mod.rs b/crates/lune-std-ffi/src/data/box_data/mod.rs index 70ce3b38..e8c4b88a 100644 --- a/crates/lune-std-ffi/src/data/box_data/mod.rs +++ b/crates/lune-std-ffi/src/data/box_data/mod.rs @@ -138,6 +138,9 @@ impl LuaUserData for BoxData { } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { method_provider::provide_copy_from(methods); + method_provider::provide_read_string(methods); + method_provider::provide_write_string(methods); + // For convenience, :zero returns box itself. methods.add_function_mut("zero", |_lua, this: LuaAnyUserData| { this.borrow_mut::()?.zero(); diff --git a/crates/lune-std-ffi/src/data/helper.rs b/crates/lune-std-ffi/src/data/helper.rs index cfd304cc..0d48e1c9 100644 --- a/crates/lune-std-ffi/src/data/helper.rs +++ b/crates/lune-std-ffi/src/data/helper.rs @@ -26,10 +26,10 @@ pub mod method_provider { let src = src.get_ffi_data()?; if !src.check_inner_boundary(src_offset, length) { - return Err(LuaError::external("Source boundary check failed")); + return Err(LuaError::external("Source out of bounds")); } if !this.check_inner_boundary(dst_offset, length) { - return Err(LuaError::external("Self boundary check failed")); + return Err(LuaError::external("Self out of bounds")); } this.copy_from(&src, length, dst_offset, src_offset); @@ -39,6 +39,61 @@ pub mod method_provider { ); } - // TODO: writeString, readString, writeBase64 and readBase64 methods + // Implement readString method + pub fn provide_read_string<'lua, Target, M>(methods: &mut M) + where + Target: FfiData, + M: LuaUserDataMethods<'lua, Target>, + { + methods.add_method( + "readString", + |lua, this, (length, offset): (usize, Option)| unsafe { + let offset = offset.unwrap_or(0); + + if !this.check_inner_boundary(offset, length) { + return Err(LuaError::external("Source out of bounds")); + } + + lua.create_string(this.read_string(length, offset)) + }, + ); + } + + // Implement writeString method + pub fn provide_write_string<'lua, Target, M>(methods: &mut M) + where + Target: FfiData, + M: LuaUserDataMethods<'lua, Target>, + { + methods.add_method( + "writeString", + |_lua, + this, + (string, length, dst_offset, src_offset): ( + LuaString, + usize, + Option, + Option, + )| unsafe { + let dst_offset = dst_offset.unwrap_or(0); + let src_offset = src_offset.unwrap_or(0); + + // Source string boundary check + if string.as_bytes().len() < src_offset + length { + return Err(LuaError::external("Source out of bounds")); + } + + // Self boundary check + if !this.check_inner_boundary(dst_offset, length) { + return Err(LuaError::external("Self out of bounds")); + } + + this.write_string(string, length, dst_offset, src_offset); + Ok(()) + }, + ); + } + // TODO: Bit operation support + // TODO: writeBase64 and readBase64 methods } diff --git a/crates/lune-std-ffi/src/data/ref_data/mod.rs b/crates/lune-std-ffi/src/data/ref_data/mod.rs index 55090155..42701b30 100644 --- a/crates/lune-std-ffi/src/data/ref_data/mod.rs +++ b/crates/lune-std-ffi/src/data/ref_data/mod.rs @@ -165,6 +165,8 @@ impl FfiData for RefData { impl LuaUserData for RefData { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { method_provider::provide_copy_from(methods); + method_provider::provide_read_string(methods); + method_provider::provide_write_string(methods); methods.add_method("deref", |_lua, this, ()| unsafe { this.dereference() }); methods.add_function("offset", |lua, (this, offset): (LuaAnyUserData, isize)| { diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index 5131b968..dc928305 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -71,8 +71,33 @@ pub trait FfiData { src_offset: isize, ) { self.get_inner_pointer() + .cast::() .byte_offset(dst_offset) - .copy_from(src.get_inner_pointer().byte_offset(src_offset), length); + .copy_from( + src.get_inner_pointer().cast::().byte_offset(src_offset), + length, + ); + } + unsafe fn read_string(&self, length: usize, offset: isize) -> Vec { + let mut string = Vec::::with_capacity(length); + string.as_mut_ptr().copy_from( + self.get_inner_pointer().cast::().byte_offset(offset), + length, + ); + string.set_len(length); + string + } + unsafe fn write_string( + &self, + src: LuaString, + length: usize, + dst_offset: isize, + src_offset: usize, + ) { + self.get_inner_pointer() + .cast::() + .byte_offset(dst_offset) + .copy_from(src.to_pointer().cast::().byte_add(src_offset), length); } } diff --git a/types/ffi.luau b/types/ffi.luau index d17d053d..d0dbd75b 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -125,9 +125,9 @@ export type RefData = { Copy content from another data with specific length. @param src The source data - @param len The amount of data to copy, in bytes - @param dstOffset The offset in the destination where the data will be pasted - @param srcOffset The offset in the source data from where the data will be copied + @param length The amount of data to copy, in bytes + @param dstOffset The offset in the destination where the content will be pasted + @param srcOffset The offset in the source data from where the content will be copied ]=] copyFrom: ( self: RefData, @@ -136,6 +136,37 @@ export type RefData = { dstOffset: number, srcOffset: number ) -> (), + --[=[ + @within RefData + @tag Method + @method readString + + Read string from data with specific length. + + @param length The amount of data to read, in bytes + @param offset Offset to read string from + @return A string + ]=] + readString: (self: RefData, length: number, offset: number?) -> string, + --[=[ + @within RefData + @tag Method + @method writeString + + Write string into data. + + @param src The source string + @param length The amount of data to write, in bytes + @param dstOffset The offset in the destination where the content will be pasted + @param srcOffset The offset in the source string from where the content will be copied + ]=] + writeString: ( + self: RefData, + src: string, + length: number, + dstOffset: number, + srcOffset: number + ) -> (), } --[=[ @@ -197,9 +228,9 @@ export type BoxData = { Copy content from another data with specific length. @param src The source data - @param len The amount of data to copy, in bytes - @param dstOffset The offset in the destination where the data will be pasted - @param srcOffset The offset in the source data from where the data will be copied + @param length The amount of data to copy, in bytes + @param dstOffset The offset in the destination where the content will be pasted + @param srcOffset The offset in the source data from where the content will be copied ]=] copyFrom: ( self: BoxData, @@ -208,6 +239,37 @@ export type BoxData = { dstOffset: number, srcOffset: number ) -> (), + --[=[ + @within BoxData + @tag Method + @method readString + + Read string from data with specific length. + + @param length The amount of data to read, in bytes + @param offset Offset to read string from + @return A string + ]=] + readString: (self: BoxData, length: number, offset: number?) -> string, + --[=[ + @within BoxData + @tag Method + @method writeString + + Write string into data. + + @param src The source string + @param length The amount of data to write, in bytes + @param dstOffset The offset in the destination where the content will be pasted + @param srcOffset The offset in the source string from where the content will be copied + ]=] + writeString: ( + self: BoxData, + src: string, + length: number, + dstOffset: number, + srcOffset: number + ) -> (), } --[=[ @@ -305,10 +367,10 @@ export type CTypeInfo = { Create an array subtype with specific length. - @param len The length of the array + @param length The length of the array @return An array subtype ]=] - arr: (self: CTypeInfo, len: number) -> CArrInfo, R>, + arr: (self: CTypeInfo, length: number) -> CArrInfo, R>, -- Create/Read/Write/Copy --[=[ @@ -353,10 +415,10 @@ export type CTypeInfo = { Copy values ​​from the source and paste them into the target. - @param dst Where the data will be pasted + @param dst Where the content will be pasted @param src The source data - @param dstOffset The offset in the destination where the data will be pasted - @param srcOffset The offset in the source data from where the data will be copied + @param dstOffset The offset in the destination where the content will be pasted + @param srcOffset The offset in the source data from where the content will be copied ]=] copyData: ( self: CTypeInfo, @@ -434,10 +496,10 @@ export type CPtrInfo = { Create an array subtype with specific length. - @param len The length of the array + @param length The length of the array @return An array subtype ]=] - arr: (self: CPtrInfo, len: number) -> any, + arr: (self: CPtrInfo, length: number) -> any, -- FIXME: recursive types; result 'any' should be CPtrInfo> --[=[ @within CPtrInfo @@ -585,10 +647,10 @@ export type CArrInfo = { Copy values ​​from the source and paste them into the target. - @param dst Where the data will be pasted + @param dst Where the content will be pasted @param src The source data - @param dstOffset The offset in the dst where the data will be pasted - @param srcOffset The offset in the source data from where the data will be copied + @param dstOffset The offset in the dst where the content will be pasted + @param srcOffset The offset in the source data from where the content will be copied ]=] copyData: ( self: CArrInfo, @@ -677,10 +739,10 @@ export type CStructInfo = { Create a struct array type. - @param len The length of the array + @param length The length of the array @return A struct array type ]=] - arr: (self: CStructInfo, len: number) -> CArrInfo, + arr: (self: CStructInfo, length: number) -> CArrInfo, --[=[ @within CSturctInfo @tag Method @@ -740,10 +802,10 @@ export type CStructInfo = { Copy values from the source and paste them into the target. - @param dst Where the data will be pasted + @param dst Where the content will be pasted @param src The source data - @param dstOffset The offset in the destination where the data will be pasted - @param srcOffset The offset in the source data from where the data will be copied + @param dstOffset The offset in the destination where the content will be pasted + @param srcOffset The offset in the source data from where the content will be copied ]=] copyData: ( self: CStructInfo, From 7a51bc9aa4a5f2d3359b2f24692958781e42edae Mon Sep 17 00:00:00 2001 From: qwreey Date: Tue, 12 Nov 2024 06:34:22 +0000 Subject: [PATCH 78/79] Fix read/writeString and add test (#243) --- crates/lune-std-ffi/src/c/helper.rs | 13 ++++++---- crates/lune-std-ffi/src/data/helper.rs | 30 +++++++++++++---------- crates/lune-std-ffi/src/ffi/mod.rs | 5 +++- crates/lune/src/tests.rs | 1 + tests/ffi/stringReadWrite.luau | 34 ++++++++++++++++++++++++++ types/ffi.luau | 34 ++++++++++++++------------ 6 files changed, 83 insertions(+), 34 deletions(-) create mode 100644 tests/ffi/stringReadWrite.luau diff --git a/crates/lune-std-ffi/src/c/helper.rs b/crates/lune-std-ffi/src/c/helper.rs index 1e246531..b56ed7f8 100644 --- a/crates/lune-std-ffi/src/c/helper.rs +++ b/crates/lune-std-ffi/src/c/helper.rs @@ -14,6 +14,7 @@ pub mod method_provider { // Implement tostring pub fn provide_to_string<'lua, Target, M>(methods: &mut M) where + Target: 'static, M: LuaUserDataMethods<'lua, Target>, { methods.add_meta_function(LuaMetaMethod::ToString, |lua, this: LuaAnyUserData| { @@ -24,6 +25,7 @@ pub mod method_provider { // Implement ptr method pub fn provide_ptr<'lua, Target, M>(methods: &mut M) where + Target: 'static, M: LuaUserDataMethods<'lua, Target>, { methods.add_function("ptr", |lua, this: LuaAnyUserData| { @@ -34,6 +36,7 @@ pub mod method_provider { // Implement arr method pub fn provide_arr<'lua, Target, M>(methods: &mut M) where + Target: 'static, M: LuaUserDataMethods<'lua, Target>, { methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| { @@ -44,7 +47,7 @@ pub mod method_provider { // Implement readData method pub fn provide_read_data<'lua, Target, M>(methods: &mut M) where - Target: FfiSize + FfiConvert, + Target: FfiSize + FfiConvert + 'static, M: LuaUserDataMethods<'lua, Target>, { methods.add_method( @@ -68,7 +71,7 @@ pub mod method_provider { // Implement writeData method pub fn provide_write_data<'lua, Target, M>(methods: &mut M) where - Target: FfiSize + FfiConvert, + Target: FfiSize + FfiConvert + 'static, M: LuaUserDataMethods<'lua, Target>, { methods.add_method( @@ -93,7 +96,7 @@ pub mod method_provider { // Implement copyData method pub fn provide_copy_data<'lua, Target, M>(methods: &mut M) where - Target: FfiSize + FfiConvert, + Target: FfiSize + FfiConvert + 'static, M: LuaUserDataMethods<'lua, Target>, { methods.add_method( @@ -134,7 +137,7 @@ pub mod method_provider { // Implement stringifyData method pub fn provide_stringify_data<'lua, Target, M>(methods: &mut M) where - Target: FfiSize + FfiConvert, + Target: FfiSize + FfiConvert + 'static, M: LuaUserDataMethods<'lua, Target>, { methods.add_method( @@ -148,7 +151,7 @@ pub mod method_provider { // Implement box method pub fn provide_box<'lua, Target, M>(methods: &mut M) where - Target: FfiSize + FfiConvert, + Target: FfiSize + FfiConvert + 'static, M: LuaUserDataMethods<'lua, Target>, { methods.add_method("box", |lua, this, value: LuaValue| { diff --git a/crates/lune-std-ffi/src/data/helper.rs b/crates/lune-std-ffi/src/data/helper.rs index 0d48e1c9..0b7de25b 100644 --- a/crates/lune-std-ffi/src/data/helper.rs +++ b/crates/lune-std-ffi/src/data/helper.rs @@ -8,19 +8,20 @@ pub mod method_provider { // Implement copyFrom method pub fn provide_copy_from<'lua, Target, M>(methods: &mut M) where - Target: FfiData, + Target: FfiData + 'static, M: LuaUserDataMethods<'lua, Target>, { - methods.add_method( + methods.add_function( "copyFrom", |_lua, - this, - (src, length, dst_offset, src_offset): ( + (this_userdata, src, length, dst_offset, src_offset): ( + LuaAnyUserData, LuaAnyUserData, usize, Option, Option, )| unsafe { + let this = this_userdata.borrow::()?; let dst_offset = dst_offset.unwrap_or(0); let src_offset = src_offset.unwrap_or(0); let src = src.get_ffi_data()?; @@ -34,7 +35,7 @@ pub mod method_provider { this.copy_from(&src, length, dst_offset, src_offset); - Ok(()) + Ok(this_userdata.clone()) }, ); } @@ -42,7 +43,7 @@ pub mod method_provider { // Implement readString method pub fn provide_read_string<'lua, Target, M>(methods: &mut M) where - Target: FfiData, + Target: FfiData + 'static, M: LuaUserDataMethods<'lua, Target>, { methods.add_method( @@ -62,24 +63,27 @@ pub mod method_provider { // Implement writeString method pub fn provide_write_string<'lua, Target, M>(methods: &mut M) where - Target: FfiData, + Target: FfiData + 'static, M: LuaUserDataMethods<'lua, Target>, { - methods.add_method( + methods.add_function( "writeString", |_lua, - this, - (string, length, dst_offset, src_offset): ( + (this_userdata, string, length, dst_offset, src_offset): ( + LuaAnyUserData, LuaString, - usize, + Option, Option, Option, )| unsafe { + let string_len = string.as_bytes().len(); let dst_offset = dst_offset.unwrap_or(0); let src_offset = src_offset.unwrap_or(0); + let length = length.unwrap_or_else(|| string_len - src_offset); + let this = this_userdata.borrow::()?; // Source string boundary check - if string.as_bytes().len() < src_offset + length { + if string_len < src_offset + length { return Err(LuaError::external("Source out of bounds")); } @@ -89,7 +93,7 @@ pub mod method_provider { } this.write_string(string, length, dst_offset, src_offset); - Ok(()) + Ok(this_userdata.clone()) }, ); } diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index dc928305..5d6073a7 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -97,7 +97,10 @@ pub trait FfiData { self.get_inner_pointer() .cast::() .byte_offset(dst_offset) - .copy_from(src.to_pointer().cast::().byte_add(src_offset), length); + .copy_from( + src.as_bytes().as_ptr().cast::().byte_add(src_offset), + length, + ); } } diff --git a/crates/lune/src/tests.rs b/crates/lune/src/tests.rs index 4d06e1b1..0a62219e 100644 --- a/crates/lune/src/tests.rs +++ b/crates/lune/src/tests.rs @@ -123,6 +123,7 @@ create_tests! { ffi_free: "ffi/free", ffi_is_integer: "ffi/isInteger", ffi_read_boundary: "ffi/readBoundary", + ffi_read_write_string: "ffi/stringReadWrite", ffi_write_boundary: "ffi/writeBoundary", } diff --git a/tests/ffi/stringReadWrite.luau b/tests/ffi/stringReadWrite.luau new file mode 100644 index 00000000..43510475 --- /dev/null +++ b/tests/ffi/stringReadWrite.luau @@ -0,0 +1,34 @@ +local ffi = require("@lune/ffi") +local ok + +local str = "hello world" +local strbox = ffi.box(#str):writeString(str) +assert(strbox:readString(#str) == str, "String read write assersion failed") + +-- Case1: Fail +ok = pcall(function() + local box = ffi.box(2) + box:readString(10) +end) +assert(not ok, "assersion failed, Case1 should fail") + +-- Case2: Fail +ok = pcall(function() + local box = ffi.box(2) + box:writeString("hello world") +end) +assert(not ok, "assersion failed, Case2 should fail") + +-- Case3: Fail +ok = pcall(function() + local box = ffi.box(2):ref() + box:readString(10) +end) +assert(not ok, "assersion failed, Case3 should fail") + +-- Case4: Fail +ok = pcall(function() + local box = ffi.box(2):ref() + box:writeString("hello world") +end) +assert(not ok, "assersion failed, Case4 should fail") diff --git a/types/ffi.luau b/types/ffi.luau index d0dbd75b..a4238c7d 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -128,6 +128,7 @@ export type RefData = { @param length The amount of data to copy, in bytes @param dstOffset The offset in the destination where the content will be pasted @param srcOffset The offset in the source data from where the content will be copied + @return `RefData` itself for convenience ]=] copyFrom: ( self: RefData, @@ -135,13 +136,13 @@ export type RefData = { length: number, dstOffset: number, srcOffset: number - ) -> (), + ) -> RefData, --[=[ @within RefData @tag Method @method readString - Read string from data with specific length. + Read string from data with specific length without null termination. @param length The amount of data to read, in bytes @param offset Offset to read string from @@ -153,20 +154,21 @@ export type RefData = { @tag Method @method writeString - Write string into data. + Write string into data without null termination. @param src The source string @param length The amount of data to write, in bytes @param dstOffset The offset in the destination where the content will be pasted @param srcOffset The offset in the source string from where the content will be copied + @return `RefData` itself for convenience ]=] writeString: ( self: RefData, src: string, - length: number, - dstOffset: number, - srcOffset: number - ) -> (), + length: number?, + dstOffset: number?, + srcOffset: number? + ) -> RefData, } --[=[ @@ -191,7 +193,7 @@ export type BoxData = { Fill the box with zero. - @return `Box` itself for convenience + @return `BoxData` itself for convenience ]=] zero: (self: BoxData) -> BoxData, --[=[ @@ -231,6 +233,7 @@ export type BoxData = { @param length The amount of data to copy, in bytes @param dstOffset The offset in the destination where the content will be pasted @param srcOffset The offset in the source data from where the content will be copied + @return `BoxData` itself for convenience ]=] copyFrom: ( self: BoxData, @@ -238,13 +241,13 @@ export type BoxData = { length: number, dstOffset: number, srcOffset: number - ) -> (), + ) -> BoxData, --[=[ @within BoxData @tag Method @method readString - Read string from data with specific length. + Read string from data with specific length without null termination. @param length The amount of data to read, in bytes @param offset Offset to read string from @@ -256,20 +259,21 @@ export type BoxData = { @tag Method @method writeString - Write string into data. + Write string into data without null termination. @param src The source string @param length The amount of data to write, in bytes @param dstOffset The offset in the destination where the content will be pasted @param srcOffset The offset in the source string from where the content will be copied + @return `BoxData` itself for convenience ]=] writeString: ( self: BoxData, src: string, - length: number, - dstOffset: number, - srcOffset: number - ) -> (), + length: number?, + dstOffset: number?, + srcOffset: number? + ) -> BoxData, } --[=[ From 8f248ff624024fd68daa46a198237a6b2d2e03ff Mon Sep 17 00:00:00 2001 From: qwreey Date: Wed, 13 Nov 2024 06:20:28 +0000 Subject: [PATCH 79/79] Chnage naming naturally (#243) --- crates/lune-std-ffi/src/c/fn_info.rs | 2 +- crates/lune-std-ffi/src/data/box_data/flag.rs | 2 +- crates/lune-std-ffi/src/data/box_data/mod.rs | 2 +- crates/lune-std-ffi/src/data/callable_data.rs | 1 + crates/lune-std-ffi/src/data/closure_data.rs | 1 + crates/lune-std-ffi/src/data/ref_data/flag.rs | 2 +- crates/lune-std-ffi/src/data/ref_data/mod.rs | 2 +- .../lune-std-ffi/src/ffi/{bit_mask.rs => bit_field.rs} | 2 ++ crates/lune-std-ffi/src/ffi/mod.rs | 2 +- tests/ffi/external_closure/callClosure.luau | 5 ++--- tests/ffi/external_closure/callClosureWithPointer.luau | 10 +++++----- tests/ffi/external_closure/callHelloWorld.luau | 5 ++--- types/ffi.luau | 6 +++++- 13 files changed, 24 insertions(+), 18 deletions(-) rename crates/lune-std-ffi/src/ffi/{bit_mask.rs => bit_field.rs} (91%) diff --git a/crates/lune-std-ffi/src/c/fn_info.rs b/crates/lune-std-ffi/src/c/fn_info.rs index fb5b8bcc..963d8a0b 100644 --- a/crates/lune-std-ffi/src/c/fn_info.rs +++ b/crates/lune-std-ffi/src/c/fn_info.rs @@ -11,7 +11,7 @@ use super::{ use crate::{ data::{CallableData, ClosureData, RefData, RefFlag}, ffi::{ - association, bit_mask::*, libffi_helper::SIZE_OF_POINTER, FfiArg, FfiData, FfiResult, + association, bit_field::*, libffi_helper::SIZE_OF_POINTER, FfiArg, FfiData, FfiResult, FfiSignedness, FfiSize, }, }; diff --git a/crates/lune-std-ffi/src/data/box_data/flag.rs b/crates/lune-std-ffi/src/data/box_data/flag.rs index 445a3b3f..a983f3ba 100644 --- a/crates/lune-std-ffi/src/data/box_data/flag.rs +++ b/crates/lune-std-ffi/src/data/box_data/flag.rs @@ -1,4 +1,4 @@ -use crate::ffi::bit_mask::*; +use crate::ffi::bit_field::*; pub enum BoxFlag { Leaked, diff --git a/crates/lune-std-ffi/src/data/box_data/mod.rs b/crates/lune-std-ffi/src/data/box_data/mod.rs index e8c4b88a..1cdf9b4b 100644 --- a/crates/lune-std-ffi/src/data/box_data/mod.rs +++ b/crates/lune-std-ffi/src/data/box_data/mod.rs @@ -10,7 +10,7 @@ use mlua::prelude::*; use super::helper::method_provider; use crate::{ data::{association_names::REF_INNER, RefBounds, RefData, RefFlag}, - ffi::{association, bit_mask::*, FfiData}, + ffi::{association, bit_field::*, FfiData}, }; mod flag; diff --git a/crates/lune-std-ffi/src/data/callable_data.rs b/crates/lune-std-ffi/src/data/callable_data.rs index 47f47953..1119a2f8 100644 --- a/crates/lune-std-ffi/src/data/callable_data.rs +++ b/crates/lune-std-ffi/src/data/callable_data.rs @@ -13,6 +13,7 @@ use mlua::prelude::*; use super::{GetFfiData, RefData}; use crate::ffi::{FfiArg, FfiData, FfiResult}; +// A function pointer that luau can call. it stores libffi cif for calling convention. pub struct CallableData { cif: *mut ffi_cif, arg_info_list: Vec, diff --git a/crates/lune-std-ffi/src/data/closure_data.rs b/crates/lune-std-ffi/src/data/closure_data.rs index 26595d1c..93d21b49 100644 --- a/crates/lune-std-ffi/src/data/closure_data.rs +++ b/crates/lune-std-ffi/src/data/closure_data.rs @@ -17,6 +17,7 @@ use crate::ffi::{ FfiArg, FfiData, FfiResult, }; +// A closure that can be created with lua function. pub struct ClosureData { lua: *const Lua, closure: *mut ffi_closure, diff --git a/crates/lune-std-ffi/src/data/ref_data/flag.rs b/crates/lune-std-ffi/src/data/ref_data/flag.rs index 36a24a00..a7068adf 100644 --- a/crates/lune-std-ffi/src/data/ref_data/flag.rs +++ b/crates/lune-std-ffi/src/data/ref_data/flag.rs @@ -1,4 +1,4 @@ -use crate::ffi::bit_mask::*; +use crate::ffi::bit_field::*; pub enum RefFlag { Leaked, diff --git a/crates/lune-std-ffi/src/data/ref_data/mod.rs b/crates/lune-std-ffi/src/data/ref_data/mod.rs index 42701b30..2f26bdd1 100644 --- a/crates/lune-std-ffi/src/data/ref_data/mod.rs +++ b/crates/lune-std-ffi/src/data/ref_data/mod.rs @@ -5,7 +5,7 @@ use mlua::prelude::*; use super::helper::method_provider; use crate::{ data::association_names::REF_INNER, - ffi::{association, bit_mask::*, FfiData}, + ffi::{association, bit_field::*, FfiData}, }; mod bounds; diff --git a/crates/lune-std-ffi/src/ffi/bit_mask.rs b/crates/lune-std-ffi/src/ffi/bit_field.rs similarity index 91% rename from crates/lune-std-ffi/src/ffi/bit_mask.rs rename to crates/lune-std-ffi/src/ffi/bit_field.rs index db88474b..175d5882 100644 --- a/crates/lune-std-ffi/src/ffi/bit_mask.rs +++ b/crates/lune-std-ffi/src/ffi/bit_field.rs @@ -1,5 +1,7 @@ #![allow(unused)] +// Simple bit field library for handling data flags + pub const U8_MASK1: u8 = 1; pub const U8_MASK2: u8 = 2; pub const U8_MASK3: u8 = 4; diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index 5d6073a7..36b27d91 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -3,7 +3,7 @@ use std::cell::Ref; use mlua::prelude::*; pub mod association; -pub mod bit_mask; +pub mod bit_field; mod cast; pub mod libffi_helper; diff --git a/tests/ffi/external_closure/callClosure.luau b/tests/ffi/external_closure/callClosure.luau index b73fe6c7..f6bd73c8 100644 --- a/tests/ffi/external_closure/callClosure.luau +++ b/tests/ffi/external_closure/callClosure.luau @@ -4,11 +4,10 @@ local lib = require("../utils/compile")("./tests/ffi/external_closure/lib.c") local c = ffi.c -- Create closure -local closureInfo = c.fn({ c.int, c.int }, c.int) -local closure = closureInfo:closure(function(ret, a, b) +local closure = c.fn({ c.int, c.int }, c.int):closure(function(ret, a, b) c.int:writeData(ret, c.int:readData(a) + c.int:readData(b)) end) -local callClosure = callableWrapper(lib:find("call_closure"), { closureInfo }, c.int) +local callClosure = callableWrapper(lib:find("call_closure"), { c.void:ptr() }, c.int) local result = callClosure(closure:ref()) assert(result == 72, `callClosure failed. result expected 20000, got {result}`) diff --git a/tests/ffi/external_closure/callClosureWithPointer.luau b/tests/ffi/external_closure/callClosureWithPointer.luau index 5fd47b91..24084647 100644 --- a/tests/ffi/external_closure/callClosureWithPointer.luau +++ b/tests/ffi/external_closure/callClosureWithPointer.luau @@ -4,12 +4,12 @@ local lib = require("../utils/compile")("./tests/ffi/external_closure/lib.c") local c = ffi.c -- Create closure -local closureWithPointerInfo = c.fn({ c.int, c.int:ptr() }, c.int) -local closureWithPointer = closureWithPointerInfo:closure(function(returnRef, aRef, bRef) - c.int:writeData(returnRef, c.int:readData(aRef) + c.int:readData(bRef:deref())) -end) +local closureWithPointer = c.fn({ c.int, c.int:ptr() }, c.int) + :closure(function(returnRef, aRef, bRef) + c.int:writeData(returnRef, c.int:readData(aRef) + c.int:readData(bRef:deref())) + end) local callClosureWithPointer = - callableWrapper(lib:find("call_closure_with_pointer"), { closureWithPointerInfo }, c.int) + callableWrapper(lib:find("call_closure_with_pointer"), { c.void:ptr() }, c.int) local result = callClosureWithPointer(closureWithPointer:ref()) assert(result == 72, `closureWithPointer failed. result expected 20000, got {result}`) diff --git a/tests/ffi/external_closure/callHelloWorld.luau b/tests/ffi/external_closure/callHelloWorld.luau index 811601d1..50a8b199 100644 --- a/tests/ffi/external_closure/callHelloWorld.luau +++ b/tests/ffi/external_closure/callHelloWorld.luau @@ -3,10 +3,9 @@ local lib = require("../utils/compile")("./tests/ffi/external_closure/lib.c") local c = ffi.c -- Create closure -local helloWorldInfo = c.fn({}, c.void) -local helloWorld = helloWorldInfo:closure(function() +local helloWorld = c.fn({}, c.void):closure(function() print("Hello world in lua closure!") end) -local callHelloWorld = c.fn({ helloWorldInfo }, c.void):callable(lib:find("call_hello_world")) +local callHelloWorld = c.fn({ c.void:ptr() }, c.void):callable(lib:find("call_hello_world")) callHelloWorld(nil, helloWorld:ref()) diff --git a/types/ffi.luau b/types/ffi.luau index a4238c7d..6cc8fc1e 100644 --- a/types/ffi.luau +++ b/types/ffi.luau @@ -563,7 +563,9 @@ export type CPtrInfo = { --[=[ @class CArrInfo - A c sized array type information. + A c sized array type information. It can be used for sturct field. + + For function arguments, use CPtr instead. ]=] export type CArrInfo = { --[=[ @@ -682,6 +684,8 @@ export type CArrInfo = { @class CFnInfo A C function pointer type information, with function signature. + + For struct field, array element, or function arguments, use `void:ptr()` instead. ]=] export type CFnInfo = { --[=[