Implement boundary check (#243)

This commit is contained in:
qwreey 2024-08-28 16:39:35 +00:00
parent 3ccb0720fd
commit b54ea519ba
No known key found for this signature in database
GPG key ID: D28DB79297A214BD
36 changed files with 925 additions and 491 deletions

View file

@ -2,7 +2,7 @@ use libffi::middle::Type;
use mlua::prelude::*;
use super::association_names::CARR_INNER;
use super::c_helper::{get_ensured_size, pretty_format_userdata, type_from_userdata};
use super::c_helper::{get_ensured_size, libffi_type_from_userdata, pretty_format_userdata};
use super::c_ptr::CPtr;
use crate::ffi::ffi_association::{get_association, set_association};
@ -44,13 +44,21 @@ impl CArr {
luatype: &LuaAnyUserData<'lua>,
length: usize,
) -> LuaResult<LuaAnyUserData<'lua>> {
let fields = type_from_userdata(lua, luatype)?;
let fields = libffi_type_from_userdata(lua, luatype)?;
let carr = lua.create_userdata(Self::new(fields, length)?)?;
set_association(lua, CARR_INNER, &carr, luatype)?;
Ok(carr)
}
pub fn get_size(&self) -> usize {
self.size
}
pub fn get_length(&self) -> usize {
self.length
}
pub fn get_type(&self) -> &Type {
&self.struct_type
}
@ -83,8 +91,8 @@ impl CArr {
impl LuaUserData for CArr {
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("size", |_, this| Ok(this.size));
fields.add_field_method_get("length", |_, this| Ok(this.length));
fields.add_field_method_get("size", |_, this| Ok(this.get_size()));
fields.add_field_method_get("length", |_, this| Ok(this.get_length()));
fields.add_field_function_get("inner", |lua, this: LuaAnyUserData| {
let inner: LuaValue = get_association(lua, CARR_INNER, this)?
// It shouldn't happen.
@ -102,7 +110,7 @@ impl LuaUserData for CArr {
}
});
methods.add_function("ptr", |lua, this: LuaAnyUserData| {
let pointer = CPtr::from_lua_userdata(lua, &this)?;
let pointer = CPtr::new_from_lua_userdata(lua, &this)?;
Ok(pointer)
});
methods.add_meta_function(LuaMetaMethod::ToString, |lua, this: LuaAnyUserData| {

View file

@ -1,7 +1,7 @@
use libffi::middle::{Cif, Type};
use mlua::prelude::*;
use super::c_helper::{type_from_userdata, type_list_from_table};
use super::c_helper::{libffi_type_from_userdata, libffi_type_list_from_table};
// cfn is a type declaration for a function.
// Basically, when calling an external function, this type declaration
@ -36,8 +36,8 @@ impl CFn {
}
pub fn new_from_lua_table(lua: &Lua, args: LuaTable, ret: LuaAnyUserData) -> LuaResult<Self> {
let args = type_list_from_table(lua, &args)?;
let ret = type_from_userdata(lua, &ret)?;
let args = libffi_type_list_from_table(lua, &args)?;
let ret = libffi_type_from_userdata(lua, &ret)?;
Ok(Self::new(args, ret))
}
}

View file

@ -1,3 +1,5 @@
#![allow(clippy::inline_always)]
use std::ptr::{self, null_mut};
use libffi::{low, middle::Type, raw};
@ -5,31 +7,70 @@ use lune_utils::fmt::{pretty_format_value, ValueFormatConfig};
use mlua::prelude::*;
use super::association_names::CTYPE_STATIC;
use super::c_arr::CArr;
use super::c_ptr::CPtr;
use super::c_struct::CStruct;
use super::c_type::CTypeStatic;
use crate::ffi::ffi_association::get_association;
use crate::ffi::ffi_helper::FFI_STATUS_NAMES;
use super::types::get_ctype_conv;
use super::{CArr, CPtr, CStruct};
use crate::ffi::{ffi_association::get_association, NativeConvert, FFI_STATUS_NAMES};
// Get the NativeConvert handle from the type UserData
// this is intended to avoid constant table lookups. (eg: struct)
// userdata must live longer than the NativeConvert handle.
// However, c_struct is a strong reference to each field, so this is not a problem.
pub unsafe fn get_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn NativeConvert> {
if userdata.is::<CStruct>() {
Ok(userdata.to_pointer().cast::<CStruct>() as *const dyn NativeConvert)
} else {
unsafe { get_ctype_conv(userdata) }
}
}
pub unsafe fn get_conv_list_from_table(
table: &LuaTable,
) -> LuaResult<Vec<*const dyn NativeConvert>> {
let len: usize = table.raw_len();
let mut conv_list = Vec::<*const dyn NativeConvert>::with_capacity(len);
for i in 0..len {
let value: LuaValue = table.raw_get(i + 1)?;
if let LuaValue::UserData(field_type) = value {
conv_list.push(get_conv(&field_type)?);
} else {
return Err(LuaError::external(format!(
"Unexpected field. CStruct, CType or CArr is required for element but got {}",
pretty_format_value(&value, &ValueFormatConfig::new())
)));
}
}
Ok(conv_list)
}
// #[inline(always)]
// pub fn type_size_from_userdata(this: &LuaAnyUserData) -> LuaResult<usize> {
// if this.is::<CStruct>() {
// Ok(this.borrow::<CStruct>()?.get_size())
// } else if this.is::<CArr>() {
// Ok(this.borrow::<CArr>()?.get_size())
// } else {
// ctype_size_from_userdata(this)
// }
// }
// get Vec<libffi_type> from table(array) of c-types userdata
pub fn type_list_from_table(lua: &Lua, table: &LuaTable) -> LuaResult<Vec<Type>> {
pub fn libffi_type_list_from_table(lua: &Lua, table: &LuaTable) -> LuaResult<Vec<Type>> {
let len: usize = table.raw_len();
let mut fields = Vec::with_capacity(len);
for i in 0..len {
// Test required
let value = table.raw_get(i + 1)?;
match value {
LuaValue::UserData(field_type) => {
fields.push(type_from_userdata(lua, &field_type)?);
}
_ => {
return Err(LuaError::external(format!(
"Unexpected field. CStruct, CType or CArr is required for element but got {}",
pretty_format_value(&value, &ValueFormatConfig::new())
)));
}
if let LuaValue::UserData(field_type) = value {
fields.push(libffi_type_from_userdata(lua, &field_type)?);
} else {
return Err(LuaError::external(format!(
"Unexpected field. CStruct, CType or CArr is required for element but got {}",
value.type_name()
)));
}
}
@ -37,7 +78,7 @@ pub fn type_list_from_table(lua: &Lua, table: &LuaTable) -> LuaResult<Vec<Type>>
}
// get libffi_type from any c-type userdata
pub fn type_from_userdata(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult<Type> {
pub fn libffi_type_from_userdata(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult<Type> {
if userdata.is::<CStruct>() {
Ok(userdata.borrow::<CStruct>()?.get_type().to_owned())
} else if let Some(t) = get_association(lua, CTYPE_STATIC, userdata)? {

View file

@ -1,11 +1,7 @@
#![allow(clippy::cargo_common_metadata)]
use libffi::middle::Type;
use mlua::prelude::*;
use super::association_names::CPTR_INNER;
use super::c_arr::CArr;
use super::c_helper::pretty_format_userdata;
use super::{association_names::CPTR_INNER, c_helper::pretty_format_userdata, CArr};
use crate::ffi::ffi_association::{get_association, set_association};
pub struct CPtr();
@ -13,7 +9,7 @@ pub struct CPtr();
impl CPtr {
// Create pointer type with '.inner' field
// inner can be CArr, CType or CStruct
pub fn from_lua_userdata<'lua>(
pub fn new_from_lua_userdata<'lua>(
lua: &'lua Lua,
inner: &LuaAnyUserData,
) -> LuaResult<LuaAnyUserData<'lua>> {
@ -56,7 +52,7 @@ impl LuaUserData for CPtr {
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_function("ptr", |lua, this: LuaAnyUserData| {
let pointer = CPtr::from_lua_userdata(lua, &this)?;
let pointer = CPtr::new_from_lua_userdata(lua, &this)?;
Ok(pointer)
});
methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| {

View file

@ -1,32 +1,38 @@
#![allow(clippy::cargo_common_metadata)]
use std::vec::Vec;
use std::{cell::Ref, vec::Vec};
use libffi::{low, middle::Type, raw};
use mlua::prelude::*;
use super::association_names::CSTRUCT_INNER;
use super::c_arr::CArr;
use super::c_helper::{pretty_format_userdata, type_list_from_table};
use super::c_ptr::CPtr;
use crate::ffi::ffi_association::{get_association, set_association};
use crate::ffi::ffi_helper::FFI_STATUS_NAMES;
use super::{
association_names::CSTRUCT_INNER,
c_helper::{get_conv_list_from_table, libffi_type_list_from_table, pretty_format_userdata},
CArr, CPtr,
};
use crate::ffi::{
ffi_association::{get_association, set_association},
FfiBox, GetNativeDataHandle, NativeConvert, NativeDataHandle, NativeSignedness, NativeSize,
FFI_STATUS_NAMES,
};
pub struct CStruct {
// libffi_cif: Cif,
fields: Vec<Type>,
// fields: Vec<Type>,
struct_type: Type,
offsets: Vec<usize>,
size: usize,
conv: Vec<*const dyn NativeConvert>,
}
impl CStruct {
pub fn new(fields: Vec<Type>) -> LuaResult<Self> {
let struct_type = Type::structure(fields.iter().cloned());
pub fn new(fields: Vec<Type>, conv: Vec<*const dyn NativeConvert>) -> LuaResult<Self> {
let len = fields.len();
let mut offsets = Vec::<usize>::with_capacity(len);
let struct_type = Type::structure(fields);
// let struct_type = Type::structure(fields.iter().cloned());
// let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void());
// Get field offsets with ffi_get_struct_offsets
let mut offsets = Vec::<usize>::with_capacity(fields.len());
// let mut offsets = Vec::<usize>::with_capacity(fields.len());
unsafe {
let offset_result: raw::ffi_status = raw::ffi_get_struct_offsets(
low::ffi_abi_FFI_DEFAULT_ABI,
@ -48,10 +54,11 @@ impl CStruct {
Ok(Self {
// libffi_cif: libffi_cfi,
fields,
// fields,
struct_type,
offsets,
size,
conv,
})
}
@ -61,8 +68,11 @@ impl CStruct {
lua: &'lua Lua,
table: LuaTable<'lua>,
) -> LuaResult<LuaAnyUserData<'lua>> {
let fields = type_list_from_table(lua, &table)?;
let cstruct = lua.create_userdata(Self::new(fields)?)?;
let cstruct = lua.create_userdata(Self::new(
libffi_type_list_from_table(lua, &table)?,
unsafe { get_conv_list_from_table(&table)? },
)?)?;
table.set_readonly(true);
set_association(lua, CSTRUCT_INNER, &cstruct, table)?;
Ok(cstruct)
@ -71,15 +81,12 @@ impl CStruct {
// Stringify cstruct for pretty printing something like:
// <CStruct( u8, i32, size = 8 )>
pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult<String> {
let field: LuaValue = userdata.get("inner")?;
if field.is_table() {
let table = field
.as_table()
.ok_or(LuaError::external("failed to get inner type table."))?;
// iterate for field
if let LuaValue::Table(fields) = get_association(lua, CSTRUCT_INNER, userdata)?
.ok_or(LuaError::external("Field table not found"))?
{
let mut result = String::from(" ");
for i in 0..table.raw_len() {
let child: LuaAnyUserData = table.raw_get(i + 1)?;
for i in 0..fields.raw_len() {
let child: LuaAnyUserData = fields.raw_get(i + 1)?;
result.push_str(pretty_format_userdata(lua, &child)?.as_str());
}
@ -101,20 +108,72 @@ impl CStruct {
Ok(offset)
}
pub fn get_fields(&self) -> &Vec<Type> {
&self.fields
}
// pub fn get_fields(&self) -> &Vec<Type> {
// &self.fields
// }
pub fn get_type(&self) -> &Type {
&self.struct_type
}
}
impl LuaUserData for CStruct {
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("size", |_, this| Ok(this.size));
impl NativeSize for CStruct {
fn get_size(&self) -> usize {
self.size
}
}
impl NativeSignedness for CStruct {
fn get_signedness(&self) -> bool {
false
}
}
impl NativeConvert for CStruct {
// FIXME: FfiBox, FfiRef support required
unsafe fn luavalue_into<'lua>(
&self,
lua: &'lua Lua,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
value: LuaValue<'lua>,
) -> LuaResult<()> {
let LuaValue::Table(ref table) = value else {
return Err(LuaError::external("Value is not a table"));
};
for (i, conv) in self.conv.iter().enumerate() {
let field_offset = self.offset(i)? as isize;
let data: LuaValue = table.get(i + 1)?;
conv.as_ref()
.unwrap()
.luavalue_into(lua, field_offset + offset, data_handle, data)?;
}
Ok(())
}
unsafe fn luavalue_from<'lua>(
&self,
lua: &'lua Lua,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
) -> LuaResult<LuaValue<'lua>> {
let table = lua.create_table_with_capacity(self.conv.len(), 0)?;
for (i, conv) in self.conv.iter().enumerate() {
let field_offset = self.offset(i)? as isize;
table.set(
i + 1,
conv.as_ref()
.unwrap()
.luavalue_from(lua, field_offset + offset, data_handle)?,
)?;
}
Ok(LuaValue::Table(table))
}
}
impl LuaUserData for CStruct {
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("size", |_, this| Ok(this.get_size()));
}
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_method("offset", |_, this, index: usize| {
let offset = this.offset(index)?;
@ -123,17 +182,55 @@ impl LuaUserData for CStruct {
// Simply pass type in the locked table used when first creating this object.
// By referencing the table to struct, the types inside do not disappear
methods.add_function("field", |lua, (this, field): (LuaAnyUserData, usize)| {
if let LuaValue::Table(t) = get_association(lua, CSTRUCT_INNER, this)?
if let LuaValue::Table(fields) = get_association(lua, CSTRUCT_INNER, this)?
.ok_or(LuaError::external("Field table not found"))?
{
let value: LuaValue = t.get(field + 1)?;
let value: LuaValue = fields.raw_get(field + 1)?;
Ok(value)
} else {
Err(LuaError::external("Failed to read field table"))
}
});
methods.add_method("box", |lua, this, table: LuaValue| {
let result = lua.create_userdata(FfiBox::new(this.get_size()))?;
unsafe { this.luavalue_into(lua, 0, &result.get_data_handle()?, table)? };
Ok(result)
});
methods.add_method(
"from",
|lua, this, (userdata, offset): (LuaAnyUserData, Option<isize>)| {
let offset = offset.unwrap_or(0);
let data_handle = &userdata.get_data_handle()?;
if !data_handle.check_boundary(offset, this.get_size()) {
return Err(LuaError::external("Out of bounds"));
}
if !data_handle.check_readable(&userdata, offset, this.get_size()) {
return Err(LuaError::external("Unreadable data handle"));
}
unsafe { this.luavalue_from(lua, offset, data_handle) }
},
);
methods.add_method(
"into",
|lua, this, (userdata, value, offset): (LuaAnyUserData, LuaValue, Option<isize>)| {
let offset = offset.unwrap_or(0);
let data_handle = &userdata.get_data_handle()?;
if !data_handle.check_boundary(offset, this.size) {
return Err(LuaError::external("Out of bounds"));
}
if !data_handle.checek_writable(&userdata, offset, this.size) {
return Err(LuaError::external("Unwritable data handle"));
}
unsafe { this.luavalue_into(lua, offset, data_handle, value) }
},
);
methods.add_function("ptr", |lua, this: LuaAnyUserData| {
let pointer = CPtr::from_lua_userdata(lua, &this)?;
let pointer = CPtr::new_from_lua_userdata(lua, &this)?;
Ok(pointer)
});
methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| {

View file

@ -1,18 +1,16 @@
#![allow(clippy::cargo_common_metadata)]
#![allow(clippy::inline_always)]
use std::marker::PhantomData;
use std::{cell::Ref, marker::PhantomData};
use libffi::middle::Type;
use lune_utils::fmt::{pretty_format_value, ValueFormatConfig};
use mlua::prelude::*;
use num::cast::AsPrimitive;
use super::{
association_names::CTYPE_STATIC, c_arr::CArr, c_helper::get_ensured_size, c_ptr::CPtr,
};
use super::{association_names::CTYPE_STATIC, c_helper::get_ensured_size, CArr, CPtr};
use crate::ffi::{
ffi_association::set_association,
ffi_native::{NativeCast, NativeConvert},
ffi_association::set_association, native_num_cast, FfiBox, GetNativeDataHandle, NativeConvert,
NativeDataHandle, NativeSignedness, NativeSize,
};
// We can't get a CType<T> through mlua, something like
@ -38,6 +36,58 @@ impl CTypeStatic {
}
impl LuaUserData for CTypeStatic {}
// Cast native data
pub trait CTypeCast {
#[inline(always)]
fn try_cast_num<T, U>(
&self,
ctype: &LuaAnyUserData,
from: &Ref<dyn NativeDataHandle>,
into: &Ref<dyn NativeDataHandle>,
) -> LuaResult<Option<()>>
where
T: AsPrimitive<U>,
U: 'static + Copy,
{
if ctype.is::<CType<U>>() {
native_num_cast::<T, U>(from, into)?;
Ok(Some(()))
} else {
Ok(None)
}
}
#[inline(always)]
fn cast(
&self,
from_ctype: &LuaAnyUserData,
into_ctype: &LuaAnyUserData,
_from: &Ref<dyn NativeDataHandle>,
_into: &Ref<dyn NativeDataHandle>,
) -> LuaResult<()> {
Err(Self::cast_failed_with(self, from_ctype, into_ctype))
}
fn cast_failed_with(
&self,
from_ctype: &LuaAnyUserData,
into_ctype: &LuaAnyUserData,
) -> LuaError {
let config = ValueFormatConfig::new();
LuaError::external(format!(
"Cannot cast {} to {}",
pretty_format_value(&LuaValue::UserData(from_ctype.to_owned()), &config),
pretty_format_value(&LuaValue::UserData(into_ctype.to_owned()), &config),
))
}
}
impl<T> NativeSize for CType<T> {
fn get_size(&self) -> usize {
self.size
}
}
pub struct CType<T: ?Sized> {
// for ffi_ptrarray_to_raw?
// libffi_cif: Cif,
@ -49,7 +99,7 @@ pub struct CType<T: ?Sized> {
impl<T> CType<T>
where
T: 'static,
Self: NativeConvert + CTypeCast + CTypeSignedness,
Self: CTypeCast + NativeSignedness + NativeConvert,
{
pub fn new_with_libffi_type<'lua>(
lua: &'lua Lua,
@ -82,101 +132,66 @@ where
}
}
}
impl<T> NativeCast for CType<T> {}
// Cast native data
pub trait CTypeCast
where
Self: NativeCast,
{
fn try_cast_num<T, U>(
&self,
ctype: &LuaAnyUserData,
from: &LuaAnyUserData,
into: &LuaAnyUserData,
) -> LuaResult<Option<()>>
where
T: AsPrimitive<U>,
U: 'static + Copy,
{
if ctype.is::<CType<U>>() {
Self::cast_num::<T, U>(self, from, into)?;
Ok(Some(()))
} else {
Ok(None)
}
}
fn cast(
&self,
from_ctype: &LuaAnyUserData,
into_ctype: &LuaAnyUserData,
from: &LuaAnyUserData,
into: &LuaAnyUserData,
) -> LuaResult<()> {
Err(Self::cast_failed_with(self, from_ctype, into_ctype))
}
fn cast_failed_with(
&self,
from_ctype: &LuaAnyUserData,
into_ctype: &LuaAnyUserData,
) -> LuaError {
let config = ValueFormatConfig::new();
LuaError::external(format!(
"Cannot cast {} to {}",
pretty_format_value(&LuaValue::UserData(from_ctype.to_owned()), &config),
pretty_format_value(&LuaValue::UserData(into_ctype.to_owned()), &config),
))
}
}
pub trait CTypeSignedness {
fn get_signedness(&self) -> bool {
true
}
}
impl<T> LuaUserData for CType<T>
where
T: 'static,
Self: CTypeCast + CTypeSignedness + NativeCast + NativeConvert,
Self: CTypeCast + NativeSignedness + NativeConvert,
{
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("size", |_, this| Ok(this.size));
fields.add_field_method_get("size", |_, this| Ok(this.get_size()));
fields.add_meta_field(LuaMetaMethod::Type, "CType");
fields.add_field_method_get("signedness", |_, this| Ok(this.get_signedness()));
}
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_function("ptr", |lua, this: LuaAnyUserData| {
CPtr::from_lua_userdata(lua, &this)
CPtr::new_from_lua_userdata(lua, &this)
});
methods.add_method("box", |lua, this, value: LuaValue| {
let result = lua.create_userdata(FfiBox::new(this.get_size()))?;
unsafe { this.luavalue_into(lua, 0, &result.get_data_handle()?, value)? };
Ok(result)
});
methods.add_function(
"from",
|lua,
(ctype, userdata, offset): (
LuaAnyUserData,
LuaAnyUserData,
Option<isize>,
)| unsafe {
ctype
.borrow::<CType<T>>()?
.read_userdata(&ctype, lua, &userdata, offset)
|lua, (this, userdata, offset): (LuaAnyUserData, LuaAnyUserData, Option<isize>)| {
let ctype = this.borrow::<Self>()?;
let offset = offset.unwrap_or(0);
let data_handle = &userdata.get_data_handle()?;
if !data_handle.check_boundary(offset, ctype.get_size()) {
return Err(LuaError::external("Out of bounds"));
}
if !data_handle.check_readable(&userdata, offset, ctype.get_size()) {
return Err(LuaError::external("Unreadable data handle"));
}
unsafe { ctype.luavalue_from(lua, offset, data_handle) }
},
);
methods.add_function(
"into",
|lua,
(ctype, value, userdata, offset): (
(this, userdata, value, offset): (
LuaAnyUserData,
LuaAnyUserData,
LuaValue,
LuaAnyUserData,
Option<isize>,
)| unsafe {
ctype
.borrow::<CType<T>>()?
.write_userdata(&ctype, lua, value, userdata, offset)
)| {
let ctype = this.borrow::<Self>()?;
let offset = offset.unwrap_or(0);
let data_handle = &userdata.get_data_handle()?;
if !data_handle.check_boundary(offset, ctype.get_size()) {
return Err(LuaError::external("Out of bounds"));
}
if !data_handle.checek_writable(&userdata, offset, ctype.get_size()) {
return Err(LuaError::external("Unwritable data handle"));
}
unsafe { ctype.luavalue_into(lua, offset, data_handle, value) }
},
);
methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| {
@ -191,9 +206,12 @@ where
LuaAnyUserData,
LuaAnyUserData,
)| {
from_type
.borrow::<Self>()?
.cast(&from_type, &into_type, &from, &into)
from_type.borrow::<Self>()?.cast(
&from_type,
&into_type,
&from.get_data_handle()?,
&into.get_data_handle()?,
)
},
);
methods.add_meta_method(LuaMetaMethod::ToString, |lua, this, ()| {

View file

View file

@ -1,15 +1,23 @@
mod c_arr;
mod c_fn;
pub mod c_helper;
mod c_ptr;
mod c_string;
mod c_struct;
mod c_type;
mod types;
pub use self::{
c_arr::CArr,
c_fn::CFn,
c_ptr::CPtr,
c_struct::CStruct,
c_type::{CType, CTypeCast},
};
pub use types::create_all_c_types;
pub use types::create_all_types;
pub mod c_arr;
pub mod c_fn;
pub mod c_helper;
pub mod c_ptr;
pub mod c_string;
pub mod c_struct;
pub mod c_type;
pub mod types;
// Named registry table names
mod association_names {
pub const CPTR_INNER: &str = "__cptr_inner";

View file

@ -1,23 +1,26 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
use super::super::c_type::{CType, CTypeSignedness};
use crate::ffi::ffi_native::NativeConvert;
use super::super::c_type::CType;
use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness};
impl CTypeSignedness for CType<f32> {
impl NativeSignedness for CType<f32> {
fn get_signedness(&self) -> bool {
true
}
}
impl NativeConvert for CType<f32> {
fn luavalue_into_ptr<'lua>(
unsafe fn luavalue_into<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
_lua: &'lua Lua,
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
value: LuaValue<'lua>,
ptr: *mut (),
) -> LuaResult<()> {
let value: f32 = match value {
LuaValue::Integer(t) => t.as_(),
@ -34,17 +37,18 @@ impl NativeConvert for CType<f32> {
}
};
unsafe {
*(ptr.cast::<f32>()) = value;
*(data_handle.get_pointer(offset).cast::<f32>()) = value;
}
Ok(())
}
fn ptr_into_luavalue<'lua>(
unsafe fn luavalue_from<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
lua: &'lua Lua,
ptr: *mut (),
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
) -> LuaResult<LuaValue<'lua>> {
let value = unsafe { (*ptr.cast::<f32>()).into_lua(lua)? };
let value = unsafe { (*data_handle.get_pointer(offset).cast::<f32>()).into_lua(lua)? };
Ok(value)
}
}

View file

@ -1,23 +1,26 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
use super::super::c_type::{CType, CTypeSignedness};
use crate::ffi::ffi_native::NativeConvert;
use super::super::c_type::CType;
use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness};
impl CTypeSignedness for CType<f64> {
impl NativeSignedness for CType<f64> {
fn get_signedness(&self) -> bool {
true
}
}
impl NativeConvert for CType<f64> {
fn luavalue_into_ptr<'lua>(
unsafe fn luavalue_into<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
_lua: &'lua Lua,
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
value: LuaValue<'lua>,
ptr: *mut (),
) -> LuaResult<()> {
let value: f64 = match value {
LuaValue::Integer(t) => t.as_(),
@ -34,17 +37,18 @@ impl NativeConvert for CType<f64> {
}
};
unsafe {
*(ptr.cast::<f64>()) = value;
*(data_handle.get_pointer(offset).cast::<f64>()) = value;
}
Ok(())
}
fn ptr_into_luavalue<'lua>(
unsafe fn luavalue_from<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
lua: &'lua Lua,
ptr: *mut (),
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
) -> LuaResult<LuaValue<'lua>> {
let value = unsafe { (*ptr.cast::<f64>()).into_lua(lua)? };
let value = unsafe { (*data_handle.get_pointer(offset).cast::<f64>()).into_lua(lua)? };
Ok(value)
}
}

View file

@ -1,23 +1,26 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
use super::super::c_type::{CType, CTypeSignedness};
use crate::ffi::ffi_native::NativeConvert;
use super::super::c_type::CType;
use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness};
impl CTypeSignedness for CType<i128> {
impl NativeSignedness for CType<i128> {
fn get_signedness(&self) -> bool {
true
}
}
impl NativeConvert for CType<i128> {
fn luavalue_into_ptr<'lua>(
unsafe fn luavalue_into<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
_lua: &'lua Lua,
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
value: LuaValue<'lua>,
ptr: *mut (),
) -> LuaResult<()> {
let value: i128 = match value {
LuaValue::Integer(t) => t.as_(),
@ -34,17 +37,18 @@ impl NativeConvert for CType<i128> {
}
};
unsafe {
*(ptr.cast::<i128>()) = value;
*(data_handle.get_pointer(offset).cast::<i128>()) = value;
}
Ok(())
}
fn ptr_into_luavalue<'lua>(
unsafe fn luavalue_from<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
lua: &'lua Lua,
ptr: *mut (),
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
) -> LuaResult<LuaValue<'lua>> {
let value = unsafe { (*ptr.cast::<i128>()).into_lua(lua)? };
let value = unsafe { (*data_handle.get_pointer(offset).cast::<i128>()).into_lua(lua)? };
Ok(value)
}
}

View file

@ -1,23 +1,26 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
use super::super::c_type::{CType, CTypeSignedness};
use crate::ffi::ffi_native::NativeConvert;
use super::super::c_type::CType;
use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness};
impl CTypeSignedness for CType<i16> {
impl NativeSignedness for CType<i16> {
fn get_signedness(&self) -> bool {
true
}
}
impl NativeConvert for CType<i16> {
fn luavalue_into_ptr<'lua>(
unsafe fn luavalue_into<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
_lua: &'lua Lua,
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
value: LuaValue<'lua>,
ptr: *mut (),
) -> LuaResult<()> {
let value: i16 = match value {
LuaValue::Integer(t) => t.as_(),
@ -34,17 +37,18 @@ impl NativeConvert for CType<i16> {
}
};
unsafe {
*(ptr.cast::<i16>()) = value;
*(data_handle.get_pointer(offset).cast::<i16>()) = value;
}
Ok(())
}
fn ptr_into_luavalue<'lua>(
unsafe fn luavalue_from<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
lua: &'lua Lua,
ptr: *mut (),
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
) -> LuaResult<LuaValue<'lua>> {
let value = unsafe { (*ptr.cast::<i16>()).into_lua(lua)? };
let value = unsafe { (*data_handle.get_pointer(offset).cast::<i16>()).into_lua(lua)? };
Ok(value)
}
}
@ -52,6 +56,6 @@ impl NativeConvert for CType<i16> {
pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
Ok((
"i16",
CType::<i16>::new_with_libffi_type(lua, Type::i16(), Some("f32"))?,
CType::<i16>::new_with_libffi_type(lua, Type::i16(), Some("i16"))?,
))
}

View file

@ -1,23 +1,26 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
use super::super::c_type::{CType, CTypeSignedness};
use crate::ffi::ffi_native::NativeConvert;
use super::super::c_type::CType;
use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness};
impl CTypeSignedness for CType<i32> {
impl NativeSignedness for CType<i32> {
fn get_signedness(&self) -> bool {
true
}
}
impl NativeConvert for CType<i32> {
fn luavalue_into_ptr<'lua>(
unsafe fn luavalue_into<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
_lua: &'lua Lua,
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
value: LuaValue<'lua>,
ptr: *mut (),
) -> LuaResult<()> {
let value: i32 = match value {
LuaValue::Integer(t) => t.as_(),
@ -34,17 +37,18 @@ impl NativeConvert for CType<i32> {
}
};
unsafe {
*(ptr.cast::<i32>()) = value;
*(data_handle.get_pointer(offset).cast::<i32>()) = value;
}
Ok(())
}
fn ptr_into_luavalue<'lua>(
unsafe fn luavalue_from<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
lua: &'lua Lua,
ptr: *mut (),
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
) -> LuaResult<LuaValue<'lua>> {
let value = unsafe { (*ptr.cast::<i32>()).into_lua(lua)? };
let value = unsafe { (*data_handle.get_pointer(offset).cast::<i32>()).into_lua(lua)? };
Ok(value)
}
}

View file

@ -1,23 +1,26 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
use super::super::c_type::{CType, CTypeSignedness};
use crate::ffi::ffi_native::NativeConvert;
use super::super::c_type::CType;
use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness};
impl CTypeSignedness for CType<i64> {
impl NativeSignedness for CType<i64> {
fn get_signedness(&self) -> bool {
true
}
}
impl NativeConvert for CType<i64> {
fn luavalue_into_ptr<'lua>(
unsafe fn luavalue_into<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
_lua: &'lua Lua,
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
value: LuaValue<'lua>,
ptr: *mut (),
) -> LuaResult<()> {
let value: i64 = match value {
LuaValue::Integer(t) => t.as_(),
@ -34,17 +37,18 @@ impl NativeConvert for CType<i64> {
}
};
unsafe {
*(ptr.cast::<i64>()) = value;
*(data_handle.get_pointer(offset).cast::<i64>()) = value;
}
Ok(())
}
fn ptr_into_luavalue<'lua>(
unsafe fn luavalue_from<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
lua: &'lua Lua,
ptr: *mut (),
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
) -> LuaResult<LuaValue<'lua>> {
let value = unsafe { (*ptr.cast::<i64>()).into_lua(lua)? };
let value = unsafe { (*data_handle.get_pointer(offset).cast::<i64>()).into_lua(lua)? };
Ok(value)
}
}

View file

@ -1,23 +1,26 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
use super::super::c_type::{CType, CTypeSignedness};
use crate::ffi::ffi_native::NativeConvert;
use super::super::c_type::CType;
use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness};
impl CTypeSignedness for CType<i8> {
impl NativeSignedness for CType<i8> {
fn get_signedness(&self) -> bool {
true
}
}
impl NativeConvert for CType<i8> {
fn luavalue_into_ptr<'lua>(
unsafe fn luavalue_into<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
_lua: &'lua Lua,
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
value: LuaValue<'lua>,
ptr: *mut (),
) -> LuaResult<()> {
let value: i8 = match value {
LuaValue::Integer(t) => t.as_(),
@ -30,17 +33,18 @@ impl NativeConvert for CType<i8> {
}
};
unsafe {
*(ptr.cast::<i8>()) = value;
*(data_handle.get_pointer(offset).cast::<i8>()) = value;
}
Ok(())
}
fn ptr_into_luavalue<'lua>(
unsafe fn luavalue_from<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
lua: &'lua Lua,
ptr: *mut (),
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
) -> LuaResult<LuaValue<'lua>> {
let value = unsafe { (*ptr.cast::<i8>()).into_lua(lua)? };
let value = unsafe { (*data_handle.get_pointer(offset).cast::<i8>()).into_lua(lua)? };
Ok(value)
}
}

View file

@ -1,23 +1,26 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
use super::super::c_type::{CType, CTypeSignedness};
use crate::ffi::ffi_native::NativeConvert;
use super::super::c_type::CType;
use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness};
impl CTypeSignedness for CType<isize> {
impl NativeSignedness for CType<isize> {
fn get_signedness(&self) -> bool {
true
}
}
impl NativeConvert for CType<isize> {
fn luavalue_into_ptr<'lua>(
unsafe fn luavalue_into<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
_lua: &'lua Lua,
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
value: LuaValue<'lua>,
ptr: *mut (),
) -> LuaResult<()> {
let value: isize = match value {
LuaValue::Integer(t) => t.as_(),
@ -34,17 +37,18 @@ impl NativeConvert for CType<isize> {
}
};
unsafe {
*(ptr.cast::<isize>()) = value;
*(data_handle.get_pointer(offset).cast::<isize>()) = value;
}
Ok(())
}
fn ptr_into_luavalue<'lua>(
unsafe fn luavalue_from<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
lua: &'lua Lua,
ptr: *mut (),
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
) -> LuaResult<LuaValue<'lua>> {
let value = unsafe { (*ptr.cast::<isize>()).into_lua(lua)? };
let value = unsafe { (*data_handle.get_pointer(offset).cast::<isize>()).into_lua(lua)? };
Ok(value)
}
}

View file

@ -1,12 +1,15 @@
#![allow(clippy::inline_always)]
use core::ffi::*;
use std::any::TypeId;
use std::cell::Ref;
use std::{any::TypeId, ops::Deref};
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
use super::c_type::CType;
use super::c_type::CTypeCast;
use super::{CType, CTypeCast};
use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness};
pub mod f32;
pub mod f64;
@ -23,6 +26,14 @@ pub mod u64;
pub mod u8;
pub mod usize;
macro_rules! cast_nums {
($T:ident, $self:ident, $from_ctype:ident, $into_ctype:ident, $from:ident, $into:ident, $t:ty, $($c:ty),*) => {
$self
.try_cast_num::<$T, $t>($into_ctype, $from, $into)?
$(.or($self.try_cast_num::<$T, $c>($into_ctype, $from, $into)?))*
.ok_or_else(|| $self.cast_failed_with($from_ctype, $into_ctype))
};
}
impl<T> CTypeCast for CType<T>
where
T: AsPrimitive<u8>
@ -44,28 +55,25 @@ where
&self,
from_ctype: &LuaAnyUserData,
into_ctype: &LuaAnyUserData,
from: &LuaAnyUserData,
into: &LuaAnyUserData,
from: &Ref<dyn NativeDataHandle>,
into: &Ref<dyn NativeDataHandle>,
) -> LuaResult<()> {
self.try_cast_num::<T, u8>(into_ctype, from, into)?
.or(self.try_cast_num::<T, u16>(into_ctype, from, into)?)
.or(self.try_cast_num::<T, u32>(into_ctype, from, into)?)
.or(self.try_cast_num::<T, u64>(into_ctype, from, into)?)
.or(self.try_cast_num::<T, u128>(into_ctype, from, into)?)
.or(self.try_cast_num::<T, i8>(into_ctype, from, into)?)
.or(self.try_cast_num::<T, i16>(into_ctype, from, into)?)
.or(self.try_cast_num::<T, i32>(into_ctype, from, into)?)
.or(self.try_cast_num::<T, i64>(into_ctype, from, into)?)
.or(self.try_cast_num::<T, i128>(into_ctype, from, into)?)
.or(self.try_cast_num::<T, f32>(into_ctype, from, into)?)
.or(self.try_cast_num::<T, f64>(into_ctype, from, into)?)
.or(self.try_cast_num::<T, usize>(into_ctype, from, into)?)
.or(self.try_cast_num::<T, isize>(into_ctype, from, into)?)
.ok_or_else(|| self.cast_failed_with(from_ctype, into_ctype))
cast_nums!(
T, self, into_ctype, from_ctype, from, into, u8, u16, u32, u64, u128, i8, i16, i128,
f32, f64, usize, isize
)
}
}
// export all default c-types
macro_rules! define_c_types {
( $lua:ident, $n:expr, $t:ident ) => {
(
$n,
CType::<$t>::new_with_libffi_type($lua, Type::$t(), Some($n))?,
)
};
}
pub fn create_all_c_types(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaAnyUserData)>> {
Ok(vec![
(
@ -77,51 +85,7 @@ pub fn create_all_c_types(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaAnyUserD
} else {
Type::c_schar()
},
Some("longlong"),
)?,
),
(
"uchar",
CType::<c_uchar>::new_with_libffi_type(lua, Type::c_uchar(), Some("uchar"))?,
),
(
"schar",
CType::<c_schar>::new_with_libffi_type(lua, Type::c_schar(), Some("schar"))?,
),
(
"short",
CType::<c_short>::new_with_libffi_type(lua, Type::c_short(), Some("short"))?,
),
(
"ushort",
CType::<c_ushort>::new_with_libffi_type(lua, Type::c_ushort(), Some("ushort"))?,
),
(
"int",
CType::<c_int>::new_with_libffi_type(lua, Type::c_int(), Some("int"))?,
),
(
"uint",
CType::<c_uint>::new_with_libffi_type(lua, Type::c_uint(), Some("uint"))?,
),
(
"long",
CType::<c_long>::new_with_libffi_type(lua, Type::c_long(), Some("long"))?,
),
(
"ulong",
CType::<c_ulong>::new_with_libffi_type(lua, Type::c_ulong(), Some("ulong"))?,
),
(
"longlong",
CType::<c_longlong>::new_with_libffi_type(lua, Type::c_longlong(), Some("longlong"))?,
),
(
"ulonglong",
CType::<c_ulonglong>::new_with_libffi_type(
lua,
Type::c_ulonglong(),
Some("ulonglong"),
Some("char"),
)?,
),
(
@ -132,6 +96,16 @@ pub fn create_all_c_types(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaAnyUserD
"double",
CType::<c_double>::new_with_libffi_type(lua, Type::f64(), Some("double"))?,
),
define_c_types!(lua, "uchar", c_uchar),
define_c_types!(lua, "schar", c_schar),
define_c_types!(lua, "short", c_short),
define_c_types!(lua, "ushort", c_ushort),
define_c_types!(lua, "int", c_int),
define_c_types!(lua, "uint", c_uint),
define_c_types!(lua, "long", c_long),
define_c_types!(lua, "ulong", c_ulong),
define_c_types!(lua, "longlong", c_longlong),
define_c_types!(lua, "ulonglong", c_ulonglong),
])
}
@ -154,3 +128,132 @@ pub fn create_all_types(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaAnyUserDat
self::isize::create_type(lua)?,
])
}
macro_rules! define_ctype_size_from_userdata {
($t:ident, $f:ty, $( $c:ty ),*) => {
if $t.is::<CType<$f>>() {
Ok(size_of::<$f>())
}$( else if $t.is::<CType<$c>>() {
Ok(size_of::<$c>())
})* else {
Err(LuaError::external("Unexpected type"))
}
};
}
#[inline(always)]
pub fn ctype_size_from_userdata(this: &LuaAnyUserData) -> LuaResult<usize> {
define_ctype_size_from_userdata!(
this, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64
)
}
macro_rules! define_ctype_luavalue_into_ptr {
($lua:ident, $this:ident, $offset:ident, $data_handle:ident, $value:ident, $f:ty, $( $c:ty ),*) => {
if $this.is::<CType<$f>>() {
let ctype = $this.borrow::<CType<$f>>()?;
ctype.luavalue_into($lua, $offset, $data_handle, $value)
}$( else if $this.is::<CType<$c>>() {
let ctype = $this.borrow::<CType<$c>>()?;
ctype.luavalue_into($lua, $offset, $data_handle, $value)
})* else {
Err(LuaError::external("Unexpected type"))
}
};
}
#[inline(always)]
pub unsafe fn ctype_luavalue_into_ptr<'lua>(
lua: &'lua Lua,
this: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
value: LuaValue<'lua>,
) -> LuaResult<()> {
define_ctype_luavalue_into_ptr!(
lua,
this,
offset,
data_handle,
value,
u8,
u16,
u32,
u64,
u128,
i8,
i16,
i32,
i64,
i128,
f32,
f64
)
}
macro_rules! define_ctype_luavalue_from_ptr {
($lua:ident, $this:ident, $offset:ident, $data_handle:ident, $f:ty, $( $c:ty ),*) => {
if $this.is::<CType<$f>>() {
$this.borrow::<CType<$f>>()?.luavalue_from($lua, $offset, $data_handle)
}$( else if $this.is::<CType<$c>>() {
$this.borrow::<CType<$c>>()?.luavalue_from($lua, $offset, $data_handle)
})* else {
Err(LuaError::external("Unexpected type"))
}
};
}
#[inline(always)]
pub unsafe fn ctype_luavalue_from_ptr<'lua>(
lua: &'lua Lua,
this: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
) -> LuaResult<LuaValue<'lua>> {
define_ctype_luavalue_from_ptr!(
lua,
this,
offset,
data_handle,
u8,
u16,
u32,
u64,
u128,
i8,
i16,
i32,
i64,
i128,
f32,
f64
)
}
// struct CastCache<'a> {
// conv: &'a [for<'lua> fn(lua: &'lua Lua)],
// ud: Box<[*const dyn NativeConvert]>,
// }
// fn test<'a>(ud: &'a LuaAnyUserData) -> LuaResult<Box<CastCache<'a>>> {
// Box::new([(ud.to_pointer() as *const CType<u8>) as *const dyn NativeConvert])
// let ff: for<'lua> unsafe fn(
// lua: &'lua Lua,
// type_userdata: &LuaAnyUserData<'lua>,
// offset: isize,
// data_handle: &Ref<dyn NativeDataHandle>,
// value: LuaValue<'lua>,
// ) -> LuaResult<()> = || CType::<f32>::luavalue_into;
// }
macro_rules! define_get_ctype_conv {
($userdata:ident, $f:ty, $( $c:ty ),*) => {
if $userdata.is::<CType<$f>>() {
Ok($userdata.to_pointer().cast::<CType<$f>>() as *const dyn NativeConvert)
}$( else if $userdata.is::<CType<$c>>() {
Ok($userdata.to_pointer().cast::<CType<$c>>() as *const dyn NativeConvert)
})* else {
Err(LuaError::external("Unexpected type"))
}
};
}
pub unsafe fn get_ctype_conv(userdata: &LuaAnyUserData) -> LuaResult<*const dyn NativeConvert> {
define_get_ctype_conv!(userdata, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64)
}

