wasmer/entities/function/inner.rs
1use std::pin::Pin;
2
3use wasmer_types::{FunctionType, RawValue};
4
5#[cfg(feature = "experimental-async")]
6use crate::{AsStoreAsync, AsyncFunctionEnvMut, entities::function::async_host::AsyncHostFunction};
7use crate::{
8 AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, FunctionEnv, FunctionEnvMut,
9 HostFunction, StoreMut, StoreRef, TypedFunction, Value, WasmTypeList, WithEnv, WithoutEnv,
10 error::RuntimeError,
11 macros::backend::{gen_rt_ty, match_rt},
12 vm::{VMExtern, VMExternFunction, VMFuncRef},
13};
14
15/// A WebAssembly `function` instance.
16///
17/// A function instance is the runtime representation of a function.
18/// It effectively is a closure of the original function (defined in either
19/// the host or the WebAssembly module) over the runtime `Instance` of its
20/// originating `Module`.
21///
22/// The module instance is used to resolve references to other definitions
23/// during execution of the function.
24///
25/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#function-instances>
26///
27/// # Panics
28/// - Closures (functions with captured environments) are not currently supported
29/// with native functions. Attempting to create a native `Function` with one will
30/// result in a panic.
31/// [Closures as host functions tracking issue](https://github.com/wasmerio/wasmer/issues/1840)
32gen_rt_ty! {
33 #[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
34 #[derive(Debug, Clone, PartialEq, Eq)]
35 pub(crate) BackendFunction(entities::function::Function);
36}
37
38impl BackendFunction {
39 /// Creates a new host `Function` (dynamic) with the provided signature.
40 ///
41 /// If you know the signature of the host function at compile time,
42 /// consider using [`Self::new_typed`] for less runtime overhead.
43 #[inline]
44 pub fn new<FT, F>(store: &mut impl AsStoreMut, ty: FT, func: F) -> Self
45 where
46 FT: Into<FunctionType>,
47 F: Fn(&[Value]) -> Result<Vec<Value>, RuntimeError> + 'static + Send + Sync,
48 {
49 let env = FunctionEnv::new(&mut store.as_store_mut(), ());
50 let wrapped_func = move |_env: FunctionEnvMut<()>,
51 args: &[Value]|
52 -> Result<Vec<Value>, RuntimeError> { func(args) };
53 Self::new_with_env(store, &env, ty, wrapped_func)
54 }
55
56 /// Creates a new host `Function` (dynamic) with the provided signature.
57 ///
58 /// If you know the signature of the host function at compile time,
59 /// consider using [`Self::new_typed_with_env`] for less runtime overhead.
60 ///
61 /// Takes a [`FunctionEnv`] that is passed into func. If that is not required,
62 /// [`Self::new`] might be an option as well.
63 ///
64 /// # Examples
65 ///
66 /// ```
67 /// # use wasmer::{Function, FunctionEnv, FunctionType, Type, Store, Value};
68 /// # let mut store = Store::default();
69 /// # let env = FunctionEnv::new(&mut store, ());
70 /// #
71 /// let signature = FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]);
72 ///
73 /// let f = Function::new_with_env(&mut store, &env, &signature, |_env, args| {
74 /// let sum = args[0].unwrap_i32() + args[1].unwrap_i32();
75 /// Ok(vec![Value::I32(sum)])
76 /// });
77 /// ```
78 ///
79 /// With constant signature:
80 ///
81 /// ```
82 /// # use wasmer::{Function, FunctionEnv, FunctionType, Type, Store, Value};
83 /// # let mut store = Store::default();
84 /// # let env = FunctionEnv::new(&mut store, ());
85 /// #
86 /// const I32_I32_TO_I32: ([Type; 2], [Type; 1]) = ([Type::I32, Type::I32], [Type::I32]);
87 ///
88 /// let f = Function::new_with_env(&mut store, &env, I32_I32_TO_I32, |_env, args| {
89 /// let sum = args[0].unwrap_i32() + args[1].unwrap_i32();
90 /// Ok(vec![Value::I32(sum)])
91 /// });
92 /// ```
93 #[inline]
94 pub fn new_with_env<FT, F, T: Send + 'static>(
95 store: &mut impl AsStoreMut,
96 env: &FunctionEnv<T>,
97 ty: FT,
98 func: F,
99 ) -> Self
100 where
101 FT: Into<FunctionType>,
102 F: Fn(FunctionEnvMut<T>, &[Value]) -> Result<Vec<Value>, RuntimeError>
103 + 'static
104 + Send
105 + Sync,
106 {
107 match &store.as_store_mut().inner.store {
108 #[cfg(feature = "sys")]
109 crate::BackendStore::Sys(_) => Self::Sys(
110 crate::backend::sys::entities::function::Function::new_with_env(
111 store, env, ty, func,
112 ),
113 ),
114 #[cfg(feature = "v8")]
115 crate::BackendStore::V8(_) => Self::V8(
116 crate::backend::v8::entities::function::Function::new_with_env(
117 store, env, ty, func,
118 ),
119 ),
120 #[cfg(feature = "js")]
121 crate::BackendStore::Js(_) => Self::Js(
122 crate::backend::js::entities::function::Function::new_with_env(
123 store, env, ty, func,
124 ),
125 ),
126 }
127 }
128
129 /// Creates a new host `Function` from a native function.
130 #[inline]
131 pub fn new_typed<F, Args, Rets>(store: &mut impl AsStoreMut, func: F) -> Self
132 where
133 F: HostFunction<(), Args, Rets, WithoutEnv> + 'static + Send + Sync,
134 Args: WasmTypeList,
135 Rets: WasmTypeList,
136 {
137 match &store.as_store_mut().inner.store {
138 #[cfg(feature = "sys")]
139 crate::BackendStore::Sys(_) => {
140 Self::Sys(crate::backend::sys::entities::function::Function::new_typed(store, func))
141 }
142 #[cfg(feature = "v8")]
143 crate::BackendStore::V8(_) => Self::V8(
144 crate::backend::v8::entities::function::Function::new_typed(store, func),
145 ),
146 #[cfg(feature = "js")]
147 crate::BackendStore::Js(_) => Self::Js(
148 crate::backend::js::entities::function::Function::new_typed(store, func),
149 ),
150 }
151 }
152
153 /// Creates a new host `Function` with an environment from a typed function.
154 ///
155 /// The function signature is automatically retrieved using the
156 /// Rust typing system.
157 ///
158 /// # Example
159 ///
160 /// ```
161 /// # use wasmer::{Store, Function, FunctionEnv, FunctionEnvMut};
162 /// # let mut store = Store::default();
163 /// # let env = FunctionEnv::new(&mut store, ());
164 /// #
165 /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
166 /// a + b
167 /// }
168 ///
169 /// let f = Function::new_typed_with_env(&mut store, &env, sum);
170 /// ```
171 #[inline]
172 pub fn new_typed_with_env<T: Send + 'static, F, Args, Rets>(
173 store: &mut impl AsStoreMut,
174 env: &FunctionEnv<T>,
175 func: F,
176 ) -> Self
177 where
178 F: HostFunction<T, Args, Rets, WithEnv> + 'static + Send + Sync,
179 Args: WasmTypeList,
180 Rets: WasmTypeList,
181 {
182 match &store.as_store_mut().inner.store {
183 #[cfg(feature = "sys")]
184 crate::BackendStore::Sys(s) => Self::Sys(
185 crate::backend::sys::entities::function::Function::new_typed_with_env(
186 store, env, func,
187 ),
188 ),
189 #[cfg(feature = "v8")]
190 crate::BackendStore::V8(s) => Self::V8(
191 crate::backend::v8::entities::function::Function::new_typed_with_env(
192 store, env, func,
193 ),
194 ),
195 #[cfg(feature = "js")]
196 crate::BackendStore::Js(s) => Self::Js(
197 crate::backend::js::entities::function::Function::new_typed_with_env(
198 store, env, func,
199 ),
200 ),
201 }
202 }
203
204 /// Creates a new async host `Function` (dynamic) with the provided
205 /// signature.
206 ///
207 /// If you know the signature of the host function at compile time,
208 /// consider using [`Self::new_typed_async`] for less runtime overhead.
209 ///
210 /// The provided closure returns a future that resolves to the function results.
211 /// When invoked synchronously
212 /// (via [`Function::call`](crate::Function::call)) the future will run to
213 /// completion immediately, provided it doesn't suspend. When invoked through
214 /// [`Function::call_async`](crate::Function::call_async), the future may suspend
215 /// and resume as needed.
216 #[inline]
217 #[cfg(feature = "experimental-async")]
218 pub fn new_async<FT, F, Fut>(store: &mut impl AsStoreMut, ty: FT, func: F) -> Self
219 where
220 FT: Into<FunctionType>,
221 F: Fn(&[Value]) -> Fut + 'static,
222 Fut: Future<Output = Result<Vec<Value>, RuntimeError>> + 'static,
223 {
224 match &store.as_store_mut().inner.store {
225 #[cfg(feature = "sys")]
226 crate::BackendStore::Sys(_) => Self::Sys(
227 crate::backend::sys::entities::function::Function::new_async(store, ty, func),
228 ),
229 #[cfg(feature = "v8")]
230 crate::BackendStore::V8(_) => unsupported_async_backend("v8"),
231 #[cfg(feature = "js")]
232 crate::BackendStore::Js(_) => Self::Js(
233 crate::backend::js::entities::function::Function::new_async(store, ty, func),
234 ),
235 }
236 }
237
238 /// Creates a new async host `Function` (dynamic) with the provided
239 /// signature and environment.
240 ///
241 /// If you know the signature of the host function at compile time,
242 /// consider using [`Self::new_typed_with_env_async`] for less runtime overhead.
243 ///
244 /// Takes an [`AsyncFunctionEnvMut`] that is passed into func. If
245 /// that is not required, [`Self::new_async`] might be an option as well.
246 #[inline]
247 #[cfg(feature = "experimental-async")]
248 pub fn new_with_env_async<FT, F, Fut, T: 'static>(
249 store: &mut impl AsStoreMut,
250 env: &FunctionEnv<T>,
251 ty: FT,
252 func: F,
253 ) -> Self
254 where
255 FT: Into<FunctionType>,
256 F: Fn(AsyncFunctionEnvMut<T>, &[Value]) -> Fut + 'static,
257 Fut: Future<Output = Result<Vec<Value>, RuntimeError>> + 'static,
258 {
259 match &store.as_store_mut().inner.store {
260 #[cfg(feature = "sys")]
261 crate::BackendStore::Sys(_) => Self::Sys(
262 crate::backend::sys::entities::function::Function::new_with_env_async(
263 store, env, ty, func,
264 ),
265 ),
266 #[cfg(feature = "v8")]
267 crate::BackendStore::V8(_) => unsupported_async_backend("v8"),
268 #[cfg(feature = "js")]
269 crate::BackendStore::Js(_) => Self::Js(
270 crate::backend::js::entities::function::Function::new_with_env_async(
271 store, env, ty, func,
272 ),
273 ),
274 }
275 }
276
277 /// Creates a new async host `Function` from a native typed function.
278 ///
279 /// The future can return either the raw result tuple or any type that implements
280 /// [`IntoResult`](crate::IntoResult) for the result tuple (e.g. `Result<Rets, E>`).
281 #[inline]
282 #[cfg(feature = "experimental-async")]
283 pub fn new_typed_async<F, Args, Rets>(store: &mut impl AsStoreMut, func: F) -> Self
284 where
285 F: AsyncHostFunction<(), Args, Rets, WithoutEnv> + 'static,
286 Args: WasmTypeList + 'static,
287 Rets: WasmTypeList + 'static,
288 {
289 match &store.as_store_mut().inner.store {
290 #[cfg(feature = "sys")]
291 crate::BackendStore::Sys(_) => Self::Sys(
292 crate::backend::sys::entities::function::Function::new_typed_async(store, func),
293 ),
294 #[cfg(feature = "v8")]
295 crate::BackendStore::V8(_) => unsupported_async_backend("v8"),
296 #[cfg(feature = "js")]
297 crate::BackendStore::Js(_) => Self::Js(
298 crate::backend::js::entities::function::Function::new_typed_async(store, func),
299 ),
300 }
301 }
302
303 /// Creates a new async host `Function` with an environment from a typed function.
304 #[inline]
305 #[cfg(feature = "experimental-async")]
306 pub fn new_typed_with_env_async<T: 'static, F, Args, Rets>(
307 store: &mut impl AsStoreMut,
308 env: &FunctionEnv<T>,
309 func: F,
310 ) -> Self
311 where
312 F: AsyncHostFunction<T, Args, Rets, WithEnv> + 'static,
313 Args: WasmTypeList + 'static,
314 Rets: WasmTypeList + 'static,
315 {
316 match &store.as_store_mut().inner.store {
317 #[cfg(feature = "sys")]
318 crate::BackendStore::Sys(_) => Self::Sys(
319 crate::backend::sys::entities::function::Function::new_typed_with_env_async(
320 store, env, func,
321 ),
322 ),
323 #[cfg(feature = "v8")]
324 crate::BackendStore::V8(_) => unsupported_async_backend("v8"),
325 #[cfg(feature = "js")]
326 crate::BackendStore::Js(_) => Self::Js(
327 crate::backend::js::entities::function::Function::new_typed_with_env_async(
328 store, env, func,
329 ),
330 ),
331 }
332 }
333
334 /// Returns the [`FunctionType`] of the `Function`.
335 ///
336 /// # Example
337 ///
338 /// ```
339 /// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type};
340 /// # let mut store = Store::default();
341 /// # let env = FunctionEnv::new(&mut store, ());
342 /// #
343 /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
344 /// a + b
345 /// }
346 ///
347 /// let f = Function::new_typed_with_env(&mut store, &env, sum);
348 ///
349 /// assert_eq!(f.ty(&mut store).params(), vec![Type::I32, Type::I32]);
350 /// assert_eq!(f.ty(&mut store).results(), vec![Type::I32]);
351 /// ```
352 #[inline]
353 pub fn ty(&self, store: &impl AsStoreRef) -> FunctionType {
354 match_rt!(on self => f {
355 f.ty(store)
356 })
357 }
358
359 /// Returns the number of parameters that this function takes.
360 ///
361 /// # Example
362 ///
363 /// ```
364 /// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type};
365 /// # let mut store = Store::default();
366 /// # let env = FunctionEnv::new(&mut store, ());
367 /// #
368 /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
369 /// a + b
370 /// }
371 ///
372 /// let f = Function::new_typed_with_env(&mut store, &env, sum);
373 ///
374 /// assert_eq!(f.param_arity(&mut store), 2);
375 /// ```
376 #[inline]
377 pub fn param_arity(&self, store: &impl AsStoreRef) -> usize {
378 self.ty(store).params().len()
379 }
380
381 /// Returns the number of results this function produces.
382 ///
383 /// # Example
384 ///
385 /// ```
386 /// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type};
387 /// # let mut store = Store::default();
388 /// # let env = FunctionEnv::new(&mut store, ());
389 /// #
390 /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
391 /// a + b
392 /// }
393 ///
394 /// let f = Function::new_typed_with_env(&mut store, &env, sum);
395 ///
396 /// assert_eq!(f.result_arity(&mut store), 1);
397 /// ```
398 #[inline]
399 pub fn result_arity(&self, store: &impl AsStoreRef) -> usize {
400 self.ty(store).params().len()
401 }
402
403 /// Call the `Function` function.
404 ///
405 /// Depending on where the Function is defined, it will call it.
406 /// 1. If the function is defined inside a WebAssembly, it will call the trampoline
407 /// for the function signature.
408 /// 2. If the function is defined in the host (in a native way), it will
409 /// call the trampoline.
410 ///
411 /// # Examples
412 ///
413 /// ```
414 /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value};
415 /// # use wasmer::FunctionEnv;
416 /// # let mut store = Store::default();
417 /// # let env = FunctionEnv::new(&mut store, ());
418 /// # let wasm_bytes = wat2wasm(r#"
419 /// # (module
420 /// # (func (export "sum") (param $x i32) (param $y i32) (result i32)
421 /// # local.get $x
422 /// # local.get $y
423 /// # i32.add
424 /// # ))
425 /// # "#.as_bytes()).unwrap();
426 /// # let module = Module::new(&store, wasm_bytes).unwrap();
427 /// # let import_object = imports! {};
428 /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
429 /// #
430 /// let sum = instance.exports.get_function("sum").unwrap();
431 ///
432 /// assert_eq!(sum.call(&mut store, &[Value::I32(1), Value::I32(2)]).unwrap().to_vec(), vec![Value::I32(3)]);
433 /// ```
434 #[inline]
435 pub fn call(
436 &self,
437 store: &mut impl AsStoreMut,
438 params: &[Value],
439 ) -> Result<Box<[Value]>, RuntimeError> {
440 match_rt!(on self => f {
441 f.call(store, params)
442 })
443 }
444
445 #[doc(hidden)]
446 #[allow(missing_docs)]
447 #[inline]
448 pub fn call_raw(
449 &self,
450 store: &mut impl AsStoreMut,
451 params: Vec<RawValue>,
452 ) -> Result<Box<[Value]>, RuntimeError> {
453 match_rt!(on self => f {
454 f.call_raw(store, params)
455 })
456 }
457
458 #[cfg(feature = "experimental-async")]
459 #[allow(clippy::type_complexity)]
460 pub fn call_async(
461 &self,
462 store: &impl AsStoreAsync,
463 params: Vec<Value>,
464 ) -> Pin<Box<dyn Future<Output = Result<Box<[Value]>, RuntimeError>> + 'static>> {
465 match self {
466 #[cfg(feature = "sys")]
467 Self::Sys(f) => f.call_async(store, params),
468 #[cfg(feature = "v8")]
469 Self::V8(_) => unsupported_async_future(),
470 #[cfg(feature = "js")]
471 Self::Js(f) => f.call_async(store, params),
472 }
473 }
474
475 #[inline]
476 pub(crate) fn vm_funcref(&self, store: &impl AsStoreRef) -> VMFuncRef {
477 match self {
478 #[cfg(feature = "sys")]
479 Self::Sys(f) => VMFuncRef::Sys(f.vm_funcref(store)),
480 #[cfg(feature = "v8")]
481 Self::V8(f) => VMFuncRef::V8(f.vm_funcref(store)),
482 #[cfg(feature = "js")]
483 Self::Js(f) => VMFuncRef::Js(f.vm_funcref(store)),
484 }
485 }
486
487 #[inline]
488 pub(crate) unsafe fn from_vm_funcref(store: &mut impl AsStoreMut, funcref: VMFuncRef) -> Self {
489 match &store.as_store_mut().inner.store {
490 #[cfg(feature = "sys")]
491 crate::BackendStore::Sys(s) => Self::Sys(unsafe {
492 crate::backend::sys::entities::function::Function::from_vm_funcref(
493 store,
494 funcref.unwrap_sys(),
495 )
496 }),
497 #[cfg(feature = "v8")]
498 crate::BackendStore::V8(s) => Self::V8(unsafe {
499 crate::backend::v8::entities::function::Function::from_vm_funcref(
500 store,
501 funcref.unwrap_v_8(),
502 )
503 }),
504 #[cfg(feature = "js")]
505 crate::BackendStore::Js(s) => Self::Js(unsafe {
506 crate::backend::js::entities::function::Function::from_vm_funcref(
507 store,
508 funcref.unwrap_js(),
509 )
510 }),
511 }
512 }
513
514 /// Transform this WebAssembly function into a typed function.
515 /// See [`TypedFunction`] to learn more.
516 ///
517 /// # Examples
518 ///
519 /// ```
520 /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, TypedFunction, Value};
521 /// # use wasmer::FunctionEnv;
522 /// # let mut store = Store::default();
523 /// # let env = FunctionEnv::new(&mut store, ());
524 /// # let wasm_bytes = wat2wasm(r#"
525 /// # (module
526 /// # (func (export "sum") (param $x i32) (param $y i32) (result i32)
527 /// # local.get $x
528 /// # local.get $y
529 /// # i32.add
530 /// # ))
531 /// # "#.as_bytes()).unwrap();
532 /// # let module = Module::new(&store, wasm_bytes).unwrap();
533 /// # let import_object = imports! {};
534 /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
535 /// #
536 /// let sum = instance.exports.get_function("sum").unwrap();
537 /// let sum_typed: TypedFunction<(i32, i32), i32> = sum.typed(&mut store).unwrap();
538 ///
539 /// assert_eq!(sum_typed.call(&mut store, 1, 2).unwrap(), 3);
540 /// ```
541 ///
542 /// # Errors
543 ///
544 /// If the `Args` generic parameter does not match the exported function
545 /// an error will be raised:
546 ///
547 /// ```should_panic
548 /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, TypedFunction, Value};
549 /// # use wasmer::FunctionEnv;
550 /// # let mut store = Store::default();
551 /// # let env = FunctionEnv::new(&mut store, ());
552 /// # let wasm_bytes = wat2wasm(r#"
553 /// # (module
554 /// # (func (export "sum") (param $x i32) (param $y i32) (result i32)
555 /// # local.get $x
556 /// # local.get $y
557 /// # i32.add
558 /// # ))
559 /// # "#.as_bytes()).unwrap();
560 /// # let module = Module::new(&store, wasm_bytes).unwrap();
561 /// # let import_object = imports! {};
562 /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
563 /// #
564 /// let sum = instance.exports.get_function("sum").unwrap();
565 ///
566 /// // This results in an error: `RuntimeError`
567 /// let sum_typed : TypedFunction<(i64, i64), i32> = sum.typed(&mut store).unwrap();
568 /// ```
569 ///
570 /// If the `Rets` generic parameter does not match the exported function
571 /// an error will be raised:
572 ///
573 /// ```should_panic
574 /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, TypedFunction, Value};
575 /// # use wasmer::FunctionEnv;
576 /// # let mut store = Store::default();
577 /// # let env = FunctionEnv::new(&mut store, ());
578 /// # let wasm_bytes = wat2wasm(r#"
579 /// # (module
580 /// # (func (export "sum") (param $x i32) (param $y i32) (result i32)
581 /// # local.get $x
582 /// # local.get $y
583 /// # i32.add
584 /// # ))
585 /// # "#.as_bytes()).unwrap();
586 /// # let module = Module::new(&store, wasm_bytes).unwrap();
587 /// # let import_object = imports! {};
588 /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
589 /// #
590 /// let sum = instance.exports.get_function("sum").unwrap();
591 ///
592 /// // This results in an error: `RuntimeError`
593 /// let sum_typed: TypedFunction<(i32, i32), i64> = sum.typed(&mut store).unwrap();
594 /// ```
595 #[inline]
596 pub fn typed<Args, Rets>(
597 &self,
598 store: &impl AsStoreRef,
599 ) -> Result<TypedFunction<Args, Rets>, RuntimeError>
600 where
601 Args: WasmTypeList,
602 Rets: WasmTypeList,
603 {
604 let ty = self.ty(store);
605
606 // type check
607 {
608 let expected = ty.params();
609 let given = Args::wasm_types();
610
611 if expected != given {
612 return Err(RuntimeError::new(format!(
613 "given types (`{given:?}`) for the function arguments don't match the actual types (`{expected:?}`)",
614 )));
615 }
616 }
617
618 {
619 let expected = ty.results();
620 let given = Rets::wasm_types();
621
622 if expected != given {
623 // todo: error result types don't match
624 return Err(RuntimeError::new(format!(
625 "given types (`{given:?}`) for the function results don't match the actual types (`{expected:?}`)",
626 )));
627 }
628 }
629
630 Ok(TypedFunction::new(store, super::Function(self.clone())))
631 }
632
633 pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternFunction) -> Self {
634 match &store.as_store_mut().inner.store {
635 #[cfg(feature = "sys")]
636 crate::BackendStore::Sys(_) => Self::Sys(
637 crate::backend::sys::entities::function::Function::from_vm_extern(store, vm_extern),
638 ),
639 #[cfg(feature = "v8")]
640 crate::BackendStore::V8(_) => Self::V8(
641 crate::backend::v8::entities::function::Function::from_vm_extern(store, vm_extern),
642 ),
643 #[cfg(feature = "js")]
644 crate::BackendStore::Js(_) => Self::Js(
645 crate::backend::js::entities::function::Function::from_vm_extern(store, vm_extern),
646 ),
647 }
648 }
649
650 /// Checks whether this `Function` can be used with the given store.
651 #[inline]
652 pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
653 match_rt!(on self => f {
654 f.is_from_store(store)
655 })
656 }
657
658 #[inline]
659 pub(crate) fn to_vm_extern(&self) -> VMExtern {
660 match_rt!(on self => f {
661 f.to_vm_extern()
662 })
663 }
664}
665
666#[cold]
667fn unsupported_async_backend(backend: &str) -> ! {
668 panic!(
669 "async host functions are only supported with the `sys` backend (attempted on {backend})"
670 )
671}
672
673#[allow(clippy::type_complexity)]
674pub(super) fn unsupported_async_future<'a>()
675-> Pin<Box<dyn Future<Output = Result<Box<[Value]>, RuntimeError>> + 'a>> {
676 Box::pin(async {
677 Err(RuntimeError::new(
678 "async calls are only supported with the `sys` backend",
679 ))
680 })
681}
682
683impl<'a> Exportable<'a> for BackendFunction {
684 fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> {
685 match _extern {
686 Extern::Function(func) => Ok(&func.0),
687 _ => Err(ExportError::IncompatibleType),
688 }
689 }
690}