Skip to content

Commit b36948c

Browse files
committed
Implement carr, cstruct, ctype and cptr (#243)
1 parent 8c38aef commit b36948c

File tree

5 files changed

+230
-65
lines changed

5 files changed

+230
-65
lines changed

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

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
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::cptr::CPtr;
6+
use crate::ctype::{
7+
libffi_type_ensured_size, libffi_type_from_userdata, type_userdata_stringify, CType,
8+
};
59

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

17-
struct CArr {
21+
const CARR_INNER: &str = "__carr_inner";
22+
23+
pub struct CArr {
1824
libffi_type: Type,
1925
struct_type: Type,
2026
length: usize,
@@ -23,7 +29,7 @@ struct CArr {
2329
}
2430

2531
impl CArr {
26-
fn new(libffi_type: Type, length: usize) -> LuaResult<Self> {
32+
pub fn new(libffi_type: Type, length: usize) -> LuaResult<Self> {
2733
let struct_type = Type::structure(vec![libffi_type.clone(); length]);
2834
let field_size = libffi_type_ensured_size(libffi_type.as_raw_ptr())?;
2935

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

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

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

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#![allow(clippy::cargo_common_metadata)]
2+
3+
use std::borrow::Borrow;
4+
5+
use libffi::middle::Type;
6+
use mlua::prelude::*;
7+
8+
use crate::association::{get_association, set_association};
9+
use crate::carr::CArr;
10+
use crate::ctype::{type_name_from_userdata, type_userdata_stringify};
11+
12+
const POINTER_INNER: &str = "__pointer_inner";
13+
14+
pub struct CPtr();
15+
16+
impl CPtr {
17+
// Create pointer type with '.inner' field
18+
// inner can be CArr, CType or CStruct
19+
pub fn from_lua_userdata<'lua>(
20+
lua: &'lua Lua,
21+
inner: &LuaAnyUserData,
22+
) -> LuaResult<LuaValue<'lua>> {
23+
let value = Self().into_lua(lua)?;
24+
25+
set_association(lua, POINTER_INNER, value.borrow(), inner)?;
26+
27+
Ok(value)
28+
}
29+
30+
// Stringify CPtr with inner ctype
31+
pub fn stringify(userdata: &LuaAnyUserData) -> LuaResult<String> {
32+
let inner: LuaValue = userdata.get("inner")?;
33+
34+
if inner.is_userdata() {
35+
let inner = inner
36+
.as_userdata()
37+
.ok_or(LuaError::external("failed to get inner type userdata."))?;
38+
Ok(format!(
39+
" <{}({})> ",
40+
type_name_from_userdata(inner),
41+
type_userdata_stringify(inner)?,
42+
))
43+
} else {
44+
Err(LuaError::external("failed to get inner type userdata."))
45+
}
46+
}
47+
48+
// Return void*
49+
pub fn get_type() -> Type {
50+
Type::pointer()
51+
}
52+
}
53+
54+
impl LuaUserData for CPtr {
55+
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
56+
fields.add_field_method_get("size", |_, _| Ok(size_of::<usize>()));
57+
fields.add_field_function_get("inner", |lua, this| {
58+
let inner = get_association(lua, POINTER_INNER, this)?
59+
.ok_or(LuaError::external("inner type not found"))?;
60+
Ok(inner)
61+
});
62+
}
63+
64+
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
65+
methods.add_function("ptr", |lua, this: LuaAnyUserData| {
66+
let pointer = CPtr::from_lua_userdata(lua, &this)?;
67+
Ok(pointer)
68+
});
69+
methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| {
70+
let carr = CArr::from_lua_userdata(lua, &this, length)?;
71+
Ok(carr)
72+
});
73+
methods.add_meta_function(LuaMetaMethod::ToString, |_, this: LuaAnyUserData| {
74+
let name: Result<String, LuaError> = CPtr::stringify(&this);
75+
Ok(name)
76+
});
77+
}
78+
}

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

Lines changed: 26 additions & 7 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::ctype::{libffi_types_from_table, type_userdata_stringify, CType};
1413
use crate::FFI_STATUS_NAMES;
14+
use crate::{
15+
association::{get_association, set_association},
16+
ctype::type_name_from_userdata,
17+
};
18+
use crate::{carr::CArr, cptr::CPtr};
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

@@ -124,15 +138,20 @@ impl LuaUserData for CStruct {
124138
Ok(table)
125139
});
126140
}
141+
127142
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
128143
methods.add_method("offset", |_, this, index: usize| {
129144
let offset = this.offset(index)?;
130145
Ok(offset)
131146
});
132147
methods.add_function("ptr", |lua, this: LuaAnyUserData| {
133-
let pointer = CType::pointer(lua, &this)?;
148+
let pointer = CPtr::from_lua_userdata(lua, &this)?;
134149
Ok(pointer)
135150
});
151+
methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| {
152+
let carr = CArr::from_lua_userdata(lua, &this, length)?;
153+
Ok(carr)
154+
});
136155
methods.add_meta_function(LuaMetaMethod::ToString, |_, this: LuaAnyUserData| {
137156
let result = CStruct::stringify(&this)?;
138157
Ok(result)

0 commit comments

Comments
 (0)