rquickjs_core/loader/
bundle.rs

1//! Utilities for embedding JS modules.
2
3use super::{util::resolve_simple, Loader, Resolver};
4use crate::{Ctx, Error, Module, Result};
5use alloc::string::String;
6use core::ops::Deref;
7
8/// The module data which contains bytecode
9///
10/// This trait needed because the modules potentially can contain any kind of data like a typing (for TypeScript) or metadata.
11pub trait HasByteCode<'bc> {
12    fn get_bytecode(&self) -> &'bc [u8];
13}
14
15impl<'bc> HasByteCode<'bc> for &'bc [u8] {
16    fn get_bytecode(&self) -> &'bc [u8] {
17        self
18    }
19}
20
21/// The alias for compiled modules represented as a static const arrays
22///
23/// The element is a tuple of `(module_name, module_data)`.
24pub type ScaBundleData<D> = &'static [(&'static str, D)];
25
26#[cfg(feature = "phf")]
27/// The alias for compiled modules represented as a perfect hash maps
28///
29/// The key is a module name and the value is a module data.
30pub type PhfBundleData<D> = &'static phf::Map<&'static str, D>;
31
32/// The resolver and loader for bundles of compiled modules
33#[derive(Debug, Clone, Copy)]
34pub struct Bundle<T>(pub T);
35
36impl<T> Deref for Bundle<T> {
37    type Target = T;
38
39    fn deref(&self) -> &Self::Target {
40        &self.0
41    }
42}
43
44impl<D> Resolver for Bundle<ScaBundleData<D>> {
45    fn resolve<'js>(&mut self, _ctx: &Ctx<'js>, base: &str, name: &str) -> Result<String> {
46        let path = resolve_simple(base, name);
47        if self.iter().any(|(name, _)| *name == path) {
48            Ok(path)
49        } else {
50            Err(Error::new_resolving(base, name))
51        }
52    }
53}
54
55#[cfg(feature = "phf")]
56impl<D> Resolver for Bundle<PhfBundleData<D>> {
57    fn resolve<'js>(&mut self, _ctx: &Ctx<'js>, base: &str, name: &str) -> Result<String> {
58        let path = resolve_simple(base, name);
59        if self.contains_key(path.as_str()) {
60            Ok(path)
61        } else {
62            Err(Error::new_resolving(base, name))
63        }
64    }
65}
66
67impl<D> Loader for Bundle<ScaBundleData<D>>
68where
69    D: HasByteCode<'static>,
70{
71    fn load<'js>(&mut self, ctx: &Ctx<'js>, name: &str) -> Result<Module<'js>> {
72        if let Some((_, x)) = self.iter().find(|(module_name, _)| *module_name == name) {
73            let module = unsafe { Module::load(ctx.clone(), x.get_bytecode())? };
74            return Ok(module);
75        }
76        Err(Error::new_loading(name))
77    }
78}
79
80#[cfg(feature = "phf")]
81impl<D> Loader for Bundle<PhfBundleData<D>>
82where
83    D: HasByteCode<'static>,
84{
85    fn load<'js>(&mut self, ctx: &Ctx<'js>, name: &str) -> Result<Module<'js>> {
86        if let Some(x) = self.get(name) {
87            let module = unsafe { Module::load(ctx.clone(), x.get_bytecode())? };
88            return Ok(module);
89        }
90        Err(Error::new_loading(name))
91    }
92}