View file

@ -1,23 +1,26 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
use super::super::c_type::{CType, CTypeSignedness};
use crate::ffi::ffi_native::NativeConvert;
use super::super::c_type::CType;
use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness};
impl CTypeSignedness for CType<u128> {
impl NativeSignedness for CType<u128> {
fn get_signedness(&self) -> bool {
false
}
}
impl NativeConvert for CType<u128> {
fn luavalue_into_ptr<'lua>(
unsafe fn luavalue_into<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
_lua: &'lua Lua,
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
value: LuaValue<'lua>,
ptr: *mut (),
) -> LuaResult<()> {
let value: u128 = match value {
LuaValue::Integer(t) => t.as_(),
@ -34,17 +37,18 @@ impl NativeConvert for CType<u128> {
}
};
unsafe {
*(ptr.cast::<u128>()) = value;
*(data_handle.get_pointer(offset).cast::<u128>()) = value;
}
Ok(())
}
fn ptr_into_luavalue<'lua>(
unsafe fn luavalue_from<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
lua: &'lua Lua,
ptr: *mut (),
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
) -> LuaResult<LuaValue<'lua>> {
let value = unsafe { (*ptr.cast::<u128>()).into_lua(lua)? };
let value = unsafe { (*data_handle.get_pointer(offset).cast::<u128>()).into_lua(lua)? };
Ok(value)
}
}

