rquickjs_core/loader/
compile.rs1use crate::{
2 loader::{util::resolve_simple, Loader, Resolver},
3 Ctx, Lock, Module, Mut, Ref, Result,
4};
5use std::{
6 collections::{hash_map::Iter as HashMapIter, HashMap},
7 iter::FusedIterator,
8 ops::{Deref, DerefMut},
9};
10
11#[derive(Default, Clone)]
13pub struct Compile<T = ()> {
14 data: Ref<Mut<CompileData>>,
15 inner: T,
16}
17
18impl<T> Deref for Compile<T> {
19 type Target = T;
20
21 fn deref(&self) -> &Self::Target {
22 &self.inner
23 }
24}
25
26impl<T> DerefMut for Compile<T> {
27 fn deref_mut(&mut self) -> &mut Self::Target {
28 &mut self.inner
29 }
30}
31
32impl Compile {
33 pub fn new() -> Self {
35 Self::default()
36 }
37
38 pub fn resolver<R: Resolver>(&self, resolver: R) -> Compile<R> {
40 Compile {
41 data: self.data.clone(),
42 inner: resolver,
43 }
44 }
45
46 pub fn loader<L: Loader>(&self, loader: L) -> Compile<L> {
48 Compile {
49 data: self.data.clone(),
50 inner: loader,
51 }
52 }
53
54 pub fn modules(&self) -> ResolvedModules {
58 ResolvedModules(self.data.lock())
59 }
60
61 pub fn bytecodes(&self) -> CompiledBytecodes {
65 CompiledBytecodes(self.data.lock())
66 }
67}
68
69pub struct ResolvedModules<'i>(Lock<'i, CompileData>);
73
74impl<'i, 'r: 'i> IntoIterator for &'r ResolvedModules<'i> {
75 type IntoIter = ResolvedModulesIter<'i>;
76 type Item = (&'i str, &'i str);
77 fn into_iter(self) -> Self::IntoIter {
78 ResolvedModulesIter(self.0.modules.iter())
79 }
80}
81
82pub struct ResolvedModulesIter<'r>(HashMapIter<'r, String, String>);
86
87impl<'i> Iterator for ResolvedModulesIter<'i> {
88 type Item = (&'i str, &'i str);
89
90 fn next(&mut self) -> Option<Self::Item> {
91 self.0
92 .next()
93 .map(|(path, name)| (name.as_str(), path.as_str()))
94 }
95
96 fn size_hint(&self) -> (usize, Option<usize>) {
97 self.0.size_hint()
98 }
99}
100
101impl<'i> ExactSizeIterator for ResolvedModulesIter<'i> {
102 fn len(&self) -> usize {
103 self.0.len()
104 }
105}
106
107impl<'i> FusedIterator for ResolvedModulesIter<'i> {}
108
109pub struct CompiledBytecodes<'i>(Lock<'i, CompileData>);
113
114impl<'i, 'r: 'i> IntoIterator for &'r CompiledBytecodes<'i> {
115 type IntoIter = CompiledBytecodesIter<'i>;
116 type Item = (&'i str, &'i [u8]);
117 fn into_iter(self) -> Self::IntoIter {
118 CompiledBytecodesIter {
119 data: &self.0,
120 index: 0,
121 }
122 }
123}
124
125pub struct CompiledBytecodesIter<'r> {
129 data: &'r CompileData,
130 index: usize,
131}
132
133impl<'i> Iterator for CompiledBytecodesIter<'i> {
134 type Item = (&'i str, &'i [u8]);
135
136 fn next(&mut self) -> Option<Self::Item> {
137 let CompileData { modules, bytecodes } = &self.data;
138 if self.index < bytecodes.len() {
139 let (path, data) = &bytecodes[self.index];
140 self.index += 1;
141 modules
142 .get(path.as_str())
143 .map(|name| (name.as_str(), data.as_ref()))
144 } else {
145 None
146 }
147 }
148
149 fn size_hint(&self) -> (usize, Option<usize>) {
150 let len = self.len();
151 (len, Some(len))
152 }
153}
154
155impl<'i> ExactSizeIterator for CompiledBytecodesIter<'i> {
156 fn len(&self) -> usize {
157 self.data.bytecodes.len() - self.index
158 }
159}
160
161impl<'i> FusedIterator for CompiledBytecodesIter<'i> {}
162
163#[derive(Debug, Default)]
164struct CompileData {
165 modules: HashMap<String, String>,
167 bytecodes: Vec<(String, Vec<u8>)>,
169}
170
171impl<R> Resolver for Compile<R>
172where
173 R: Resolver,
174{
175 fn resolve<'js>(&mut self, ctx: &Ctx<'js>, base: &str, name: &str) -> Result<String> {
176 self.inner.resolve(ctx, base, name).inspect(|path| {
177 let name = resolve_simple(base, name);
178 self.data.lock().modules.insert(path.clone(), name);
179 })
180 }
181}
182
183impl<L> Loader for Compile<L>
184where
185 L: Loader,
186{
187 fn load<'js>(&mut self, ctx: &Ctx<'js>, path: &str) -> Result<Module<'js>> {
188 let module = self.inner.load(ctx, path)?;
189 let data = module.write(false)?;
190 self.data.lock().bytecodes.push((path.into(), data));
191 Ok(module)
192 }
193}