flams_math_archives/
artifacts.rs1use 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 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 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}