wasm_bridge_js/no_bindgen/
func.rs

1use 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            // TODO: could really use name of the function in the error here
37            .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}