flams_math_archives/utils/
errors.rs1use std::path::PathBuf;
2
3use ftml_uris::errors::UriParseError;
4
5#[derive(Debug, thiserror::Error)]
6pub enum BackendError {
7 #[error("element not found")]
8 NotFound(ftml_uris::UriKind),
9 #[error("archive not found")]
10 ArchiveNotFound,
11 #[error("{0}")]
12 Channel(#[from] ftml_ontology::utils::awaitable::ChannelError),
13 #[error("io: {0}")]
14 Io(#[from] std::io::Error),
15 #[error("decoding error: {0}")]
16 Decode(#[from] bincode::error::DecodeError),
17 #[error("out of range error: {0}--{1}")]
18 OutOfRangeError(usize, usize),
19}
20impl Clone for BackendError {
21 fn clone(&self) -> Self {
22 match self {
23 Self::NotFound(k) => Self::NotFound(*k),
24 Self::ArchiveNotFound => Self::ArchiveNotFound,
25 Self::Channel(e) => Self::Channel(*e),
26 Self::Io(err) => Self::Io(clone_io(err)),
27 Self::Decode(e) => Self::Decode(clone_bincode(e)),
28 Self::OutOfRangeError(a, b) => Self::OutOfRangeError(*a, *b),
29 }
30 }
31}
32impl<E: std::fmt::Debug> From<BackendError> for ftml_backend::BackendError<E> {
33 fn from(value: BackendError) -> Self {
34 match value {
35 BackendError::NotFound(u) => ftml_backend::BackendError::NotFound(u),
36 BackendError::ArchiveNotFound => {
37 ftml_backend::BackendError::NotFound(ftml_uris::UriKind::Archive)
38 }
39 _ => ftml_backend::BackendError::ToDo(value.to_string()),
40 }
41 }
42}
43
44#[allow(clippy::fallible_impl_from)]
45impl From<ReadError> for BackendError {
46 fn from(value: ReadError) -> Self {
47 match value {
48 ReadError::Channel(c) => Self::Channel(c),
49 ReadError::Decode(e) => Self::Decode(e),
50 ReadError::Io(e) => Self::Io(e),
51 ReadError::NumberOfFields { .. } => panic!("{value} -- this is a bug"),
52 }
53 }
54}
55
56#[derive(Debug, thiserror::Error)]
57pub enum ManifestParseError {
58 #[error("file path has no parent")]
59 NoParent,
60 #[error("io: {0}")]
61 Io(#[from] std::io::Error),
62 #[error("id {0} does not match its relative location")]
63 IdMismatch(String),
64 #[error("id field is empty")]
65 EmptyId,
66 #[error("invalid archive id: {0}")]
67 InvalidId(String),
68 #[error("unknown format: {0}")]
69 UnknownFormat(String),
70 #[error("missing format or kind field")]
71 NoFormatOrKind,
72 #[error("unknown archive kind: {0}")]
73 UnknownKind(String),
74 #[error("missing url-base field")]
75 NoUrlBase,
76 #[error("invalid uri in url-base \"{0}\":{1}")]
77 InvalidUrlBase(String, #[source] UriParseError),
78 #[error("invalid archive for kind {0}: {1}")]
79 InvalidKind(&'static str, String),
80}
81
82#[derive(Debug, thiserror::Error)]
83pub enum NewArchiveError {
84 #[error("no mathhub directory found")]
85 NoMathHub,
86 #[error("error creating directory {a}: {1}",a=.0.display())]
87 CreateDir(PathBuf, #[source] std::io::Error),
88 #[error("error writing to file {a}: {1}",a=.0.display())]
89 Write(PathBuf, #[source] std::io::Error),
90}
91
92#[derive(Debug, thiserror::Error)]
93pub enum FileError {
94 #[error("error creating file {f}: {1}",f=.0.display())]
95 Creation(PathBuf, #[source] std::io::Error),
96 #[error("error writing to file {f}: {1}",f=.0.display())]
97 Write(PathBuf, #[source] std::io::Error),
98 #[error("error renaming directory {f}: {1}",f=.0.display())]
99 Rename(PathBuf, #[source] std::io::Error),
100 #[error("error reading directory {f}: {1}",f=.0.display())]
101 ReadDir(PathBuf, #[source] std::io::Error),
102 #[error("error reading entry of directory {f}: {1}",f=.0.display())]
103 ReadEntry(PathBuf, #[source] std::io::Error),
104 #[error("error determining type of file {f}: {1}",f=.0.display())]
105 FileType(PathBuf, #[source] std::io::Error),
106 #[error("error obtaining metadata of file {f}: {1}",f=.0.display())]
107 MetaData(PathBuf, #[source] std::io::Error),
108 #[error("error copying {f} to {t}: {error}",f=.from.display(),t=.to.display())]
109 Copying {
110 from: PathBuf,
111 to: PathBuf,
112 #[source]
113 error: std::io::Error,
114 },
115 #[error("Error setting file modification time for {f}: {1}",f=.0.display())]
116 SetFileModTime(PathBuf, #[source] std::io::Error),
117 #[error("target file/directory already exists")]
118 AlreadyExists,
119}
120
121#[derive(Debug, thiserror::Error)]
122pub enum WriteError {
123 #[error("field number out of bounds: {index} of {max}")]
124 NumberOfFields { max: usize, index: usize },
125 #[error("io: {0}")]
126 Io(#[from] std::io::Error),
127 #[error("encoding error: {0}")]
128 Encode(#[from] bincode::error::EncodeError),
129}
130
131#[derive(Debug, thiserror::Error)]
132pub enum ArtifactSaveError {
133 #[error("fs error: {0}")]
134 Fs(#[from] FileError),
135 #[error("encoding error: {0}")]
136 Encode(#[from] bincode::error::EncodeError),
137 #[error("archive not found")]
138 NoArchive,
139}
140
141#[derive(Debug, thiserror::Error)]
142pub enum ReadError {
143 #[error("field number out of bounds: {index} of {max}")]
144 NumberOfFields { max: usize, index: usize },
145 #[error("io: {0}")]
146 Io(#[from] std::io::Error),
147 #[error("decoding error: {0}")]
148 Decode(#[from] bincode::error::DecodeError),
149 #[error("internal channel error: {0}")]
150 Channel(#[from] ftml_ontology::utils::awaitable::ChannelError),
151}
152impl Clone for ReadError {
153 fn clone(&self) -> Self {
154 match self {
155 Self::Io(err) => Self::Io(clone_io(err)),
156 Self::Decode(bc) => Self::Decode(clone_bincode(bc)),
157 Self::Channel(e) => Self::Channel(*e),
158 Self::NumberOfFields { max, index } => Self::NumberOfFields {
159 max: *max,
160 index: *index,
161 },
162 }
163 }
164}
165
166#[must_use]
167pub fn clone_io(err: &std::io::Error) -> std::io::Error {
168 std::io::Error::new(err.kind(), err.to_string())
169}
170
171#[must_use]
172pub fn clone_bincode(err: &bincode::error::DecodeError) -> bincode::error::DecodeError {
173 use bincode::error::DecodeError::*;
174 match err {
175 UnexpectedEnd { additional } => UnexpectedEnd {
176 additional: *additional,
177 },
178 LimitExceeded => LimitExceeded,
179 InvalidIntegerType { expected, found } => InvalidIntegerType {
180 expected: clone_int_tp(expected),
181 found: clone_int_tp(found),
182 },
183 NonZeroTypeIsZero { non_zero_type } => NonZeroTypeIsZero {
184 non_zero_type: clone_int_tp(non_zero_type),
185 },
186 UnexpectedVariant {
187 type_name,
188 allowed,
189 found,
190 } => UnexpectedVariant {
191 type_name,
192 allowed,
193 found: *found,
194 },
195 Utf8 { inner } => Utf8 { inner: *inner },
196 InvalidCharEncoding(a) => InvalidCharEncoding(*a),
197 InvalidBooleanValue(a) => InvalidBooleanValue(*a),
198 ArrayLengthMismatch { required, found } => ArrayLengthMismatch {
199 required: *required,
200 found: *found,
201 },
202 OutsideUsizeRange(i) => OutsideUsizeRange(*i),
203 EmptyEnum { type_name } => EmptyEnum { type_name },
204 InvalidDuration { secs, nanos } => InvalidDuration {
205 secs: *secs,
206 nanos: *nanos,
207 },
208 InvalidSystemTime { duration } => InvalidSystemTime {
209 duration: *duration,
210 },
211 CStringNulError { position } => CStringNulError {
212 position: *position,
213 },
214 Io { inner, additional } => Io {
215 inner: clone_io(inner),
216 additional: *additional,
217 },
218 Other(s) => Other(s),
219 OtherString(s) => OtherString(s.clone()),
220 Serde(s) => Serde(clone_serde(s)),
221 o => OtherString(o.to_string()),
222 }
223}
224
225const fn clone_serde(s: &bincode::serde::DecodeError) -> bincode::serde::DecodeError {
226 use bincode::serde::DecodeError::*;
227 match s {
228 IdentifierNotSupported => IdentifierNotSupported,
229 IgnoredAnyNotSupported => IgnoredAnyNotSupported,
230 CannotBorrowOwnedData => CannotBorrowOwnedData,
231 _ => AnyNotSupported,
232 }
233}
234
235const fn clone_int_tp(i: &bincode::error::IntegerType) -> bincode::error::IntegerType {
236 pub use bincode::error::IntegerType::*;
237 match i {
238 U8 => U8,
239 U16 => U16,
240 U32 => U32,
241 U64 => U64,
242 U128 => U128,
243 Usize => Usize,
244
245 I8 => I8,
246 I16 => I16,
247 I32 => I32,
248 I64 => I64,
249 I128 => I128,
250 Isize => Isize,
251 _ => Reserved,
252 }
253}