flams_math_archives/utils/
errors.rs

1use 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}