mun_runtime/
function_info.rs

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/// A linked version of [`mun_abi::FunctionDefinition`] that has resolved all occurrences of `TypeId` with `TypeInfo`.
7#[derive(Clone)]
8pub struct FunctionDefinition {
9    /// Function prototype
10    pub prototype: FunctionPrototype,
11    /// Function pointer
12    pub fn_ptr: *const c_void,
13}
14
15impl FunctionDefinition {
16    /// Creates a builder to easily create a new `FunctionDefinition`.
17    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    /// Tries to convert from an `abi::FunctionDefinition`.
32    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/// A linked version of [`mun_abi::FunctionPrototype`] that has resolved all occurrences of `TypeId` with `TypeInfo`.
46#[derive(Clone)]
47pub struct FunctionPrototype {
48    /// Function name
49    pub name: String,
50    /// The type signature of the function
51    pub signature: FunctionSignature,
52}
53
54impl FunctionPrototype {
55    /// Tries to convert from an `abi::FunctionPrototype`.
56    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/// A linked version of [`mun_abi::FunctionSignature`] that has resolved all occurrences of `TypeId` with `TypeInfo`.
70#[derive(Clone)]
71pub struct FunctionSignature {
72    /// Argument types
73    pub arg_types: Vec<Type>,
74    /// Return type
75    pub return_type: Type,
76}
77
78impl FunctionSignature {
79    /// Tries to convert from an `abi::FunctionSignature`.
80    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
105/// A value-to-`FunctionDefinition` conversion that consumes the input value.
106pub trait IntoFunctionDefinition {
107    /// Performs the conversion.
108    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/// A helper struct to ergonomically build functions.
151#[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    /// Adds an argument
161    pub fn add_argument(mut self, arg: Type) -> Self {
162        self.arg_types.push(arg);
163        self
164    }
165
166    /// Adds arguments
167    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    /// Sets the return type
175    pub fn set_return_type(mut self, ty: Type) -> Self {
176        self.return_type = ty;
177        self
178    }
179
180    /// Sets the function pointer
181    pub fn set_ptr(mut self, ptr: *const c_void) -> Self {
182        self.fn_ptr = ptr;
183        self
184    }
185
186    /// Construct the [`FunctionDefinition`]
187    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}