Skip to content

Commit dd6a386

Browse files
committed
Improve conversion performance by caching dyn handle on subtype (#243)
1 parent b54ea51 commit dd6a386

File tree

12 files changed

+244
-176
lines changed

12 files changed

+244
-176
lines changed

crates/lune-std-ffi/src/c/c_arr.rs

Lines changed: 122 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
1+
use std::cell::Ref;
2+
13
use libffi::middle::Type;
24
use mlua::prelude::*;
35

4-
use super::association_names::CARR_INNER;
5-
use super::c_helper::{get_ensured_size, libffi_type_from_userdata, pretty_format_userdata};
6-
use super::c_ptr::CPtr;
7-
use crate::ffi::ffi_association::{get_association, set_association};
6+
use super::{
7+
association_names::CARR_INNER,
8+
c_helper::{get_conv, get_ensured_size, libffi_type_from_userdata, pretty_format_userdata},
9+
CPtr,
10+
};
11+
use crate::ffi::{
12+
ffi_association::{get_association, set_association},
13+
FfiBox, GetNativeDataHandle, NativeConvert, NativeDataHandle, NativeSignedness, NativeSize,
14+
};
815

916
// This is a series of some type.
1017
// It provides the final size and the offset of the index,
@@ -18,24 +25,30 @@ use crate::ffi::ffi_association::{get_association, set_association};
1825
// 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.
1926

2027
pub struct CArr {
21-
element_type: Type,
28+
// element_type: Type,
2229
struct_type: Type,
2330
length: usize,
2431
field_size: usize,
2532
size: usize,
33+
conv: *const dyn NativeConvert,
2634
}
2735

2836
impl CArr {
29-
pub fn new(element_type: Type, length: usize) -> LuaResult<Self> {
30-
let struct_type = Type::structure(vec![element_type.clone(); length]);
37+
pub fn new(
38+
element_type: Type,
39+
length: usize,
40+
conv: *const dyn NativeConvert,
41+
) -> LuaResult<Self> {
3142
let field_size = get_ensured_size(element_type.as_raw_ptr())?;
43+
let struct_type = Type::structure(vec![element_type.clone(); length]);
3244

3345
Ok(Self {
34-
element_type,
46+
// element_type,
3547
struct_type,
3648
length,
3749
field_size,
3850
size: field_size * length,
51+
conv,
3952
})
4053
}
4154

@@ -45,16 +58,13 @@ impl CArr {
4558
length: usize,
4659
) -> LuaResult<LuaAnyUserData<'lua>> {
4760
let fields = libffi_type_from_userdata(lua, luatype)?;
48-
let carr = lua.create_userdata(Self::new(fields, length)?)?;
61+
let conv = unsafe { get_conv(luatype)? };
62+
let carr = lua.create_userdata(Self::new(fields, length, conv)?)?;
4963

5064
set_association(lua, CARR_INNER, &carr, luatype)?;
5165
Ok(carr)
5266
}
5367

54-
pub fn get_size(&self) -> usize {
55-
self.size
56-
}
57-
5868
pub fn get_length(&self) -> usize {
5969
self.length
6070
}
@@ -63,9 +73,9 @@ impl CArr {
6373
&self.struct_type
6474
}
6575

66-
pub fn get_element_type(&self) -> &Type {
67-
&self.element_type
68-
}
76+
// pub fn get_element_type(&self) -> &Type {
77+
// &self.element_type
78+
// }
6979

7080
// Stringify cstruct for pretty printing something like:
7181
// <CStruct( u8, i32, size = 8 )>
@@ -89,6 +99,64 @@ impl CArr {
8999
}
90100
}
91101

102+
impl NativeSize for CArr {
103+
fn get_size(&self) -> usize {
104+
self.size
105+
}
106+
}
107+
impl NativeSignedness for CArr {
108+
fn get_signedness(&self) -> bool {
109+
false
110+
}
111+
}
112+
impl NativeConvert for CArr {
113+
// FIXME: FfiBox, FfiRef support required
114+
unsafe fn luavalue_into<'lua>(
115+
&self,
116+
lua: &'lua Lua,
117+
offset: isize,
118+
data_handle: &Ref<dyn NativeDataHandle>,
119+
value: LuaValue<'lua>,
120+
) -> LuaResult<()> {
121+
let LuaValue::Table(ref table) = value else {
122+
return Err(LuaError::external("Value is not a table"));
123+
};
124+
for i in 0..self.length {
125+
let field_offset = (i * self.field_size) as isize;
126+
let data: LuaValue = table.get(i + 1)?;
127+
128+
self.conv.as_ref().unwrap().luavalue_into(
129+
lua,
130+
field_offset + offset,
131+
data_handle,
132+
data,
133+
)?;
134+
}
135+
Ok(())
136+
}
137+
138+
unsafe fn luavalue_from<'lua>(
139+
&self,
140+
lua: &'lua Lua,
141+
offset: isize,
142+
data_handle: &Ref<dyn NativeDataHandle>,
143+
) -> LuaResult<LuaValue<'lua>> {
144+
let table = lua.create_table_with_capacity(self.length, 0)?;
145+
for i in 0..self.length {
146+
let field_offset = (i * self.field_size) as isize;
147+
table.set(
148+
i + 1,
149+
self.conv.as_ref().unwrap().luavalue_from(
150+
lua,
151+
field_offset + offset,
152+
data_handle,
153+
)?,
154+
)?;
155+
}
156+
Ok(LuaValue::Table(table))
157+
}
158+
}
159+
92160
impl LuaUserData for CArr {
93161
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
94162
fields.add_field_method_get("size", |_, this| Ok(this.get_size()));
@@ -109,6 +177,44 @@ impl LuaUserData for CArr {
109177
Err(LuaError::external("Out of index"))
110178
}
111179
});
180+
methods.add_method("box", |lua, this, table: LuaValue| {
181+
let result = lua.create_userdata(FfiBox::new(this.get_size()))?;
182+
183+
unsafe { this.luavalue_into(lua, 0, &result.get_data_handle()?, table)? };
184+
Ok(result)
185+
});
186+
methods.add_method(
187+
"from",
188+
|lua, this, (userdata, offset): (LuaAnyUserData, Option<isize>)| {
189+
let offset = offset.unwrap_or(0);
190+
191+
let data_handle = &userdata.get_data_handle()?;
192+
if !data_handle.check_boundary(offset, this.get_size()) {
193+
return Err(LuaError::external("Out of bounds"));
194+
}
195+
if !data_handle.check_readable(&userdata, offset, this.get_size()) {
196+
return Err(LuaError::external("Unreadable data handle"));
197+
}
198+
199+
unsafe { this.luavalue_from(lua, offset, data_handle) }
200+
},
201+
);
202+
methods.add_method(
203+
"into",
204+
|lua, this, (userdata, value, offset): (LuaAnyUserData, LuaValue, Option<isize>)| {
205+
let offset = offset.unwrap_or(0);
206+
207+
let data_handle = &userdata.get_data_handle()?;
208+
if !data_handle.check_boundary(offset, this.size) {
209+
return Err(LuaError::external("Out of bounds"));
210+
}
211+
if !data_handle.checek_writable(&userdata, offset, this.size) {
212+
return Err(LuaError::external("Unwritable data handle"));
213+
}
214+
215+
unsafe { this.luavalue_into(lua, offset, data_handle, value) }
216+
},
217+
);
112218
methods.add_function("ptr", |lua, this: LuaAnyUserData| {
113219
let pointer = CPtr::new_from_lua_userdata(lua, &this)?;
114220
Ok(pointer)

crates/lune-std-ffi/src/c/c_helper.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@ use libffi::{low, middle::Type, raw};
66
use lune_utils::fmt::{pretty_format_value, ValueFormatConfig};
77
use mlua::prelude::*;
88

9-
use super::association_names::CTYPE_STATIC;
10-
use super::c_type::CTypeStatic;
11-
use super::types::get_ctype_conv;
12-
use super::{CArr, CPtr, CStruct};
9+
use super::{
10+
association_names::CTYPE_STATIC, types::get_ctype_conv, CArr, CPtr, CStruct, CTypeStatic,
11+
};
1312
use crate::ffi::{ffi_association::get_association, NativeConvert, FFI_STATUS_NAMES};
1413

1514
// Get the NativeConvert handle from the type UserData

crates/lune-std-ffi/src/c/c_type.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ impl<T> NativeSize for CType<T> {
8888
}
8989
}
9090

91-
pub struct CType<T: ?Sized> {
91+
pub struct CType<T> {
9292
// for ffi_ptrarray_to_raw?
9393
// libffi_cif: Cif,
9494
libffi_type: Type,

crates/lune-std-ffi/src/c/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub use self::{
1212
c_fn::CFn,
1313
c_ptr::CPtr,
1414
c_struct::CStruct,
15-
c_type::{CType, CTypeCast},
15+
c_type::{CType, CTypeCast, CTypeStatic},
1616
};
1717

1818
pub use types::create_all_c_types;

0 commit comments

Comments
 (0)