Skip to content

Commit

Permalink
Move helper functions into chelper mod
Browse files Browse the repository at this point in the history
  • Loading branch information
qwreey committed Aug 24, 2024
1 parent 519f72a commit 0eb9326
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 140 deletions.
10 changes: 4 additions & 6 deletions crates/lune-std-ffi/src/carr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ use libffi::middle::Type;
use mlua::prelude::*;

use crate::association::{get_association, set_association};
use crate::chelper::{get_ensured_size, stringify_userdata, type_from_userdata};
use crate::cptr::CPtr;
use crate::ctype::{
libffi_type_ensured_size, libffi_type_from_userdata, type_userdata_stringify, CType,
};

// This is a series of some type.
// It provides the final size and the offset of the index,
Expand All @@ -31,7 +29,7 @@ pub struct CArr {
impl CArr {
pub fn new(libffi_type: Type, length: usize) -> LuaResult<Self> {
let struct_type = Type::structure(vec![libffi_type.clone(); length]);
let field_size = libffi_type_ensured_size(libffi_type.as_raw_ptr())?;
let field_size = get_ensured_size(libffi_type.as_raw_ptr())?;

Ok(Self {
libffi_type,
Expand All @@ -47,7 +45,7 @@ impl CArr {
luatype: &LuaAnyUserData<'lua>,
length: usize,
) -> LuaResult<LuaAnyUserData<'lua>> {
let fields = libffi_type_from_userdata(luatype)?;
let fields = type_from_userdata(luatype)?;
let carr = lua.create_userdata(Self::new(fields, length)?)?;

set_association(lua, CARR_INNER, carr.clone(), luatype)?;
Expand All @@ -69,7 +67,7 @@ impl CArr {
.ok_or(LuaError::external("failed to get inner type userdata."))?;
Ok(format!(
" {} ; {} ",
type_userdata_stringify(inner)?,
stringify_userdata(inner)?,
carr.length
))
} else {
Expand Down
6 changes: 3 additions & 3 deletions crates/lune-std-ffi/src/cfn.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use libffi::middle::{Cif, Type};
use mlua::prelude::*;

use crate::ctype::{libffi_type_from_userdata, libffi_types_from_table};
use crate::chelper::{type_from_userdata, type_list_from_table};

// cfn is a type declaration for a function.
// Basically, when calling an external function, this type declaration
Expand Down Expand Up @@ -36,8 +36,8 @@ impl CFn {
}

pub fn from_lua_table(args: LuaTable, ret: LuaAnyUserData) -> LuaResult<Self> {
let args = libffi_types_from_table(&args)?;
let ret = libffi_type_from_userdata(&ret)?;
let args = type_list_from_table(&args)?;
let ret = type_from_userdata(&ret)?;
Ok(Self::new(args, ret))
}
}
Expand Down
115 changes: 115 additions & 0 deletions crates/lune-std-ffi/src/chelper.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use std::ptr::{self, null_mut};

use libffi::{low, middle::Type, raw};
use lune_utils::fmt::{pretty_format_value, ValueFormatConfig};
use mlua::prelude::*;

use crate::carr::CArr;
use crate::cptr::CPtr;
use crate::cstruct::CStruct;
use crate::ctype::CType;
use crate::FFI_STATUS_NAMES;

// get Vec<libffi_type> from table(array) of c-types userdata
pub fn type_list_from_table(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(&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())
)));
}
}
}

Ok(fields)
}

// get libffi_type from any c-type userdata
pub fn type_from_userdata(userdata: &LuaAnyUserData) -> LuaResult<Type> {
if userdata.is::<CStruct>() {
Ok(userdata.borrow::<CStruct>()?.get_type())
} else if userdata.is::<CType>() {
Ok(userdata.borrow::<CType>()?.get_type())
} else if userdata.is::<CArr>() {
Ok(userdata.borrow::<CArr>()?.get_type())
} else if userdata.is::<CPtr>() {
Ok(CPtr::get_type())
} else {
Err(LuaError::external(format!(
"Unexpected field. CStruct, CType, CString or CArr is required for element but got {}",
pretty_format_value(
// Since the data is in the Lua location,
// there is no problem with the clone.
&LuaValue::UserData(userdata.to_owned()),
&ValueFormatConfig::new()
)
)))
}
}

