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#[cfg(feature = "rdf")]
108impl Artifact for Vec<ulo::rdf_types::Triple> {
109    #[inline]
110    fn kind(&self) -> &'static str {
111        "index.ttl"
112    }
113    #[inline]
114    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
115        self as _
116    }
117    #[inline]
118    fn as_any(&self) -> &dyn std::any::Any {
119        self as _
120    }
121    #[inline]
122    fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> {
123        self as _
124    }
125    fn write(&self, into: &Path) -> Result<(), ArtifactSaveError> {
126        let file = match std::fs::File::create(into) {
127            Ok(f) => f,
128            Err(e) => {
129                return Err(ArtifactSaveError::Other(
130                    format!("error writing rdf: {e}").into(),
131                ));
132            }
133        };
134        let writer = std::io::BufWriter::new(file);
135        let mut writer = oxigraph::io::RdfSerializer::from_format(oxigraph::io::RdfFormat::Turtle)
136            .for_writer(writer);
137        for t in self {
138            let _ = writer.serialize_triple(t);
139        }
140        let _ = writer.finish();
141        Ok(())
142    }
143}
144
145#[derive(Debug)]
146pub struct ContentResult {
147    pub body: DocumentRange,
148    pub inner_offset: u32,
149    pub css: Box<[Css]>,
150    pub data: Box<[u8]>,
151    pub document: Document,
152    pub ftml: Box<str>,
153    pub modules: Vec<Module>,
154    #[cfg(feature = "rdf")]
155    pub triples: Vec<ulo::rdf_types::Triple>,
156}
157impl ContentResult {
158    const NUM_FIELDS: usize = 6;
159    /// ### Errors
160    pub fn read(path: PathBuf) -> Result<Self, ArtifactSaveError> {
161        macro_rules! err {
162            (F $e:expr) => {
163                match $e {
164                    Ok(r) => r,
165                    Err(e) => return Err(ArtifactSaveError::Fs(FileError::ReadEntry(path, e))),
166                }
167            };
168            ($e:expr) => {
169                $e.map_err(|e| ArtifactSaveError::Other(e.to_string().into()))?
170            };
171        }
172        let f = err!(DocumentFile::from_file(path));
173        let (body, inner_offset, css, data, document, ftml) = err!(f.get_all());
174        Ok(Self {
175            body,
176            inner_offset,
177            css,
178            data,
179            document,
180            ftml,
181            modules: Vec::new(),
182            #[cfg(feature = "rdf")]
183            triples: Vec::new(),
184        })
185    }
186}
187impl Artifact for ContentResult {
188    #[inline]
189    fn kind(&self) -> &'static str {
190        "content"
191    }
192    #[inline]
193    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
194        self as _
195    }
196    #[inline]
197    fn as_any(&self) -> &dyn std::any::Any {
198        self as _
199    }
200    #[inline]
201    fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> {
202        self as _
203    }
204    fn write(&self, into: &Path) -> Result<(), ArtifactSaveError> {
205        let mut writer = match LazyFileWriter::<{ Self::NUM_FIELDS }>::new(into) {
206            Ok(w) => w,
207            Err(e) => {
208                return Err(ArtifactSaveError::Fs(FileError::Write(
209                    into.to_path_buf(),
210                    e,
211                )));
212            }
213        };
214        macro_rules! err {
215            ($e:expr) => {
216                if let Err(e) = $e {
217                    match e {
218                        WriteError::Io(e) => {
219                            return Err(ArtifactSaveError::Fs(FileError::Write(
220                                into.to_path_buf(),
221                                e,
222                            )));
223                        }
224                        WriteError::Encode(e) => return Err(ArtifactSaveError::Encode(e)),
225                        _ => unreachable!(),
226                    }
227                }
228            };
229        }
230        err!(writer.write(&self.body));
231        err!(writer.write(&self.inner_offset));
232        err!(writer.write(&self.css));
233        err!(writer.write_bytes(&self.data));
234        err!(writer.write(&self.document));
235        err!(writer.write_string(&self.ftml));
236        Ok(())
237    }
238}
239#[derive(Debug)]
240pub struct ContentUpdate {
241    pub document: Option<Document>,
242    pub modules: Vec<Module>,
243}
244impl Artifact for ContentUpdate {
245    #[inline]
246    fn kind(&self) -> &'static str {
247        "content"
248    }
249    #[inline]
250    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
251        self as _
252    }
253    #[inline]
254    fn as_any(&self) -> &dyn std::any::Any {
255        self as _
256    }
257    #[inline]
258    fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> {
259        self as _
260    }
261    fn write(&self, _: &Path) -> Result<(), ArtifactSaveError> {
262        Err(ArtifactSaveError::Other(
263            "Cannot write update in isolation".into(),
264        ))
265    }
266}