View file

@ -1,11 +1,13 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
use super::super::c_type::{CType, CTypeSignedness};
use crate::ffi::ffi_native::NativeConvert;
use super::super::c_type::CType;
use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness};
impl CTypeSignedness for CType<u16> {
impl NativeSignedness for CType<u16> {
fn get_signedness(&self) -> bool {
false
}
@ -13,12 +15,13 @@ impl CTypeSignedness for CType<u16> {
impl NativeConvert for CType<u16> {
// Convert luavalue into data, then write into ptr
fn luavalue_into_ptr<'lua>(
unsafe fn luavalue_into<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
_lua: &'lua Lua,
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
value: LuaValue<'lua>,
ptr: *mut (),
) -> LuaResult<()> {
let value: u16 = match value {
LuaValue::Integer(t) => t.as_(),
@ -35,17 +38,18 @@ impl NativeConvert for CType<u16> {
}
};
unsafe {
*(ptr.cast::<u16>()) = value;
*(data_handle.get_pointer(offset).cast::<u16>()) = value;
}
Ok(())
}
fn ptr_into_luavalue<'lua>(
unsafe fn luavalue_from<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
lua: &'lua Lua,
ptr: *mut (),
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
) -> LuaResult<LuaValue<'lua>> {
let value = unsafe { (*ptr.cast::<u16>()).into_lua(lua)? };
let value = unsafe { (*data_handle.get_pointer(offset).cast::<u16>()).into_lua(lua)? };
Ok(value)
}
}

