Skip to content

Commit 46dd185

Browse files
committed
Implement call (#243)
1 parent 7ce5be2 commit 46dd185

File tree

23 files changed

+271
-113
lines changed

23 files changed

+271
-113
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ luneDocs.json
2222
luneTypes.d.luau
2323

2424
# Files generated by runtime or build scripts
25+
2526
scripts/brick_color.rs
2627
scripts/font_enum_map.rs
2728
scripts/physical_properties_enum_map.rs
29+
30+
# Files generated by tests
31+
32+
/tests/ffi/**/*.so

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ use mlua::prelude::*;
55

66
use super::{
77
association_names::CARR_INNER,
8-
c_helper::{get_conv, get_ensured_size, libffi_type_from_userdata, pretty_format_userdata},
8+
c_helper::{get_conv, libffi_type_from_userdata, pretty_format_userdata},
99
CPtr,
1010
};
1111
use crate::ffi::{
1212
ffi_association::{get_association, set_association},
1313
FfiBox, GetNativeData, NativeConvert, NativeData, NativeSize,
1414
};
15+
use crate::libffi_helper::get_ensured_size;
1516

1617
// This is a series of some type.
1718
// It provides the final size and the offset of the index,

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

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
use std::ptr;
22

3-
use libffi::low::ffi_cif;
43
use libffi::middle::{Cif, Type};
54
use mlua::prelude::*;
65

6+
use super::c_helper::{get_size, get_userdata};
77
use super::{
88
association_names::{CALLABLE_CFN, CALLABLE_REF, CFN_ARGS, CFN_RESULT},
9-
c_helper::{
10-
get_conv, get_conv_list_from_table, libffi_type_from_userdata, libffi_type_list_from_table,
11-
},
9+
c_helper::{get_conv, libffi_type_from_userdata, libffi_type_list_from_table},
1210
};
13-
use crate::ffi::bit_mask::u8_test_not;
1411
use crate::ffi::{
15-
ffi_association::set_association, FfiClosure, NativeArgInfo, NativeConvert, NativeResultInfo,
12+
bit_mask::u8_test_not, ffi_association::set_association, FfiCallable, FfiRef, FfiRefFlag,
13+
NativeArgInfo, NativeData, NativeResultInfo,
1614
};
17-
use crate::ffi::{FfiCallable, FfiRef, FfiRefFlag, NativeData};
1815

1916
// cfn is a type declaration for a function.
2017
// Basically, when calling an external function, this type declaration
@@ -33,7 +30,7 @@ use crate::ffi::{FfiCallable, FfiRef, FfiRefFlag, NativeData};
3330
// moved to a Lua function or vice versa.
3431

3532
pub struct CFn {
36-
cif: *mut ffi_cif,
33+
cif: Cif,
3734
arg_info_list: Vec<NativeArgInfo>,
3835
result_info: NativeResultInfo,
3936
}
@@ -46,37 +43,44 @@ impl CFn {
4643
ret: Type,
4744
arg_info_list: Vec<NativeArgInfo>,
4845
result_info: NativeResultInfo,
49-
) -> Self {
50-
Self {
51-
cif: Cif::new(args.clone(), ret.clone()).as_raw_ptr(),
46+
) -> LuaResult<Self> {
47+
// let cif = ;
48+
49+
Ok(Self {
50+
cif: Cif::new(args.clone(), ret.clone()),
5251
arg_info_list,
5352
result_info,
54-
}
53+
})
5554
}
5655

5756
pub fn new_from_lua_table<'lua>(
5857
lua: &'lua Lua,
59-
args: LuaTable,
58+
arg_table: LuaTable,
6059
ret: LuaAnyUserData,
6160
) -> LuaResult<LuaAnyUserData<'lua>> {
62-
let args_types = libffi_type_list_from_table(lua, &args)?;
61+
let args_types = libffi_type_list_from_table(lua, &arg_table)?;
6362
let ret_type = libffi_type_from_userdata(lua, &ret)?;
6463

