wasm_bridge_js/no_bindgen/
func.rs1use std::rc::Rc;
2
3use anyhow::bail;
4use js_sys::{Array, Function, Reflect};
5use wasm_bindgen::JsValue;
6
7use crate::{helpers::map_js_error, *};
8
9pub struct Func {
10 function: Function,
11 _closures: Rc<Vec<DropHandle>>,
12}
13
14impl Func {
15 pub(crate) fn new(function: Function, closures: Rc<Vec<DropHandle>>) -> Self {
16 Self {
17 function,
18 _closures: closures,
19 }
20 }
21
22 pub fn call(&self, _store: impl AsContextMut, args: &[Val], rets: &mut [Val]) -> Result<()> {
23 if self.function.length() != args.len() as u32 {
24 bail!(
25 "Exported function takes {} arguments, but {} arguments were provided instead",
26 self.function.length(),
27 args.len()
28 );
29 }
30
31 let js_args: Array = args.iter().map(Val::to_js_value).collect();
32
33 let js_rets = self
34 .function
35 .apply(&JsValue::UNDEFINED, &js_args)
36 .map_err(map_js_error("call untyped exported function"))?;
38
39 match rets.len() {
40 0 => {
41 <()>::from_js_value(&js_rets)?;
42 }
43 1 => {
44 rets[0] = Val::from_js_value(&js_rets)?;
45 }
46 n => {
47 if !js_rets.is_array() {
48 return Err(map_js_error("Exported function did not return an array")(
49 js_rets,
50 ));
51 }
52 let js_array: Array = js_rets.into();
53 if js_array.length() != n as u32 {
54 bail!(
55 "Exported function returned {} values, but {} result slots were provided",
56 js_array.length(),
57 n
58 );
59 }
60
61 for (index, ret) in rets.iter_mut().enumerate() {
62 let js_val = Reflect::get_u32(&js_array, index as _)
63 .map_err(map_js_error("set rets at index"))?;
64
65 *ret = Val::from_js_value(&js_val)?;
66 }
67 }
68 }
69
70 Ok(())
71 }
72}