View file

@ -1,23 +1,26 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
use super::super::c_type::{CType, CTypeSignedness};
use crate::ffi::ffi_native::NativeConvert;
use super::super::c_type::CType;
use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness};
impl CTypeSignedness for CType<u32> {
impl NativeSignedness for CType<u32> {
fn get_signedness(&self) -> bool {
false
}
}
impl NativeConvert for CType<u32> {
fn luavalue_into_ptr<'lua>(
unsafe fn luavalue_into<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
_lua: &'lua Lua,
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
value: LuaValue<'lua>,
ptr: *mut (),
) -> LuaResult<()> {
let value: u32 = match value {
LuaValue::Integer(t) => t.as_(),
@ -34,17 +37,18 @@ impl NativeConvert for CType<u32> {
}
};
unsafe {
*(ptr.cast::<u32>()) = value;
*(data_handle.get_pointer(offset).cast::<u32>()) = value;
}
Ok(())
}
fn ptr_into_luavalue<'lua>(
unsafe fn luavalue_from<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
lua: &'lua Lua,
ptr: *mut (),
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
) -> LuaResult<LuaValue<'lua>> {
let value = unsafe { (*ptr.cast::<u32>()).into_lua(lua)? };
let value = unsafe { (*data_handle.get_pointer(offset).cast::<u32>()).into_lua(lua)? };
Ok(value)
}
}