65-
let mut arg_info_list = Vec::<NativeArgInfo>::with_capacity(args.raw_len());
66-
for conv in unsafe { get_conv_list_from_table(&args)? } {
67-
arg_info_list.push(NativeArgInfo { conv })
64+
let arg_len = arg_table.raw_len();
65+
let mut arg_info_list = Vec::<NativeArgInfo>::with_capacity(arg_len);
66+
for index in 0..arg_len {
67+
let userdata = get_userdata(arg_table.raw_get(index + 1)?)?;
68+
arg_info_list.push(NativeArgInfo {
69+
conv: unsafe { get_conv(&userdata)? },
70+
size: get_size(&userdata)?,
71+
});
6872
}
69-
7073
let result_info = NativeResultInfo {
7174
conv: unsafe { get_conv(&ret)? },
75+
size: get_size(&ret)?,
7276
};
7377

7478
let cfn =
75-
lua.create_userdata(Self::new(args_types, ret_type, arg_info_list, result_info))?;
79+
lua.create_userdata(Self::new(args_types, ret_type, arg_info_list, result_info)?)?;
7680

7781
// Create association to hold argument and result type
78-
set_association(lua, CFN_ARGS, &cfn, args)?;
79-
set_association(lua, CFN_ARGS, &cfn, ret)?;
82+
set_association(lua, CFN_ARGS, &cfn, arg_table)?;
83+
set_association(lua, CFN_RESULT, &cfn, ret)?;
8084

8185
Ok(cfn)
8286
}
@@ -88,22 +92,22 @@ impl LuaUserData for CFn {
8892
// lua.create_userdata(FfiClosure::new(this.cif, userdata))
8993
// })
9094
methods.add_function(
91-
"func",
95+
"caller",
9296
|lua, (cfn, function_ref): (LuaAnyUserData, LuaAnyUserData)| {
9397
let this = cfn.borrow::<CFn>()?;
9498

9599
if !function_ref.is::<FfiRef>() {
96-
return Err(LuaError::external(""));
100+
return Err(LuaError::external("argument 0 must be ffiref"));
97101
}
98102

99103
let ffi_ref = function_ref.borrow::<FfiRef>()?;
100104
if u8_test_not(ffi_ref.flags, FfiRefFlag::Function.value()) {
101-
return Err(LuaError::external(""));
105+
return Err(LuaError::external("not a function ref"));
102106
}
103107

104108
let callable = lua.create_userdata(unsafe {
105109
FfiCallable::new(
106-
this.cif,
110+
this.cif.as_raw_ptr(),
107111
ptr::from_ref(&this.arg_info_list),
108112
ptr::from_ref(&this.result_info),
109113
ffi_ref.get_pointer(0),

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

Lines changed: 26 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,26 @@
11
#![allow(clippy::inline_always)]
22

3-
use std::ptr::{self, null_mut};
4-
5-
use libffi::{low, middle::Type, raw};
3+
use libffi::middle::Type;
64
use lune_utils::fmt::{pretty_format_value, ValueFormatConfig};
75
use mlua::prelude::*;
86

97
use super::{
10-
association_names::CTYPE_STATIC, types::get_ctype_conv, CArr, CPtr, CStruct, CTypeStatic,
11-
};
12-
use crate::ffi::{
13-
ffi_association::get_association, NativeConvert, NativeSignedness, NativeSize, FFI_STATUS_NAMES,
8+
association_names::CTYPE_STATIC,
9+
types::{get_ctype_conv, get_ctype_size},
10+
CArr, CPtr, CStruct, CTypeStatic,
1411
};
12+
use crate::ffi::{ffi_association::get_association, NativeConvert, NativeSize};
13+
14+
pub fn get_userdata(value: LuaValue) -> LuaResult<LuaAnyUserData> {
15+
if let LuaValue::UserData(field_type) = value {
16+
Ok(field_type)
17+
} else {
18+
Err(LuaError::external(format!(
19+
"Unexpected field. CStruct, CType or CArr is required for element but got {}",
20+
pretty_format_value(&value, &ValueFormatConfig::new())
21+
)))
22+
}
23+
}
1524

1625
// Get the NativeConvert handle from the type UserData
1726
// 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(
3342

3443
for i in 0..len {
3544
let value: LuaValue = table.raw_get(i + 1)?;
36-
37-
if let LuaValue::UserData(field_type) = value {
38-
conv_list.push(get_conv(&field_type)?);
39-
} else {
40-
return Err(LuaError::external(format!(
41-
"Unexpected field. CStruct, CType or CArr is required for element but got {}",
42-
pretty_format_value(&value, &ValueFormatConfig::new())
43-
)));
44-
}
45+
conv_list.push(get_conv(&get_userdata(value)?)?);
4546
}
4647

4748
Ok(conv_list)
4849
}
4950

50-
// #[inline(always)]
51-
// pub fn type_size_from_userdata(this: &LuaAnyUserData) -> LuaResult<usize> {
52-
// if this.is::<CStruct>() {
53-
// Ok(this.borrow::<CStruct>()?.get_size())
54-
// } else if this.is::<CArr>() {
55-
// Ok(this.borrow::<CArr>()?.get_size())
56-
// } else {
57-
// ctype_size_from_userdata(this)
58-
// }
59-
// }
51+
pub fn get_size(this: &LuaAnyUserData) -> LuaResult<usize> {
52+
if this.is::<CStruct>() {
53+
Ok(this.borrow::<CStruct>()?.get_size())
54+
} else if this.is::<CArr>() {
55+
Ok(this.borrow::<CArr>()?.get_size())
56+
} else {
57+
get_ctype_size(this)
58+
}
59+
}
6060

6161
// get Vec<libffi_type> from table(array) of c-type userdata
6262
pub fn libffi_type_list_from_table(lua: &Lua, table: &LuaTable) -> LuaResult<Vec<Type>> {
@@ -162,26 +162,3 @@ pub fn pretty_format_userdata(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult
162162
))
163163
}
164164
}
165-
166-
// Ensure sizeof c-type (raw::libffi_type)
167-
// See: http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html
168-
pub fn get_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult<usize> {
169-
let mut cif = low::ffi_cif::default();
170-
let result = unsafe {
171-
raw::ffi_prep_cif(
172-
ptr::from_mut(&mut cif),
173-
raw::ffi_abi_FFI_DEFAULT_ABI,
174-
0,
175-
ffi_type,
176-
null_mut(),
177-
)
178-
};
179-
180-
if result != raw::ffi_status_FFI_OK {
181-
return Err(LuaError::external(format!(
182-
"ffi_get_struct_offsets failed. expected result {}, got {}",
183-
FFI_STATUS_NAMES[0], FFI_STATUS_NAMES[result as usize]
184-
)));
185-
}
186-
unsafe { Ok((*ffi_type).size) }
187-
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@
44
// but separated it for clarity.
55
// This also allows operations such as ffi.string:intoBox().
66
// (Write a string to an already existing box)
7+
8+
// FIXME: use buffer instead?

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ use lune_utils::fmt::{pretty_format_value, ValueFormatConfig};
77
use mlua::prelude::*;
88
use num::cast::AsPrimitive;
99

10-
use super::{association_names::CTYPE_STATIC, c_helper::get_ensured_size, CArr, CPtr};
10+
use super::{association_names::CTYPE_STATIC, CArr, CPtr};
1111
use crate::ffi::{
1212
ffi_association::set_association, native_num_cast, FfiBox, GetNativeData, NativeConvert,
1313
NativeData, NativeSignedness, NativeSize,
1414
};
15+
use crate::libffi_helper::get_ensured_size;
1516

1617
// We can't get a CType<T> through mlua, something like
1718
// .is::<CType<dyn Any>> will fail.
@@ -106,11 +107,9 @@ where
106107
libffi_type: Type,
107108
name: Option<&'static str>,
108109
) -> LuaResult<LuaAnyUserData<'lua>> {
109-
// let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void());
110110
let size = get_ensured_size(libffi_type.as_raw_ptr())?;
111111

112112
let ctype = Self {
113-
// libffi_cif: libffi_cfi,
114113
libffi_type,
115114
size,
116115
name,

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use mlua::prelude::*;
88
use num::cast::AsPrimitive;
99

1010
use super::{CType, CTypeCast};
11-
use crate::ffi::{NativeConvert, NativeData};
11+
use crate::ffi::{NativeConvert, NativeData, NativeSize};
1212

1313
pub mod f32;
1414
pub mod f64;
@@ -145,3 +145,18 @@ macro_rules! define_get_ctype_conv {
145145
pub unsafe fn get_ctype_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn NativeConvert> {
146146
define_get_ctype_conv!(userdata, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64)
147147
}
148+
149+
macro_rules! define_get_ctype_size {
150+
($userdata:ident, $f:ty, $( $c:ty ),*) => {
151+
if $userdata.is::<CType<$f>>() {
152+
Ok($userdata.borrow::<CType<$f>>()?.get_size())
153+
}$( else if $userdata.is::<CType<$c>>() {
154+
Ok($userdata.borrow::<CType<$c>>()?.get_size())
155+
})* else {
156+
Err(LuaError::external("Unexpected type"))
157+
}
158+
};
159+
}
160+
pub fn get_ctype_size(userdata: &LuaAnyUserData) -> LuaResult<usize> {
161+
define_get_ctype_size!(userdata, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64)
162+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ impl NativeData for FfiBox {
128128
if offset < 0 {
129129
return false;
130130
}
131-
self.size() > ((offset as usize) + size)
131+
self.size() - (offset as usize) >= size
132132
}
133133
unsafe fn get_pointer(&self, offset: isize) -> *mut () {
134134
self.data

0 commit comments

Comments
 (0)