Skip to main content

flams_math_archives/utils/
errors.rs

1use std::path::PathBuf;
2
3use ftml_uris::{ArchiveUri, errors::UriParseError};
4
5#[derive(Debug, thiserror::Error)]
6pub enum BackendError {
7    #[error("element not found")]
8    NotFound(ftml_uris::Uri),
9    #[error("archive not found")]
10    ArchiveNotFound(ArchiveUri),
11    #[error("{0}")]
12    Cache(#[from] ftml_backend::utils::async_cache::CacheError),
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.clone()),
24            Self::ArchiveNotFound(uri) => Self::ArchiveNotFound(uri.clone()),
25            Self::Cache(e) => Self::Cache(*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(uri) => ftml_backend::BackendError::NotFound(uri.into()),
37            _ => ftml_backend::BackendError::ToDo(value.to_string()),
38        }
39    }
40}
41
42#[allow(clippy::fallible_impl_from)]
43impl From<ReadError> for BackendError {
44    fn from(value: ReadError) -> Self {
45        match value {
46            ReadError::Cache(c) => Self::Cache(c),
47            ReadError::Decode(e) => Self::Decode(e),
48            ReadError::Io(e) => Self::Io(e),
49            ReadError::NumberOfFields { .. } => panic!("{value} -- this is a bug"),
50        }
51    }
52}
53
54#[derive(Debug, thiserror::Error)]
55pub enum ManifestParseError {
56    #[error("file path has no parent")]
57    NoParent,
58    #[error("io: {0}")]
59    Io(#[from] std::io::Error),
60    #[error("id {0} does not match its relative location")]
61    IdMismatch(String),
62    #[error("id field is empty")]
63    EmptyId,
64    #[error("invalid archive id: {0}")]
65    InvalidId(String),
66    #[error("unknown format: {0}")]
67    UnknownFormat(String),
68    #[error("missing format or kind field")]
69    NoFormatOrKind,
70    #[error("unknown archive kind: {0}")]
71    UnknownKind(String),
72    #[error("missing url-base field")]
73    NoUrlBase,
74    #[error("invalid uri in url-base \"{0}\":{1}")]
75    InvalidUrlBase(String, #[source] UriParseError),
76    #[error("invalid archive for kind {0}: {1}")]
77    InvalidKind(&'static str, String),
78}
79
80#[derive(Debug, thiserror::Error)]
81pub enum NewArchiveError {
82    #[error("no mathhub directory found")]
83    NoMathHub,
84    #[error("error creating directory {a}: {1}",a=.0.display())]
85    CreateDir(PathBuf, #[source] std::io::Error),
86    #[error("error writing to file {a}: {1}",a=.0.display())]
87    Write(PathBuf, #[source] std::io::Error),
88}
89
90#[derive(Debug, thiserror::Error)]
91pub enum FileError {
92    #[error("error creating file {f}: {1}",f=.0.display())]
93    Creation(PathBuf, #[source] std::io::Error),
94    #[error("error writing to file {f}: {1}",f=.0.display())]
95    Write(PathBuf, #[source] std::io::Error),
96    #[error("error renaming directory {f}: {1}",f=.0.display())]
97    Rename(PathBuf, #[source] std::io::Error),
98    #[error("error reading directory {f}: {1}",f=.0.display())]
99    ReadDir(PathBuf, #[source] std::io::Error),
100    #[error("error reading entry of directory {f}: {1}",f=.0.display())]
101    ReadEntry(PathBuf, #[source] std::io::Error),
102    #[error("error determining type of file {f}: {1}",f=.0.display())]
103    FileType(PathBuf, #[source] std::io::Error),
104    #[error("error obtaining metadata of file {f}: {1}",f=.0.display())]
105    MetaData(PathBuf, #[source] std::io::Error),
106    #[error("error copying {f} to {t}: {error}",f=.from.display(),t=.to.display())]
107    Copying {
108        from: PathBuf,
109        to: PathBuf,
110        #[source]
111        error: std::io::Error,
112    },
113    #[error("Error setting file modification time for {f}: {1}",f=.0.display())]
114    SetFileModTime(PathBuf, #[source] std::io::Error),
115    #[error("target file/directory already exists")]
116    AlreadyExists,
117}
118
119#[derive(Debug, thiserror::Error)]
120pub enum WriteError {
121    #[error("field number out of bounds: {index} of {max}")]
122    NumberOfFields { max: usize, index: usize },
123    #[error("io: {0}")]
124    Io(#[from] std::io::Error),
125    #[error("encoding error: {0}")]
126    Encode(#[from] bincode::error::EncodeError),
127}
128
129#[derive(Debug, thiserror::Error)]
130pub enum ArtifactSaveError {
131    #[error("fs error: {0}")]
132    Fs(#[from] FileError),
133    #[error("encoding error: {0}")]
134    Encode(#[from] bincode::error::EncodeError),
135    #[error("archive not found")]
136    NoArchive,
137    #[error("error: {0}")]
138    Other(std::borrow::Cow<'static, str>),
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    Cache(#[from] ftml_backend::utils::async_cache::CacheError),
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::Cache(e) => Self::Cache(*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}