View file

@ -1,23 +1,26 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
use super::super::c_type::{CType, CTypeSignedness};
use crate::ffi::ffi_native::NativeConvert;
use super::super::c_type::CType;
use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness};
impl CTypeSignedness for CType<u64> {
impl NativeSignedness for CType<u64> {
fn get_signedness(&self) -> bool {
false
}
}
impl NativeConvert for CType<u64> {
fn luavalue_into_ptr<'lua>(
unsafe fn luavalue_into<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
_lua: &'lua Lua,
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
value: LuaValue<'lua>,
ptr: *mut (),
) -> LuaResult<()> {
let value: u64 = match value {
LuaValue::Integer(t) => t.as_(),
@ -34,17 +37,18 @@ impl NativeConvert for CType<u64> {
}
};
unsafe {
*(ptr.cast::<u64>()) = value;
*(data_handle.get_pointer(offset).cast::<u64>()) = value;
}
Ok(())
}
fn ptr_into_luavalue<'lua>(
unsafe fn luavalue_from<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
lua: &'lua Lua,
ptr: *mut (),
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
) -> LuaResult<LuaValue<'lua>> {
let value = unsafe { (*ptr.cast::<u64>()).into_lua(lua)? };
let value = unsafe { (*data_handle.get_pointer(offset).cast::<u64>()).into_lua(lua)? };
Ok(value)
}
}

