runtime/module/
standard.rs1use ion::flags::PropertyFlags;
8use ion::module::{Module, ModuleRequest, ModuleType};
9use ion::{Context, Object};
10
11pub trait StandardModules {
12 fn init(self, cx: &Context, global: &Object) -> bool;
13
14 fn init_globals(self, cx: &Context, global: &Object) -> bool;
15}
16
17impl StandardModules for () {
18 fn init(self, _: &Context, _: &Object) -> bool {
19 true
20 }
21
22 fn init_globals(self, _: &Context, _: &Object) -> bool {
23 true
24 }
25}
26
27pub trait NativeModule<'cx> {
28 const NAME: &'static str;
29 const VARIABLE_NAME: &'static str;
30 const SOURCE: &'static str;
31
32 fn module(&self, cx: &'cx Context) -> Option<Object<'cx>>;
33}
34
35impl<M: for<'cx> NativeModule<'cx> + 'static> StandardModules for M {
36 fn init(self, cx: &Context, global: &Object) -> bool {
37 init_module(cx, global, &self).is_some()
38 }
39
40 fn init_globals(self, cx: &Context, global: &Object) -> bool {
41 init_global_module(cx, global, &self).is_some()
42 }
43}
44
45pub fn init_module<'cx, M: NativeModule<'cx>>(cx: &'cx Context, global: &Object, module: &M) -> Option<Object<'cx>> {
48 let internal = format!("______{}Internal______", M::VARIABLE_NAME);
49
50 if let Some(module) = module.module(cx)
51 && global.define_as(cx, internal, &module, PropertyFlags::CONSTANT)
52 {
53 let loader = unsafe { &mut (*cx.get_inner_data().as_ptr()).module_loader };
54 return loader
55 .as_mut()
56 .is_some_and(|loader| {
57 let module = Module::compile(cx, M::NAME, None, M::SOURCE, ModuleType::JavaScript).unwrap();
58 let request = ModuleRequest::new(cx, M::NAME, ModuleType::JavaScript);
59 loader.register(cx, module.0.handle().get(), &request).is_ok()
60 })
61 .then_some(module);
62 }
63 None
64}
65
66pub fn init_global_module<'cx, M: NativeModule<'cx>>(
67 cx: &'cx Context, global: &Object, module: &M,
68) -> Option<Object<'cx>> {
69 let module = module.module(cx)?;
70 global
71 .define_as(cx, M::VARIABLE_NAME, &module, PropertyFlags::CONSTANT_ENUMERATED)
72 .then_some(module)
73}