flams_math_archives/
artifacts.rs

1use crate::utils::{
2    errors::{ArtifactSaveError, FileError, WriteError},
3    lazy_file::LazyFileWriter,
4    path_ext::PathExt,
5};
6use ftml_ontology::{
7    domain::modules::Module,
8    narrative::{DocumentRange, documents::Document},
9    utils::Css,
10};
11use std::path::{Path, PathBuf};
12
13pub enum FileOrString {
14    File(PathBuf),
15    Str(Box<str>),
16}
17
18pub trait Artifact: std::any::Any {
19    fn kind(&self) -> &'static str;
20    /// # Errors
21    fn write(&self, into: &Path) -> Result<(), ArtifactSaveError>;
22    fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
23    fn as_any(&self) -> &dyn std::any::Any;
24}
25
26pub trait FileArtifact: std::any::Any {
27    fn kind(&self) -> &'static str;
28    fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
29    fn as_any(&self) -> &dyn std::any::Any;
30    fn source(&self) -> &Path;
31}
32impl<F: FileArtifact> Artifact for F {
33    #[inline]
34    fn kind(&self) -> &'static str {
35        <Self as FileArtifact>::kind(self)
36    }
37    #[inline]
38    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
39        <Self as FileArtifact>::as_any_mut(self)
40    }
41    #[inline]
42    fn as_any(&self) -> &dyn std::any::Any {
43        <Self as FileArtifact>::as_any(self)
44    }
45    fn write(&self, into: &Path) -> Result<(), ArtifactSaveError> {
46        self.source().rename_safe(&into)?;
47        Ok(())
48    }
49}
50
51pub struct FtmlString(pub Box<str>);
52impl Artifact for FtmlString {
53    #[inline]
54    fn kind(&self) -> &'static str {
55        "ftml"
56    }
57    #[inline]
58    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
59        self as _
60    }
61    #[inline]
62    fn as_any(&self) -> &dyn std::any::Any {
63        self as _
64    }
65    fn write(&self, into: &Path) -> Result<(), ArtifactSaveError> {
66        std::fs::write(into, self.0.as_bytes())
67            .map_err(|e| ArtifactSaveError::Fs(FileError::Write(into.to_path_buf(), e)))
68    }
69}
70pub struct FtmlFile(pub PathBuf);
71impl Artifact for FtmlFile {
72    #[inline]
73    fn kind(&self) -> &'static str {
74        "ftml"
75    }
76    #[inline]
77    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
78        self as _
79    }
80    #[inline]
81    fn as_any(&self) -> &dyn std::any::Any {
82        self as _
83    }
84    fn write(&self, into: &Path) -> Result<(), ArtifactSaveError> {
85        std::fs::copy(&self.0, into)
86            .map(|_| ())
87            .map_err(|e| ArtifactSaveError::Fs(FileError::Write(into.to_path_buf(), e)))
88    }
89}
90
91#[derive(Debug)]
92pub struct ContentResult {
93    pub document: Document,
94    pub modules: Vec<Module>,
95    pub data: Box<[u8]>,
96    pub body: DocumentRange,
97    pub inner_offset: u32,
98    pub css: Box<[Css]>,
99    pub ftml: Box<str>,
100    #[cfg(feature = "rdf")]
101    pub triples: Vec<ulo::rdf_types::Triple>,
102}
103impl Artifact for ContentResult {
104    #[inline]
105    fn kind(&self) -> &'static str {
106        "content"
107    }
108    #[inline]
109    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
110        self as _
111    }
112    #[inline]
113    fn as_any(&self) -> &dyn std::any::Any {
114        self as _
115    }
116    fn write(&self, into: &Path) -> Result<(), ArtifactSaveError> {
117        let mut writer = match LazyFileWriter::<6>::new(into) {
118            Ok(w) => w,
119            Err(e) => {
120                return Err(ArtifactSaveError::Fs(FileError::Write(
121                    into.to_path_buf(),
122                    e,
123                )));
124            }
125        };
126        macro_rules! err {
127            ($e:expr) => {
128                if let Err(e) = $e {
129                    match e {
130                        WriteError::Io(e) => {
131                            return Err(ArtifactSaveError::Fs(FileError::Write(
132                                into.to_path_buf(),
133                                e,
134                            )));
135                        }
136                        WriteError::Encode(e) => return Err(ArtifactSaveError::Encode(e)),
137                        _ => unreachable!(),
138                    }
139                }
140            };
141        }
142        err!(writer.write(&self.body));
143        err!(writer.write(&self.inner_offset));
144        err!(writer.write(&self.css));
145        err!(writer.write_bytes(&self.data));
146        err!(writer.write(&self.document));
147        err!(writer.write_string(&self.ftml));
148        Ok(())
149    }
150}