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