Skip to main content

flams_math_archives/backend/
temp.rs

1use 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                //tracing::info!("Getting document globally");
96                self.inner.parent.get_document(uri)
97            },
98            |e| {
99                //tracing::info!("Got document locally");
100                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            //tracing::info!("Got document locally");
114            return Box::pin(std::future::ready(Ok(d.value().clone()))) as _;
115        }
116        //tracing::info!("Getting document globally");
117        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            // SAFETY: !is_top()
128            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            // SAFETY: !is_top()
155            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        //tracing::warn!("Gettin ({},{}) from {}", rf.start, rf.end, rf.in_doc);
328        //tracing::warn!("Here: {}\n{bytes:?}", String::from_utf8_lossy(bytes));
329        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        //self.inner.parent.get_notations::<E>(uri)
351    }
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        //self.inner.parent.get_var_notations::<E>(uri)
371    }
372}