rama_error/ext/
wrapper.rs

1use crate::BoxError;
2use std::fmt::{self, Debug, Display};
3
4#[repr(transparent)]
5/// A type-erased error type that can be used as a trait object.
6///
7/// Note this type is not intended to be used directly,
8/// it is used by `rama` to hide the concrete error type.
9///
10/// See the [module level documentation](crate::error) for more information.
11pub struct OpaqueError(BoxError);
12
13impl OpaqueError {
14    /// create an [`OpaqueError`] from an std error
15    pub fn from_std(error: impl std::error::Error + Send + Sync + 'static) -> Self {
16        Self(Box::new(error))
17    }
18
19    /// create an [`OpaqueError`] from a display object
20    pub fn from_display(msg: impl Display + Debug + Send + Sync + 'static) -> Self {
21        Self::from_std(MessageError(msg))
22    }
23
24    /// create an [`OpaqueError`] from a boxed error
25    pub fn from_boxed(inner: BoxError) -> Self {
26        Self(inner)
27    }
28
29    /// Returns true if the underlying error is of type `T`.
30    pub fn is<T>(&self) -> bool
31    where
32        T: std::error::Error + 'static,
33    {
34        self.0.is::<T>()
35    }
36
37    /// Consumes the [`OpaqueError`] and returns it as a [`BoxError`].
38    pub fn into_boxed(self) -> BoxError {
39        self.0
40    }
41
42    /// Attempts to downcast the error to the concrete type `T`.
43    pub fn downcast<T>(self) -> Result<T, Self>
44    where
45        T: std::error::Error + 'static,
46    {
47        match self.0.downcast::<T>() {
48            Ok(error) => Ok(*error),
49            Err(inner) => Err(Self(inner)),
50        }
51    }
52
53    /// Attempts to downcast the error to a shared reference
54    /// of the concrete type `T`.
55    pub fn downcast_ref<T>(&self) -> Option<&T>
56    where
57        T: std::error::Error + 'static,
58    {
59        self.0.downcast_ref()
60    }
61
62    /// Attempts to downcast the error to the exclusive reference
63    /// of the concrete type `T`.
64    pub fn downcast_mut<T>(&mut self) -> Option<&mut T>
65    where
66        T: std::error::Error + 'static,
67    {
68        self.0.downcast_mut()
69    }
70}
71
72impl Debug for OpaqueError {
73    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74        Debug::fmt(&self.0, f)
75    }
76}
77
78impl Display for OpaqueError {
79    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
80        Display::fmt(&self.0, f)
81    }
82}
83
84impl std::error::Error for OpaqueError {
85    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
86        if let Some(err) = self.0.source() {
87            return Some(err);
88        }
89        let err = self.0.as_ref();
90        Some(err as &(dyn std::error::Error + 'static))
91    }
92}
93
94impl From<BoxError> for OpaqueError {
95    fn from(error: BoxError) -> Self {
96        Self(error)
97    }
98}
99
100#[repr(transparent)]
101/// An error type that wraps a message.
102pub(crate) struct MessageError<M>(pub(crate) M);
103
104impl<M> Debug for MessageError<M>
105where
106    M: Display + Debug,
107{
108    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
109        Debug::fmt(&self.0, f)
110    }
111}
112
113impl<M> Display for MessageError<M>
114where
115    M: Display + Debug,
116{
117    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118        Display::fmt(&self.0, f)
119    }
120}
121
122impl<M> std::error::Error for MessageError<M> where M: Display + Debug + 'static {}
123
124#[cfg(test)]
125mod tests {
126    use super::*;
127
128    #[derive(Debug)]
129    struct CustomError(usize);
130
131    impl Display for CustomError {
132        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
133            write!(f, "Custom error ({})", self.0)
134        }
135    }
136
137    impl std::error::Error for CustomError {}
138
139    #[test]
140    fn opaque_error_is() {
141        let error = OpaqueError::from_std(CustomError(1));
142        assert!(error.is::<CustomError>());
143    }
144
145    #[test]
146    fn opaque_error_is_not() {
147        let error = OpaqueError::from_display("hello");
148        assert!(!error.is::<CustomError>());
149    }
150
151    #[test]
152    fn opaque_error_downcast() {
153        let error = OpaqueError::from_std(CustomError(2));
154        let custom_error = error.downcast::<CustomError>().unwrap();
155        assert_eq!(custom_error.0, 2);
156    }
157
158    #[test]
159    fn opaque_error_downcast_fail() {
160        let error = OpaqueError::from_display("hello");
161        assert!(error.downcast::<CustomError>().is_err());
162    }
163
164    #[test]
165    fn opaque_error_downcast_ref() {
166        let error = OpaqueError::from_std(CustomError(3));
167        let custom_error = error.downcast_ref::<CustomError>().unwrap();
168        assert_eq!(custom_error.0, 3);
169    }
170
171    #[test]
172    fn opaque_error_downcast_ref_fail() {
173        let error = OpaqueError::from_display("hello");
174        assert!(error.downcast_ref::<CustomError>().is_none());
175    }
176
177    #[test]
178    fn opaque_error_downcast_mut() {
179        let error = {
180            let mut error = OpaqueError::from_std(CustomError(4));
181            error.downcast_mut::<CustomError>().unwrap().0 = 42;
182            error
183        };
184
185        let custom_error = error.downcast_ref::<CustomError>().unwrap();
186        assert_eq!(custom_error.0, 42);
187    }
188
189    #[test]
190    fn opaque_error_downcast_mut_fail() {
191        let mut error = OpaqueError::from_display("hello");
192        assert!(error.downcast_mut::<CustomError>().is_none());
193    }
194}