Skip to content

Commit 5c49dad

Browse files
committed
More impl for carr, cstruct, ctype
1 parent 570a4b0 commit 5c49dad

File tree

3 files changed

+139
-38
lines changed

3 files changed

+139
-38
lines changed

crates/lune-std-ffi/src/carr.rs

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
use libffi::middle::Type;
22
use mlua::prelude::*;
33

4-
use crate::ctype::libffi_type_ensured_size;
4+
use crate::association::{get_association, set_association};
5+
use crate::ctype::{
6+
libffi_type_ensured_size, libffi_type_from_userdata, type_userdata_stringify, CType,
7+
};
58

69
// This is a series of some type.
710
// It provides the final size and the offset of the index,
@@ -14,7 +17,9 @@ use crate::ctype::libffi_type_ensured_size;
1417
// Padding after each field inside the struct is set to next field can follow the alignment.
1518
// 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.
1619

17-
struct CArr {
20+
const CARR_INNER: &str = "__carr_inner";
21+
22+
pub struct CArr {
1823
libffi_type: Type,
1924
struct_type: Type,
2025
length: usize,
@@ -23,7 +28,7 @@ struct CArr {
2328
}
2429

2530
impl CArr {
26-
fn new(libffi_type: Type, length: usize) -> LuaResult<Self> {
31+
pub fn new(libffi_type: Type, length: usize) -> LuaResult<Self> {
2732
let struct_type = Type::structure(vec![libffi_type.clone(); length]);
2833
let field_size = libffi_type_ensured_size(libffi_type.as_raw_ptr())?;
2934

@@ -35,6 +40,69 @@ impl CArr {
3540
size: field_size * length,
3641
})
3742
}
43+
44+
pub fn from_lua_userdata<'lua>(
45+
lua: &'lua Lua,
46+
luatype: &LuaAnyUserData<'lua>,
47+
length: usize,
48+
) -> LuaResult<LuaAnyUserData<'lua>> {
49+
let fields = libffi_type_from_userdata(luatype)?;
50+
let carr = lua.create_userdata(Self::new(fields, length)?)?;
51+
52+
set_association(lua, CARR_INNER, carr.clone(), luatype)?;
53+
Ok(carr)
54+
}
55+
56+
pub fn get_type(&self) -> Type {
57+
self.libffi_type.clone()
58+
}
59+
60+
// Stringify cstruct for pretty printing something like:
61+
// <CStruct( u8, i32, size = 8 )>
62+
pub fn stringify(userdata: &LuaAnyUserData) -> LuaResult<String> {
63+
let inner: LuaValue = userdata.get("inner")?;
64+
let carr = userdata.borrow::<CArr>()?;
65+
if inner.is_userdata() {
66+
let inner = inner
67+
.as_userdata()
68+
.ok_or(LuaError::external("failed to get inner type userdata."))?;
69+
Ok(format!(
70+
" {} ; {} ",
71+
type_userdata_stringify(inner)?,
72+
carr.length
73+
))
74+
} else {
75+
Err(LuaError::external("failed to get inner type userdata."))
76+
}
77+
}
3878
}
3979

40-
impl LuaUserData for CArr {}
80+
impl LuaUserData for CArr {
81+
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
82+
fields.add_field_method_get("size", |_, this| Ok(this.size));
83+
fields.add_field_method_get("length", |_, this| Ok(this.length));
84+
fields.add_field_function_get("inner", |lua, this: LuaAnyUserData| {
85+
let inner: LuaValue = get_association(lua, CARR_INNER, this)?
86+
// It shouldn't happen.
87+
.ok_or(LuaError::external("inner field not found"))?;
88+
Ok(inner)
89+
});
90+
}
91+
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
92+
methods.add_method("offset", |_, this, offset: isize| {
93+
if this.length > (offset as usize) && offset >= 0 {
94+
Ok(this.field_size * (offset as usize))
95+
} else {
96+
Err(LuaError::external("Out of index"))
97+
}
98+
});
99+
methods.add_function("ptr", |lua, this: LuaAnyUserData| {
100+
let pointer = CType::pointer(lua, &this)?;
101+
Ok(pointer)
102+
});
103+
methods.add_meta_function(LuaMetaMethod::ToString, |_, this: LuaAnyUserData| {
104+
let result = CArr::stringify(&this)?;
105+
Ok(result)
106+
});
107+
}
108+
}

crates/lune-std-ffi/src/cstruct.rs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@ use libffi::{
99
};
1010
use mlua::prelude::*;
1111

12-
use crate::association::{get_association, set_association};
13-
use crate::ctype::{libffi_types_from_table, type_name_from_userdata, CType};
12+
use crate::carr::CArr;
13+
use crate::ctype::{libffi_types_from_table, type_userdata_stringify, CType};
1414
use crate::FFI_STATUS_NAMES;
15+
use crate::{
16+
association::{get_association, set_association},
17+
ctype::type_name_from_userdata,
18+
};
1519

