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#[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 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}