1use std::{ffi::c_void, ptr, sync::Arc};
2
3use mun_abi as abi;
4use mun_memory::{type_table::TypeTable, HasStaticType, TryFromAbiError, Type};
5
6#[derive(Clone)]
8pub struct FunctionDefinition {
9 pub prototype: FunctionPrototype,
11 pub fn_ptr: *const c_void,
13}
14
15impl FunctionDefinition {
16 pub fn builder(name: impl Into<String>) -> FunctionDefinitionBuilder {
18 FunctionDefinitionBuilder {
19 name: name.into(),
20 arg_types: vec![],
21 return_type: <()>::type_info().clone(),
22 fn_ptr: ptr::null(),
23 }
24 }
25}
26
27unsafe impl Send for FunctionDefinition {}
28unsafe impl Sync for FunctionDefinition {}
29
30impl FunctionDefinition {
31 pub fn try_from_abi<'abi>(
33 fn_def: &'abi abi::FunctionDefinition<'abi>,
34 type_table: &TypeTable,
35 ) -> Result<Self, TryFromAbiError<'abi>> {
36 let prototype = FunctionPrototype::try_from_abi(&fn_def.prototype, type_table)?;
37
38 Ok(Self {
39 prototype,
40 fn_ptr: fn_def.fn_ptr,
41 })
42 }
43}
44
45#[derive(Clone)]
47pub struct FunctionPrototype {
48 pub name: String,
50 pub signature: FunctionSignature,
52}
53
54impl FunctionPrototype {
55 pub fn try_from_abi<'abi>(
57 fn_prototype: &'abi abi::FunctionPrototype<'abi>,
58 type_table: &TypeTable,
59 ) -> Result<Self, TryFromAbiError<'abi>> {
60 let signature = FunctionSignature::try_from_abi(&fn_prototype.signature, type_table)?;
61
62 Ok(Self {
63 name: fn_prototype.name().to_owned(),
64 signature,
65 })
66 }
67}
68
69#[derive(Clone)]
71pub struct FunctionSignature {
72 pub arg_types: Vec<Type>,
74 pub return_type: Type,
76}
77
78impl FunctionSignature {
79 pub fn try_from_abi<'abi>(
81 fn_sig: &'abi abi::FunctionSignature<'abi>,
82 type_table: &TypeTable,
83 ) -> Result<Self, TryFromAbiError<'abi>> {
84 let arg_types: Vec<Type> = fn_sig
85 .arg_types()
86 .iter()
87 .map(|type_id| {
88 type_table
89 .find_type_info_by_id(type_id)
90 .ok_or_else(|| TryFromAbiError::UnknownTypeId(type_id.clone()))
91 })
92 .collect::<Result<_, _>>()?;
93
94 let return_type = type_table
95 .find_type_info_by_id(&fn_sig.return_type)
96 .ok_or_else(|| TryFromAbiError::UnknownTypeId(fn_sig.return_type.clone()))?;
97
98 Ok(Self {
99 arg_types,
100 return_type,
101 })
102 }
103}
104
105pub trait IntoFunctionDefinition {
107 fn into<S: Into<String>>(self, name: S) -> FunctionDefinition;
109}
110
111macro_rules! into_function_info_impl {
112 ($(
113 extern "C" fn($($T:ident),*) -> $R:ident;
114 )+) => {
115 $(
116 impl<$R: mun_memory::HasStaticType, $($T: mun_memory::HasStaticType,)*> IntoFunctionDefinition
117 for extern "C" fn($($T),*) -> $R
118 {
119 fn into<S: Into<String>>(self, name: S) -> FunctionDefinition {
120 FunctionDefinition {
121 fn_ptr: self as *const std::ffi::c_void,
122 prototype: FunctionPrototype {
123 name: name.into(),
124 signature: FunctionSignature {
125 arg_types: vec![$(<$T as mun_memory::HasStaticType>::type_info().clone(),)*],
126 return_type: <R as mun_memory::HasStaticType>::type_info().clone(),
127 }
128 }
129 }
130 }
131 }
132 )+
133 }
134}
135
136into_function_info_impl! {
137 extern "C" fn() -> R;
138 extern "C" fn(A) -> R;
139 extern "C" fn(A, B) -> R;
140 extern "C" fn(A, B, C) -> R;
141 extern "C" fn(A, B, C, D) -> R;
142 extern "C" fn(A, B, C, D, E) -> R;
143 extern "C" fn(A, B, C, D, E, F) -> R;
144 extern "C" fn(A, B, C, D, E, F, G) -> R;
145 extern "C" fn(A, B, C, D, E, F, G, H) -> R;
146 extern "C" fn(A, B, C, D, E, F, G, H, I) -> R;
147 extern "C" fn(A, B, C, D, E, F, G, H, I, J) -> R;
148}
149
150#[derive(Debug)]
152pub struct FunctionDefinitionBuilder {
153 name: String,
154 arg_types: Vec<Type>,
155 return_type: Type,
156 fn_ptr: *const c_void,
157}
158
159impl FunctionDefinitionBuilder {
160 pub fn add_argument(mut self, arg: Type) -> Self {
162 self.arg_types.push(arg);
163 self
164 }
165
166 pub fn add_arguments(mut self, iter: impl IntoIterator<Item = Type>) -> Self {
168 for arg in iter.into_iter() {
169 self.arg_types.push(arg);
170 }
171 self
172 }
173
174 pub fn set_return_type(mut self, ty: Type) -> Self {
176 self.return_type = ty;
177 self
178 }
179
180 pub fn set_ptr(mut self, ptr: *const c_void) -> Self {
182 self.fn_ptr = ptr;
183 self
184 }
185
186 pub fn finish(self) -> Arc<FunctionDefinition> {
188 Arc::new(FunctionDefinition {
189 prototype: FunctionPrototype {
190 name: self.name,
191 signature: FunctionSignature {
192 arg_types: self.arg_types,
193 return_type: self.return_type,
194 },
195 },
196 fn_ptr: self.fn_ptr,
197 })
198 }
199}