View file

@ -1,11 +1,13 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
use super::super::c_type::{CType, CTypeSignedness};
use crate::ffi::ffi_native::NativeConvert;
use super::super::c_type::CType;
use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness};
impl CTypeSignedness for CType<u8> {
impl NativeSignedness for CType<u8> {
fn get_signedness(&self) -> bool {
false
}
@ -13,12 +15,13 @@ impl CTypeSignedness for CType<u8> {
impl NativeConvert for CType<u8> {
// Convert luavalue into data, then write into ptr
fn luavalue_into_ptr<'lua>(
unsafe fn luavalue_into<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
_lua: &'lua Lua,
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
value: LuaValue<'lua>,
ptr: *mut (),
) -> LuaResult<()> {
let value: u8 = match value {
LuaValue::Integer(t) => t.as_(),
@ -31,19 +34,20 @@ impl NativeConvert for CType<u8> {
}
};
unsafe {
*(ptr.cast::<u8>()) = value;
*(data_handle.get_pointer(offset).cast::<u8>()) = value;
}
Ok(())
}
// Read data from ptr, then convert into luavalue
fn ptr_into_luavalue<'lua>(
unsafe fn luavalue_from<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
lua: &'lua Lua,
ptr: *mut (),
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
) -> LuaResult<LuaValue<'lua>> {
let value = unsafe { (*ptr.cast::<u8>()).into_lua(lua)? };
let value = unsafe { (*data_handle.get_pointer(offset).cast::<u8>()).into_lua(lua)? };
Ok(value)
}
}

View file

@ -1,23 +1,26 @@
use std::cell::Ref;
use libffi::middle::Type;
use mlua::prelude::*;
use num::cast::AsPrimitive;
use super::super::c_type::{CType, CTypeSignedness};
use crate::ffi::ffi_native::NativeConvert;
use super::super::c_type::CType;
use crate::ffi::{NativeConvert, NativeDataHandle, NativeSignedness};
impl CTypeSignedness for CType<usize> {
impl NativeSignedness for CType<usize> {
fn get_signedness(&self) -> bool {
false
}
}
impl NativeConvert for CType<usize> {
fn luavalue_into_ptr<'lua>(
unsafe fn luavalue_into<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
_lua: &'lua Lua,
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
value: LuaValue<'lua>,
ptr: *mut (),
) -> LuaResult<()> {
let value: usize = match value {
LuaValue::Integer(t) => t.as_(),
@ -34,17 +37,18 @@ impl NativeConvert for CType<usize> {
}
};
unsafe {
*(ptr.cast::<usize>()) = value;
*(data_handle.get_pointer(offset).cast::<usize>()) = value;
}
Ok(())
}
fn ptr_into_luavalue<'lua>(
unsafe fn luavalue_from<'lua>(
&self,
_this: &LuaAnyUserData<'lua>,
lua: &'lua Lua,
ptr: *mut (),
// _type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
) -> LuaResult<LuaValue<'lua>> {
let value = unsafe { (*ptr.cast::<usize>()).into_lua(lua)? };
let value = unsafe { (*data_handle.get_pointer(offset).cast::<usize>()).into_lua(lua)? };
Ok(value)
}
}

