FFI: Nested structs
This commit is contained in:
283
src/ffi.rs
283
src/ffi.rs
@@ -30,15 +30,16 @@ pub struct ForeignFunctionTable {
|
|||||||
structs: HashMap<String, StructImpl>,
|
structs: HashMap<String, StructImpl>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
struct StructImpl {
|
struct StructImpl {
|
||||||
ffi_type: ffi_type,
|
ffi_type: ffi_type,
|
||||||
fields: Vec<*mut ffi_type>,
|
fields: Vec<*mut ffi_type>,
|
||||||
|
atom_fields: Vec<Atom>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PointerArgs {
|
struct PointerArgs {
|
||||||
pointers: Vec<*mut c_void>,
|
pointers: Vec<*mut c_void>,
|
||||||
memory: Vec<Box<dyn Any>>,
|
_memory: Vec<Box<dyn Any>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ForeignFunctionTable {
|
impl ForeignFunctionTable {
|
||||||
@@ -46,42 +47,42 @@ impl ForeignFunctionTable {
|
|||||||
self.table.extend(other.table);
|
self.table.extend(other.table);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn define_struct(&mut self, name: &str, fields: Vec<Atom>) {
|
pub fn define_struct(&mut self, name: &str, atom_fields: Vec<Atom>) {
|
||||||
let mut fields: Vec<_> = fields.iter().map(|x| self.map_type_ffi(&x)).collect();
|
let mut fields: Vec<_> = atom_fields.iter().map(|x| self.map_type_ffi(&x)).collect();
|
||||||
fields.push(std::ptr::null_mut::<ffi_type>());
|
fields.push(std::ptr::null_mut::<ffi_type>());
|
||||||
let mut struct_type: ffi_type = Default::default();
|
let mut struct_type: ffi_type = Default::default();
|
||||||
struct_type.type_ = type_tag::STRUCT;
|
struct_type.type_ = type_tag::STRUCT;
|
||||||
struct_type.elements = fields.as_mut_ptr();
|
struct_type.elements = fields.as_mut_ptr();
|
||||||
self.structs.insert(name.to_string(), StructImpl { ffi_type: struct_type, fields});
|
self.structs.insert(name.to_string(), StructImpl { ffi_type: struct_type, fields, atom_fields});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_type_ffi(&mut self, source: &Atom) -> *mut ffi_type {
|
fn map_type_ffi(&mut self, source: &Atom) -> *mut ffi_type {
|
||||||
unsafe {
|
unsafe {
|
||||||
match source {
|
match source {
|
||||||
atom!("sint64") => &mut types::sint64,
|
atom!("sint64") => &mut types::sint64,
|
||||||
atom!("sint32") => &mut types::sint32,
|
atom!("sint32") => &mut types::sint32,
|
||||||
atom!("sint16") => &mut types::sint16,
|
atom!("sint16") => &mut types::sint16,
|
||||||
atom!("sint8") => &mut types::sint8,
|
atom!("sint8") => &mut types::sint8,
|
||||||
atom!("uint64") => &mut types::uint64,
|
atom!("uint64") => &mut types::uint64,
|
||||||
atom!("uint32") => &mut types::uint32,
|
atom!("uint32") => &mut types::uint32,
|
||||||
atom!("uint16") => &mut types::uint16,
|
atom!("uint16") => &mut types::uint16,
|
||||||
atom!("uint8") => &mut types::uint8,
|
atom!("uint8") => &mut types::uint8,
|
||||||
atom!("bool") => &mut types::sint8,
|
atom!("bool") => &mut types::sint8,
|
||||||
atom!("void") => &mut types::void,
|
atom!("void") => &mut types::void,
|
||||||
atom!("cstr") => &mut types::pointer,
|
atom!("cstr") => &mut types::pointer,
|
||||||
atom!("ptr") => &mut types::pointer,
|
atom!("ptr") => &mut types::pointer,
|
||||||
atom!("f32") => &mut types::float,
|
atom!("f32") => &mut types::float,
|
||||||
atom!("f64") => &mut types::double,
|
atom!("f64") => &mut types::double,
|
||||||
struct_name => {
|
struct_name => {
|
||||||
match self.structs.get_mut(struct_name.as_str()) {
|
match self.structs.get_mut(struct_name.as_str()) {
|
||||||
Some(ref mut struct_type) => {
|
Some(ref mut struct_type) => {
|
||||||
&mut struct_type.ffi_type
|
&mut struct_type.ffi_type
|
||||||
},
|
},
|
||||||
None => unreachable!()
|
None => unreachable!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn load_library(&mut self, library_name: &str, functions: &Vec<FunctionDefinition>) -> Result<(), Box<dyn Error>> {
|
pub(crate) fn load_library(&mut self, library_name: &str, functions: &Vec<FunctionDefinition>) -> Result<(), Box<dyn Error>> {
|
||||||
@@ -122,7 +123,7 @@ impl ForeignFunctionTable {
|
|||||||
|
|
||||||
fn build_pointer_args(args: &mut Vec<Value>, type_args: &Vec<*mut ffi_type>, structs_table: &mut HashMap<String, StructImpl>) -> Result<PointerArgs, FFIError> {
|
fn build_pointer_args(args: &mut Vec<Value>, type_args: &Vec<*mut ffi_type>, structs_table: &mut HashMap<String, StructImpl>) -> Result<PointerArgs, FFIError> {
|
||||||
let mut pointers = Vec::with_capacity(args.len());
|
let mut pointers = Vec::with_capacity(args.len());
|
||||||
let mut memory = Vec::new();
|
let mut _memory = Vec::new();
|
||||||
for i in 0..args.len() {
|
for i in 0..args.len() {
|
||||||
let field_type = type_args[i];
|
let field_type = type_args[i];
|
||||||
unsafe {
|
unsafe {
|
||||||
@@ -132,7 +133,7 @@ impl ForeignFunctionTable {
|
|||||||
let n: $type = <$type>::try_from(args[i].as_int()?).map_err(|_| FFIError::ValueDontFit)?;
|
let n: $type = <$type>::try_from(args[i].as_int()?).map_err(|_| FFIError::ValueDontFit)?;
|
||||||
let mut box_value = Box::new(n) as Box<dyn Any>;
|
let mut box_value = Box::new(n) as Box<dyn Any>;
|
||||||
pointers.push(&mut *box_value as *mut _ as *mut c_void);
|
pointers.push(&mut *box_value as *mut _ as *mut c_void);
|
||||||
memory.push(box_value);
|
_memory.push(box_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,73 +151,22 @@ impl ForeignFunctionTable {
|
|||||||
let n: f32 = args[i].as_float()? as f32;
|
let n: f32 = args[i].as_float()? as f32;
|
||||||
let mut box_value = Box::new(n) as Box<dyn Any>;
|
let mut box_value = Box::new(n) as Box<dyn Any>;
|
||||||
pointers.push(&mut *box_value as *mut _ as *mut c_void);
|
pointers.push(&mut *box_value as *mut _ as *mut c_void);
|
||||||
memory.push(box_value);
|
_memory.push(box_value);
|
||||||
},
|
},
|
||||||
libffi::raw::FFI_TYPE_DOUBLE => {
|
libffi::raw::FFI_TYPE_DOUBLE => {
|
||||||
let n: f64 = args[i].as_float()?;
|
let n: f64 = args[i].as_float()?;
|
||||||
let mut box_value = Box::new(n) as Box<dyn Any>;
|
let mut box_value = Box::new(n) as Box<dyn Any>;
|
||||||
pointers.push(&mut *box_value as *mut _ as *mut c_void);
|
pointers.push(&mut *box_value as *mut _ as *mut c_void);
|
||||||
memory.push(box_value);
|
_memory.push(box_value);
|
||||||
},
|
},
|
||||||
libffi::raw::FFI_TYPE_POINTER => {
|
libffi::raw::FFI_TYPE_POINTER => {
|
||||||
let ptr: *mut c_void = args[i].as_ptr()?;
|
let ptr: *mut c_void = args[i].as_ptr()?;
|
||||||
pointers.push(ptr);
|
pointers.push(ptr);
|
||||||
},
|
},
|
||||||
libffi::raw::FFI_TYPE_STRUCT => {
|
libffi::raw::FFI_TYPE_STRUCT => {
|
||||||
match args[i] {
|
let (mut ptr, _size, _align) = Self::build_struct(&mut args[i], structs_table)?;
|
||||||
Value::Struct(ref name, ref mut struct_args) => {
|
pointers.push(&mut *ptr as *mut _ as *mut c_void);
|
||||||
if let Some(ref mut struct_type) = structs_table.get_mut(name) {
|
_memory.push(ptr);
|
||||||
let layout = Layout::from_size_align(struct_type.ffi_type.size, struct_type.ffi_type.alignment.into()).unwrap();
|
|
||||||
let ptr = alloc(layout) as *mut c_void;
|
|
||||||
let mut field_ptr = ptr;
|
|
||||||
|
|
||||||
for i in 0..(struct_type.fields.len()-1) {
|
|
||||||
macro_rules! try_write_int {
|
|
||||||
($type:ty) => {
|
|
||||||
{
|
|
||||||
let n: $type = <$type>::try_from(struct_args[i].as_int()?).map_err(|_| FFIError::ValueDontFit)?;
|
|
||||||
std::ptr::write(field_ptr as *mut $type, n);
|
|
||||||
field_ptr = field_ptr.add(std::mem::size_of::<$type>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! write {
|
|
||||||
($type:ty, $value:expr) => {
|
|
||||||
{
|
|
||||||
let data: $type = $value;
|
|
||||||
std::ptr::write(field_ptr as *mut $type, data);
|
|
||||||
field_ptr = field_ptr.add(std::mem::size_of::<$type>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let field = struct_type.fields[i];
|
|
||||||
match (*field).type_ as u32 {
|
|
||||||
libffi::raw::FFI_TYPE_UINT8 => try_write_int!(u8),
|
|
||||||
libffi::raw::FFI_TYPE_SINT8 => try_write_int!(i8),
|
|
||||||
libffi::raw::FFI_TYPE_UINT16 => try_write_int!(u16),
|
|
||||||
libffi::raw::FFI_TYPE_SINT16 => try_write_int!(i16),
|
|
||||||
libffi::raw::FFI_TYPE_UINT32 => try_write_int!(u32),
|
|
||||||
libffi::raw::FFI_TYPE_SINT32 => try_write_int!(i32),
|
|
||||||
libffi::raw::FFI_TYPE_UINT64 => try_write_int!(u64),
|
|
||||||
libffi::raw::FFI_TYPE_SINT64 => try_write_int!(i64),
|
|
||||||
libffi::raw::FFI_TYPE_POINTER => write!(*mut c_void, struct_args[i].as_ptr()?),
|
|
||||||
libffi::raw::FFI_TYPE_FLOAT => write!(f32, struct_args[i].as_float()? as f32),
|
|
||||||
libffi::raw::FFI_TYPE_DOUBLE => write!(f64, struct_args[i].as_float()?),
|
|
||||||
_ => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pointers.push(ptr);
|
|
||||||
memory.push(Box::from_raw(ptr));
|
|
||||||
} else {
|
|
||||||
return Err(FFIError::InvalidStructName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => return Err(FFIError::ValueCast)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
_ => return Err(FFIError::InvalidFFIType)
|
_ => return Err(FFIError::InvalidFFIType)
|
||||||
}
|
}
|
||||||
@@ -224,10 +174,78 @@ impl ForeignFunctionTable {
|
|||||||
}
|
}
|
||||||
Ok(PointerArgs {
|
Ok(PointerArgs {
|
||||||
pointers,
|
pointers,
|
||||||
memory
|
_memory
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_struct(arg: &mut Value, structs_table: &mut HashMap<String, StructImpl>) -> Result<(Box<dyn Any>, usize, usize), FFIError> {
|
||||||
|
unsafe {
|
||||||
|
match arg {
|
||||||
|
Value::Struct(ref name, ref mut struct_args) => {
|
||||||
|
if let Some(ref mut struct_type) = structs_table.clone().get_mut(name) {
|
||||||
|
let layout = Layout::from_size_align(struct_type.ffi_type.size, struct_type.ffi_type.alignment.into()).unwrap();
|
||||||
|
let align = struct_type.ffi_type.alignment as usize;
|
||||||
|
let size = struct_type.ffi_type.size;
|
||||||
|
let ptr = alloc(layout) as *mut c_void;
|
||||||
|
let mut field_ptr = ptr;
|
||||||
|
|
||||||
|
for i in 0..(struct_type.fields.len()-1) {
|
||||||
|
macro_rules! try_write_int {
|
||||||
|
($type:ty) => {
|
||||||
|
{
|
||||||
|
field_ptr = field_ptr.add(field_ptr.align_offset(std::mem::align_of::<$type>()));
|
||||||
|
let n: $type = <$type>::try_from(struct_args[i].as_int()?).map_err(|_| FFIError::ValueDontFit)?;
|
||||||
|
std::ptr::write(field_ptr as *mut $type, n);
|
||||||
|
field_ptr = field_ptr.add(std::mem::size_of::<$type>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! write {
|
||||||
|
($type:ty, $value:expr) => {
|
||||||
|
{
|
||||||
|
let data: $type = $value;
|
||||||
|
std::ptr::write(field_ptr as *mut $type, data);
|
||||||
|
field_ptr = field_ptr.add(align);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let field = struct_type.fields[i];
|
||||||
|
match (*field).type_ as u32 {
|
||||||
|
libffi::raw::FFI_TYPE_UINT8 => try_write_int!(u8),
|
||||||
|
libffi::raw::FFI_TYPE_SINT8 => try_write_int!(i8),
|
||||||
|
libffi::raw::FFI_TYPE_UINT16 => try_write_int!(u16),
|
||||||
|
libffi::raw::FFI_TYPE_SINT16 => try_write_int!(i16),
|
||||||
|
libffi::raw::FFI_TYPE_UINT32 => try_write_int!(u32),
|
||||||
|
libffi::raw::FFI_TYPE_SINT32 => try_write_int!(i32),
|
||||||
|
libffi::raw::FFI_TYPE_UINT64 => try_write_int!(u64),
|
||||||
|
libffi::raw::FFI_TYPE_SINT64 => try_write_int!(i64),
|
||||||
|
libffi::raw::FFI_TYPE_POINTER => write!(*mut c_void, struct_args[i].as_ptr()?),
|
||||||
|
libffi::raw::FFI_TYPE_FLOAT => write!(f32, struct_args[i].as_float()? as f32),
|
||||||
|
libffi::raw::FFI_TYPE_DOUBLE => write!(f64, struct_args[i].as_float()?),
|
||||||
|
libffi::raw::FFI_TYPE_STRUCT => {
|
||||||
|
let (struct_ptr, struct_size, struct_align) = Self::build_struct(&mut struct_args[i], structs_table)?;
|
||||||
|
field_ptr = field_ptr.add(field_ptr.align_offset(struct_align));
|
||||||
|
|
||||||
|
std::ptr::copy(& *struct_ptr as *const _ as *const c_void, field_ptr as *mut c_void, struct_size);
|
||||||
|
field_ptr = field_ptr.add(struct_size);
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok((Box::from_raw(ptr), size, align));
|
||||||
|
} else {
|
||||||
|
return Err(FFIError::InvalidStructName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => return Err(FFIError::ValueCast)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn exec(&mut self, name: &str, mut args: Vec<Value>) -> Result<Value, FFIError> {
|
pub fn exec(&mut self, name: &str, mut args: Vec<Value>) -> Result<Value, FFIError> {
|
||||||
let function_impl = self.table.get_mut(name).ok_or(FFIError::FunctionNotFound)?;
|
let function_impl = self.table.get_mut(name).ok_or(FFIError::FunctionNotFound)?;
|
||||||
let mut pointer_args = Self::build_pointer_args(&mut args, &function_impl.args, &mut self.structs)?;
|
let mut pointer_args = Self::build_pointer_args(&mut args, &function_impl.args, &mut self.structs)?;
|
||||||
@@ -288,56 +306,75 @@ impl ForeignFunctionTable {
|
|||||||
Ok(Value::Float(*n))
|
Ok(Value::Float(*n))
|
||||||
},
|
},
|
||||||
libffi::raw::FFI_TYPE_STRUCT => {
|
libffi::raw::FFI_TYPE_STRUCT => {
|
||||||
let mut returns = Vec::new();
|
let name = &function_impl.return_struct_name.clone().ok_or(FFIError::StructNotFound)?;
|
||||||
let struct_type = self.structs.get_mut(&function_impl.return_struct_name.clone().ok_or(FFIError::StructNotFound)?).ok_or(FFIError::StructNotFound)?;
|
let struct_type = self.structs.get(name).ok_or(FFIError::StructNotFound)?;
|
||||||
let layout = Layout::from_size_align(struct_type.ffi_type.size, struct_type.ffi_type.alignment.into()).unwrap();
|
let layout = Layout::from_size_align(struct_type.ffi_type.size, struct_type.ffi_type.alignment.into()).unwrap();
|
||||||
let ptr = alloc(layout) as *mut c_void;
|
let ptr = alloc(layout) as *mut c_void;
|
||||||
|
|
||||||
libffi::raw::ffi_call(
|
libffi::raw::ffi_call(
|
||||||
&mut function_impl.cif,
|
&mut function_impl.cif,
|
||||||
Some(*function_impl.code_ptr.as_safe_fun()),
|
Some(*function_impl.code_ptr.as_safe_fun()),
|
||||||
&mut *ptr as *mut _ as *mut c_void,
|
&mut *ptr as *mut _ as *mut c_void,
|
||||||
pointer_args.pointers.as_mut_ptr() as *mut *mut c_void
|
pointer_args.pointers.as_mut_ptr() as *mut *mut c_void
|
||||||
);
|
);
|
||||||
|
let struct_val = self.read_struct(ptr, name, struct_type);
|
||||||
let mut field_ptr = ptr;
|
|
||||||
|
|
||||||
macro_rules! read_and_push_int {
|
|
||||||
($type:ty) => {
|
|
||||||
{
|
|
||||||
let n = std::ptr::read(field_ptr as *mut $type);
|
|
||||||
returns.push(Value::Int(i64::from(n)));
|
|
||||||
field_ptr = field_ptr.add(std::mem::size_of::<$type>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in 0..(struct_type.fields.len()-1) {
|
|
||||||
let field = struct_type.fields[i];
|
|
||||||
match (*field).type_ as u32 {
|
|
||||||
libffi::raw::FFI_TYPE_UINT8 => read_and_push_int!(u8),
|
|
||||||
libffi::raw::FFI_TYPE_SINT8 => read_and_push_int!(i8),
|
|
||||||
libffi::raw::FFI_TYPE_UINT16 => read_and_push_int!(u16),
|
|
||||||
libffi::raw::FFI_TYPE_SINT16 => read_and_push_int!(i16),
|
|
||||||
libffi::raw::FFI_TYPE_UINT32 => read_and_push_int!(u32),
|
|
||||||
libffi::raw::FFI_TYPE_SINT32 => read_and_push_int!(i32),
|
|
||||||
libffi::raw::FFI_TYPE_UINT64 => {
|
|
||||||
let n = std::ptr::read(field_ptr as *mut u64);
|
|
||||||
returns.push(Value::Int(i64::try_from(n).map_err(|_| FFIError::ValueDontFit)?));
|
|
||||||
field_ptr = field_ptr.add(std::mem::size_of::<u64>());
|
|
||||||
},
|
|
||||||
libffi::raw::FFI_TYPE_SINT64 => read_and_push_int!(i64),
|
|
||||||
_ => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
drop(Box::from_raw(ptr));
|
drop(Box::from_raw(ptr));
|
||||||
Ok(Value::Struct("texture".into(), returns))
|
struct_val
|
||||||
},
|
}
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_struct(&self, ptr: *mut c_void, name: &str, struct_type: &StructImpl) -> Result<Value, FFIError> {
|
||||||
|
unsafe {
|
||||||
|
let mut returns = Vec::new();
|
||||||
|
let mut field_ptr = ptr;
|
||||||
|
|
||||||
|
for i in 0..(struct_type.fields.len()-1) {
|
||||||
|
let field = struct_type.fields[i];
|
||||||
|
|
||||||
|
macro_rules! read_and_push_int {
|
||||||
|
($type:ty) => {
|
||||||
|
{
|
||||||
|
field_ptr = field_ptr.add(field_ptr.align_offset(std::mem::align_of::<$type>()));
|
||||||
|
let n = std::ptr::read(field_ptr as *mut $type);
|
||||||
|
returns.push(Value::Int(i64::from(n)));
|
||||||
|
field_ptr = field_ptr.add(std::mem::size_of::<$type>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match (*field).type_ as u32 {
|
||||||
|
libffi::raw::FFI_TYPE_UINT8 => read_and_push_int!(u8),
|
||||||
|
libffi::raw::FFI_TYPE_SINT8 => read_and_push_int!(i8),
|
||||||
|
libffi::raw::FFI_TYPE_UINT16 => read_and_push_int!(u16),
|
||||||
|
libffi::raw::FFI_TYPE_SINT16 => read_and_push_int!(i16),
|
||||||
|
libffi::raw::FFI_TYPE_UINT32 => read_and_push_int!(u32),
|
||||||
|
libffi::raw::FFI_TYPE_SINT32 => read_and_push_int!(i32),
|
||||||
|
libffi::raw::FFI_TYPE_UINT64 => {
|
||||||
|
field_ptr = field_ptr.add(field_ptr.align_offset(std::mem::align_of::<u64>()));
|
||||||
|
let n = std::ptr::read(field_ptr as *mut u64);
|
||||||
|
returns.push(Value::Int(i64::try_from(n).map_err(|_| FFIError::ValueDontFit)?));
|
||||||
|
field_ptr = field_ptr.add(std::mem::size_of::<u64>());
|
||||||
|
},
|
||||||
|
libffi::raw::FFI_TYPE_SINT64 => read_and_push_int!(i64),
|
||||||
|
libffi::raw::FFI_TYPE_STRUCT => {
|
||||||
|
let substruct = struct_type.atom_fields[i].as_str();
|
||||||
|
let struct_type = self.structs.get(substruct).ok_or(FFIError::StructNotFound)?;
|
||||||
|
field_ptr = field_ptr.add(field_ptr.align_offset(struct_type.ffi_type.alignment as usize));
|
||||||
|
let struct_val = self.read_struct(field_ptr, substruct, struct_type);
|
||||||
|
returns.push(struct_val?);
|
||||||
|
field_ptr = field_ptr.add(struct_type.ffi_type.size);
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Value::Struct(name.into(), returns))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|||||||
@@ -4257,6 +4257,7 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.machine_st.try_from_list(args_reg, stub_gen) {
|
match self.machine_st.try_from_list(args_reg, stub_gen) {
|
||||||
Ok(args) => {
|
Ok(args) => {
|
||||||
let args: Vec<_> = args.into_iter().map(|x| map_arg(&mut self.machine_st, x)).collect();
|
let args: Vec<_> = args.into_iter().map(|x| map_arg(&mut self.machine_st, x)).collect();
|
||||||
@@ -4264,22 +4265,9 @@ impl Machine {
|
|||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
match result {
|
match result {
|
||||||
Value::Int(n) => self.machine_st.unify_fixnum(Fixnum::build_with(n), return_value),
|
Value::Int(n) => self.machine_st.unify_fixnum(Fixnum::build_with(n), return_value),
|
||||||
Value::Struct(name, mut args) => {
|
Value::Struct(name, args) => {
|
||||||
args.insert(0, Value::CString(CString::new(name).unwrap()));
|
let struct_value = self.build_struct(&name, args);
|
||||||
let struct_list = heap_loc_as_cell!(
|
unify!(self.machine_st, return_value, struct_value);
|
||||||
iter_to_heap_list(
|
|
||||||
&mut self.machine_st.heap,
|
|
||||||
args.into_iter()
|
|
||||||
.map(|val| {
|
|
||||||
match val {
|
|
||||||
Value::Int(n) => fixnum_as_cell!(Fixnum::build_with(n)),
|
|
||||||
Value::CString(cstr) => atom_as_cell!(self.machine_st.atom_tbl.build_with(&cstr.into_string().unwrap())),
|
|
||||||
_ => unreachable!()
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
unify!(self.machine_st, return_value, struct_list);
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
@@ -4302,6 +4290,26 @@ impl Machine {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_struct(&mut self, name: &str, mut args: Vec<Value>) -> HeapCellValue {
|
||||||
|
args.insert(0, Value::CString(CString::new(name).unwrap()));
|
||||||
|
let cells: Vec<_> = args.into_iter()
|
||||||
|
.map(|val| {
|
||||||
|
match val {
|
||||||
|
Value::Int(n) => fixnum_as_cell!(Fixnum::build_with(n)),
|
||||||
|
Value::CString(cstr) => atom_as_cell!(self.machine_st.atom_tbl.build_with(&cstr.into_string().unwrap())),
|
||||||
|
Value::Struct(name, struct_args) => self.build_struct(&name, struct_args),
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
heap_loc_as_cell!(
|
||||||
|
iter_to_heap_list(
|
||||||
|
&mut self.machine_st.heap,
|
||||||
|
cells.into_iter()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn define_foreign_struct(&mut self) -> CallResult {
|
pub(crate) fn define_foreign_struct(&mut self) -> CallResult {
|
||||||
let struct_name = self.deref_register(1);
|
let struct_name = self.deref_register(1);
|
||||||
|
|||||||
Reference in New Issue
Block a user