Skip to content

Commit

Permalink
More impl
Browse files Browse the repository at this point in the history
ffi:
    Cleaned up the code

    ref: high, low mem range for bound check
    platform: add platform value such as ffi.os, ffi.endian, ffi.arch, ffi.family
  • Loading branch information
qwreey committed Aug 25, 2024
1 parent 975723f commit d63c3dd
Show file tree
Hide file tree
Showing 11 changed files with 319 additions and 92 deletions.
26 changes: 20 additions & 6 deletions crates/lune-std-ffi/src/carr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ use mlua::prelude::*;

use crate::association::{get_association, set_association};
use crate::association_names::CARR_INNER;
use crate::chelper::{get_ensured_size, stringify_userdata, type_from_userdata};
use crate::chelper::{
get_ensured_size, name_from_userdata, stringify_userdata, type_from_userdata,
};
use crate::cptr::CPtr;
use crate::ctype::CType;

// This is a series of some type.
// It provides the final size and the offset of the index,
Expand Down Expand Up @@ -60,15 +63,26 @@ impl CArr {
pub fn stringify(userdata: &LuaAnyUserData) -> LuaResult<String> {
let inner: LuaValue = userdata.get("inner")?;
let carr = userdata.borrow::<CArr>()?;

if inner.is_userdata() {
let inner = inner
.as_userdata()
.ok_or(LuaError::external("failed to get inner type userdata."))?;
Ok(format!(
" {} ; {} ",
stringify_userdata(inner)?,
carr.length
))

if inner.is::<CType>() {
Ok(format!(
" {} ; {} ",
stringify_userdata(inner)?,
carr.length
))
} else {
Ok(format!(
" <{}({})> ; {} ",
name_from_userdata(inner),
stringify_userdata(inner)?,
carr.length
))
}
} else {
Err(LuaError::external("failed to get inner type userdata."))
}
Expand Down
1 change: 1 addition & 0 deletions crates/lune-std-ffi/src/ccast.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

154 changes: 113 additions & 41 deletions crates/lune-std-ffi/src/ctype.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,49 @@
#![allow(clippy::cargo_common_metadata)]

use core::ffi::{
c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint,
c_ulong, c_ulonglong, c_ushort, c_void,
};

use libffi::middle::{Cif, Type};
use mlua::prelude::*;

use crate::carr::CArr;
use crate::chelper::get_ensured_size;
use crate::cptr::CPtr;
use crate::ffihelper::get_ptr_from_userdata;
use crate::platform::CHAR_IS_SIGNED;
// use libffi::raw::{ffi_cif, ffi_ptrarray_to_raw};

pub struct CType {
libffi_cif: Cif,
libffi_type: Type,
size: usize,
name: Option<String>,

// Write converted data from luavalue into some ptr
pub luavalue_into_ptr: fn(value: LuaValue, ptr: *mut c_void) -> LuaResult<()>,

// Read luavalue from some ptr
pub ptr_into_luavalue: fn(lua: &Lua, ptr: *mut c_void) -> LuaResult<LuaValue>,
}

impl CType {
pub fn new(libffi_type: Type, name: Option<String>) -> LuaResult<Self> {
pub fn new(
libffi_type: Type,
name: Option<String>,
luavalue_into_ptr: fn(value: LuaValue, ptr: *mut c_void) -> LuaResult<()>,
ptr_into_luavalue: fn(lua: &Lua, ptr: *mut c_void) -> LuaResult<LuaValue>,
) -> LuaResult<Self> {
let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void());
let size = get_ensured_size(libffi_type.as_raw_ptr())?;
Ok(Self {
libffi_cif: libffi_cfi,
libffi_type,
size,
name,
luavalue_into_ptr,
ptr_into_luavalue,
})
}

Expand All @@ -37,6 +57,30 @@ impl CType {
None => String::from("unnamed"),
}
}

// Read data from ptr and convert it into luavalue
pub unsafe fn read_ptr<'lua>(
&self,
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)(lua, ptr)?;
Ok(value)
}

