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