runtime/module/
standard.rs

1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 */
6
7use 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
45// TODO: Remove JS Wrapper, Stop Global Scope Pollution, Use CreateEmptyModule and AddModuleExport
46// TODO: Waiting on https://bugzilla.mozilla.org/show_bug.cgi?id=1722802
47pub 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}