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