flams_math_archives/backend/
temp.rs1use crate::{
2 Archive,
3 backend::{AnyBackend, GlobalBackend, LocalBackend},
4 manager::ArchiveOrGroup,
5 utils::{AsyncEngine, errors::BackendError},
6};
7use ftml_ontology::{
8 domain::modules::{Module, ModuleLike},
9 narrative::{DocDataRef, DocumentRange, documents::Document, elements::Notation},
10 utils::Css,
11};
12use ftml_uris::{ArchiveId, DocumentElementUri, DocumentUri, ModuleUri, SymbolUri, UriPath};
13
14#[derive(Debug)]
15pub struct HTMLData {
16 pub html: Box<str>,
17 pub css: Box<[Css]>,
18 pub body: DocumentRange,
19 pub inner_offset: usize,
20 pub refs: Box<[u8]>,
21}
22
23#[derive(Clone, Debug)]
24pub struct TemporaryBackend {
25 inner: triomphe::Arc<TemporaryBackendI>,
26}
27impl Default for TemporaryBackend {
28 #[inline]
29 fn default() -> Self {
30 Self::new(AnyBackend::Global)
31 }
32}
33
34#[derive(Debug)]
35struct TemporaryBackendI {
36 modules: dashmap::DashMap<ModuleUri, Module, rustc_hash::FxBuildHasher>,
37 documents: dashmap::DashMap<DocumentUri, Document, rustc_hash::FxBuildHasher>,
38 html: dashmap::DashMap<DocumentUri, HTMLData, rustc_hash::FxBuildHasher>,
39 parent: AnyBackend,
40}
41
42impl TemporaryBackend {
43 pub fn reset<A: AsyncEngine>(&self) {
44 self.inner.modules.clear();
45 self.inner.documents.clear();
46 GlobalBackend.reset::<A>();
47 }
48
49 #[must_use]
50 pub fn new(parent: AnyBackend) -> Self {
51 Self {
52 inner: triomphe::Arc::new(TemporaryBackendI {
53 modules: dashmap::DashMap::default(),
54 documents: dashmap::DashMap::default(),
55 html: dashmap::DashMap::default(),
56 parent,
57 }),
58 }
59 }
60 pub fn add_module(&self, m: Module) {
61 self.inner.modules.insert(m.uri.clone(), m);
62 }
63 pub fn add_document(&self, d: Document) {
64 self.inner.documents.insert(d.uri.clone(), d);
65 }
66 pub fn add_html(&self, uri: DocumentUri, d: HTMLData) {
67 self.inner.html.insert(uri, d);
68 }
69}
70
71impl LocalBackend for TemporaryBackend {
72 type ArchiveIter<'a> = <AnyBackend as LocalBackend>::ArchiveIter<'a>;
73
74 #[inline]
75 fn save(
76 &self,
77 in_doc: &ftml_uris::DocumentUri,
78 rel_path: Option<&UriPath>,
79 log: crate::artifacts::FileOrString,
80 from: crate::formats::BuildTargetId,
81 result: Option<Box<dyn crate::artifacts::Artifact>>,
82 ) -> std::result::Result<(), crate::utils::errors::ArtifactSaveError> {
83 self.inner.parent.save(in_doc, rel_path, log, from, result)
84 }
85
86 fn get_document(&self, uri: &DocumentUri) -> Result<Document, BackendError> {
87 self.inner.documents.get(uri).map_or_else(
88 || self.inner.parent.get_document(uri),
89 |e| Ok(e.value().clone()),
90 )
91 }
92
93 fn get_document_async<A: AsyncEngine>(
94 &self,
95 uri: &DocumentUri,
96 ) -> std::pin::Pin<Box<dyn Future<Output = Result<Document, BackendError>> + Send>>
97 where
98 Self: Sized,
99 {
100 if let Some(d) = self.inner.documents.get(uri) {
101 return Box::pin(std::future::ready(Ok(d.value().clone()))) as _;
102 }
103 Box::pin(self.inner.parent.get_document_async::<A>(uri)) as _
104 }
105
106 fn get_module(&self, uri: &ModuleUri) -> Result<ModuleLike, BackendError> {
107 if uri.is_top() {
108 self.inner.modules.get(uri).map_or_else(
109 || self.inner.parent.get_module(uri),
110 |e| Ok(ModuleLike::Module(e.value().clone())),
111 )
112 } else {
113 let SymbolUri { name, module } =
115 unsafe { uri.clone().into_symbol().unwrap_unchecked() };
116 let Some(m) = self.inner.modules.get(&module) else {
117 return self.inner.parent.get_module(uri);
118 };
119 m.as_module_like(&name)
120 .ok_or(BackendError::NotFound(ftml_uris::UriKind::Symbol))
121 }
122 }
123
124 fn get_module_async<A: AsyncEngine>(
125 &self,
126 uri: &ModuleUri,
127 ) -> std::pin::Pin<Box<dyn Future<Output = Result<ModuleLike, BackendError>> + Send>>
128 where
129 Self: Sized,
130 {
131 if uri.is_top() {
132 if let Some(m) = self.inner.modules.get(uri) {
133 Box::pin(std::future::ready(Ok(ModuleLike::Module(
134 m.value().clone(),
135 ))))
136 } else {
137 Box::pin(self.inner.parent.get_module_async::<A>(uri)) as _
138 }
139 } else {
140 let SymbolUri { name, module } =
142 unsafe { uri.clone().into_symbol().unwrap_unchecked() };
143 if let Some(m) = self.inner.modules.get(&module) {
144 let r = m
145 .as_module_like(&name)
146 .ok_or(BackendError::NotFound(ftml_uris::UriKind::Symbol));
147 Box::pin(std::future::ready(r)) as _
148 } else {
149 Box::pin(self.inner.parent.get_module_async::<A>(&uri)) as _
150 }
151 }
152 }
153
154 #[inline]
155 fn with_archive_or_group<R>(
156 &self,
157 id: &ArchiveId,
158 f: impl FnOnce(Option<&ArchiveOrGroup>) -> R,
159 ) -> R
160 where
161 Self: Sized,
162 {
163 self.inner.parent.with_archive_or_group(id, f)
164 }
165
166 #[inline]
167 fn with_archive<R>(&self, id: &ArchiveId, f: impl FnOnce(Option<&Archive>) -> R) -> R
168 where
169 Self: Sized,
170 {
171 self.inner.parent.with_archive(id, f)
172 }
173
174 #[inline]
175 fn with_archives<R>(&self, f: impl FnOnce(Self::ArchiveIter<'_>) -> R) -> R
176 where
177 Self: Sized,
178 {
179 self.inner.parent.with_archives(f)
180 }
181
182 fn get_html_body(&self, d: &DocumentUri) -> Result<(Box<[Css]>, Box<str>), BackendError> {
183 self.inner.html.get(d).map_or_else(
184 || self.inner.parent.get_html_body(d),
185 |html| {
186 Ok((
187 html.css.clone(),
188 html.html[html.body.start..html.body.end]
189 .to_string()
190 .into_boxed_str(),
191 ))
192 },
193 )
194 }
195
196 fn get_html_body_async<A: AsyncEngine>(
197 &self,
198 uri: &ftml_uris::DocumentUri,
199 ) -> std::pin::Pin<
200 Box<
201 dyn Future<Output = Result<(Box<[ftml_ontology::utils::Css]>, Box<str>), BackendError>>
202 + Send,
203 >,
204 >
205 where
206 Self: Sized,
207 {
208 if let Some(html) = self.inner.html.get(uri) {
209 return Box::pin(std::future::ready(Ok((
210 html.css.clone(),
211 html.html[html.body.start..html.body.end]
212 .to_string()
213 .into_boxed_str(),
214 )))) as _;
215 }
216 Box::pin(self.inner.parent.get_html_body_async::<A>(uri)) as _
217 }
218
219 fn get_html_body_inner(&self, d: &DocumentUri) -> Result<(Box<[Css]>, Box<str>), BackendError> {
220 self.inner.html.get(d).map_or_else(
221 || self.inner.parent.get_html_body_inner(d),
222 |html| {
223 Ok((
224 html.css.clone(),
225 html.html[html.body.start + html.inner_offset..html.body.end - "</body>".len()]
226 .to_string()
227 .into_boxed_str(),
228 ))
229 },
230 )
231 }
232
233 fn get_html_body_inner_async<A: AsyncEngine>(
234 &self,
235 uri: &ftml_uris::DocumentUri,
236 ) -> std::pin::Pin<
237 Box<
238 dyn Future<Output = Result<(Box<[ftml_ontology::utils::Css]>, Box<str>), BackendError>>
239 + Send,
240 >,
241 >
242 where
243 Self: Sized,
244 {
245 if let Some(html) = self.inner.html.get(uri) {
246 return Box::pin(std::future::ready(Ok((
247 html.css.clone(),
248 html.html[html.body.start + html.inner_offset..html.body.end - "</body>".len()]
249 .to_string()
250 .into_boxed_str(),
251 )))) as _;
252 }
253 Box::pin(self.inner.parent.get_html_body_inner_async::<A>(uri)) as _
254 }
255
256 fn get_html_full(&self, d: &DocumentUri) -> Result<Box<str>, BackendError> {
257 self.inner.html.get(d).map_or_else(
258 || self.inner.parent.get_html_full(d),
259 |html| Ok(html.html.clone()),
260 )
261 }
262
263 fn get_html_fragment(
264 &self,
265 d: &DocumentUri,
266 range: DocumentRange,
267 ) -> Result<(Box<[Css]>, Box<str>), BackendError> {
268 self.inner.html.get(d).map_or_else(
269 || self.inner.parent.get_html_fragment(d, range),
270 |html| {
271 Ok((
272 html.css.clone(),
273 html.html[range.start..range.end]
274 .to_string()
275 .into_boxed_str(),
276 ))
277 },
278 )
279 }
280
281 fn get_html_fragment_async<A: AsyncEngine>(
282 &self,
283 uri: &ftml_uris::DocumentUri,
284 range: ftml_ontology::narrative::DocumentRange,
285 ) -> std::pin::Pin<
286 Box<
287 dyn Future<Output = Result<(Box<[ftml_ontology::utils::Css]>, Box<str>), BackendError>>
288 + Send,
289 >,
290 > {
291 if let Some(html) = self.inner.html.get(uri) {
292 return Box::pin(std::future::ready(Ok((
293 html.css.clone(),
294 html.html[html.body.start + html.inner_offset..html.body.end]
295 .to_string()
296 .into_boxed_str(),
297 ))));
298 }
299 Box::pin(self.inner.parent.get_html_fragment_async::<A>(uri, range)) as _
300 }
301
302 fn get_reference<T: bincode::Decode<()>>(&self, rf: &DocDataRef<T>) -> Result<T, BackendError>
303 where
304 Self: Sized,
305 {
306 let Some(html) = self.inner.html.get(&rf.in_doc) else {
307 return self.inner.parent.get_reference(rf);
308 };
309
310 let Some(bytes) = html.refs.get(rf.start..rf.end) else {
311 return Err(BackendError::OutOfRangeError(rf.start, rf.end));
312 };
313 let (r, _) = bincode::decode_from_slice(bytes, bincode::config::standard())?;
314 Ok(r)
315 }
316
317 #[cfg(feature = "rdf")]
318 #[inline]
319 fn get_notations<E: AsyncEngine>(
320 &self,
321 uri: &SymbolUri,
322 ) -> impl Iterator<Item = (DocumentElementUri, Notation)>
323 where
324 Self: Sized,
325 {
326 self.inner.parent.get_notations::<E>(uri)
327 }
328
329 #[cfg(feature = "rdf")]
330 #[inline]
331 fn get_var_notations<E: AsyncEngine>(
332 &self,
333 uri: &DocumentElementUri,
334 ) -> impl Iterator<Item = (DocumentElementUri, Notation)>
335 where
336 Self: Sized,
337 {
338 self.inner.parent.get_var_notations::<E>(uri)
339 }
340
341 }