Skip to main content

object_rainbow/
error.rs

1#[cfg(doc)]
2use crate::{Hash, Resolve};
3
4#[macro_export]
5/// Construct [`Error::Parse`].
6macro_rules! error_parse {
7    ($($t:tt)*) => {
8        $crate::Error::Parse($crate::anyhow!($($t)*))
9    };
10}
11
12#[macro_export]
13/// Construct [`Error::Fetch`].
14macro_rules! error_fetch {
15    ($($t:tt)*) => {
16        $crate::Error::Fetch($crate::anyhow!($($t)*))
17    };
18}
19
20#[macro_export]
21/// Construct [`Error::Operation`].
22macro_rules! error_operation {
23    ($($t:tt)*) => {
24        $crate::Error::Operation($crate::anyhow!($($t)*))
25    };
26}
27
28#[macro_export]
29/// Construct [`Error::Consistency`].
30macro_rules! error_consistency {
31    ($($t:tt)*) => {
32        $crate::Error::Consistency($crate::anyhow!($($t)*))
33    };
34}
35
36/// Errors encountered during fetching an object. Mostly related to parsing.
37#[derive(Debug, thiserror::Error)]
38#[non_exhaustive]
39pub enum Error {
40    /// Arbitrary parsing error.
41    #[error(transparent)]
42    Parse(anyhow::Error),
43    /// Arbitrary fetching error.
44    #[error(transparent)]
45    Fetch(anyhow::Error),
46    /// Arbitrary operation error.
47    #[error(transparent)]
48    Operation(anyhow::Error),
49    /// Arbitrary consistency error.
50    #[error(transparent)]
51    Consistency(anyhow::Error),
52    /// Plain [`std::io::Error`], possibly converted from some other error.
53    #[error(transparent)]
54    Io(#[from] std::io::Error),
55    /// Data left after an [`Inline`] got parsed.
56    #[error("extra input left")]
57    ExtraInputLeft,
58    /// EOF.
59    #[error("end of input")]
60    EndOfInput,
61    /// Overran [`PointInput`]'s [`Address`] vector.
62    #[error("address index out of bounds")]
63    AddressOutOfBounds,
64    /// [`Address::hash`] doesn't match what [`Resolve`] returned.
65    #[error("hash resolution mismatch")]
66    ResolutionMismatch,
67    /// [`FullHash::full_hash`] doesn't match [`Singular::hash`].
68    #[error("full hash mismatch")]
69    FullHashMismatch,
70    /// Discriminant out of range for an [`Enum`].
71    #[error("discriminant overflow")]
72    DiscriminantOverflow,
73    /// Unepxected zero for a non-zero value.
74    #[error("zero")]
75    Zero,
76    /// Value out of bounds for a certain type.
77    #[error("out of bounds")]
78    OutOfBounds,
79    /// Current architecture (32-bit) is unable to handle lengths of this size.
80    #[error("length out of bounds")]
81    UnsupportedLength,
82    /// Not UTF-8.
83    #[error(transparent)]
84    Utf8(#[from] std::string::FromUtf8Error),
85    /// [`Resolve::extension`] (or related things) were unable to resolve the extension.
86    #[error("unknown extension")]
87    UnknownExtension,
88    /// Extension type didn't match what we asked for. This might be turned into panic later.
89    #[error("wrong extension type")]
90    ExtensionType,
91    /// This functionality hasn't been implemented yet or won't ever be supported.
92    #[error("not implemented")]
93    Unimplemented,
94    /// [`Hash`]-based [`Resolve`] couldn't find what we asked for.
95    #[error("hash not found in the resolve")]
96    HashNotFound,
97    /// Operation has been interrupted. Usually means some other error already occured.
98    #[error("interrupted")]
99    Interrupted,
100}
101
102impl Error {
103    /// Construct [`Error::Parse`] from another error.
104    pub fn parse(e: impl Into<anyhow::Error>) -> Self {
105        Self::Parse(e.into())
106    }
107
108    /// Construct [`Error::Fetch`] from another error.
109    pub fn fetch(e: impl Into<anyhow::Error>) -> Self {
110        Self::Fetch(e.into())
111    }
112
113    /// Construct [`Error::Operation`] from another error.
114    pub fn operation(e: impl Into<anyhow::Error>) -> Self {
115        Self::Fetch(e.into())
116    }
117
118    /// Construct [`Error::Consistency`] from another error.
119    pub fn consistency(e: impl Into<anyhow::Error>) -> Self {
120        Self::Fetch(e.into())
121    }
122
123    /// Convert from something that can be converted into [`std::io::Error`] (e.g. `zmq::Error`).
124    pub fn io(e: impl Into<std::io::Error>) -> Self {
125        e.into().into()
126    }
127
128    fn io_kind(&self) -> std::io::ErrorKind {
129        use std::io::ErrorKind;
130        match self {
131            Error::Parse(_) => ErrorKind::InvalidData,
132            Error::Fetch(_) => ErrorKind::Other,
133            Error::Operation(_) => ErrorKind::Other,
134            Error::Consistency(_) => ErrorKind::InvalidData,
135            Error::Io(e) => e.kind(),
136            Error::ExtraInputLeft => ErrorKind::InvalidData,
137            Error::EndOfInput => ErrorKind::UnexpectedEof,
138            Error::AddressOutOfBounds => ErrorKind::Other,
139            Error::ResolutionMismatch => ErrorKind::InvalidData,
140            Error::FullHashMismatch => ErrorKind::InvalidData,
141            Error::DiscriminantOverflow => ErrorKind::InvalidData,
142            Error::Zero => ErrorKind::InvalidData,
143            Error::OutOfBounds => ErrorKind::InvalidData,
144            Error::UnsupportedLength => ErrorKind::FileTooLarge,
145            Error::Utf8(_) => ErrorKind::InvalidData,
146            Error::UnknownExtension => ErrorKind::Other,
147            Error::ExtensionType => ErrorKind::Other,
148            Error::Unimplemented => ErrorKind::Unsupported,
149            Error::HashNotFound => ErrorKind::NotFound,
150            Error::Interrupted => ErrorKind::Interrupted,
151        }
152    }
153}
154
155impl From<Error> for std::io::Error {
156    fn from(value: Error) -> Self {
157        match value {
158            Error::Io(e) => e,
159            e => Self::new(e.io_kind(), e),
160        }
161    }
162}
163
164/// Default output for fallible functions.
165pub type Result<T> = std::result::Result<T, Error>;