Update readRef method to allow reuse RefData (#243)

This commit is contained in:
qwreey 2024-11-12 03:05:55 +00:00
parent 461ab26dea
commit 627c2c9afb
No known key found for this signature in database
GPG key ID: D28DB79297A214BD
6 changed files with 132 additions and 86 deletions

View file

@ -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

View file

@ -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<FfiArg>,
@ -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);

View file

@ -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<dyn FfiData>,
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<dyn FfiData>,
) -> LuaResult<LuaValue<'lua>> {
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<LuaAnyUserData<'lua>> {
let value = lua.create_userdata(Self {
inner_size: helper::get_size(inner)?,
inner_is_cptr: inner.is::<CPtrInfo>(),
})?;
@ -143,8 +150,36 @@ impl LuaUserData for CPtrInfo {
methods.add_method(
"readRef",
|lua, this, (target, offset): (LuaAnyUserData, Option<isize>)| unsafe {
this.value_from_data(lua, offset.unwrap_or(0), &target.get_ffi_data()?)
|lua,
this,
(target, offset, ref_data): (
LuaAnyUserData,
Option<isize>,
Option<LuaAnyUserData>,
)| unsafe {
if let Some(ref_userdata) = ref_data {
if !ref_userdata.is::<RefData>() {
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(

View file

@ -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;

View file

@ -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::<RefData>()?;
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,

View file

@ -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<T, R> = {
]=]
signedness: boolean,
-- subtype
-- Subtype
--[=[
@within CTypeInfo
@tag Method
@ -301,7 +298,6 @@ export type CTypeInfo<T, R> = {
@return A pointer subtype
]=]
ptr: (self: CTypeInfo<T, R>) -> CPtrInfo<CTypeInfo<T, R>>,
--[=[
@within CTypeInfo
@tag Method
@ -314,7 +310,7 @@ export type CTypeInfo<T, R> = {
]=]
arr: (self: CTypeInfo<T, R>, len: number) -> CArrInfo<CTypeInfo<T, R>, R>,
-- realize
-- Create/Read/Write/Copy
--[=[
@within CTypeInfo
@tag Method
@ -326,33 +322,30 @@ export type CTypeInfo<T, R> = {
@return A box
]=]
box: (self: CTypeInfo<T, R>, 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<T, R>, 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<T, R>, target: RefData | BoxData, value: R, offset: number?) -> (),
--[=[
@within CTypeInfo
@tag Method
@ -372,7 +365,6 @@ export type CTypeInfo<T, R> = {
dstOffset: number?,
srcOffset: number?
) -> (),
--[=[
@within CTypeInfo
@tag Method
@ -385,6 +377,7 @@ export type CTypeInfo<T, R> = {
]=]
stringifyData: (self: CTypeInfo<T, R>, target: RefData | BoxData, offset: number?) -> string,
-- ETC
-- FIXME: recursive types; 'intoType' should be CTypes
--[=[
@within CTypeInfo
@ -432,7 +425,7 @@ export type CPtrInfo<T> = {
]=]
inner: T,
-- subtype
-- Subtype
-- FIXME: recursive types; result 'any' should be CArrInfo<CPtrInfo<T>>
--[=[
@within CPtrInfo
@ -457,34 +450,46 @@ export type CPtrInfo<T> = {
]=]
ptr: (self: CPtrInfo<T>) -> 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<T>, target: RefData | BoxData, offset: number?) -> any,
readRef: (
self: CPtrInfo<T>,
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<T>,
target: RefData | BoxData,
value: RefData | BoxData,
ref: RefData | BoxData | ClosureData,
offset: number?
) -> (),
}
@ -520,7 +525,7 @@ export type CArrInfo<T, R> = {
]=]
inner: T,
-- subtype
-- Subtype
--[=[
@within CArrInfo
@tag Method
@ -532,7 +537,7 @@ export type CArrInfo<T, R> = {
]=]
ptr: (self: CArrInfo<T, R>) -> CPtrInfo<CArrInfo<T, R>>,
-- realize
-- Create/Read/Write/Copy
--[=[
@within CArrInfo
@tag Method
@ -544,7 +549,6 @@ export type CArrInfo<T, R> = {
@return A box
]=]
box: (self: CArrInfo<T, R>, table: { T }) -> BoxData,
--[=[
@within CArrInfo
@tag Method
@ -557,7 +561,6 @@ export type CArrInfo<T, R> = {
@return A table
]=]
readData: (self: CArrInfo<T, R>, target: RefData | BoxData, offset: number?) -> { T },
--[=[
@within CArrInfo
@tag Method
@ -575,7 +578,6 @@ export type CArrInfo<T, R> = {
value: { R },
target_offset: number?
) -> (),
--[=[
@within CArrInfo
@tag Method
@ -596,6 +598,7 @@ export type CArrInfo<T, R> = {
srcOffset: number?
) -> (),
-- ETC
--[=[
@within CArrInfo
@tag Method
@ -612,7 +615,7 @@ export type CArrInfo<T, R> = {
--[=[
@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<CStructInfo>,
-- 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