makepad_stitch/
func.rs

1use {
2    crate::{
3        code::{Code, UncompiledCode},
4        decode::{Decode, DecodeError, Decoder},
5        error::Error,
6        exec,
7        instance::Instance,
8        into_func::IntoFunc,
9        stack::StackGuard,
10        store::{Handle, InternedFuncType, Store, StoreId, UnguardedHandle},
11        val::{Val, ValType},
12    },
13    std::{error, fmt, mem, sync::Arc},
14};
15
16/// A Wasm function.
17///
18/// A [`Func`] is either a Wasm function or a host function.
19#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
20pub struct Func(pub(crate) Handle<FuncEntity>);
21
22impl Func {
23    /// Creates a new host function that wraps the given closure.
24    pub fn wrap<Ts, U>(store: &mut Store, f: impl IntoFunc<Ts, U>) -> Self {
25        let (type_, trampoline) = f.into_func();
26        let type_ = store.get_or_intern_type(&type_);
27        Self(store.insert_func(FuncEntity::Host(HostFuncEntity::new(type_, trampoline))))
28    }
29
30    /// Returns the [`FuncType`] of this [`Func`].
31    pub fn type_(self, store: &Store) -> &FuncType {
32        store.resolve_type(self.0.as_ref(store).type_())
33    }
34
35    /// Calls this [`Func`] with the given arguments.
36    ///
37    /// The results are written to the `results` slice.
38    ///
39    /// # Errors
40    ///
41    /// - If the argument count does not match the expected parameter count.
42    /// - If the actual result count does not match the expected result count.
43    /// - If the argument types do not match the expected parameter types.
44    pub fn call(self, store: &mut Store, args: &[Val], results: &mut [Val]) -> Result<(), Error> {
45        let type_ = self.type_(store);
46        if args.len() != type_.params().len() {
47            return Err(FuncError::ParamCountMismatch)?;
48        }
49        if results.len() != type_.results().len() {
50            return Err(FuncError::ResultCountMismatch)?;
51        }
52        for (arg, param_type) in args.iter().zip(type_.params().iter().copied()) {
53            if arg.type_() != param_type {
54                return Err(FuncError::ParamTypeMismatch)?;
55            }
56        }
57        exec::exec(store, self, args, results)
58    }
59
60    /// Creates a new Wasm function from its raw parts.
61    pub(crate) fn new_wasm(
62        store: &mut Store,
63        type_: InternedFuncType,
64        instance: Instance,
65        code: UncompiledCode,
66    ) -> Self {
67        Self(store.insert_func(FuncEntity::Wasm(WasmFuncEntity::new(type_, instance, code))))
68    }
69
70    /// Converts the given [`UnguardedFunc`] to a [`Func`].
71    ///
72    /// # Safety
73    ///
74    /// The given [`UnguardedFunc`] must be owned by the [`Store`] with the given [`StoreId`].
75    pub(crate) unsafe fn from_unguarded(func: UnguardedFunc, store_id: StoreId) -> Self {
76        Self(Handle::from_unguarded(func, store_id))
77    }
78
79    /// Converts this [`Func`] to an [`UnguardedFunc`].
80    ///
81    /// # Panics
82    ///
83    /// This [`Func`] is not owned by the [`Store`] with the given [`StoreId`].
84    pub(crate) fn to_unguarded(self, store_id: StoreId) -> UnguardedFunc {
85        self.0.to_unguarded(store_id)
86    }
87
88    /// Ensures that this [`Func`] is compiled, if it is a Wasm function.
89    pub(crate) fn compile(self, store: &mut Store) {
90        let FuncEntity::Wasm(func) = self.0.as_mut(store) else {
91            return;
92        };
93        let instance = func.instance().clone();
94        let code = match mem::replace(func.code_mut(), Code::Compiling) {
95            Code::Uncompiled(code) => {
96                let engine = store.engine().clone();
97                engine.compile(store, self, &instance, &code)
98            }
99            Code::Compiling => panic!("function is already being compiled"),
100            Code::Compiled(state) => state,
101        };
102        let FuncEntity::Wasm(func) = self.0.as_mut(store) else {
103            unreachable!();
104        };
105        *func.code_mut() = Code::Compiled(code);
106    }
107}
108
109/// An unguarded version of [`Func`].
110pub(crate) type UnguardedFunc = UnguardedHandle<FuncEntity>;
111
112/// The type of a [`Func`].
113#[derive(Clone, Debug, Eq, Hash, PartialEq)]
114pub struct FuncType {
115    params_results: Arc<[ValType]>,
116    param_count: usize,
117}
118
119impl FuncType {
120    /// Creates a new [`FuncType`] with the given parameters and results.
121    pub fn new(
122        params: impl IntoIterator<Item = ValType>,
123        results: impl IntoIterator<Item = ValType>,
124    ) -> Self {
125        let mut params_results = params.into_iter().collect::<Vec<_>>();
126        let param_count = params_results.len();
127        params_results.extend(results);
128        Self {
129            params_results: params_results.into(),
130            param_count,
131        }
132    }
133
134    /// Returns the parameters of this [`FuncType`].
135    pub fn params(&self) -> &[ValType] {
136        &self.params_results[..self.param_count]
137    }
138
139    /// Returns the results of this [`FuncType`].
140    pub fn results(&self) -> &[ValType] {
141        &self.params_results[self.param_count..]
142    }
143
144    /// Creates a [`FuncType`] from an optional [`ValType`], which is a shorthand for the
145    /// [`FuncType`] [] -> [`ValType`?].
146    pub(crate) fn from_val_type(type_: Option<ValType>) -> FuncType {
147        thread_local! {
148            static TYPES: [FuncType; 7] = [
149                FuncType::new(vec![], vec![]),
150                FuncType::new(vec![], vec![ValType::I32]),
151                FuncType::new(vec![], vec![ValType::I64]),
152                FuncType::new(vec![], vec![ValType::F32]),
153                FuncType::new(vec![], vec![ValType::F64]),
154                FuncType::new(vec![], vec![ValType::FuncRef]),
155                FuncType::new(vec![], vec![ValType::ExternRef]),
156            ];
157        }
158
159        TYPES.with(|types| match type_ {
160            None => types[0].clone(),
161            Some(ValType::I32) => types[1].clone(),
162            Some(ValType::I64) => types[2].clone(),
163            Some(ValType::F32) => types[3].clone(),
164            Some(ValType::F64) => types[4].clone(),
165            Some(ValType::FuncRef) => types[5].clone(),
166            Some(ValType::ExternRef) => types[6].clone(),
167        })
168    }
169
170    /// Returns the size of a call frame for a function with this [`FuncType`], in number of
171    /// [`StackSlot`]s.
172    pub(crate) fn call_frame_size(&self) -> usize {
173        self.params().len().max(self.results().len()) + 4
174    }
175}
176
177impl Decode for FuncType {
178    fn decode(decoder: &mut Decoder<'_>) -> Result<Self, DecodeError> {
179        if decoder.read_byte()? != 0x60 {
180            return Err(DecodeError::new("malformed function type"))?;
181        }
182        let mut param_result_types: Vec<_> = decoder.decode_iter()?.collect::<Result<_, _>>()?;
183        let param_count = param_result_types.len();
184        let result_types = decoder.decode_iter()?;
185        param_result_types.reserve(result_types.size_hint().0);
186        for result_type in result_types {
187            param_result_types.push(result_type?);
188        }
189        Ok(Self {
190            params_results: param_result_types.into(),
191            param_count,
192        })
193    }
194}
195
196/// An error that can occur when operating on a [`Func`].
197#[derive(Clone, Copy, Debug)]
198pub enum FuncError {
199    ParamCountMismatch,
200    ParamTypeMismatch,
201    ResultCountMismatch,
202}
203
204impl fmt::Display for FuncError {
205    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206        match self {
207            Self::ParamCountMismatch => write!(f, "function parameter count mismatch"),
208            Self::ParamTypeMismatch => write!(f, "function parameter type mismatch"),
209            Self::ResultCountMismatch => write!(f, "function result count mismatch"),
210        }
211    }
212}
213
214impl error::Error for FuncError {}
215
216/// The representation of a [`Func`] in a [`Store`].
217#[derive(Debug)]
218pub enum FuncEntity {
219    Wasm(WasmFuncEntity),
220    Host(HostFuncEntity),
221}
222
223impl FuncEntity {
224    /// Returns the [`FuncType`] of this [`FuncEntity`].
225    pub(crate) fn type_(&self) -> InternedFuncType {
226        match self {
227            Self::Wasm(func) => func.type_(),
228            Self::Host(func) => func.type_(),
229        }
230    }
231}
232
233#[derive(Debug)]
234pub(crate) struct WasmFuncEntity {
235    type_: InternedFuncType,
236    instance: Instance,
237    code: Code,
238}
239
240impl WasmFuncEntity {
241    /// Creates a new [`WasmFuncEntity`] from its raw parts.
242    fn new(type_: InternedFuncType, instance: Instance, code: UncompiledCode) -> WasmFuncEntity {
243        WasmFuncEntity {
244            type_,
245            instance,
246            code: Code::Uncompiled(code),
247        }
248    }
249
250    /// Returns the [`InternedFuncType`] of this [`WasmFuncEntity`].
251    pub(crate) fn type_(&self) -> InternedFuncType {
252        self.type_
253    }
254
255    /// Returns the [`Instance`] of this [`WasmFuncEntity`].
256    pub(crate) fn instance(&self) -> &Instance {
257        &self.instance
258    }
259
260    /// Returns a reference to the [`Code`] of this [`WasmFuncEntity`].
261    pub(crate) fn code(&self) -> &Code {
262        &self.code
263    }
264
265    /// Returns a mutable reference to the [`Code`] of this [`WasmFuncEntity`].
266    pub(crate) fn code_mut(&mut self) -> &mut Code {
267        &mut self.code
268    }
269}
270
271#[derive(Debug)]
272pub struct HostFuncEntity {
273    type_: InternedFuncType,
274    trampoline: HostFuncTrampoline,
275}
276
277impl HostFuncEntity {
278    /// Creates a new [`HostFuncEntity`] from its raw parts.
279    pub(crate) fn new(type_: InternedFuncType, trampoline: HostFuncTrampoline) -> Self {
280        Self { type_, trampoline }
281    }
282
283    /// Returns the [`InternedFuncType`] of this [`HostFuncEntity`].
284    pub(crate) fn type_(&self) -> InternedFuncType {
285        self.type_
286    }
287
288    /// Returns the [`HostFuncTrampoline`] of this [`HostFuncEntity`].
289    pub(crate) fn trampoline(&self) -> &HostFuncTrampoline {
290        &self.trampoline
291    }
292}
293
294#[derive(Clone)]
295pub struct HostFuncTrampoline {
296    inner: Arc<dyn Fn(&mut Store, StackGuard) -> Result<StackGuard, Error> + Send + Sync + 'static>,
297}
298
299impl HostFuncTrampoline {
300    pub fn new(
301        inner: impl Fn(&mut Store, StackGuard) -> Result<StackGuard, Error> + Send + Sync + 'static,
302    ) -> Self {
303        Self {
304            inner: Arc::new(inner),
305        }
306    }
307
308    pub(crate) fn call(&self, store: &mut Store, stack: StackGuard) -> Result<StackGuard, Error> {
309        (self.inner)(store, stack)
310    }
311}
312
313impl fmt::Debug for HostFuncTrampoline {
314    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
315        f.debug_struct("HostFuncTrampoline").finish()
316    }
317}