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