use std::{ffi::c_void, ptr, sync::Arc};
use mun_abi as abi;
use mun_memory::{type_table::TypeTable, HasStaticType, TryFromAbiError, Type};
#[derive(Clone)]
pub struct FunctionDefinition {
pub prototype: FunctionPrototype,
pub fn_ptr: *const c_void,
}
impl FunctionDefinition {
pub fn builder(name: impl Into<String>) -> FunctionDefinitionBuilder {
FunctionDefinitionBuilder {
name: name.into(),
arg_types: vec![],
return_type: <()>::type_info().clone(),
fn_ptr: ptr::null(),
}
}
}
unsafe impl Send for FunctionDefinition {}
unsafe impl Sync for FunctionDefinition {}
impl FunctionDefinition {
pub fn try_from_abi<'abi>(
fn_def: &'abi abi::FunctionDefinition<'abi>,
type_table: &TypeTable,
) -> Result<Self, TryFromAbiError<'abi>> {
let prototype = FunctionPrototype::try_from_abi(&fn_def.prototype, type_table)?;
Ok(Self {
prototype,
fn_ptr: fn_def.fn_ptr,
})
}
}
#[derive(Clone)]
pub struct FunctionPrototype {
pub name: String,
pub signature: FunctionSignature,
}
impl FunctionPrototype {
pub fn try_from_abi<'abi>(
fn_prototype: &'abi abi::FunctionPrototype<'abi>,
type_table: &TypeTable,
) -> Result<Self, TryFromAbiError<'abi>> {
let signature = FunctionSignature::try_from_abi(&fn_prototype.signature, type_table)?;
Ok(Self {
name: fn_prototype.name().to_owned(),
signature,
})
}
}
#[derive(Clone)]
pub struct FunctionSignature {
pub arg_types: Vec<Type>,
pub return_type: Type,
}
impl FunctionSignature {
pub fn try_from_abi<'abi>(
fn_sig: &'abi abi::FunctionSignature<'abi>,
type_table: &TypeTable,
) -> Result<Self, TryFromAbiError<'abi>> {
let arg_types: Vec<Type> = fn_sig
.arg_types()
.iter()
.map(|type_id| {
type_table
.find_type_info_by_id(type_id)
.ok_or_else(|| TryFromAbiError::UnknownTypeId(type_id.clone()))
})
.collect::<Result<_, _>>()?;
let return_type = type_table
.find_type_info_by_id(&fn_sig.return_type)
.ok_or_else(|| TryFromAbiError::UnknownTypeId(fn_sig.return_type.clone()))?;
Ok(Self {
arg_types,
return_type,
})
}
}
pub trait IntoFunctionDefinition {
fn into<S: Into<String>>(self, name: S) -> FunctionDefinition;
}
macro_rules! into_function_info_impl {
($(
extern "C" fn($($T:ident),*) -> $R:ident;
)+) => {
$(
impl<$R: mun_memory::HasStaticType, $($T: mun_memory::HasStaticType,)*> IntoFunctionDefinition
for extern "C" fn($($T),*) -> $R
{
fn into<S: Into<String>>(self, name: S) -> FunctionDefinition {
FunctionDefinition {
fn_ptr: self as *const std::ffi::c_void,
prototype: FunctionPrototype {
name: name.into(),
signature: FunctionSignature {
arg_types: vec![$(<$T as mun_memory::HasStaticType>::type_info().clone(),)*],
return_type: <R as mun_memory::HasStaticType>::type_info().clone(),
}
}
}
}
}
)+
}
}
into_function_info_impl! {
extern "C" fn() -> R;
extern "C" fn(A) -> R;
extern "C" fn(A, B) -> R;
extern "C" fn(A, B, C) -> R;
extern "C" fn(A, B, C, D) -> R;
extern "C" fn(A, B, C, D, E) -> R;
extern "C" fn(A, B, C, D, E, F) -> R;
extern "C" fn(A, B, C, D, E, F, G) -> R;
extern "C" fn(A, B, C, D, E, F, G, H) -> R;
extern "C" fn(A, B, C, D, E, F, G, H, I) -> R;
extern "C" fn(A, B, C, D, E, F, G, H, I, J) -> R;
}
#[derive(Debug)]
pub struct FunctionDefinitionBuilder {
name: String,
arg_types: Vec<Type>,
return_type: Type,
fn_ptr: *const c_void,
}
impl FunctionDefinitionBuilder {
pub fn add_argument(mut self, arg: Type) -> Self {
self.arg_types.push(arg);
self
}
pub fn add_arguments(mut self, iter: impl IntoIterator<Item = Type>) -> Self {
for arg in iter.into_iter() {
self.arg_types.push(arg);
}
self
}
pub fn set_return_type(mut self, ty: Type) -> Self {
self.return_type = ty;
self
}
pub fn set_ptr(mut self, ptr: *const c_void) -> Self {
self.fn_ptr = ptr;
self
}
pub fn finish(self) -> Arc<FunctionDefinition> {
Arc::new(FunctionDefinition {
prototype: FunctionPrototype {
name: self.name,
signature: FunctionSignature {
arg_types: self.arg_types,
return_type: self.return_type,
},
},
fn_ptr: self.fn_ptr,
})
}
}