From 3ccb0720fd8f806bb398ae726bd5f0ecd3374988 Mon Sep 17 00:00:00 2001 From: qwreey Date: Tue, 27 Aug 2024 13:24:17 +0000 Subject: [PATCH] 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 3940569..95c90cf 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 e61256b..0000000 --- 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 168d7d2..16e2f8f 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 5300bea..17c6171 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 35ba063..7b510d7 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 adaec6a..0000000 --- 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 9f63f99..0000000 --- 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 c02fc80..0000000 --- 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 ac3551d..0000000 --- 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 60691c7..0000000 --- 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 0000000..79baa3e --- /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 0000000..7dec899 --- /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 0000000..8f75d9c --- /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 0000000..e9a33cc --- /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 0000000..6478370 --- /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 0000000..ff1e228 --- /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 0000000..0c8cc28 --- /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 0000000..634d7bf --- /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 af90e57..a059967 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 0000000..80ff621 --- /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 0000000..b2a172b --- /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 0000000..3f494c2 --- /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 0000000..13cc41a --- /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 0000000..65c81d6 --- /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 0000000..8b959d6 --- /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 be242de..6990938 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 9eb892b..f31a825 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 00605e7..26be508 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 a4a657f..6e393da 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 0000000..50bd651 --- /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 0000000..e3b5d19 --- /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 0000000..16490b5 --- /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 30600d2..0000000 --- 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 5c73bb3..89c7f21 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 0000000..faf969e --- /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 8700e72..19aa6f4 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 dd36905..c13f88a 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 355cf3b..36549a9 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 fbd8999..0000000 --- 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