Skip to main content

flams_math_archives/
artifacts.rs

1use crate::{
2    document_file::DocumentFile,
3    utils::{
4        errors::{ArtifactSaveError, FileError, WriteError},
5        lazy_file::{LazyField, LazyFile, LazyFileWriter},
6        path_ext::PathExt,
7    },
8};
9use ftml_ontology::{
10    domain::modules::Module,
11    narrative::{DocumentRange, documents::Document},
12    utils::Css,
13};
14use std::path::{Path, PathBuf};
15
16pub enum FileOrString {
17    File(PathBuf),
18    Str(Box<str>),
19}
20
21pub trait Artifact: std::any::Any {
22    fn kind(&self) -> &'static str;
23    /// # Errors
24    fn write(&self, into: &Path) -> Result<(), ArtifactSaveError>;
25    fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
26    fn as_any(&self) -> &dyn std::any::Any;
27    fn into_any(self: Box<Self>) -> Box<dyn std::any::Any>;
28}
29
30pub trait FileArtifact: std::any::Any {
31    fn kind(&self) -> &'static str;
32    fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
33    fn as_any(&self) -> &dyn std::any::Any;
34    fn source(&self) -> &Path;
35}
36impl<F: FileArtifact> Artifact for F {
37    #[inline]
38    fn kind(&self) -> &'static str {
39        <Self as FileArtifact>::kind(self)
40    }
41    #[inline]
42    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
43        <Self as FileArtifact>::as_any_mut(self)
44    }
45    #[inline]
46    fn as_any(&self) -> &dyn std::any::Any {
47        <Self as FileArtifact>::as_any(self)
48    }
49    #[inline]
50    fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> {
51        self as _
52    }
53    fn write(&self, into: &Path) -> Result<(), ArtifactSaveError> {
54        self.source().rename_safe(&into)?;
55        Ok(())
56    }
57}
58
59pub struct FtmlString(pub Box<str>);
60impl Artifact for FtmlString {
61    #[inline]
62    fn kind(&self) -> &'static str {
63        "ftml"
64    }
65    #[inline]
66    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
67        self as _
68    }
69    #[inline]
70    fn as_any(&self) -> &dyn std::any::Any {
71        self as _
72    }
73    #[inline]
74    fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> {
75        self as _
76    }
77    fn write(&self, into: &Path) -> Result<(), ArtifactSaveError> {
78        std::fs::write(into, self.0.as_bytes())
79            .map_err(|e| ArtifactSaveError::Fs(FileError::Write(into.to_path_buf(), e)))
80    }
81}
82pub struct FtmlFile(pub PathBuf);
83impl Artifact for FtmlFile {
84    #[inline]
85    fn kind(&self) -> &'static str {
86        "ftml"
87    }
88    #[inline]
89    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
90        self as _
91    }
92    #[inline]
93    fn as_any(&self) -> &dyn std::any::Any {
94        self as _
95    }
96    #[inline]
97    fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> {
98        self as _
99    }
100    fn write(&self, into: &Path) -> Result<(), ArtifactSaveError> {
101        std::fs::copy(&self.0, into)
102            .map(|_| ())
103            .map_err(|e| ArtifactSaveError::Fs(FileError::Write(into.to_path_buf(), e)))
104    }
105}
106
107#[derive(Debug)]
108pub struct ContentResult {
109    pub body: DocumentRange,
110    pub inner_offset: u32,
111    pub css: Box<[Css]>,
112    pub data: Box<[u8]>,
113    pub document: Document,
114    pub ftml: Box<str>,
115    pub modules: Vec<Module>,
116    #[cfg(feature = "rdf")]
117    pub triples: Vec<ulo::rdf_types::Triple>,
118}
119impl ContentResult {
120    const NUM_FIELDS: usize = 6;
121    /// ### Errors
122    pub fn read(path: PathBuf) -> Result<Self, ArtifactSaveError> {
123        macro_rules! err {
124            (F $e:expr) => {
125                match $e {
126                    Ok(r) => r,
127                    Err(e) => return Err(ArtifactSaveError::Fs(FileError::ReadEntry(path, e))),
128                }
129            };
130            ($e:expr) => {
131                $e.map_err(|e| ArtifactSaveError::Other(e.to_string().into()))?
132            };
133        }
134        let f = err!(DocumentFile::from_file(path));
135        let (body, inner_offset, css, data, document, ftml) = err!(f.get_all());
136        Ok(Self {
137            body,
138            inner_offset,
139            css,
140            data,
141            document,
142            ftml,
143            modules: Vec::new(),
144            #[cfg(feature = "rdf")]
145            triples: Vec::new(),
146        })
147    }
148}
149impl Artifact for ContentResult {
150    #[inline]
151    fn kind(&self) -> &'static str {
152        "content"
153    }
154    #[inline]
155    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
156        self as _
157    }
158    #[inline]
159    fn as_any(&self) -> &dyn std::any::Any {
160        self as _
161    }
162    #[inline]
163    fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> {
164        self as _
165    }
166    fn write(&self, into: &Path) -> Result<(), ArtifactSaveError> {
167        let mut writer = match LazyFileWriter::<{ Self::NUM_FIELDS }>::new(into) {
168            Ok(w) => w,
169            Err(e) => {
170                return Err(ArtifactSaveError::Fs(FileError::Write(
171                    into.to_path_buf(),
172                    e,
173                )));
174            }
175        };
176        macro_rules! err {
177            ($e:expr) => {
178                if let Err(e) = $e {
179                    match e {
180                        WriteError::Io(e) => {
181                            return Err(ArtifactSaveError::Fs(FileError::Write(
182                                into.to_path_buf(),
183                                e,
184                            )));
185                        }
186                        WriteError::Encode(e) => return Err(ArtifactSaveError::Encode(e)),
187                        _ => unreachable!(),
188                    }
189                }
190            };
191        }
192        err!(writer.write(&self.body));
193        err!(writer.write(&self.inner_offset));
194        err!(writer.write(&self.css));
195        err!(writer.write_bytes(&self.data));
196        err!(writer.write(&self.document));
197        err!(writer.write_string(&self.ftml));
198        Ok(())
199    }
200}
201#[derive(Debug)]
202pub struct ContentUpdate {
203    pub document: Option<Document>,
204    pub modules: Vec<Module>,
205}
206impl Artifact for ContentUpdate {
207    #[inline]
208    fn kind(&self) -> &'static str {
209        "content"
210    }
211    #[inline]
212    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
213        self as _
214    }
215    #[inline]
216    fn as_any(&self) -> &dyn std::any::Any {
217        self as _
218    }
219    #[inline]
220    fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> {
221        self as _
222    }
223    fn write(&self, _: &Path) -> Result<(), ArtifactSaveError> {
224        Err(ArtifactSaveError::Other(
225            "Cannot write update in isolation".into(),
226        ))
227    }
228}