assets_manager/
error.rs

1use std::{fmt, io};
2
3use crate::SharedString;
4
5/// A boxed error
6pub type BoxedError = Box<dyn std::error::Error + Send + Sync + 'static>;
7
8#[derive(Debug)]
9pub(crate) enum ErrorKind {
10    /// An asset without extension was loaded.
11    NoDefaultValue,
12
13    /// An I/O error occured.
14    Io(io::Error),
15
16    /// The conversion from raw bytes failed.
17    Conversion(BoxedError),
18
19    /// The provided ID was invalid.
20    InvalidId,
21}
22
23impl From<io::Error> for ErrorKind {
24    fn from(err: io::Error) -> Self {
25        Self::Io(err)
26    }
27}
28
29impl From<BoxedError> for ErrorKind {
30    fn from(err: BoxedError) -> Self {
31        Self::Conversion(err)
32    }
33}
34
35impl From<ErrorKind> for BoxedError {
36    fn from(err: ErrorKind) -> Self {
37        match err {
38            ErrorKind::NoDefaultValue => Box::new(NoDefaultValueError),
39            ErrorKind::Io(err) => Box::new(err),
40            ErrorKind::Conversion(err) => err,
41            ErrorKind::InvalidId => Box::new(InvalidIdError),
42        }
43    }
44}
45
46impl ErrorKind {
47    pub fn or(self, other: Self) -> Self {
48        use ErrorKind::*;
49
50        match (self, other) {
51            (NoDefaultValue, other) => other,
52            (Io(_), other @ Conversion(_)) => other,
53            (Io(err), other @ Io(_)) if err.kind() == io::ErrorKind::NotFound => other,
54            (this, _) => this,
55        }
56    }
57}
58
59#[derive(Debug)]
60struct NoDefaultValueError;
61
62impl fmt::Display for NoDefaultValueError {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        f.write_str("the asset has neither extension nor default value")
65    }
66}
67
68impl std::error::Error for NoDefaultValueError {}
69
70#[derive(Debug)]
71struct InvalidIdError;
72
73impl fmt::Display for InvalidIdError {
74    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75        f.write_str("invalid id")
76    }
77}
78
79impl std::error::Error for InvalidIdError {}
80
81struct ErrorRepr {
82    id: SharedString,
83    error: BoxedError,
84}
85
86/// The error type which is used when loading an asset.
87pub struct Error(Box<ErrorRepr>);
88
89impl Error {
90    #[cold]
91    pub(crate) fn new(id: SharedString, error: BoxedError) -> Self {
92        Self(Box::new(ErrorRepr { id, error }))
93    }
94
95    /// The id of the asset that was being loaded when the error happened.
96    #[inline]
97    pub fn id(&self) -> &SharedString {
98        &self.0.id
99    }
100
101    /// Like `source`, but never fails.
102    #[inline]
103    pub fn reason(&self) -> &(dyn std::error::Error + 'static) {
104        &*self.0.error
105    }
106
107    /// Consumes the `Error`, returning its inner error.
108    #[inline]
109    pub fn into_inner(self) -> BoxedError {
110        self.0.error
111    }
112
113    /// Attempt to downgrade the inner error to `E`.
114    #[inline]
115    pub fn downcast<E: std::error::Error + 'static>(mut self) -> Result<E, Self> {
116        match self.0.error.downcast() {
117            Ok(err) => Ok(*err),
118            Err(err) => {
119                self.0.error = err;
120                Err(self)
121            }
122        }
123    }
124}
125
126impl fmt::Debug for Error {
127    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128        f.debug_struct("Error")
129            .field("id", &self.0.id)
130            .field("error", &self.0.error)
131            .finish()
132    }
133}
134
135impl fmt::Display for Error {
136    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137        f.write_fmt(format_args!("failed to load \"{}\"", self.id()))
138    }
139}
140
141impl std::error::Error for Error {
142    #[inline]
143    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
144        Some(self.reason())
145    }
146}