mirror of
https://github.com/lune-org/lune.git
synced 2025-04-04 10:30:54 +01:00
Provide ptr conversion and test case (#243)
This commit is contained in:
parent
e19d9748e5
commit
7ee757ac9c
13 changed files with 160 additions and 107 deletions
|
@ -155,8 +155,8 @@ impl LuaUserData for CArrInfo {
|
||||||
|
|
||||||
// Realize
|
// Realize
|
||||||
method_provider::provide_box(methods);
|
method_provider::provide_box(methods);
|
||||||
method_provider::provide_from_data(methods);
|
method_provider::provide_read_data(methods);
|
||||||
method_provider::provide_into_data(methods);
|
method_provider::provide_write_data(methods);
|
||||||
|
|
||||||
methods.add_method("offset", |_, this, offset: isize| {
|
methods.add_method("offset", |_, this, offset: isize| {
|
||||||
if this.length > (offset as usize) && offset >= 0 {
|
if this.length > (offset as usize) && offset >= 0 {
|
||||||
|
|
|
@ -96,12 +96,7 @@ impl CFnInfo {
|
||||||
let args_types = helper::get_middle_type_list(&arg_table)?;
|
let args_types = helper::get_middle_type_list(&arg_table)?;
|
||||||
let ret_type = helper::get_middle_type(&ret)?;
|
let ret_type = helper::get_middle_type(&ret)?;
|
||||||
|
|
||||||
let arg_len = arg_table.raw_len();
|
let arg_info_list = helper::create_list(&arg_table, create_arg_info)?;
|
||||||
let mut arg_info_list = Vec::<FfiArg>::with_capacity(arg_len);
|
|
||||||
for index in 0..arg_len {
|
|
||||||
let userdata = helper::get_userdata(arg_table.raw_get(index + 1)?)?;
|
|
||||||
arg_info_list.push(create_arg_info(&userdata)?);
|
|
||||||
}
|
|
||||||
let result_info = FfiResult {
|
let result_info = FfiResult {
|
||||||
size: helper::get_size(&ret)?,
|
size: helper::get_size(&ret)?,
|
||||||
};
|
};
|
||||||
|
@ -117,7 +112,7 @@ impl CFnInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stringify for pretty printing like:
|
// Stringify for pretty printing like:
|
||||||
// <CFunc( (u8, i32) -> u8 )>
|
// <CFn( (u8, i32) -> u8 )>
|
||||||
pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult<String> {
|
pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult<String> {
|
||||||
let mut result = String::from(" (");
|
let mut result = String::from(" (");
|
||||||
if let (Some(LuaValue::Table(arg_table)), Some(LuaValue::UserData(result_userdata))) = (
|
if let (Some(LuaValue::Table(arg_table)), Some(LuaValue::UserData(result_userdata))) = (
|
||||||
|
|
|
@ -23,7 +23,7 @@ pub mod method_provider {
|
||||||
where
|
where
|
||||||
M: LuaUserDataMethods<'lua, Target>,
|
M: LuaUserDataMethods<'lua, Target>,
|
||||||
{
|
{
|
||||||
methods.add_function("pointerInfo", |lua, this: LuaAnyUserData| {
|
methods.add_function("ptrInfo", |lua, this: LuaAnyUserData| {
|
||||||
CPtrInfo::from_userdata(lua, &this)
|
CPtrInfo::from_userdata(lua, &this)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -37,17 +37,17 @@ pub mod method_provider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn provide_from_data<'lua, Target, M>(methods: &mut M)
|
pub fn provide_read_data<'lua, Target, M>(methods: &mut M)
|
||||||
where
|
where
|
||||||
Target: FfiSize + FfiConvert,
|
Target: FfiSize + FfiConvert,
|
||||||
M: LuaUserDataMethods<'lua, Target>,
|
M: LuaUserDataMethods<'lua, Target>,
|
||||||
{
|
{
|
||||||
methods.add_method(
|
methods.add_method(
|
||||||
"fromData",
|
"readData",
|
||||||
|lua, this, (userdata, offset): (LuaAnyUserData, Option<isize>)| {
|
|lua, this, (target, offset): (LuaAnyUserData, Option<isize>)| {
|
||||||
let offset = offset.unwrap_or(0);
|
let offset = offset.unwrap_or(0);
|
||||||
|
|
||||||
let data_handle = &userdata.get_data_handle()?;
|
let data_handle = &target.get_ffi_data()?;
|
||||||
if !data_handle.check_boundary(offset, this.get_size()) {
|
if !data_handle.check_boundary(offset, this.get_size()) {
|
||||||
return Err(LuaError::external("Out of bounds"));
|
return Err(LuaError::external("Out of bounds"));
|
||||||
}
|
}
|
||||||
|
@ -60,17 +60,17 @@ pub mod method_provider {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn provide_into_data<'lua, Target, M>(methods: &mut M)
|
pub fn provide_write_data<'lua, Target, M>(methods: &mut M)
|
||||||
where
|
where
|
||||||
Target: FfiSize + FfiConvert,
|
Target: FfiSize + FfiConvert,
|
||||||
M: LuaUserDataMethods<'lua, Target>,
|
M: LuaUserDataMethods<'lua, Target>,
|
||||||
{
|
{
|
||||||
methods.add_method(
|
methods.add_method(
|
||||||
"intoData",
|
"writeData",
|
||||||
|lua, this, (userdata, value, offset): (LuaAnyUserData, LuaValue, Option<isize>)| {
|
|lua, this, (target, value, offset): (LuaAnyUserData, LuaValue, Option<isize>)| {
|
||||||
let offset = offset.unwrap_or(0);
|
let offset = offset.unwrap_or(0);
|
||||||
|
|
||||||
let data_handle = &userdata.get_data_handle()?;
|
let data_handle = &target.get_ffi_data()?;
|
||||||
// use or functions
|
// use or functions
|
||||||
if !data_handle.check_boundary(offset, this.get_size()) {
|
if !data_handle.check_boundary(offset, this.get_size()) {
|
||||||
return Err(LuaError::external("Out of bounds"));
|
return Err(LuaError::external("Out of bounds"));
|
||||||
|
@ -91,7 +91,7 @@ pub mod method_provider {
|
||||||
{
|
{
|
||||||
methods.add_method("box", |lua, this, table: LuaValue| {
|
methods.add_method("box", |lua, this, table: LuaValue| {
|
||||||
let result = lua.create_userdata(BoxData::new(this.get_size()))?;
|
let result = lua.create_userdata(BoxData::new(this.get_size()))?;
|
||||||
unsafe { this.value_into_data(lua, 0, &result.get_data_handle()?, table)? };
|
unsafe { this.value_into_data(lua, 0, &result.get_ffi_data()?, table)? };
|
||||||
Ok(result)
|
Ok(result)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -121,20 +121,26 @@ pub unsafe fn get_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn FfiCon
|
||||||
Ok(userdata.to_pointer().cast::<CPtrInfo>() as *const dyn FfiConvert)
|
Ok(userdata.to_pointer().cast::<CPtrInfo>() as *const dyn FfiConvert)
|
||||||
} else {
|
} else {
|
||||||
ctype_helper::get_conv(userdata)
|
ctype_helper::get_conv(userdata)
|
||||||
// TODO: struct and more
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn get_conv_list(table: &LuaTable) -> LuaResult<Vec<*const dyn FfiConvert>> {
|
pub fn create_list<T>(
|
||||||
|
table: &LuaTable,
|
||||||
|
callback: fn(&LuaAnyUserData) -> LuaResult<T>,
|
||||||
|
) -> LuaResult<Vec<T>> {
|
||||||
let len: usize = table.raw_len();
|
let len: usize = table.raw_len();
|
||||||
let mut conv_list = Vec::<*const dyn FfiConvert>::with_capacity(len);
|
let mut list = Vec::<T>::with_capacity(len);
|
||||||
|
|
||||||
for i in 0..len {
|
for i in 0..len {
|
||||||
let value: LuaValue = table.raw_get(i + 1)?;
|
let value: LuaValue = table.raw_get(i + 1)?;
|
||||||
conv_list.push(get_conv(&get_userdata(value)?)?);
|
list.push(callback(&get_userdata(value)?)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(conv_list)
|
Ok(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn get_conv_list(table: &LuaTable) -> LuaResult<Vec<*const dyn FfiConvert>> {
|
||||||
|
create_list(table, |userdata| get_conv(userdata))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_size(this: &LuaAnyUserData) -> LuaResult<usize> {
|
pub fn get_size(this: &LuaAnyUserData) -> LuaResult<usize> {
|
||||||
|
@ -174,23 +180,7 @@ pub fn get_middle_type(userdata: &LuaAnyUserData) -> LuaResult<Type> {
|
||||||
|
|
||||||
// get Vec<libffi_type> from table(array) of c-type userdata
|
// get Vec<libffi_type> from table(array) of c-type userdata
|
||||||
pub fn get_middle_type_list(table: &LuaTable) -> LuaResult<Vec<Type>> {
|
pub fn get_middle_type_list(table: &LuaTable) -> LuaResult<Vec<Type>> {
|
||||||
let len: usize = table.raw_len();
|
create_list(table, get_middle_type)
|
||||||
let mut fields = Vec::with_capacity(len);
|
|
||||||
|
|
||||||
for i in 0..len {
|
|
||||||
// Test required
|
|
||||||
let value = table.raw_get(i + 1)?;
|
|
||||||
if let LuaValue::UserData(field_type) = value {
|
|
||||||
fields.push(get_middle_type(&field_type)?);
|
|
||||||
} else {
|
|
||||||
return Err(LuaError::external(format!(
|
|
||||||
"Unexpected field. CStruct, CType or CArr is required for element but got {}",
|
|
||||||
value.type_name()
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(fields)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// stringify any c-type userdata (for recursive)
|
// stringify any c-type userdata (for recursive)
|
||||||
|
@ -219,7 +209,7 @@ pub fn get_tag_name(userdata: &LuaAnyUserData) -> LuaResult<String> {
|
||||||
} else if userdata.is::<CPtrInfo>() {
|
} else if userdata.is::<CPtrInfo>() {
|
||||||
String::from("CPtr")
|
String::from("CPtr")
|
||||||
} else if userdata.is::<CFnInfo>() {
|
} else if userdata.is::<CFnInfo>() {
|
||||||
String::from("CFunc")
|
String::from("CFn")
|
||||||
} else if ctype_helper::is_ctype(userdata) {
|
} else if ctype_helper::is_ctype(userdata) {
|
||||||
String::from("CType")
|
String::from("CType")
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -5,14 +5,22 @@ use mlua::prelude::*;
|
||||||
|
|
||||||
use super::{association_names::CPTR_INNER, ctype_helper, helper, method_provider};
|
use super::{association_names::CPTR_INNER, ctype_helper, helper, method_provider};
|
||||||
use crate::{
|
use crate::{
|
||||||
data::RefData,
|
data::{GetFfiData, RefBounds, RefData, RefFlag},
|
||||||
ffi::{
|
ffi::{
|
||||||
association, libffi_helper::SIZE_OF_POINTER, FfiConvert, FfiData, FfiSignedness, FfiSize,
|
association, libffi_helper::SIZE_OF_POINTER, FfiConvert, FfiData, FfiSignedness, FfiSize,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const READ_CPTR_REF_FLAGS: u8 =
|
||||||
|
RefFlag::Dereferenceable.value() | RefFlag::Offsetable.value() | RefFlag::Leaked.value();
|
||||||
|
const READ_REF_FLAGS: u8 = RefFlag::Offsetable.value()
|
||||||
|
| RefFlag::Leaked.value()
|
||||||
|
| RefFlag::Readable.value()
|
||||||
|
| RefFlag::Writable.value();
|
||||||
|
|
||||||
pub struct CPtrInfo {
|
pub struct CPtrInfo {
|
||||||
inner_size: usize,
|
inner_size: usize,
|
||||||
|
inner_is_cptr: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FfiSignedness for CPtrInfo {
|
impl FfiSignedness for CPtrInfo {
|
||||||
|
@ -34,34 +42,47 @@ impl FfiConvert for CPtrInfo {
|
||||||
data_handle: &Ref<dyn FfiData>,
|
data_handle: &Ref<dyn FfiData>,
|
||||||
value: LuaValue<'lua>,
|
value: LuaValue<'lua>,
|
||||||
) -> LuaResult<()> {
|
) -> LuaResult<()> {
|
||||||
if let LuaValue::UserData(value_userdata) = value {
|
let value_userdata = value
|
||||||
if value_userdata.is::<RefData>() {
|
.as_userdata()
|
||||||
let value_ref = value_userdata.borrow::<RefData>()?;
|
.ok_or_else(|| LuaError::external("CPtrInfo:writeRef only allows data"))?;
|
||||||
value_ref
|
|
||||||
.check_boundary(0, self.inner_size)
|
data_handle
|
||||||
.then_some(())
|
.check_boundary(offset, self.get_size())
|
||||||
.ok_or_else(|| LuaError::external("boundary check failed"))?;
|
.then_some(())
|
||||||
*data_handle
|
.ok_or_else(|| LuaError::external("Out of bounds"))?;
|
||||||
.get_pointer()
|
data_handle
|
||||||
.byte_offset(offset)
|
.is_writable()
|
||||||
.cast::<*mut ()>() = value_ref.get_pointer();
|
.then_some(())
|
||||||
Ok(())
|
.ok_or_else(|| LuaError::external("Unwritable data handle"))?;
|
||||||
} else {
|
|
||||||
Err(LuaError::external("Ptr:into only allows FfiRef"))
|
*data_handle
|
||||||
}
|
.get_pointer()
|
||||||
} else {
|
.byte_offset(offset)
|
||||||
Err(LuaError::external("Conversion of pointer is not allowed"))
|
.cast::<*mut ()>() = value_userdata.get_ffi_data()?.get_pointer();
|
||||||
}
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read data from ptr, then convert into luavalue
|
// Read data from ptr, then convert into luavalue
|
||||||
unsafe fn value_from_data<'lua>(
|
unsafe fn value_from_data<'lua>(
|
||||||
&self,
|
&self,
|
||||||
_lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
_offset: isize,
|
offset: isize,
|
||||||
_data_handle: &Ref<dyn FfiData>,
|
data_handle: &Ref<dyn FfiData>,
|
||||||
) -> LuaResult<LuaValue<'lua>> {
|
) -> LuaResult<LuaValue<'lua>> {
|
||||||
Err(LuaError::external("Conversion of pointer is not allowed"))
|
if !data_handle.check_boundary(offset, SIZE_OF_POINTER) {
|
||||||
|
return Err(LuaError::external("Out of bounds"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(LuaValue::UserData(lua.create_userdata(RefData::new(
|
||||||
|
unsafe { data_handle.get_pointer().byte_offset(offset) },
|
||||||
|
if self.inner_is_cptr {
|
||||||
|
READ_CPTR_REF_FLAGS
|
||||||
|
} else {
|
||||||
|
READ_REF_FLAGS
|
||||||
|
},
|
||||||
|
RefBounds::new(0, self.inner_size),
|
||||||
|
))?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,6 +95,7 @@ impl CPtrInfo {
|
||||||
) -> LuaResult<LuaAnyUserData<'lua>> {
|
) -> LuaResult<LuaAnyUserData<'lua>> {
|
||||||
let value = lua.create_userdata(Self {
|
let value = lua.create_userdata(Self {
|
||||||
inner_size: helper::get_size(inner)?,
|
inner_size: helper::get_size(inner)?,
|
||||||
|
inner_is_cptr: inner.is::<CPtrInfo>(),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
association::set(lua, CPTR_INNER, &value, inner)?;
|
association::set(lua, CPTR_INNER, &value, inner)?;
|
||||||
|
@ -118,5 +140,18 @@ impl LuaUserData for CPtrInfo {
|
||||||
|
|
||||||
// ToString
|
// ToString
|
||||||
method_provider::provide_to_string(methods);
|
method_provider::provide_to_string(methods);
|
||||||
|
|
||||||
|
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()?)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
methods.add_method(
|
||||||
|
"writeRef",
|
||||||
|
|lua, this, (target, value, offset): (LuaAnyUserData, LuaValue, Option<isize>)| unsafe {
|
||||||
|
this.value_into_data(lua, offset.unwrap_or(0), &target.get_ffi_data()?, value)
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,7 +115,6 @@ impl FfiSignedness for CStructInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl FfiConvert for CStructInfo {
|
impl FfiConvert for CStructInfo {
|
||||||
// FIXME: FfiBox, FfiRef support required
|
|
||||||
unsafe fn value_into_data<'lua>(
|
unsafe fn value_into_data<'lua>(
|
||||||
&self,
|
&self,
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
|
@ -126,9 +125,9 @@ impl FfiConvert for CStructInfo {
|
||||||
let LuaValue::Table(ref table) = value else {
|
let LuaValue::Table(ref table) = value else {
|
||||||
return Err(LuaError::external("Value is not a table"));
|
return Err(LuaError::external("Value is not a table"));
|
||||||
};
|
};
|
||||||
for (i, conv) in self.inner_conv_list.iter().enumerate() {
|
for (index, conv) in self.inner_conv_list.iter().enumerate() {
|
||||||
let field_offset = self.offset(i)? as isize;
|
let field_offset = self.offset(index)? as isize;
|
||||||
let data: LuaValue = table.get(i + 1)?;
|
let data: LuaValue = table.get(index + 1)?;
|
||||||
|
|
||||||
conv.as_ref().unwrap().value_into_data(
|
conv.as_ref().unwrap().value_into_data(
|
||||||
lua,
|
lua,
|
||||||
|
@ -174,8 +173,8 @@ impl LuaUserData for CStructInfo {
|
||||||
|
|
||||||
// Realize
|
// Realize
|
||||||
method_provider::provide_box(methods);
|
method_provider::provide_box(methods);
|
||||||
method_provider::provide_from_data(methods);
|
method_provider::provide_read_data(methods);
|
||||||
method_provider::provide_into_data(methods);
|
method_provider::provide_write_data(methods);
|
||||||
|
|
||||||
methods.add_method("offset", |_, this, index: usize| {
|
methods.add_method("offset", |_, this, index: usize| {
|
||||||
let offset = this.offset(index)?;
|
let offset = this.offset(index)?;
|
||||||
|
|
|
@ -58,7 +58,7 @@ where
|
||||||
T: 'static,
|
T: 'static,
|
||||||
Self: CTypeCast + FfiSignedness + FfiConvert + FfiSize,
|
Self: CTypeCast + FfiSignedness + FfiConvert + FfiSize,
|
||||||
{
|
{
|
||||||
pub fn new_with_libffi_type<'lua>(
|
pub fn from_middle_type<'lua>(
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
libffi_type: Type,
|
libffi_type: Type,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
|
@ -106,8 +106,8 @@ where
|
||||||
|
|
||||||
// Realize
|
// Realize
|
||||||
method_provider::provide_box(methods);
|
method_provider::provide_box(methods);
|
||||||
method_provider::provide_from_data(methods);
|
method_provider::provide_read_data(methods);
|
||||||
method_provider::provide_into_data(methods);
|
method_provider::provide_write_data(methods);
|
||||||
|
|
||||||
methods.add_function(
|
methods.add_function(
|
||||||
"cast",
|
"cast",
|
||||||
|
@ -121,8 +121,8 @@ where
|
||||||
from_type.borrow::<Self>()?.cast(
|
from_type.borrow::<Self>()?.cast(
|
||||||
&from_type,
|
&from_type,
|
||||||
&into_type,
|
&into_type,
|
||||||
&from.get_data_handle()?,
|
&from.get_ffi_data()?,
|
||||||
&into.get_data_handle()?,
|
&into.get_ffi_data()?,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -30,7 +30,7 @@ macro_rules! create_ctypes {
|
||||||
($lua:ident, $(( $name:expr, $rust_type:ty, $libffi_type:expr ),)* ) => {
|
($lua:ident, $(( $name:expr, $rust_type:ty, $libffi_type:expr ),)* ) => {
|
||||||
Ok(vec![$((
|
Ok(vec![$((
|
||||||
$name,
|
$name,
|
||||||
CTypeInfo::<$rust_type>::new_with_libffi_type($lua, $libffi_type, $name)?,
|
CTypeInfo::<$rust_type>::from_middle_type($lua, $libffi_type, $name)?,
|
||||||
),)*])
|
),)*])
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ impl CallableData {
|
||||||
.get(index)
|
.get(index)
|
||||||
.ok_or_else(|| LuaError::external(format!("argument {index} required")))?;
|
.ok_or_else(|| LuaError::external(format!("argument {index} required")))?;
|
||||||
let arg_pointer = if let LuaValue::UserData(userdata) = arg {
|
let arg_pointer = if let LuaValue::UserData(userdata) = arg {
|
||||||
let data_handle = userdata.get_data_handle()?;
|
let data_handle = userdata.get_ffi_data()?;
|
||||||
data_handle
|
data_handle
|
||||||
.check_boundary(0, arg_info.size)
|
.check_boundary(0, arg_info.size)
|
||||||
.then_some(())
|
.then_some(())
|
||||||
|
@ -86,7 +86,7 @@ impl LuaUserData for CallableData {
|
||||||
return Err(LuaError::external(""));
|
return Err(LuaError::external(""));
|
||||||
};
|
};
|
||||||
// FIXME: clone
|
// FIXME: clone
|
||||||
unsafe { this.call(&result.clone().get_data_handle()?, args) }
|
unsafe { this.call(&result.clone().get_ffi_data()?, args) }
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
// ref, leak ..?
|
// ref, leak ..?
|
||||||
|
|
|
@ -25,24 +25,44 @@ mod association_names {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait GetFfiData {
|
pub trait GetFfiData {
|
||||||
fn get_data_handle(&self) -> LuaResult<Ref<dyn FfiData>>;
|
fn get_ffi_data(&self) -> LuaResult<Ref<dyn FfiData>>;
|
||||||
|
fn is_ffi_data(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GetFfiData for LuaAnyUserData<'_> {
|
impl GetFfiData for LuaAnyUserData<'_> {
|
||||||
fn get_data_handle(&self) -> LuaResult<Ref<dyn FfiData>> {
|
fn get_ffi_data(&self) -> LuaResult<Ref<dyn FfiData>> {
|
||||||
if self.is::<BoxData>() {
|
if self.is::<BoxData>() {
|
||||||
Ok(self.borrow::<BoxData>()? as Ref<dyn FfiData>)
|
Ok(self.borrow::<BoxData>()? as Ref<dyn FfiData>)
|
||||||
} else if self.is::<RefData>() {
|
} else if self.is::<RefData>() {
|
||||||
Ok(self.borrow::<RefData>()? as Ref<dyn FfiData>)
|
Ok(self.borrow::<RefData>()? as Ref<dyn FfiData>)
|
||||||
// } else if self.is::<FfiRaw>() {
|
} else if self.is::<ClosureData>() {
|
||||||
// Ok(self.borrow::<FfiRaw>()? as Ref<dyn ReadWriteHandle>)
|
Ok(self.borrow::<ClosureData>()? as Ref<dyn FfiData>)
|
||||||
} else {
|
} else {
|
||||||
let config = ValueFormatConfig::new();
|
let config = ValueFormatConfig::new();
|
||||||
Err(LuaError::external(format!(
|
Err(LuaError::external(format!(
|
||||||
"Expected FfiBox, FfiRef or FfiRaw. got {}",
|
"Expected FfiBox, FfiRef or ClosureData. got {}",
|
||||||
// what?
|
|
||||||
pretty_format_value(&LuaValue::UserData(self.to_owned()), &config)
|
pretty_format_value(&LuaValue::UserData(self.to_owned()), &config)
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn is_ffi_data(&self) -> bool {
|
||||||
|
self.is::<BoxData>() | self.is::<RefData>() | self.is::<ClosureData>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetFfiData for LuaValue<'_> {
|
||||||
|
fn get_ffi_data(&self) -> LuaResult<Ref<dyn FfiData>> {
|
||||||
|
self.as_userdata()
|
||||||
|
.ok_or_else(|| {
|
||||||
|
let config = ValueFormatConfig::new();
|
||||||
|
LuaError::external(format!(
|
||||||
|
"Expected FfiBox, FfiRef or ClosureData. got {}",
|
||||||
|
pretty_format_value(self, &config)
|
||||||
|
))
|
||||||
|
})?
|
||||||
|
.get_ffi_data()
|
||||||
|
}
|
||||||
|
fn is_ffi_data(&self) -> bool {
|
||||||
|
self.as_userdata().map_or(false, GetFfiData::is_ffi_data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,16 +8,16 @@ compile(`{testdir}/lib.c`, `{testdir}/lib.so`)
|
||||||
local lib = ffi.open(`{testdir}/lib.so`)
|
local lib = ffi.open(`{testdir}/lib.so`)
|
||||||
|
|
||||||
local function test_add_int()
|
local function test_add_int()
|
||||||
local add_int = ffi.fn({ ffi.int, ffi.int }, ffi.int)
|
local add_int = ffi.fnInfo({ ffi.int, ffi.int }, ffi.int)
|
||||||
|
|
||||||
local add_int_caller = add_int:caller(lib:find("add_int"))
|
local add_int_caller = add_int:callable(lib:find("add_int"))
|
||||||
|
|
||||||
local resultBox = ffi.box(ffi.int.size)
|
local resultBox = ffi.box(ffi.int.size)
|
||||||
local arg1 = ffi.int:box(100)
|
local arg1 = ffi.int:box(100)
|
||||||
local arg2 = ffi.int:box(200)
|
local arg2 = ffi.int:box(200)
|
||||||
|
|
||||||
add_int_caller:call(resultBox, arg1, arg2)
|
add_int_caller:call(resultBox, arg1, arg2)
|
||||||
local result = ffi.int:from(resultBox)
|
local result = ffi.int:readData(resultBox)
|
||||||
|
|
||||||
assert(result == 300, `add_int failed. result expected 300, got {result}`)
|
assert(result == 300, `add_int failed. result expected 300, got {result}`)
|
||||||
end
|
end
|
||||||
|
@ -25,16 +25,16 @@ end
|
||||||
test_add_int()
|
test_add_int()
|
||||||
|
|
||||||
local function test_mul_int()
|
local function test_mul_int()
|
||||||
local mul_int = ffi.fn({ ffi.int, ffi.int }, ffi.int)
|
local mul_int = ffi.fnInfo({ ffi.int, ffi.int }, ffi.int)
|
||||||
|
|
||||||
local mul_int_caller = mul_int:caller(lib:find("mul_int"))
|
local mul_int_caller = mul_int:callable(lib:find("mul_int"))
|
||||||
|
|
||||||
local resultBox = ffi.box(ffi.int.size)
|
local resultBox = ffi.box(ffi.int.size)
|
||||||
local arg1 = ffi.int:box(100)
|
local arg1 = ffi.int:box(100)
|
||||||
local arg2 = ffi.int:box(200)
|
local arg2 = ffi.int:box(200)
|
||||||
|
|
||||||
mul_int_caller:call(resultBox, arg1, arg2)
|
mul_int_caller:call(resultBox, arg1, arg2)
|
||||||
local result = ffi.int:from(resultBox)
|
local result = ffi.int:readData(resultBox)
|
||||||
|
|
||||||
assert(result == 20000, `mul_int failed. result expected 20000, got {result}`)
|
assert(result == 20000, `mul_int failed. result expected 20000, got {result}`)
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,12 +8,12 @@ compile(`{testdir}/lib.c`, `{testdir}/lib.so`)
|
||||||
local lib = ffi.open(`{testdir}/lib.so`)
|
local lib = ffi.open(`{testdir}/lib.so`)
|
||||||
|
|
||||||
local function test_AB()
|
local function test_AB()
|
||||||
local ArgStruct = ffi.struct({ ffi.int, ffi.int:ptr() })
|
local ArgStruct = ffi.structInfo({ ffi.int, ffi.int:ptrInfo() })
|
||||||
local ResultStruct = ffi.struct({ ffi.int, ffi.int })
|
local ResultStruct = ffi.structInfo({ ffi.int, ffi.int })
|
||||||
|
|
||||||
local AB = ffi.fn({ ArgStruct }, ResultStruct)
|
local AB = ffi.fnInfo({ ArgStruct }, ResultStruct)
|
||||||
|
|
||||||
local AB_caller = AB:caller(lib:find("AB"))
|
local AB_caller = AB:callable(lib:find("AB"))
|
||||||
|
|
||||||
local resultBox = ffi.box(ffi.int.size)
|
local resultBox = ffi.box(ffi.int.size)
|
||||||
local a = ffi.int:box(100)
|
local a = ffi.int:box(100)
|
||||||
|
@ -21,7 +21,7 @@ local function test_AB()
|
||||||
local arg = ArgStruct:box({ a, b:leak() })
|
local arg = ArgStruct:box({ a, b:leak() })
|
||||||
|
|
||||||
AB_caller:call(resultBox, arg)
|
AB_caller:call(resultBox, arg)
|
||||||
local result = ResultStruct:from(resultBox)
|
local result = ResultStruct:readData(resultBox)
|
||||||
|
|
||||||
assert(result[0] == 300, `AB failed. result expected 300, got {result}`)
|
assert(result[0] == 300, `AB failed. result expected 300, got {result}`)
|
||||||
assert(result[1] == 20000, `AB failed. result expected 300, got {result}`)
|
assert(result[1] == 20000, `AB failed. result expected 300, got {result}`)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
local process = require("@lune/process")
|
local process = require("@lune/process")
|
||||||
local function compile(file, out)
|
local function compile(file, out)
|
||||||
local gcc = process.spawn("gcc", { "-shared", "-o", out, "-fPIC", file })
|
local gcc = process.exec("gcc", { "-shared", "-o", out, "-fPIC", file })
|
||||||
if not gcc.ok then
|
if not gcc.ok then
|
||||||
error("Failed to execute gcc command\n" .. gcc.stdout .. gcc.stderr)
|
error("Failed to execute gcc command\n" .. gcc.stdout .. gcc.stderr)
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,9 +9,9 @@ export type CTypeInfo<T, R> = {
|
||||||
|
|
||||||
-- realize
|
-- realize
|
||||||
box: (self: CTypeInfo<T, R>, val: R) -> Box,
|
box: (self: CTypeInfo<T, R>, val: R) -> Box,
|
||||||
fromData: (self: CTypeInfo<T, R>, data: (Ref|Box), offset: number?) -> R,
|
readData: (self: CTypeInfo<T, R>, target: (Ref|Box), offset: number?) -> R,
|
||||||
intoData: (self: CTypeInfo<T, R>, data: (Ref|Box), value: R, offset: number?) -> (),
|
writeData: (self: CTypeInfo<T, R>, target: (Ref|Box), value: R, offset: number?) -> (),
|
||||||
|
|
||||||
-- FIXME: recursive types; 'intoType' should be CTypes
|
-- FIXME: recursive types; 'intoType' should be CTypes
|
||||||
cast: (self: CTypeInfo<T, R>, intoType: any, fromData: (Ref|Box), intoData: (Ref|Box)) -> (),
|
cast: (self: CTypeInfo<T, R>, intoType: any, fromData: (Ref|Box), intoData: (Ref|Box)) -> (),
|
||||||
} & { ["__phantom"]: T }
|
} & { ["__phantom"]: T }
|
||||||
|
@ -24,6 +24,10 @@ export type CPtrInfo<T> = {
|
||||||
-- FIXME: recursive types; 'any' should be CPtrInfo
|
-- FIXME: recursive types; 'any' should be CPtrInfo
|
||||||
arrInfo: (self: CPtrInfo<T>, len: number) -> any,
|
arrInfo: (self: CPtrInfo<T>, len: number) -> any,
|
||||||
ptrInfo: (self: CPtrInfo<T>) -> any,
|
ptrInfo: (self: CPtrInfo<T>) -> any,
|
||||||
|
|
||||||
|
readRef: (self: CPtrInfo<T>, target: (Ref|Box), offset: number?) -> Ref,
|
||||||
|
writeRef: (self: CPtrInfo<T>, target: (Ref|Box), value: (Ref|Box), offset: number?) -> (),
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CArrInfo<T, R> = {
|
export type CArrInfo<T, R> = {
|
||||||
|
@ -36,19 +40,24 @@ export type CArrInfo<T, R> = {
|
||||||
|
|
||||||
-- realize
|
-- realize
|
||||||
box: (self: CArrInfo<T, R>, table: { T }) -> Box,
|
box: (self: CArrInfo<T, R>, table: { T }) -> Box,
|
||||||
fromData: (self: CArrInfo<T, R>, data: (Ref|Box), offset: number?) -> { T },
|
readData: (self: CArrInfo<T, R>, target: (Ref|Box), offset: number?) -> { T },
|
||||||
intoData: (self: CArrInfo<T, R>, data: (Ref|Box), value: { T }, offset: number?) -> (),
|
writeData: (self: CArrInfo<T, R>, target: (Ref|Box), value: { T }, offset: number?) -> (),
|
||||||
|
|
||||||
offset: (self: CArrInfo<T, R>, offset: number) -> number,
|
offset: (self: CArrInfo<T, R>, offset: number) -> number,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CFuncInfo = {
|
export type CFnInfo = {
|
||||||
callable: (self: CFuncInfo, functionRef: Ref) -> Callable,
|
callable: (self: CFnInfo, functionRef: Ref) -> Callable,
|
||||||
|
closure: (self: CFnInfo, (...Ref)->()) -> (),
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CStructInfo = {
|
export type CStructInfo = {
|
||||||
arrInfo: (self: CStructInfo, len: number) -> CArrInfo<CStructInfo, {any}>,
|
arrInfo: (self: CStructInfo, len: number) -> CArrInfo<CStructInfo, {any}>,
|
||||||
ptrInfo: (self: CStructInfo) -> CPtrInfo<CStructInfo>,
|
ptrInfo: (self: CStructInfo) -> CPtrInfo<CStructInfo>,
|
||||||
|
|
||||||
|
box: (self: CStructInfo, table: { any }) -> Box,
|
||||||
|
readData: (self: CStructInfo, target: (Ref|Box), offset: number?) -> { any },
|
||||||
|
writeData: (self: CStructInfo, target: (Ref|Box), table: { any }, offset: number?) -> (),
|
||||||
}
|
}
|
||||||
|
|
||||||
type NumCType<T> = CTypeInfo<T, (number|any)>
|
type NumCType<T> = CTypeInfo<T, (number|any)>
|
||||||
|
@ -114,7 +123,8 @@ export type CTypes =
|
||||||
| ulonglong
|
| ulonglong
|
||||||
| CArrInfo<CTypes, any>
|
| CArrInfo<CTypes, any>
|
||||||
| CPtrInfo<CTypes>
|
| CPtrInfo<CTypes>
|
||||||
| CFuncInfo
|
| CFnInfo
|
||||||
|
| CStructInfo
|
||||||
|
|
||||||
export type Ref = {
|
export type Ref = {
|
||||||
deref: (self: Ref) -> Ref,
|
deref: (self: Ref) -> Ref,
|
||||||
|
@ -136,7 +146,7 @@ export type Lib = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Callable = {
|
export type Callable = {
|
||||||
call: (self: Callable, result: Ref, ...(Ref | Box))->();
|
call: (self: Callable, result: (Ref | Box), ...(Ref | Box))->();
|
||||||
}
|
}
|
||||||
|
|
||||||
local ffi = {}
|
local ffi = {}
|
||||||
|
@ -190,7 +200,11 @@ function ffi.isInteger<T>(val: T): boolean
|
||||||
return nil :: any
|
return nil :: any
|
||||||
end
|
end
|
||||||
|
|
||||||
function ffi.funcInfo<T>(args: { CTypes }, ret: CTypes): CFuncInfo
|
function ffi.fnInfo(args: { CTypes }, ret: CTypes): CFnInfo
|
||||||
|
return nil :: any
|
||||||
|
end
|
||||||
|
|
||||||
|
function ffi.structInfo(inner: { CTypes }): CStructInfo
|
||||||
return nil :: any
|
return nil :: any
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue