Skip to main content

singlefile/
error.rs

1//! Errors that can occur within `singlefile`.
2
3use thiserror::Error;
4
5use crate::manager::FileMode;
6
7use std::convert::Infallible;
8use std::io;
9
10/// An error that can occur within `singlefile`.
11#[derive(Debug, Error)]
12pub enum Error<FE> {
13  /// An error caused by an implementation of [`FileFormat`].
14  ///
15  /// [`FileFormat`]: crate::format::FileFormat
16  #[error("format error: {0}")]
17  Format(FE),
18  /// An error caused by the filesystem.
19  #[error(transparent)]
20  Io(#[from] io::Error),
21  /// Any other kind of error.
22  #[error(transparent)]
23  Other(#[from] OtherError)
24}
25
26impl From<Error<io::Error>> for io::Error {
27  fn from(err: Error<io::Error>) -> Self {
28    match err {
29      Error::Format(err) | Error::Io(err) => err,
30      Error::Other(err) => io::Error::other(err)
31    }
32  }
33}
34
35/// A value that may be an error or a user-generated error.
36#[derive(Debug, Error)]
37pub enum OrUserError<T, U> {
38  /// An error.
39  #[error(transparent)]
40  Base(T),
41  /// A user-generated error.
42  #[error("user error: {0}")]
43  User(U)
44}
45
46impl<T, U> OrUserError<T, U> {
47  /// Converts this error into another error.
48  /// The new error type `E` must implement [`From<T>`].
49  /// Additionally takes a closure allowing the user to decide how to convert the user error.
50  pub fn convert_with<E, F>(self, f: F) -> E
51  where T: Into<E>, F: FnOnce(U) -> E {
52    match self {
53      Self::Base(err) => err.into(),
54      Self::User(err) => f(err)
55    }
56  }
57
58  /// Converts this error into another error.
59  /// The new error type `E` must implement [`From<T>`] and [`From<U>`].
60  pub fn convert<E>(self) -> E
61  where T: Into<E>, U: Into<E> {
62    self.convert_with(U::into)
63  }
64}
65
66impl<T> OrUserError<T, Infallible> {
67  /// Converts this error to `T` (the base error variant), given that `U` (the user error variant) is [`Infallible`].
68  pub fn into_base(self) -> T {
69    match self {
70      Self::Base(err) => err,
71      Self::User(i) => match i {}
72    }
73  }
74}
75
76impl<U> OrUserError<Infallible, U> {
77  /// Converts this error to `U` (the user error variant), given that `T` (the base error variant) is [`Infallible`].
78  pub fn into_user(self) -> U {
79    match self {
80      Self::User(err) => err,
81      Self::Base(i) => match i {}
82    }
83  }
84}
85
86impl<T, U> From<T> for OrUserError<T, U> {
87  fn from(err: T) -> Self {
88    OrUserError::Base(err)
89  }
90}
91
92/// An error that can occur within `singlefile`, with the exception of:
93/// - Format Errors
94/// - I/O Errors
95/// - User Errors
96#[non_exhaustive]
97#[derive(Debug, Error)]
98pub enum OtherError {
99  /// The user tried to perform an operation that is incompatible with the set [`FileMode`].
100  #[error("file mode {0:?} is incompatible with this operation")]
101  IncompatibleFileMode(FileMode)
102}