View file

@ -1,4 +1,4 @@
#![allow(clippy::cargo_common_metadata)]
#![allow(clippy::inline_always)]
use mlua::prelude::*;
@ -29,6 +29,8 @@ use mlua::prelude::*;
// 'value' can only hold one value. If you want to keep something else,
// use a table with a different name.
// You can delete the relationship by changing 'associated' to nil
#[inline(always)]
pub fn set_association<'lua, T, U>(
lua: &'lua Lua,
regname: &str,
@ -60,6 +62,7 @@ where
// returns the Lua value that 'value' keeps.
// If there is no table in registry, it returns None.
// If there is no value in table, it returns LuaNil.
#[inline(always)]
pub fn get_association<'lua, T>(
lua: &'lua Lua,
regname: &str,

View file

@ -1,5 +1,3 @@
#![allow(clippy::cargo_common_metadata)]
use std::boxed::Box;
use std::sync::LazyLock;
@ -7,6 +5,7 @@ use mlua::prelude::*;
use super::association_names::REF_INNER;
use super::ffi_association::set_association;
use super::ffi_native::NativeDataHandle;
use super::ffi_ref::{FfiRef, FfiRefBounds, FfiRefFlag, FfiRefFlagList};
static BOX_REF_FLAGS: LazyLock<FfiRefFlagList> = LazyLock::new(|| {
@ -26,7 +25,15 @@ static BOX_REF_FLAGS: LazyLock<FfiRefFlagList> = LazyLock::new(|| {
// rather, it creates more heap space, so it should be used appropriately
// where necessary.
pub struct FfiBox(Box<[u8]>);
struct RefData {
address: usize,
offset: usize,
}
pub struct FfiBox {
data: Box<[u8]>,
refs: Vec<RefData>,
}
impl FfiBox {
// For efficiency, it is initialized non-zeroed.
@ -40,7 +47,10 @@ impl FfiBox {
vec_heap.set_len(size);
}
Self(vec_heap.into_boxed_slice())
Self {
data: vec_heap.into_boxed_slice(),
refs: vec![],
}
}
// pub fn copy(&self, target: &mut FfiBox) {}
@ -48,7 +58,7 @@ impl FfiBox {
// Todo: if too big, print as another format
pub fn stringify(&self) -> String {
let mut buff: String = String::with_capacity(self.size() * 2);
for value in &self.0 {
for value in &self.data {
buff.push_str(format!("{:x}", value.to_be()).as_str());
}
buff
@ -66,7 +76,7 @@ impl FfiBox {
// Calculate offset
if let Some(t) = offset {
if !bounds.check(t) {
if !bounds.check_boundary(t) {
return Err(LuaError::external(format!(
"Offset is out of bounds. box.size: {}. offset got {}",
target.size(),
@ -92,17 +102,37 @@ impl FfiBox {
// Fill every field with 0
pub fn zero(&mut self) {
self.0.fill(0u8);
self.data.fill(0u8);
}
// Get size of box
pub fn size(&self) -> usize {
self.0.len()
self.data.len()
}
// Get raw ptr
pub fn get_ptr(&mut self) -> *mut u8 {
self.0.as_mut_ptr()
pub fn get_ptr(&self) -> *mut u8 {
self.data.as_ptr() as *mut u8
}
}
impl NativeDataHandle for FfiBox {
fn check_boundary(&self, offset: isize, size: usize) -> bool {
if offset < 0 {
return false;
}
self.size() > ((offset as usize) + size)
}
// FIXME
fn checek_writable(&self, userdata: &LuaAnyUserData, offset: isize, size: usize) -> bool {
true
}
// FIXME
fn check_readable(&self, userdata: &LuaAnyUserData, offset: isize, size: usize) -> bool {
true
}
unsafe fn get_pointer(&self, offset: isize) -> *mut () {
self.get_ptr().byte_offset(offset) as *mut ()
}
}
@ -110,7 +140,6 @@ impl LuaUserData for FfiBox {
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("size", |_, this| Ok(this.size()));
}
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
// For convenience, :zero returns self.
methods.add_function_mut("zero", |_, this: LuaAnyUserData| {

View file

@ -1,7 +1,4 @@
use mlua::prelude::*;
use super::ffi_box::FfiBox;
use super::ffi_ref::FfiRef;
#![allow(clippy::inline_always)]
// Converts ffi status into &str
pub const FFI_STATUS_NAMES: [&str; 4] = [
@ -11,30 +8,6 @@ pub const FFI_STATUS_NAMES: [&str; 4] = [
"ffi_status_FFI_BAD_ARGTYPE",
];
// TODO: using trait
// Get raw pointer from userdata
// TODO: boundary check
pub unsafe fn get_ptr_from_userdata(
userdata: &LuaAnyUserData,
offset: Option<isize>,
) -> LuaResult<*mut ()> {
let ptr = if userdata.is::<FfiBox>() {
userdata.borrow_mut::<FfiBox>()?.get_ptr().cast()
} else if userdata.is::<FfiRef>() {
userdata.borrow::<FfiRef>()?.get_ptr()
} else {
return Err(LuaError::external("Unexpected userdata"));
};
let ptr = if let Some(t) = offset {
ptr.cast::<u8>().offset(t).cast()
} else {
ptr
};
Ok(ptr)
}
#[allow(unused)]
pub mod bit_mask {
pub const U8_MASK1: u8 = 1;

View file

@ -1,24 +1,29 @@
#![allow(clippy::cargo_common_metadata)]
#![allow(clippy::inline_always)]
use std::cell::Ref;
use mlua::prelude::*;
use num::cast::AsPrimitive;
use super::super::ffi_helper::get_ptr_from_userdata;
use super::NativeDataHandle;
pub trait NativeCast {
// Cast T as U
fn cast_num<T, U>(&self, from: &LuaAnyUserData, into: &LuaAnyUserData) -> LuaResult<()>
where
T: AsPrimitive<U>,
U: 'static + Copy,
{
let from_ptr = unsafe { get_ptr_from_userdata(from, None)?.cast::<T>() };
let into_ptr = unsafe { get_ptr_from_userdata(into, None)?.cast::<U>() };
// Cast T as U
unsafe {
*into_ptr = (*from_ptr).as_();
}
#[inline(always)]
pub fn native_num_cast<T, U>(
from: &Ref<dyn NativeDataHandle>,
into: &Ref<dyn NativeDataHandle>,
) -> LuaResult<()>
where
T: AsPrimitive<U>,
U: 'static + Copy,
{
let from_ptr = unsafe { from.get_pointer(0).cast::<T>() };
let into_ptr = unsafe { into.get_pointer(0).cast::<U>() };
Ok(())
unsafe {
*into_ptr = (*from_ptr).as_();
}
Ok(())
}

View file

@ -1,52 +1,29 @@
#![allow(clippy::cargo_common_metadata)]
#![allow(clippy::inline_always)]
use std::cell::Ref;
use mlua::prelude::*;
use super::super::ffi_helper::get_ptr_from_userdata;
use super::NativeDataHandle;
// Handle native data, provide type conversion between luavalue and native types
pub trait NativeConvert {
// Convert luavalue into data, then write into ptr
fn luavalue_into_ptr<'lua>(
unsafe fn luavalue_into<'lua>(
&self,
this: &LuaAnyUserData<'lua>,
lua: &'lua Lua,
// type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
value: LuaValue<'lua>,
ptr: *mut (),
) -> LuaResult<()>;
// Read data from ptr, then convert into luavalue
fn ptr_into_luavalue<'lua>(
unsafe fn luavalue_from<'lua>(
&self,
this: &LuaAnyUserData<'lua>,
lua: &'lua Lua,
ptr: *mut (),
// type_userdata: &LuaAnyUserData<'lua>,
offset: isize,
data_handle: &Ref<dyn NativeDataHandle>,
) -> LuaResult<LuaValue<'lua>>;
// Read data from userdata (such as box or ref) and convert it into luavalue
unsafe fn read_userdata<'lua>(
&self,
this: &LuaAnyUserData<'lua>,
lua: &'lua Lua,
userdata: &LuaAnyUserData<'lua>,
offset: Option<isize>,
) -> LuaResult<LuaValue<'lua>> {
let ptr = unsafe { get_ptr_from_userdata(userdata, offset)? };
let value = Self::ptr_into_luavalue(self, this, lua, ptr)?;
Ok(value)
}
// Write data into userdata (such as box or ref) from luavalue
unsafe fn write_userdata<'lua>(
&self,
this: &LuaAnyUserData<'lua>,
lua: &'lua Lua,
luavalue: LuaValue<'lua>,
userdata: LuaAnyUserData<'lua>,
offset: Option<isize>,
) -> LuaResult<()> {
let ptr = unsafe { get_ptr_from_userdata(&userdata, offset)? };
Self::luavalue_into_ptr(self, this, lua, luavalue, ptr)?;
Ok(())
}
}

View file

@ -1,5 +1,18 @@
mod cast;
mod convert;
mod readwrite;
pub use self::cast::NativeCast;
pub use self::convert::NativeConvert;
pub trait NativeSize {
fn get_size(&self) -> usize;
}
pub trait NativeSignedness {
fn get_signedness(&self) -> bool {
false
}
}
pub use self::{
cast::native_num_cast, convert::NativeConvert, readwrite::GetNativeDataHandle,
readwrite::NativeDataHandle,
};

View file

@ -0,0 +1,40 @@
use std::cell::Ref;
use lune_utils::fmt::{pretty_format_value, ValueFormatConfig};
use mlua::prelude::*;
use super::super::{FfiBox, FfiRef};
pub trait NativeDataHandle {
fn check_boundary(&self, offset: isize, size: usize) -> bool;
fn check_readable(&self, userdata: &LuaAnyUserData, offset: isize, size: usize) -> bool;
fn checek_writable(&self, userdata: &LuaAnyUserData, offset: isize, size: usize) -> bool;
unsafe fn get_pointer(&self, offset: isize) -> *mut ();
}
pub trait GetNativeDataHandle {
fn get_data_handle(&self) -> LuaResult<Ref<dyn NativeDataHandle>>;
}
// I tried to remove dyn (which have little bit costs)
// But, maybe this is best option for now.
// If remove dyn, we must spam self.is::<>() / self.borrow::<>()?
// more costly....
impl GetNativeDataHandle for LuaAnyUserData<'_> {
fn get_data_handle(&self) -> LuaResult<Ref<dyn NativeDataHandle>> {
if self.is::<FfiBox>() {
Ok(self.borrow::<FfiBox>()? as Ref<dyn NativeDataHandle>)
} else if self.is::<FfiRef>() {
Ok(self.borrow::<FfiRef>()? as Ref<dyn NativeDataHandle>)
// } else if self.is::<FfiRaw>() {
// Ok(self.borrow::<FfiRaw>()? as Ref<dyn ReadWriteHandle>)
} else {
let config = ValueFormatConfig::new();
Err(LuaError::external(format!(
"Expected FfiBox, FfiRef or FfiRaw. got {}",
// what?
pretty_format_value(&LuaValue::UserData(self.to_owned()), &config)
)))
}
}
}

View file

@ -9,3 +9,5 @@
// This will help you distinguish between safe operations and
// relatively insecure operations, and help ensure that as little
// data copy as possible occurs, while allowing you to do little restrictions.
pub struct FfiRaw();

View file

@ -21,7 +21,7 @@ impl FfiRefBounds {
}
// Check boundary
pub fn check(&self, offset: isize) -> bool {
pub fn check_boundary(&self, offset: isize) -> bool {
if self.is_unsized() {
return true;
}
@ -38,16 +38,20 @@ impl FfiRefBounds {
}
// Check boundary
// Check required here
pub fn check_sized(&self, offset: isize, size: usize) -> bool {
if self.is_unsized() {
return true;
}
if offset < 0 && self.above < offset.unsigned_abs() {
return true;
}
let end = offset + (size as isize) - 1;
let sign = end.signum();
let end_sign = end.signum();
let end_abs = end.unsigned_abs();
if sign == -1 {
if end_sign == -1 {
self.above >= end_abs
} else if sign == 1 {
} else if end_sign == 1 {
self.below >= end_abs
} else {
// sign == 0

View file

@ -1,4 +1,4 @@
use super::super::ffi_helper::bit_mask::*;
use super::super::bit_mask::*;
pub enum FfiRefFlag {
Dereferenceable,

View file

@ -4,6 +4,7 @@ use mlua::prelude::*;
use super::association_names::REF_INNER;
use super::ffi_association::{get_association, set_association};
use super::ffi_native::NativeDataHandle;
mod bounds;
mod flags;
@ -21,8 +22,8 @@ pub use self::flags::{FfiRefFlag, FfiRefFlagList};
pub struct FfiRef {
ptr: *mut (),
flags: FfiRefFlagList,
boundary: FfiRefBounds,
pub flags: FfiRefFlagList,
pub boundary: FfiRefBounds,
}
impl FfiRef {
@ -97,15 +98,19 @@ impl FfiRef {
.ok_or(LuaError::external("This pointer is not offsetable."))?;
// Check boundary, if exceed, return error
self.boundary.check(offset).then_some(()).ok_or_else(|| {
LuaError::external(format!(
"Offset is out of bounds. high: {}, low: {}. offset got {}",
self.boundary.above, self.boundary.below, offset
))
})?;
self.boundary
.check_boundary(offset)
.then_some(())
.ok_or_else(|| {
LuaError::external(format!(
"Offset is out of bounds. high: {}, low: {}. offset got {}",
self.boundary.above, self.boundary.below, offset
))
})?;
let boundary = self.boundary.offset(offset);
// TODO
Ok(Self::new(
self.ptr.byte_offset(offset),
self.flags.clone(),
@ -114,6 +119,22 @@ impl FfiRef {
}
}
impl NativeDataHandle for FfiRef {
fn check_boundary(&self, offset: isize, size: usize) -> bool {
self.boundary.check_sized(offset, size)
}
fn checek_writable(&self, userdata: &LuaAnyUserData, offset: isize, size: usize) -> bool {
self.flags.is_writable()
}
// TODO: if ref points box , check box too
fn check_readable(&self, userdata: &LuaAnyUserData, offset: isize, size: usize) -> bool {
self.flags.is_readable()
}
unsafe fn get_pointer(&self, offset: isize) -> *mut () {
self.get_ptr().byte_offset(offset)
}
}
impl LuaUserData for FfiRef {
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_function("deref", |lua, this: LuaAnyUserData| {

View file

@ -1,12 +1,49 @@
pub mod ffi_association;
pub mod ffi_box;
pub mod ffi_helper;
pub mod ffi_lib;
pub mod ffi_native;
pub mod ffi_raw;
pub mod ffi_ref;
mod ffi_box;
mod ffi_lib;
mod ffi_native;
mod ffi_raw;
mod ffi_ref;
pub use self::{
ffi_box::FfiBox,
ffi_lib::FfiLib,
ffi_native::{
native_num_cast, GetNativeDataHandle, NativeConvert, NativeDataHandle, NativeSignedness,
NativeSize,
},
ffi_ref::{create_nullptr, FfiRef},
};
// Named registry table names
mod association_names {
pub const REF_INNER: &str = "__ref_inner";
}
// Converts ffi status into &str
pub const FFI_STATUS_NAMES: [&str; 4] = [
"ffi_status_FFI_OK",
"ffi_status_FFI_BAD_TYPEDEF",
"ffi_status_FFI_BAD_ABI",
"ffi_status_FFI_BAD_ARGTYPE",
];
#[allow(unused)]
pub mod bit_mask {
pub const U8_MASK1: u8 = 1;
pub const U8_MASK2: u8 = 2;
pub const U8_MASK3: u8 = 4;
pub const U8_MASK4: u8 = 8;
pub const U8_MASK5: u8 = 16;
pub const U8_MASK6: u8 = 32;
pub const U8_MASK7: u8 = 64;
pub const U8_MASK8: u8 = 128;
macro_rules! U8_TEST {
($val:expr, $mask:ident) => {
($val & $mask != 0)
};
}
pub(crate) use U8_TEST;
}

View file

@ -3,12 +3,14 @@
use lune_utils::TableBuilder;
use mlua::prelude::*;
use crate::c::{c_fn::CFn, c_struct::CStruct, create_all_c_types, create_all_types};
use crate::ffi::{ffi_box::FfiBox, ffi_lib::FfiLib, ffi_ref::create_nullptr};
mod c;
mod ffi;
use crate::{
c::{create_all_c_types, create_all_types, CFn, CStruct},
ffi::{create_nullptr, FfiBox, FfiLib},
};
/**
Creates the `ffi` standard library module.
@ -38,6 +40,7 @@ pub fn module(lua: &Lua) -> LuaResult<LuaTable> {
#[cfg(debug_assertions)]
let result = result.with_function("debug_associate", |lua, str: String| {
println!("WARNING: ffi.debug_associate is GC debug function, which only works for debug build. Do not use this function in production level codes.");
crate::ffi::ffi_association::get_table(lua, str.as_ref())
})?;