1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use std::rc::Rc;

use js_sys::{Object, Reflect};
use wasm_bindgen::JsValue;

use crate::*;

pub struct Linker {
    import_object: JsValue,
    closures: Vec<DropHandler>,
}

impl Linker {
    pub fn new(_engine: &Engine) -> Self {
        Self {
            import_object: Object::new().into(),
            closures: vec![],
        }
    }

    pub fn instantiate(
        &self,
        _store: impl AsContextMut,
        module: &Module,
    ) -> Result<Instance, Error> {
        let imports = self.import_object.clone().into();
        Instance::new_with_imports(module, &imports, self.closures.clone())
    }

    pub fn func_wrap<Params, Results, F>(
        &mut self,
        module: &str,
        name: &str,
        func: F,
    ) -> Result<&mut Self, Error>
    where
        F: IntoClosure<Params, Results>,
    {
        let module = self.module(module)?;

        let (js_val, handler) = func.into_closure();

        Reflect::set(&module, &name.into(), &js_val)?;

        self.closures.push(handler);

        Ok(self)
    }

    fn module(&self, module: &str) -> Result<JsValue, Error> {
        let module_str: JsValue = module.into();
        let existing = Reflect::get(&self.import_object, &module_str)?;

        if existing.is_object() {
            Ok(existing)
        } else {
            let new_module: JsValue = Object::new().into();
            Reflect::set(&self.import_object, &module_str, &new_module)?;
            Ok(new_module)
        }
    }
}

#[derive(Clone, Debug)]
pub struct DropHandler(Rc<dyn std::fmt::Debug>);

impl DropHandler {
    pub fn new<T: std::fmt::Debug + 'static>(value: T) -> Self {
        Self(Rc::new(value))
    }
}