1use alloc::boxed::Box;
16use alloc::string::String;
17use alloc::string::ToString;
18use alloc::vec;
19use alloc::vec::Vec;
20use core::error::Error;
21use core::fmt;
22use core::marker::PhantomData;
23use core::ops::Deref;
24use core::panic::Location;
25
26pub struct Exn<E: Error + Send + Sync + 'static> {
28 frame: Box<Frame>,
30 phantom: PhantomData<E>,
31}
32
33impl<E: Error + Send + Sync + 'static> From<E> for Exn<E> {
34 #[track_caller]
35 fn from(error: E) -> Self {
36 Exn::new(error)
37 }
38}
39
40impl<E: Error + Send + Sync + 'static> Exn<E> {
41 #[track_caller]
54 pub fn new(error: E) -> Self {
55 struct SourceError(String);
56
57 impl fmt::Debug for SourceError {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 fmt::Debug::fmt(&self.0, f)
60 }
61 }
62
63 impl fmt::Display for SourceError {
64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 fmt::Display::fmt(&self.0, f)
66 }
67 }
68
69 impl Error for SourceError {}
70
71 fn walk(error: &dyn Error, location: &'static Location<'static>) -> Vec<Frame> {
72 if let Some(source) = error.source() {
73 let children = vec![Frame {
74 error: Box::new(SourceError(source.to_string())),
75 location,
76 children: walk(source, location),
77 }];
78 children
79 } else {
80 vec![]
81 }
82 }
83
84 let location = Location::caller();
85 let children = walk(&error, location);
86 let frame = Frame {
87 error: Box::new(error),
88 location,
89 children,
90 };
91
92 Self {
93 frame: Box::new(frame),
94 phantom: PhantomData,
95 }
96 }
97
98 #[track_caller]
100 pub fn raise_all<T, I>(error: E, children: I) -> Self
101 where
102 T: Error + Send + Sync + 'static,
103 I: IntoIterator,
104 I::Item: Into<Exn<T>>,
105 {
106 let mut new_exn = Exn::new(error);
107 for exn in children {
108 let exn = exn.into();
109 new_exn.frame.children.push(*exn.frame);
110 }
111 new_exn
112 }
113
114 #[track_caller]
116 pub fn raise<T: Error + Send + Sync + 'static>(self, err: T) -> Exn<T> {
117 let mut new_exn = Exn::new(err);
118 new_exn.frame.children.push(*self.frame);
119 new_exn
120 }
121
122 pub fn frame(&self) -> &Frame {
124 &self.frame
125 }
126}
127
128impl<E> Deref for Exn<E>
129where
130 E: Error + Send + Sync + 'static,
131{
132 type Target = E;
133
134 fn deref(&self) -> &Self::Target {
135 self.frame
136 .error()
137 .downcast_ref()
138 .expect("error type must match")
139 }
140}
141
142pub struct Frame {
144 error: Box<dyn Error + Send + Sync + 'static>,
146 location: &'static Location<'static>,
148 children: Vec<Frame>,
150}
151
152impl Frame {
153 pub fn error(&self) -> &(dyn Error + Send + Sync + 'static) {
155 &*self.error
156 }
157
158 pub fn location(&self) -> &'static Location<'static> {
160 self.location
161 }
162
163 pub fn children(&self) -> &[Frame] {
165 &self.children
166 }
167}
168
169impl Error for Frame {
170 fn source(&self) -> Option<&(dyn Error + 'static)> {
171 self.children
172 .first()
173 .map(|child| child as &(dyn Error + 'static))
174 }
175}
176
177impl<E: Error + Send + Sync + 'static> From<Exn<E>> for Box<dyn Error + 'static> {
178 fn from(exn: Exn<E>) -> Self {
179 exn.frame
180 }
181}
182
183impl<E: Error + Send + Sync + 'static> From<Exn<E>> for Box<dyn Error + Send + 'static> {
184 fn from(exn: Exn<E>) -> Self {
185 exn.frame
186 }
187}
188
189impl<E: Error + Send + Sync + 'static> From<Exn<E>> for Box<dyn Error + Send + Sync + 'static> {
190 fn from(exn: Exn<E>) -> Self {
191 exn.frame
192 }
193}