1620
pub struct CStruct {
1721
libffi_cif: Cif,
@@ -78,20 +82,30 @@ impl CStruct {
7882
if field.is_table() {
7983
let table = field
8084
.as_table()
81-
.ok_or(LuaError::external("failed to get inner table."))?;
82-
85+
.ok_or(LuaError::external("failed to get inner type table."))?;
8386
// iterate for field
8487
let mut result = String::from(" ");
8588
for i in 0..table.raw_len() {
8689
let child: LuaAnyUserData = table.raw_get(i + 1)?;
87-
result.push_str(format!("{}, ", type_name_from_userdata(&child)?).as_str());
90+
if child.is::<CType>() {
91+
result.push_str(format!("{}, ", type_userdata_stringify(&child)?).as_str());
92+
} else {
93+
result.push_str(
94+
format!(
95+
"<{}({})>, ",
96+
type_name_from_userdata(&child),
97+
type_userdata_stringify(&child)?
98+
)
99+
.as_str(),
100+
);
101+
}
88102
}
89103

90104
// size of
91105
result.push_str(format!("size = {} ", userdata.borrow::<CStruct>()?.size).as_str());
92106
Ok(result)
93107
} else {
94-
Ok(String::from("unnamed"))
108+
Err(LuaError::external("failed to get inner type table."))
95109
}
96110
}
97111

@@ -133,6 +147,10 @@ impl LuaUserData for CStruct {
133147
let pointer = CType::pointer(lua, &this)?;
134148
Ok(pointer)
135149
});
150+
methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| {
151+
let carr = CArr::from_lua_userdata(lua, &this, length)?;
152+
Ok(carr)
153+
});
136154
methods.add_meta_function(LuaMetaMethod::ToString, |_, this: LuaAnyUserData| {
137155
let result = CStruct::stringify(&this)?;
138156
Ok(result)

crates/lune-std-ffi/src/ctype.rs

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use lune_utils::fmt::{pretty_format_value, ValueFormatConfig};
1212
use mlua::prelude::*;
1313

1414
use crate::association::{get_association, set_association};
15+
use crate::carr::CArr;
1516
use crate::cstruct::CStruct;
1617
use crate::FFI_STATUS_NAMES;
1718
// use libffi::raw::{ffi_cif, ffi_ptrarray_to_raw};
@@ -26,38 +27,32 @@ pub struct CType {
2627
}
2728

2829
impl CType {
29-
pub fn new(libffi_type: Type, name: Option<String>) -> Self {
30+
pub fn new(libffi_type: Type, name: Option<String>) -> LuaResult<Self> {
3031
let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void());
31-
let size = unsafe { (*libffi_type.as_raw_ptr()).size };
32-
Self {
32+
let size = libffi_type_ensured_size(libffi_type.as_raw_ptr())?;
33+
Ok(Self {
3334
libffi_cif: libffi_cfi,
3435
libffi_type,
3536
size,
3637
name,
37-
}
38+
})
3839
}
3940

4041
pub fn get_type(&self) -> Type {
4142
self.libffi_type.clone()
4243
}
4344

45+
// Create pointer type with '.inner' field
46+
// inner can be CArr, CType or CStruct
4447
pub fn pointer<'lua>(lua: &'lua Lua, inner: &LuaAnyUserData) -> LuaResult<LuaValue<'lua>> {
4548
let value = Self {
4649
libffi_cif: Cif::new(vec![Type::pointer()], Type::void()),
4750
libffi_type: Type::pointer(),
4851
size: size_of::<usize>(),
4952
name: Some(format!(
5053
"Ptr<{}({})>",
51-
{
52-
if inner.is::<CStruct>() {
53-
"CStruct"
54-
} else if inner.is::<CType>() {
55-
"CType"
56-
} else {
57-
"unnamed"
58-
}
59-
},
60-
type_name_from_userdata(inner)?
54+
type_name_from_userdata(inner),
55+
type_userdata_stringify(inner)?
6156
)),
6257
}
6358
.into_lua(lua)?;
@@ -92,7 +87,10 @@ impl LuaUserData for CType {
9287
let pointer = CType::pointer(lua, &this)?;
9388
Ok(pointer)
9489
});
95-
90+
methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| {
91+
let carr = CArr::from_lua_userdata(lua, &this, length)?;
92+
Ok(carr)
93+
});
9694
methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| {
9795
let name = this.stringify();
9896
Ok(name)
@@ -105,47 +103,47 @@ pub fn create_all_types(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaValue)>> {
105103
Ok(vec![
106104
(
107105
"u8",
108-
CType::new(Type::u8(), Some(String::from("u8"))).into_lua(lua)?,
106+
CType::new(Type::u8(), Some(String::from("u8")))?.into_lua(lua)?,
109107
),
110108
(
111109
"u16",
112-
CType::new(Type::u16(), Some(String::from("u16"))).into_lua(lua)?,
110+
CType::new(Type::u16(), Some(String::from("u16")))?.into_lua(lua)?,
113111
),
114112
(
115113
"u32",
116-
CType::new(Type::u32(), Some(String::from("u32"))).into_lua(lua)?,
114+
CType::new(Type::u32(), Some(String::from("u32")))?.into_lua(lua)?,
117115
),
118116
(
119117
"u64",
120-
CType::new(Type::u64(), Some(String::from("u64"))).into_lua(lua)?,
118+
CType::new(Type::u64(), Some(String::from("u64")))?.into_lua(lua)?,
121119
),
122120
(
123121
"i8",
124-
CType::new(Type::i8(), Some(String::from("i8"))).into_lua(lua)?,
122+
CType::new(Type::i8(), Some(String::from("i8")))?.into_lua(lua)?,
125123
),
126124
(
127125
"i16",
128-
CType::new(Type::i16(), Some(String::from("i16"))).into_lua(lua)?,
126+
CType::new(Type::i16(), Some(String::from("i16")))?.into_lua(lua)?,
129127
),
130128
(
131129
"i32",
132-
CType::new(Type::i32(), Some(String::from("i32"))).into_lua(lua)?,
130+
CType::new(Type::i32(), Some(String::from("i32")))?.into_lua(lua)?,
133131
),
134132
(
135133
"i64",
136-
CType::new(Type::i64(), Some(String::from("i64"))).into_lua(lua)?,
134+
CType::new(Type::i64(), Some(String::from("i64")))?.into_lua(lua)?,
137135
),
138136
(
139137
"f32",
140-
CType::new(Type::f32(), Some(String::from("f32"))).into_lua(lua)?,
138+
CType::new(Type::f32(), Some(String::from("f32")))?.into_lua(lua)?,
141139
),
142140
(
143141
"f64",
144-
CType::new(Type::f64(), Some(String::from("f64"))).into_lua(lua)?,
142+
CType::new(Type::f64(), Some(String::from("f64")))?.into_lua(lua)?,
145143
),
146144
(
147145
"void",
148-
CType::new(Type::void(), Some(String::from("void"))).into_lua(lua)?,
146+
CType::new(Type::void(), Some(String::from("void")))?.into_lua(lua)?,
149147
),
150148
])
151149
}
@@ -180,9 +178,11 @@ pub fn libffi_type_from_userdata(userdata: &LuaAnyUserData) -> LuaResult<Type> {
180178
Ok(userdata.borrow::<CStruct>()?.get_type())
181179
} else if userdata.is::<CType>() {
182180
Ok(userdata.borrow::<CType>()?.get_type())
181+
} else if userdata.is::<CArr>() {
182+
Ok(userdata.borrow::<CArr>()?.get_type())
183183
} else {
184184
Err(LuaError::external(format!(
185-
"Unexpected field. CStruct, CType or CArr is required for element but got {}",
185+
"Unexpected field. CStruct, CType, CString or CArr is required for element but got {}",
186186
pretty_format_value(
187187
// Since the data is in the Lua location,
188188
// there is no problem with the clone.
@@ -194,18 +194,33 @@ pub fn libffi_type_from_userdata(userdata: &LuaAnyUserData) -> LuaResult<Type> {
194194
}
195195

196196
// stringify any c-types userdata (for recursive)
197-
pub fn type_name_from_userdata(userdata: &LuaAnyUserData) -> LuaResult<String> {
197+
pub fn type_userdata_stringify(userdata: &LuaAnyUserData) -> LuaResult<String> {
198198
if userdata.is::<CType>() {
199199
let name = userdata.borrow::<CType>()?.stringify();
200200
Ok(name)
201201
} else if userdata.is::<CStruct>() {
202202
let name = CStruct::stringify(userdata)?;
203203
Ok(name)
204+
} else if userdata.is::<CArr>() {
205+
let name = CArr::stringify(userdata)?;
206+
Ok(name)
204207
} else {
205208
Ok(String::from("unnamed"))
206209
}
207210
}
208211

212+
pub fn type_name_from_userdata(userdata: &LuaAnyUserData) -> String {
213+
if userdata.is::<CStruct>() {
214+
String::from("CStruct")
215+
} else if userdata.is::<CType>() {
216+
String::from("CType")
217+
} else if userdata.is::<CArr>() {
218+
String::from("CArr")
219+
} else {
220+
String::from("unnamed")
221+
}
222+
}
223+
209224
// Ensure sizeof c-type (raw::libffi_type)
210225
// See: http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html
211226
pub fn libffi_type_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult<usize> {

0 commit comments

Comments
 (0)