// stringify any c-type userdata (for recursive)
pub fn stringify_userdata(userdata: &LuaAnyUserData) -> LuaResult<String> {
if userdata.is::<CType>() {
let name = userdata.borrow::<CType>()?.stringify();
Ok(name)
} else if userdata.is::<CStruct>() {
let name = CStruct::stringify(userdata)?;
Ok(name)
} else if userdata.is::<CArr>() {
let name = CArr::stringify(userdata)?;
Ok(name)
} else if userdata.is::<CPtr>() {
let name: String = CPtr::stringify(userdata)?;
Ok(name)
} else {
Ok(String::from("unnamed"))
}
}

// get name tag for any c-type userdata
pub fn name_from_userdata(userdata: &LuaAnyUserData) -> String {
if userdata.is::<CStruct>() {
String::from("CStruct")
} else if userdata.is::<CType>() {
String::from("CType")
} else if userdata.is::<CArr>() {
String::from("CArr")
} else if userdata.is::<CPtr>() {
String::from("CPtr")
} else {
String::from("unnamed")
}
}

// Ensure sizeof c-type (raw::libffi_type)
// See: http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html
pub fn get_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult<usize> {
let mut cif = low::ffi_cif::default();
let result = unsafe {
raw::ffi_prep_cif(
ptr::from_mut(&mut cif),
raw::ffi_abi_FFI_DEFAULT_ABI,
0,
ffi_type,
null_mut(),
)
};

if result != raw::ffi_status_FFI_OK {
return Err(LuaError::external(format!(
"ffi_get_struct_offsets failed. expected result {}, got {}",
FFI_STATUS_NAMES[0], FFI_STATUS_NAMES[result as usize]
)));
}
unsafe { Ok((*ffi_type).size) }
}
6 changes: 3 additions & 3 deletions crates/lune-std-ffi/src/cptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use mlua::prelude::*;

use crate::association::{get_association, set_association};
use crate::carr::CArr;
use crate::ctype::{type_name_from_userdata, type_userdata_stringify};
use crate::chelper::{name_from_userdata, stringify_userdata};

const POINTER_INNER: &str = "__pointer_inner";

