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 #[cfg(feature = "rdf")]
71 #[inline]
72 pub fn add_triples(&self, doc: &DocumentUri, triples: Vec<ulo::rdf_types::Triple>) {
73 self.inner.parent.add_triples(doc, triples);
74 }
75}
76
77impl LocalBackend for TemporaryBackend {
78 type ArchiveIter<'a> = <AnyBackend as LocalBackend>::ArchiveIter<'a>;
79
80 #[inline]
81 fn save(
82 &self,
83 in_doc: &ftml_uris::DocumentUri,
84 rel_path: Option<&UriPath>,
85 log: crate::artifacts::FileOrString,
86 from: crate::formats::BuildTargetId,
87 result: Option<Box<dyn crate::artifacts::Artifact>>,
88 ) -> std::result::Result<(), crate::utils::errors::ArtifactSaveError> {
89 self.inner.parent.save(in_doc, rel_path, log, from, result)
90 }
91
92 fn get_document(&self, uri: &DocumentUri) -> Result<Document, BackendError> {
93 self.inner.documents.get(uri).map_or_else(
94 || {
95 self.inner.parent.get_document(uri)
97 },
98 |e| {
99 Ok(e.value().clone())
101 },
102 )
103 }
104
105 fn get_document_async<A: AsyncEngine>(
106 &self,
107 uri: &DocumentUri,
108 ) -> std::pin::Pin<Box<dyn Future<Output = Result<Document, BackendError>> + Send>>
109 where
110 Self: Sized,
111 {
112 if let Some(d) = self.inner.documents.get(uri) {
113 return Box::pin(std::future::ready(Ok(d.value().clone()))) as _;
115 }
116 Box::pin(self.inner.parent.get_document_async::<A>(uri)) as _
118 }
119
120 fn get_module(&self, uri: &ModuleUri) -> Result<ModuleLike, BackendError> {
121 if uri.is_top() {
122 self.inner.modules.get(uri).map_or_else(
123 || self.inner.parent.get_module(uri),
124 |e| Ok(ModuleLike::Module(e.value().clone())),
125 )
126 } else {
127 let SymbolUri { name, module } =
129 unsafe { uri.clone().into_symbol().unwrap_unchecked() };
130 let Some(m) = self.inner.modules.get(&module) else {
131 return self.inner.parent.get_module(uri);
132 };
133 m.as_module_like(&name)
134 .ok_or_else(|| BackendError::NotFound(SymbolUri { name, module }.into()))
135 }
136 }
137
138 fn get_module_async<A: AsyncEngine>(
139 &self,
140 uri: &ModuleUri,
141 ) -> std::pin::Pin<Box<dyn Future<Output = Result<ModuleLike, BackendError>> + Send>>
142 where
143 Self: Sized,
144 {
145 if uri.is_top() {
146 if let Some(m) = self.inner.modules.get(uri) {
147 Box::pin(std::future::ready(Ok(ModuleLike::Module(
148 m.value().clone(),
149 ))))
150 } else {
151 Box::pin(self.inner.parent.get_module_async::<A>(uri)) as _
152 }
153 } else {
154 let SymbolUri { name, module } =
156 unsafe { uri.clone().into_symbol().unwrap_unchecked() };
157 if let Some(m) = self.inner.modules.get(&module) {
158 let r = m
159 .as_module_like(&name)
160 .ok_or_else(|| BackendError::NotFound(SymbolUri { name, module }.into()));
161 Box::pin(std::future::ready(r)) as _
162 } else {
163 Box::pin(self.inner.parent.get_module_async::<A>(&uri)) as _
164 }
165 }
166 }
167
168 #[inline]
169 fn with_archive_or_group<R>(
170 &self,
171 id: &ArchiveId,
172 f: impl FnOnce(Option<&ArchiveOrGroup>) -> R,
173 ) -> R
174 where
175 Self: Sized,
176 {
177 self.inner.parent.with_archive_or_group(id, f)
178 }
179
180 #[inline]
181 fn with_archive<R>(&self, id: &ArchiveId, f: impl FnOnce(Option<&Archive>) -> R) -> R
182 where
183 Self: Sized,
184 {
185 self.inner.parent.with_archive(id, f)
186 }
187
188 #[inline]
189 fn with_archives<R>(&self, f: impl FnOnce(Self::ArchiveIter<'_>) -> R) -> R
190 where
191 Self: Sized,
192 {
193 self.inner.parent.with_archives(f)
194 }
195
196 fn get_html_body(&self, d: &DocumentUri) -> Result<(Box<[Css]>, Box<str>), BackendError> {
197 self.inner.html.get(d).map_or_else(
198 || self.inner.parent.get_html_body(d),
199 |html| {
200 Ok((
201 html.css.clone(),
202 html.html[html.body.start..html.body.end]
203 .to_string()
204 .into_boxed_str(),
205 ))
206 },
207 )
208 }
209
210 fn get_html_body_async<A: AsyncEngine>(
211 &self,
212 uri: &ftml_uris::DocumentUri,
213 ) -> std::pin::Pin<
214 Box<
215 dyn Future<Output = Result<(Box<[ftml_ontology::utils::Css]>, Box<str>), BackendError>>
216 + Send,
217 >,
218 >
219 where
220 Self: Sized,
221 {
222 if let Some(html) = self.inner.html.get(uri) {
223 return Box::pin(std::future::ready(Ok((
224 html.css.clone(),
225 html.html[html.body.start..html.body.end]
226 .to_string()
227 .into_boxed_str(),
228 )))) as _;
229 }
230 Box::pin(self.inner.parent.get_html_body_async::<A>(uri)) as _
231 }
232
233 fn get_html_body_inner(&self, d: &DocumentUri) -> Result<(Box<[Css]>, Box<str>), BackendError> {
234 self.inner.html.get(d).map_or_else(
235 || self.inner.parent.get_html_body_inner(d),
236 |html| {
237 Ok((
238 html.css.clone(),
239 html.html[html.body.start + html.inner_offset..html.body.end - "</body>".len()]
240 .to_string()
241 .into_boxed_str(),
242 ))
243 },
244 )
245 }
246
247 fn get_html_body_inner_async<A: AsyncEngine>(
248 &self,
249 uri: &ftml_uris::DocumentUri,
250 ) -> std::pin::Pin<
251 Box<
252 dyn Future<Output = Result<(Box<[ftml_ontology::utils::Css]>, Box<str>), BackendError>>
253 + Send,
254 >,
255 >
256 where
257 Self: Sized,
258 {
259 if let Some(html) = self.inner.html.get(uri) {
260 return Box::pin(std::future::ready(Ok((
261 html.css.clone(),
262 html.html[html.body.start + html.inner_offset..html.body.end - "</body>".len()]
263 .to_string()
264 .into_boxed_str(),
265 )))) as _;
266 }
267 Box::pin(self.inner.parent.get_html_body_inner_async::<A>(uri)) as _
268 }
269
270 fn get_html_full(&self, d: &DocumentUri) -> Result<Box<str>, BackendError> {
271 self.inner.html.get(d).map_or_else(
272 || self.inner.parent.get_html_full(d),
273 |html| Ok(html.html.clone()),
274 )
275 }
276
277 fn get_html_fragment(
278 &self,
279 d: &DocumentUri,
280 range: DocumentRange,
281 ) -> Result<(Box<[Css]>, Box<str>), BackendError> {
282 self.inner.html.get(d).map_or_else(
283 || self.inner.parent.get_html_fragment(d, range),
284 |html| {
285 Ok((
286 html.css.clone(),
287 html.html[range.start..range.end]
288 .to_string()
289 .into_boxed_str(),
290 ))
291 },
292 )
293 }
294
295 fn get_html_fragment_async<A: AsyncEngine>(
296 &self,
297 uri: &ftml_uris::DocumentUri,
298 range: ftml_ontology::narrative::DocumentRange,
299 ) -> std::pin::Pin<
300 Box<
301 dyn Future<Output = Result<(Box<[ftml_ontology::utils::Css]>, Box<str>), BackendError>>
302 + Send,
303 >,
304 > {
305 if let Some(html) = self.inner.html.get(uri) {
306 return Box::pin(std::future::ready(Ok((
307 html.css.clone(),
308 html.html[html.body.start + html.inner_offset..html.body.end]
309 .to_string()
310 .into_boxed_str(),
311 ))));
312 }
313 Box::pin(self.inner.parent.get_html_fragment_async::<A>(uri, range)) as _
314 }
315
316 fn get_reference<T: bincode::Decode<()>>(&self, rf: &DocDataRef<T>) -> Result<T, BackendError>
317 where
318 Self: Sized,
319 {
320 let Some(html) = self.inner.html.get(&rf.in_doc) else {
321 return self.inner.parent.get_reference(rf);
322 };
323
324 let Some(bytes) = html.refs.get(rf.start..rf.end) else {
325 return Err(BackendError::OutOfRangeError(rf.start, rf.end));
326 };
327 let (r, _) = bincode::decode_from_slice(bytes, bincode::config::standard())?;
330 Ok(r)
331 }
332
333 #[cfg(feature = "rdf")]
334 #[inline]
335 fn get_notations<E: AsyncEngine>(
336 &self,
337 uri: &SymbolUri,
338 ) -> impl Iterator<Item = (DocumentElementUri, Notation)>
339 where
340 Self: Sized,
341 {
342 use ftml_uris::FtmlUri;
343
344 GlobalBackend
345 .query_notations::<E, ftml_ontology::narrative::elements::notations::NotationReference>(
346 uri.to_iri(),
347 self,
348 |n| n.notation,
349 )
350 }
352
353 #[cfg(feature = "rdf")]
354 #[inline]
355 fn get_var_notations<E: AsyncEngine>(
356 &self,
357 uri: &DocumentElementUri,
358 ) -> impl Iterator<Item = (DocumentElementUri, Notation)>
359 where
360 Self: Sized,
361 {
362 use ftml_uris::FtmlUri;
363
364 GlobalBackend
365 .query_notations::<E, ftml_ontology::narrative::elements::notations::VariableNotationReference>(
366 uri.to_iri(),
367 self,
368 |n| n.notation,
369 )
370 }
372}