error2/boxed/
mod.rs

1mod root_err;
2mod std_err;
3
4use std::{
5    any::TypeId,
6    error::Error,
7    fmt::{self, Debug, Display, Formatter},
8};
9
10use self::{root_err::RootErr, std_err::StdErr};
11use crate::{Backtrace, Error2, Location, SourceToTarget, private};
12
13pub enum ErrorKind<E, B> {
14    Std { source: E, backtrace: B },
15    Err2 { source: E },
16}
17
18pub struct BoxedError2 {
19    source: Box<dyn Error2 + Send + Sync + 'static>,
20}
21
22impl BoxedError2 {
23    #[inline]
24    const fn source_ref(&self) -> &(dyn Error + Send + Sync + 'static) {
25        &*self.source
26    }
27
28    #[inline]
29    const fn source_mut(&mut self) -> &mut (dyn Error + Send + Sync + 'static) {
30        &mut *self.source
31    }
32
33    #[inline]
34    fn source(self) -> Box<dyn Error + Send + Sync + 'static> {
35        self.source
36    }
37
38    #[inline]
39    pub fn is_root(&self) -> bool {
40        self.source_ref().is::<RootErr>()
41    }
42
43    fn generic_is_root<T: Error + 'static>() -> bool {
44        TypeId::of::<RootErr>() == TypeId::of::<T>()
45    }
46
47    #[inline]
48    pub fn is<T: Error + 'static>(&self) -> bool {
49        debug_assert!(!Self::generic_is_root::<T>());
50        let source = self.source_ref();
51
52        source.is::<StdErr<T>>() || source.is::<T>()
53    }
54
55    #[inline]
56    pub fn downcast_ref<T: Error + 'static>(&self) -> Option<ErrorKind<&T, &Backtrace>> {
57        debug_assert!(!Self::generic_is_root::<T>());
58        let source = self.source_ref();
59
60        if let Some(StdErr { source, backtrace }) = source.downcast_ref::<StdErr<T>>() {
61            Some(ErrorKind::Std { source, backtrace })
62        } else if let Some(source) = source.downcast_ref::<T>() {
63            Some(ErrorKind::Err2 { source })
64        } else {
65            None
66        }
67    }
68
69    #[inline]
70    pub fn downcast_mut<T: Error + 'static>(
71        &mut self,
72    ) -> Option<ErrorKind<&mut T, &mut Backtrace>> {
73        debug_assert!(!Self::generic_is_root::<T>());
74        let source = self.source_ref();
75
76        if source.is::<StdErr<T>>() {
77            let StdErr { source, backtrace } =
78                self.source_mut().downcast_mut::<StdErr<T>>().unwrap();
79            Some(ErrorKind::Std { source, backtrace })
80        } else if source.is::<T>() {
81            let source = self.source_mut().downcast_mut::<T>().unwrap();
82            Some(ErrorKind::Err2 { source })
83        } else {
84            None
85        }
86    }
87
88    #[inline]
89    pub fn downcast<T: Error + 'static>(self) -> Result<ErrorKind<T, Backtrace>, Self> {
90        debug_assert!(!Self::generic_is_root::<T>());
91        let source = self.source_ref();
92
93        if source.is::<StdErr<T>>() {
94            let StdErr { source, backtrace } = *self.source().downcast::<StdErr<T>>().unwrap();
95            Ok(ErrorKind::Std { source, backtrace })
96        } else if source.is::<T>() {
97            let source = *self.source().downcast::<T>().unwrap();
98            Ok(ErrorKind::Err2 { source })
99        } else {
100            Err(self)
101        }
102    }
103}
104
105impl Display for BoxedError2 {
106    #[inline]
107    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
108        Display::fmt(&self.source, f)
109    }
110}
111
112impl Debug for BoxedError2 {
113    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
114        if f.alternate() {
115            Debug::fmt(&self.source, f)
116        } else {
117            Display::fmt(&self.source, f)?;
118            write!(f, "\n\n")?;
119
120            let m = self.backtrace().error_message();
121            Display::fmt(&m, f)
122        }
123    }
124}
125
126impl Error for BoxedError2 {
127    #[inline]
128    fn source(&self) -> Option<&(dyn Error + 'static)> {
129        if self.is_root() {
130            None
131        } else {
132            Some(&*self.source)
133        }
134    }
135}
136
137impl Error2 for BoxedError2 {
138    #[inline]
139    fn backtrace(&self) -> &Backtrace {
140        self.source.backtrace()
141    }
142
143    #[inline]
144    fn backtrace_mut(&mut self) -> &mut Backtrace {
145        self.source.backtrace_mut()
146    }
147}
148
149impl BoxedError2 {
150    #[track_caller]
151    #[inline]
152    pub fn from_root<R>(root: R) -> BoxedError2
153    where
154        R: Display + Debug + Send + Sync + 'static,
155    {
156        Self::from_root_with_location(root, Location::caller())
157    }
158
159    pub fn from_root_with_location<R>(root: R, location: Location) -> BoxedError2
160    where
161        R: Display + Debug + Send + Sync + 'static,
162    {
163        let mut error = BoxedError2 {
164            source: Box::new(RootErr::new(root)),
165        };
166
167        crate::push_error(&mut error, location);
168
169        error
170    }
171
172    #[track_caller]
173    #[inline]
174    pub fn from_std<T>(source: T) -> BoxedError2
175    where
176        T: Error + Send + Sync + 'static,
177    {
178        Self::from_std_with_location(source, Location::caller())
179    }
180
181    pub fn from_std_with_location<T>(source: T, location: Location) -> BoxedError2
182    where
183        T: Error + Send + Sync + 'static,
184    {
185        if (&source as &(dyn Error + Send + Sync)).is::<BoxedError2>() {
186            let mut e =
187                <dyn Error + Send + Sync>::downcast::<BoxedError2>(Box::new(source)).unwrap();
188
189            e.backtrace_mut().push_location(location);
190            *e
191        } else {
192            let mut error = BoxedError2 {
193                source: Box::new(StdErr::new(source)),
194            };
195
196            crate::push_error(&mut error, location);
197
198            error
199        }
200    }
201
202    #[track_caller]
203    #[inline]
204    pub fn from_err2<T>(source: T) -> BoxedError2
205    where
206        T: Error2 + Send + Sync + 'static,
207    {
208        Self::from_err2_with_location(source, Location::caller())
209    }
210
211    pub fn from_err2_with_location<T>(source: T, location: Location) -> BoxedError2
212    where
213        T: Error2 + Send + Sync + 'static,
214    {
215        if (&source as &(dyn Error + Send + Sync)).is::<BoxedError2>() {
216            let mut e =
217                <dyn Error + Send + Sync>::downcast::<BoxedError2>(Box::new(source)).unwrap();
218
219            e.backtrace_mut().push_location(location);
220            *e
221        } else {
222            let mut error = BoxedError2 {
223                source: Box::new(source),
224            };
225
226            crate::push_error(&mut error, location);
227
228            error
229        }
230    }
231}
232
233pub struct ViaRoot<M>(pub M)
234where
235    M: Display + Debug + Send + Sync + 'static;
236
237impl<M> SourceToTarget<private::ViaFull, (), (), BoxedError2> for ViaRoot<M>
238where
239    M: Display + Debug + Send + Sync + 'static,
240{
241    #[inline]
242    fn source_to_target(self, _source: (), location: Location) -> BoxedError2 {
243        BoxedError2::from_root_with_location(self.0, location)
244    }
245}
246
247pub struct ViaStd;
248
249impl<T> SourceToTarget<private::ViaFull, T, T, BoxedError2> for ViaStd
250where
251    T: Error + Send + Sync + 'static,
252{
253    #[inline]
254    fn source_to_target(self, source: T, location: Location) -> BoxedError2 {
255        BoxedError2::from_std_with_location(source, location)
256    }
257}
258
259pub struct ViaErr2;
260
261impl<T> SourceToTarget<private::ViaFull, T, T, BoxedError2> for ViaErr2
262where
263    T: Error2 + Send + Sync + 'static,
264{
265    #[inline]
266    fn source_to_target(self, source: T, location: Location) -> BoxedError2 {
267        BoxedError2::from_err2_with_location(source, location)
268    }
269}