Expand Down Expand Up @@ -37,8 +37,8 @@ impl CPtr {
.ok_or(LuaError::external("failed to get inner type userdata."))?;
Ok(format!(
" <{}({})> ",
type_name_from_userdata(inner),
type_userdata_stringify(inner)?,
name_from_userdata(inner),
stringify_userdata(inner)?,
))
} else {
Err(LuaError::external("failed to get inner type userdata."))
Expand Down
16 changes: 7 additions & 9 deletions crates/lune-std-ffi/src/cstruct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@ use libffi::{
};
use mlua::prelude::*;

use crate::ctype::{libffi_types_from_table, type_userdata_stringify, CType};
use crate::association::{get_association, set_association};
use crate::chelper::{name_from_userdata, stringify_userdata, type_list_from_table};
use crate::ctype::CType;
use crate::FFI_STATUS_NAMES;
use crate::{
association::{get_association, set_association},
ctype::type_name_from_userdata,
};
use crate::{carr::CArr, cptr::CPtr};

pub struct CStruct {
Expand Down Expand Up @@ -68,7 +66,7 @@ impl CStruct {
lua: &'lua Lua,
table: LuaTable<'lua>,
) -> LuaResult<LuaAnyUserData<'lua>> {
let fields = libffi_types_from_table(&table)?;
let fields = type_list_from_table(&table)?;
let cstruct = lua.create_userdata(Self::new(fields)?)?;
table.set_readonly(true);
set_association(lua, CSTRUCT_INNER, cstruct.clone(), table)?;
Expand All @@ -88,13 +86,13 @@ impl CStruct {
for i in 0..table.raw_len() {
let child: LuaAnyUserData = table.raw_get(i + 1)?;
if child.is::<CType>() {
result.push_str(format!("{}, ", type_userdata_stringify(&child)?).as_str());
result.push_str(format!("{}, ", stringify_userdata(&child)?).as_str());
} else {
result.push_str(
format!(
"<{}({})>, ",
type_name_from_userdata(&child),
type_userdata_stringify(&child)?
name_from_userdata(&child),
stringify_userdata(&child)?
)
.as_str(),
);
Expand Down
122 changes: 3 additions & 119 deletions crates/lune-std-ffi/src/ctype.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,13 @@
#![allow(clippy::cargo_common_metadata)]

use std::borrow::Borrow;
use std::ptr::{self, null_mut};

use libffi::{
low,
middle::{Cif, Type},
raw,
};
use lune_utils::fmt::{pretty_format_value, ValueFormatConfig};
use libffi::middle::{Cif, Type};
use mlua::prelude::*;

use crate::association::{get_association, set_association};
use crate::carr::CArr;
use crate::chelper::get_ensured_size;
use crate::cptr::CPtr;
use crate::cstruct::CStruct;
use crate::FFI_STATUS_NAMES;
// use libffi::raw::{ffi_cif, ffi_ptrarray_to_raw};

const POINTER_INNER: &str = "__pointer_inner";

pub struct CType {
libffi_cif: Cif,
libffi_type: Type,
Expand All @@ -30,7 +18,7 @@ pub struct CType {
impl CType {
pub fn new(libffi_type: Type, name: Option<String>) -> LuaResult<Self> {
let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void());
let size = libffi_type_ensured_size(libffi_type.as_raw_ptr())?;
let size = get_ensured_size(libffi_type.as_raw_ptr())?;
Ok(Self {
libffi_cif: libffi_cfi,
libffi_type,
Expand Down Expand Up @@ -121,107 +109,3 @@ pub fn create_all_types(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaValue)>> {
),
])
}

// get Vec<libffi_type> from table(array) of c-types userdata
pub fn libffi_types_from_table(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(libffi_type_from_userdata(&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())
)));
}
}
}

Ok(fields)
}

// get libffi_type from any c-type userdata
pub fn libffi_type_from_userdata(userdata: &LuaAnyUserData) -> LuaResult<Type> {
if userdata.is::<CStruct>() {
Ok(userdata.borrow::<CStruct>()?.get_type())
} else if userdata.is::<CType>() {
Ok(userdata.borrow::<CType>()?.get_type())
} else if userdata.is::<CArr>() {
Ok(userdata.borrow::<CArr>()?.get_type())
} else if userdata.is::<CPtr>() {
Ok(CPtr::get_type())
} else {
Err(LuaError::external(format!(
"Unexpected field. CStruct, CType, CString or CArr is required for element but got {}",
pretty_format_value(
// Since the data is in the Lua location,
// there is no problem with the clone.
&LuaValue::UserData(userdata.to_owned()),
&ValueFormatConfig::new()
)
)))
}
}

// stringify any c-type userdata (for recursive)
pub fn type_userdata_stringify(userdata: &LuaAnyUserData) -> LuaResult<String> {
if userdata.is::<CType>() {
let name = userdata.borrow::<CType>()?.stringify();
Ok(name)
} else if userdata.is::<CStruct>() {
let name = CStruct::stringify(userdata)?;
Ok(name)
} else if userdata.is::<CArr>() {
let name = CArr::stringify(userdata)?;
Ok(name)
} else if userdata.is::<CPtr>() {
let name: String = CPtr::stringify(userdata)?;
Ok(name)
} else {
Ok(String::from("unnamed"))
}
}

// get name tag for any c-type userdata
pub fn type_name_from_userdata(userdata: &LuaAnyUserData) -> String {
if userdata.is::<CStruct>() {
String::from("CStruct")
} else if userdata.is::<CType>() {
String::from("CType")
} else if userdata.is::<CArr>() {
String::from("CArr")
} else if userdata.is::<CPtr>() {
String::from("CPtr")
} else {
String::from("unnamed")
}
}

// Ensure sizeof c-type (raw::libffi_type)
// See: http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html
pub fn libffi_type_ensured_size(ffi_type: *mut raw::ffi_type) -> LuaResult<usize> {
let mut cif: low::ffi_cif = Default::default();
let result = unsafe {
raw::ffi_prep_cif(
ptr::from_mut(&mut cif),
raw::ffi_abi_FFI_DEFAULT_ABI,
0,
ffi_type,
null_mut(),
)
};

if result != raw::ffi_status_FFI_OK {
return Err(LuaError::external(format!(
"ffi_get_struct_offsets failed. expected result {}, got {}",
FFI_STATUS_NAMES[0], FFI_STATUS_NAMES[result as usize]
)));
}
unsafe { Ok((*ffi_type).size) }
}
1 change: 1 addition & 0 deletions crates/lune-std-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use mlua::prelude::*;
mod association;
mod carr;
mod cfn;
mod chelper;
mod cptr;
mod cstring;
mod cstruct;
Expand Down

0 comments on commit 0eb9326

Please sign in to comment.