// Write converted data from luavalue into ptr
pub unsafe fn write_ptr<'lua>(
&self,
luavalue: LuaValue<'lua>,
userdata: LuaAnyUserData<'lua>,
offset: Option<isize>,
) -> LuaResult<()> {
let ptr = unsafe { get_ptr_from_userdata(&userdata, offset)? };
(self.luavalue_into_ptr)(luavalue, ptr)?;
Ok(())
}
}

impl LuaUserData for CType {
Expand All @@ -49,6 +93,20 @@ impl LuaUserData for CType {
let pointer = CPtr::from_lua_userdata(lua, &this)?;
Ok(pointer)
});
methods.add_method(
"from",
|lua, ctype, (userdata, offset): (LuaAnyUserData, Option<isize>)| {
let value = unsafe { ctype.read_ptr(lua, userdata, offset)? };
Ok(value)
},
);
methods.add_method(
"into",
|_, ctype, (value, userdata, offset): (LuaValue, LuaAnyUserData, Option<isize>)| {
unsafe { ctype.write_ptr(value, userdata, offset)? };
Ok(())
},
);
methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| {
let carr = CArr::from_lua_userdata(lua, &this, length)?;
Ok(carr)
Expand All @@ -64,48 +122,62 @@ impl LuaUserData for CType {
pub fn create_all_types(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaValue)>> {
Ok(vec![
(
"u8",
CType::new(Type::u8(), Some(String::from("u8")))?.into_lua(lua)?,
),
(
"u16",
CType::new(Type::u16(), Some(String::from("u16")))?.into_lua(lua)?,
),
(
"u32",
CType::new(Type::u32(), Some(String::from("u32")))?.into_lua(lua)?,
),
(
"u64",
CType::new(Type::u64(), Some(String::from("u64")))?.into_lua(lua)?,
),
(
"i8",
CType::new(Type::i8(), Some(String::from("i8")))?.into_lua(lua)?,
),
(
"i16",
CType::new(Type::i16(), Some(String::from("i16")))?.into_lua(lua)?,
),
(
"i32",
CType::new(Type::i32(), Some(String::from("i32")))?.into_lua(lua)?,
),
(
"i64",
CType::new(Type::i64(), Some(String::from("i64")))?.into_lua(lua)?,
),
(
"f32",
CType::new(Type::f32(), Some(String::from("f32")))?.into_lua(lua)?,
),
(
"f64",
CType::new(Type::f64(), Some(String::from("f64")))?.into_lua(lua)?,
"int",
CType::new(
Type::c_int(),
Some(String::from("int")),
|data, ptr| {
let value = match data {
LuaValue::Integer(t) => t,
_ => {
return Err(LuaError::external(format!(
"Integer expected, got {}",
data.type_name()
)))
}
} as c_int;
unsafe {
*(ptr.cast::<c_int>()) = value;
}
Ok(())
},
|lua: &Lua, ptr: *mut c_void| {
let value = unsafe { (*ptr.cast::<c_int>()).into_lua(lua)? };
Ok(value)
},
)?
.into_lua(lua)?,
),
(
"void",
CType::new(Type::void(), Some(String::from("void")))?.into_lua(lua)?,
"char",
CType::new(
if CHAR_IS_SIGNED {
Type::c_schar()
} else {
Type::c_uchar()
},
Some(String::from("char")),
|data, ptr| {
let value = match data {
LuaValue::Integer(t) => t,
_ => {
return Err(LuaError::external(format!(
"Integer expected, got {}",
data.type_name()
)))
}
} as c_char;
unsafe {
*(ptr.cast::<c_char>()) = value;
}
Ok(())
},
|lua: &Lua, ptr: *mut c_void| {
let value = unsafe { (*ptr.cast::<c_char>()).into_lua(lua)? };
Ok(value)
},
)?
.into_lua(lua)?,
),
])
}
100 changes: 75 additions & 25 deletions crates/lune-std-ffi/src/ffibox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,25 @@ use core::ffi::c_void;
use mlua::prelude::*;

use crate::association::set_association;
use crate::association_names::BOX_REF_INNER;
use crate::ffiref::FfiRange;
use crate::ffiref::FfiRef;

const BOX_REF_INNER: &str = "__box_ref";

pub struct FfiBox(Box<[u8]>);

impl FfiBox {
// For efficiency, it is initialized non-zeroed.
pub fn new(size: usize) -> Self {
Self(vec![0u8; size].into_boxed_slice())
// Create new vector to allocate heap memory. sized with 'size'
let mut vec_heap = Vec::<u8>::with_capacity(size);

// It is safe to have a length equal to the capacity
#[allow(clippy::uninit_vec)]
unsafe {
vec_heap.set_len(size);
}

Self(vec_heap.into_boxed_slice())
}

pub fn size(&self) -> usize {
Expand All @@ -36,14 +46,62 @@ impl FfiBox {
self.0.as_ptr() as *mut c_void
}

pub fn stringify(&self) -> String {
let mut buff = String::from(" ");
for i in &self.0 {
buff.push_str(i.to_string().as_str());
buff.push_str(", ");
}
buff.pop();
buff.pop();
buff.push(' ');
buff
}

pub fn binary_print(&self) -> String {
let mut buff: String = String::with_capacity(self.size() * 10 - 2);
for (pos, value) in self.0.iter().enumerate() {
for i in 0..8 {
if (value & (1 << i)) == 0 {
buff.push('0');
} else {
buff.push('1');
}
}
if pos < self.size() - 1 {
buff.push_str(", ");
}
}
buff
}

// bad naming. i have no idea what should i use
pub fn luaref<'lua>(
lua: &'lua Lua,
this: LuaAnyUserData<'lua>,
offset: Option<isize>,
) -> LuaResult<LuaAnyUserData<'lua>> {
let target = this.borrow::<FfiBox>()?;

let luaref = lua.create_userdata(FfiRef::new(target.get_ptr()))?;
let ptr = if let Some(t) = offset {
if t < 0 || t >= (target.size() as isize) {
return Err(LuaError::external(format!(
"Offset is out of bounds. box.size: {}. offset got {}",
target.size(),
t
)));
}
unsafe { target.get_ptr().offset(t) }
} else {
target.get_ptr()
};

let luaref = lua.create_userdata(FfiRef::new(
ptr,
Some(FfiRange {
low: 0,
high: target.size() as isize,
}),
))?;

set_association(lua, BOX_REF_INNER, luaref.clone(), this.clone())?;

Expand All @@ -61,27 +119,19 @@ impl LuaUserData for FfiBox {
}

fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_method_mut("zero", |_, this, ()| {
this.zero();
Ok(())
methods.add_function_mut("zero", |_, this: LuaAnyUserData| {
this.borrow_mut::<FfiBox>()?.zero();
Ok(this)
});
methods.add_function("ref", |lua, this: LuaAnyUserData| {
let luaref = FfiBox::luaref(lua, this)?;
Ok(luaref)
});
methods.add_meta_method(LuaMetaMethod::Len, |_, this, ()| Ok(this.size()));
methods.add_meta_method(LuaMetaMethod::ToString, |lua, this, ()| {
dbg!(&this.0.len());
let mut buff = String::from("[ ");
for i in &this.0 {
buff.push_str(i.to_owned().to_string().as_str());
buff.push_str(", ");
}
buff.pop();
buff.pop();
buff.push_str(" ]");
let luastr = lua.create_string(buff.as_bytes())?;
Ok(luastr)
methods.add_function(
"ref",
|lua, (this, offset): (LuaAnyUserData, Option<isize>)| {
let luaref = FfiBox::luaref(lua, this, offset)?;
Ok(luaref)
},
);
methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| {
Ok(this.binary_print())
});
}
}
Loading

0 comments on commit d63c3dd

Please sign in to comment.