mirror of
https://github.com/lune-org/lune.git
synced 2025-04-03 01:50:55 +01:00
Void type support in call (#243)
This commit is contained in:
parent
27e250daa5
commit
a67661a753
10 changed files with 86 additions and 24 deletions
|
@ -93,6 +93,10 @@ impl CFnInfo {
|
|||
arg_table: LuaTable,
|
||||
ret: LuaAnyUserData,
|
||||
) -> LuaResult<LuaAnyUserData<'lua>> {
|
||||
if helper::has_void(&arg_table)? {
|
||||
return Err(LuaError::external("Arguments can not include void type"));
|
||||
}
|
||||
|
||||
let args_types = helper::get_middle_type_list(&arg_table)?;
|
||||
let ret_type = helper::get_middle_type(&ret)?;
|
||||
|
||||
|
|
|
@ -211,6 +211,7 @@ pub unsafe fn get_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn FfiCon
|
|||
}
|
||||
}
|
||||
|
||||
// Create vec<T> from table with (userdata)->T
|
||||
pub fn create_list<T>(
|
||||
table: &LuaTable,
|
||||
callback: fn(&LuaAnyUserData) -> LuaResult<T>,
|
||||
|
@ -226,10 +227,12 @@ pub fn create_list<T>(
|
|||
Ok(list)
|
||||
}
|
||||
|
||||
//Get
|
||||
pub unsafe fn get_conv_list(table: &LuaTable) -> LuaResult<Vec<*const dyn FfiConvert>> {
|
||||
create_list(table, |userdata| get_conv(userdata))
|
||||
}
|
||||
|
||||
// Get type size from ctype userdata
|
||||
pub fn get_size(userdata: &LuaAnyUserData) -> LuaResult<usize> {
|
||||
if userdata.is::<CStructInfo>() {
|
||||
Ok(userdata.borrow::<CStructInfo>()?.get_size())
|
||||
|
@ -244,7 +247,7 @@ pub fn get_size(userdata: &LuaAnyUserData) -> LuaResult<usize> {
|
|||
}
|
||||
}
|
||||
|
||||
// get libffi_type from any c-type userdata
|
||||
// Get libffi_type from ctype userdata
|
||||
pub fn get_middle_type(userdata: &LuaAnyUserData) -> LuaResult<Type> {
|
||||
if userdata.is::<CStructInfo>() {
|
||||
Ok(userdata.borrow::<CStructInfo>()?.get_middle_type())
|
||||
|
@ -274,6 +277,16 @@ pub fn get_middle_type_list(table: &LuaTable) -> LuaResult<Vec<Type>> {
|
|||
create_list(table, get_middle_type)
|
||||
}
|
||||
|
||||
pub fn has_void(table: &LuaTable) -> LuaResult<bool> {
|
||||
for i in 0..table.raw_len() {
|
||||
let value: LuaValue = table.raw_get(i + 1)?;
|
||||
if get_userdata(value)?.is::<CVoidInfo>() {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
// stringify any c-type userdata (for recursive)
|
||||
pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult<String> {
|
||||
if userdata.is::<CStructInfo>() {
|
||||
|
|
|
@ -15,6 +15,7 @@ pub use self::{
|
|||
struct_info::CStructInfo,
|
||||
type_info::{CTypeCast, CTypeInfo},
|
||||
types::{ctype_helper, export_ctypes},
|
||||
void_info::CVoidInfo,
|
||||
};
|
||||
|
||||
// Named registry table names
|
||||
|
|
|
@ -65,6 +65,10 @@ impl CStructInfo {
|
|||
lua: &'lua Lua,
|
||||
table: LuaTable<'lua>,
|
||||
) -> LuaResult<LuaAnyUserData<'lua>> {
|
||||
if helper::has_void(&table)? {
|
||||
return Err(LuaError::external("Void field in sturct is not allowed"));
|
||||
}
|
||||
|
||||
let cstruct = lua
|
||||
.create_userdata(Self::new(helper::get_middle_type_list(&table)?, unsafe {
|
||||
helper::get_conv_list(&table)?
|
||||
|
|
|
@ -16,6 +16,9 @@ impl FfiSize for CVoidInfo {
|
|||
}
|
||||
}
|
||||
impl CVoidInfo {
|
||||
pub fn new() -> Self {
|
||||
Self()
|
||||
}
|
||||
pub fn get_middle_type() -> Type {
|
||||
Type::void()
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use core::ffi::c_void;
|
||||
use std::cell::Ref;
|
||||
use std::ptr;
|
||||
|
||||
use libffi::{
|
||||
low::{ffi_cif, CodePtr},
|
||||
|
@ -7,7 +7,7 @@ use libffi::{
|
|||
};
|
||||
use mlua::prelude::*;
|
||||
|
||||
use super::{FfiData, GetFfiData};
|
||||
use super::GetFfiData;
|
||||
use crate::ffi::{FfiArg, FfiResult};
|
||||
|
||||
pub struct CallableData {
|
||||
|
@ -34,30 +34,38 @@ impl CallableData {
|
|||
|
||||
// TODO? async call: if have no lua closure in arguments, fficallble can be called with async way
|
||||
|
||||
pub unsafe fn call(&self, result: &Ref<dyn FfiData>, args: LuaMultiValue) -> LuaResult<()> {
|
||||
result
|
||||
.check_boundary(0, self.result_info.size)
|
||||
.then_some(())
|
||||
.ok_or_else(|| LuaError::external("result boundary check failed"))?;
|
||||
|
||||
pub unsafe fn call(&self, result: LuaValue, args: LuaMultiValue) -> LuaResult<()> {
|
||||
// cache Vec => unable to create async call but no allocation
|
||||
let mut arg_list = Vec::<*mut c_void>::with_capacity(self.arg_info_list.len());
|
||||
|
||||
let result_pointer = if self.result_info.size == 0 {
|
||||
ptr::null_mut()
|
||||
} else {
|
||||
let result_data = result.get_ffi_data()?;
|
||||
if result_data.check_boundary(0, self.result_info.size) {
|
||||
return Err(LuaError::external("Result boundary check failed"));
|
||||
}
|
||||
result_data.get_pointer()
|
||||
}
|
||||
.cast::<c_void>();
|
||||
|
||||
for index in 0..self.arg_info_list.len() {
|
||||
let arg_info = self.arg_info_list.get(index).unwrap();
|
||||
let arg = args
|
||||
.get(index)
|
||||
.ok_or_else(|| LuaError::external(format!("argument {index} required")))?;
|
||||
|
||||
let arg_pointer = if let LuaValue::UserData(userdata) = arg {
|
||||
// BoxData, RefData, ...
|
||||
let data_handle = userdata.get_ffi_data()?;
|
||||
data_handle
|
||||
.check_boundary(0, arg_info.size)
|
||||
.then_some(())
|
||||
.ok_or_else(|| {
|
||||
LuaError::external(format!("argument {index} boundary check failed"))
|
||||
})?;
|
||||
if !data_handle.check_boundary(0, arg_info.size) {
|
||||
return Err(LuaError::external(format!(
|
||||
"argument {index} boundary check failed"
|
||||
)));
|
||||
}
|
||||
data_handle.get_pointer()
|
||||
} else {
|
||||
// FIXME: buffer, string here
|
||||
return Err(LuaError::external("unimpl"));
|
||||
};
|
||||
arg_list.push(arg_pointer.cast::<c_void>());
|
||||
|
@ -66,7 +74,7 @@ impl CallableData {
|
|||
ffi_call(
|
||||
self.cif,
|
||||
Some(*self.code.as_safe_fun()),
|
||||
result.get_pointer().cast::<c_void>(),
|
||||
result_pointer,
|
||||
arg_list.as_mut_ptr(),
|
||||
);
|
||||
|
||||
|
@ -79,14 +87,11 @@ impl LuaUserData for CallableData {
|
|||
methods.add_method(
|
||||
"call",
|
||||
|_lua, this: &CallableData, mut args: LuaMultiValue| {
|
||||
let result_userdata = args.pop_front().ok_or_else(|| {
|
||||
LuaError::external("first argument must be result data handle")
|
||||
let result = args.pop_front().ok_or_else(|| {
|
||||
LuaError::external("First argument must be result data handle or nil")
|
||||
})?;
|
||||
let LuaValue::UserData(result) = result_userdata else {
|
||||
return Err(LuaError::external(""));
|
||||
};
|
||||
// FIXME: clone
|
||||
unsafe { this.call(&result.clone().get_ffi_data()?, args) }
|
||||
unsafe { this.call(result, args) }
|
||||
},
|
||||
);
|
||||
// ref, leak ..?
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#![allow(clippy::cargo_common_metadata)]
|
||||
|
||||
use c::CVoidInfo;
|
||||
use data::RefData;
|
||||
use lune_utils::TableBuilder;
|
||||
use mlua::prelude::*;
|
||||
|
@ -23,6 +24,7 @@ use crate::{
|
|||
pub fn module(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let result = TableBuilder::new(lua)?
|
||||
.with_values(export_ctypes(lua)?)?
|
||||
.with_value("void", CVoidInfo::new())?
|
||||
.with_function("nullRef", |lua, ()| create_nullptr(lua))?
|
||||
.with_function("box", |_lua, size: usize| Ok(BoxData::new(size)))?
|
||||
.with_function("open", |_lua, name: String| LibData::new(name))?
|
||||
|
|
18
tests/ffi/external_print/init.luau
Normal file
18
tests/ffi/external_print/init.luau
Normal file
|
@ -0,0 +1,18 @@
|
|||
local ffi = require("@lune/ffi")
|
||||
|
||||
local testdir = "./tests/ffi/external_print"
|
||||
|
||||
local compile = require("../utility/compile")
|
||||
compile(`{testdir}/lib.c`, `{testdir}/lib.so`)
|
||||
|
||||
local lib = ffi.open(`{testdir}/lib.so`)
|
||||
|
||||
local function test_hello_world()
|
||||
local add_int = ffi.fnInfo({}, ffi.void)
|
||||
|
||||
local hello_world_caller = add_int:callable(lib:find("hello_world"))
|
||||
|
||||
hello_world_caller:call(nil)
|
||||
end
|
||||
|
||||
test_hello_world()
|
5
tests/ffi/external_print/lib.c
Normal file
5
tests/ffi/external_print/lib.c
Normal file
|
@ -0,0 +1,5 @@
|
|||
#include<stdio.h>
|
||||
|
||||
void hello_world() {
|
||||
printf("Hello world from external function!");
|
||||
}
|
|
@ -61,6 +61,10 @@ export type CStructInfo = {
|
|||
writeData: (self: CStructInfo, target: (Ref|Box), table: { any }, offset: number?) -> (),
|
||||
}
|
||||
|
||||
export type CVoidInfo = {
|
||||
ptrInfo: (self: CVoidInfo) -> CPtrInfo<CVoidInfo>,
|
||||
}
|
||||
|
||||
type NumCType<T> = CTypeInfo<T, (number|any)>
|
||||
|
||||
-- Fixed size Rust-style types --
|
||||
|
@ -126,6 +130,7 @@ export type CTypes =
|
|||
| CPtrInfo<CTypes>
|
||||
| CFnInfo
|
||||
| CStructInfo
|
||||
| CVoidInfo
|
||||
|
||||
export type Ref = {
|
||||
deref: (self: Ref) -> Ref,
|
||||
|
@ -147,12 +152,12 @@ export type Lib = {
|
|||
}
|
||||
|
||||
export type Callable = {
|
||||
call: (self: Callable, result: (Ref | Box), ...(Ref | Box))->();
|
||||
call: (self: Callable, result: (Ref | Box)?, ...(Ref | Box))->();
|
||||
}
|
||||
|
||||
local ffi = {}
|
||||
|
||||
ffi.u8 = (nil :: unknown) :: u8
|
||||
ffi.u8 = {} :: u8
|
||||
ffi.u16 = {} :: u16
|
||||
ffi.u32 = {} :: u32
|
||||
ffi.u64 = {} :: u64
|
||||
|
@ -181,6 +186,8 @@ ffi.ulong = {} :: ulong
|
|||
ffi.longlong = {} :: longlong
|
||||
ffi.ulonglong = {} :: ulonglong
|
||||
|
||||
ffi.void = {} :: CVoidInfo
|
||||
|
||||
function ffi.nullRef(): Ref
|
||||
return nil :: any
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue