flams_math_archives/
formats.rs1use std::path::Path;
2
3use ftml_uris::{ArchiveId, DocumentUri, ModuleUri, UriPath};
4
5use crate::{
6 artifacts::{Artifact, FileOrString},
7 backend::AnyBackend,
8};
9
10pub mod __reexport {
11 pub use inventory::*;
12}
13
14#[derive(Copy, Clone, Debug, PartialEq, Eq)]
15pub enum FormatOrTargets<'a> {
16 Format(SourceFormatId),
17 Targets(&'a [BuildTargetId]),
18}
19
20#[derive(Copy, Clone, Debug)]
21pub struct SourceFormat {
22 pub name: &'static str,
23 pub description: &'static str,
24 pub targets: &'static [BuildTargetId],
25 pub file_extensions: &'static [&'static str],
26 pub dependencies: fn(BuildSpec) -> Vec<(BuildTargetId, TaskDependency)>,
27}
28impl SourceFormat {
29 #[inline]
30 #[must_use]
31 pub const fn id(&'static self) -> SourceFormatId {
32 SourceFormatId(self)
33 }
34}
35inventory::collect!(SourceFormat);
36#[macro_export]
37macro_rules! source_format {
38 ($i:ident { $($t:tt)* }) => {
39 pub static $i : $crate::formats::SourceFormat = $crate::formats::SourceFormat { $($t)* };
40 $crate::formats::__reexport::submit!{ $i }
41 };
42}
43
44impl SourceFormat {
45 #[inline]
46 pub fn all() -> impl Iterator<Item = SourceFormatId> {
47 inventory::iter.into_iter().map(SourceFormatId)
48 }
49 #[must_use]
50 pub fn get(name: &str) -> Option<SourceFormatId> {
51 Self::all().find(|e| e.name == name)
52 }
53}
54
55pub struct BuildResult {
56 pub log: FileOrString,
57 pub result: Result<Option<Box<dyn Artifact>>, Vec<TaskDependency>>,
58}
59impl BuildResult {
60 #[must_use]
61 pub fn err() -> Self {
62 Self {
63 log: FileOrString::Str(String::new().into_boxed_str()),
64 result: Err(Vec::new()),
65 }
66 }
67}
68impl Default for BuildResult {
69 fn default() -> Self {
70 Self {
71 log: FileOrString::Str(String::new().into_boxed_str()),
72 result: Ok(None),
73 }
74 }
75}
76
77pub struct BuildSpec<'a> {
78 pub uri: &'a DocumentUri,
79 pub source: either::Either<&'a Path, &'a str>,
80 pub backend: &'a AnyBackend,
81 pub rel_path: &'a UriPath,
82}
83
84#[derive(Debug, Clone, Hash, PartialEq, Eq)]
85pub struct TaskRef {
86 pub archive: ArchiveId,
87 pub rel_path: UriPath,
88 pub target: BuildTargetId,
89}
90
91#[derive(Debug, Clone, PartialEq, Eq)]
92pub enum TaskDependency {
93 Physical { task: TaskRef, strict: bool },
94 Logical { uri: ModuleUri, strict: bool },
95}
96
97#[derive(Copy, Clone, Debug)]
98pub struct BuildTarget {
99 pub name: &'static str,
100 pub description: &'static str,
101 pub run: fn(BuildSpec<'_>) -> BuildResult,
104}
105impl BuildTarget {
106 #[inline]
107 #[must_use]
108 pub const fn id(&'static self) -> BuildTargetId {
109 BuildTargetId(self)
110 }
111}
112inventory::collect!(BuildTarget);
113#[macro_export]
114macro_rules! build_target {
115 ($i:ident { $($t:tt)* }) => {
116 pub static $i : $crate::formats::BuildTarget = $crate::formats::BuildTarget { $($t)* };
117 $crate::formats::__reexport::submit!{ $i }
118 };
119}
120
121build_target!(CHECK {
122 name: "check",
123 description: "check content",
124 run: |_| BuildResult::default()
125});
126
127impl BuildTarget {
128 #[inline]
129 pub fn all() -> impl Iterator<Item = BuildTargetId> {
130 inventory::iter.into_iter().map(BuildTargetId)
131 }
132 #[must_use]
133 pub fn get(name: &str) -> Option<BuildTargetId> {
134 Self::all().find(|e| e.name == name)
135 }
136}
137
138#[derive(Copy, Clone)]
139pub struct SourceFormatId(&'static SourceFormat);
140impl std::ops::Deref for SourceFormatId {
141 type Target = &'static SourceFormat;
142 #[inline]
143 fn deref(&self) -> &Self::Target {
144 &self.0
145 }
146}
147impl PartialEq for SourceFormatId {
148 fn eq(&self, other: &Self) -> bool {
149 std::ptr::addr_eq(self.0, other.0)
150 }
151}
152impl Eq for SourceFormatId {}
153impl std::hash::Hash for SourceFormatId {
154 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
155 self.0.name.hash(state);
156 }
157}
158impl std::fmt::Debug for SourceFormatId {
159 #[inline]
160 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
161 self.0.name.fmt(f)
162 }
163}
164
165impl std::fmt::Display for SourceFormatId {
166 #[inline]
167 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
168 self.0.name.fmt(f)
169 }
170}
171
172impl ::serde::Serialize for SourceFormatId {
173 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
174 where
175 S: ::serde::Serializer,
176 {
177 serializer.serialize_str(self.0.name)
178 }
179}
180
181impl<'de> ::serde::Deserialize<'de> for SourceFormatId {
182 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
183 where
184 D: ::serde::Deserializer<'de>,
185 {
186 let s = String::deserialize(deserializer)?;
187 SourceFormat::get(&s).map_or_else(
188 || Err(::serde::de::Error::custom("Unknown source format")),
189 Ok,
190 )
191 }
192}
193
194#[derive(Copy, Clone)]
195pub struct BuildTargetId(&'static BuildTarget);
196impl std::ops::Deref for BuildTargetId {
197 type Target = &'static BuildTarget;
198 #[inline]
199 fn deref(&self) -> &Self::Target {
200 &self.0
201 }
202}
203impl PartialEq for BuildTargetId {
204 fn eq(&self, other: &Self) -> bool {
205 std::ptr::addr_eq(self.0, other.0)
206 }
207}
208impl Eq for BuildTargetId {}
209impl std::hash::Hash for BuildTargetId {
210 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
211 self.0.name.hash(state);
212 }
213}
214impl std::fmt::Debug for BuildTargetId {
215 #[inline]
216 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
217 self.0.name.fmt(f)
218 }
219}
220
221impl std::fmt::Display for BuildTargetId {
222 #[inline]
223 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
224 self.0.name.fmt(f)
225 }
226}
227
228impl ::serde::Serialize for BuildTargetId {
229 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
230 where
231 S: ::serde::Serializer,
232 {
233 serializer.serialize_str(self.0.name)
234 }
235}
236
237impl<'de> ::serde::Deserialize<'de> for BuildTargetId {
238 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
239 where
240 D: ::serde::Deserializer<'de>,
241 {
242 let s = String::deserialize(deserializer)?;
243 BuildTarget::get(&s).map_or_else(
244 || Err(::serde::de::Error::custom("Unknown build target")),
245 Ok,
246 )
247 }
248}