1use std::{
2 convert::Infallible,
3 fmt::{self, Formatter},
4 ops::Deref,
5};
6
7use crate::{ErrorRef, FromString, Meta, SourceFormat, StackError, StackErrorExt};
8
9pub struct AnyError(Inner);
22
23enum Inner {
24 Stack(Box<dyn StackError>),
25 Std(Box<dyn std::error::Error + Send + Sync>, Meta),
26}
27
28impl AnyError {
29 #[track_caller]
33 pub fn from_std(err: impl std::error::Error + Send + Sync + 'static) -> Self {
34 Self::from_std_box(Box::new(err))
35 }
36
37 #[track_caller]
39 #[cfg(feature = "anyhow")]
40 pub fn from_anyhow(err: anyhow::Error) -> Self {
41 Self::from_std_box(err.into_boxed_dyn_error())
42 }
43
44 #[track_caller]
48 pub fn from_std_box(err: Box<dyn std::error::Error + Send + Sync + 'static>) -> Self {
49 Self(Inner::Std(err, Meta::default()))
50 }
51
52 #[track_caller]
54 pub fn from_display(s: impl fmt::Display) -> Self {
55 Self::from_string(s.to_string())
56 }
57
58 #[track_caller]
60 pub fn from_string(message: String) -> Self {
61 FromString::WithoutSource {
62 message,
63 meta: Meta::default(),
64 }
65 .into_any()
66 }
67
68 #[track_caller]
74 pub fn from_stack(err: impl StackError + 'static) -> Self {
75 Self::from_stack_box(Box::new(err))
76 }
77
78 #[track_caller]
80 pub fn from_stack_box(err: Box<dyn StackError>) -> Self {
81 Self(Inner::Stack(err))
82 }
83
84 #[track_caller]
86 pub fn context(self, context: impl fmt::Display) -> AnyError {
87 FromString::WithSource {
88 message: context.to_string(),
89 source: self,
90 meta: Meta::default(),
91 }
92 .into_any()
93 }
94
95 pub fn into_boxed_dyn_error(self) -> Box<dyn std::error::Error + Send + Sync + 'static> {
97 Box::new(self)
98 }
99
100 pub fn downcast_ref<T: std::error::Error + 'static>(&self) -> Option<&T> {
102 match &self.0 {
103 Inner::Stack(err) => err.as_std().downcast_ref(),
104 Inner::Std(err, _) => err.downcast_ref(),
105 }
106 }
107
108 pub fn downcast<T: std::error::Error + 'static>(self) -> Option<T> {
110 match self.0 {
111 Inner::Stack(err) => err.into_std().downcast().ok().map(|b| *b),
112 Inner::Std(err, _) => err.downcast().ok().map(|b| *b),
113 }
114 }
115}
116
117impl fmt::Display for AnyError {
118 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
119 let sources = f.alternate().then_some(SourceFormat::OneLine);
120 write!(f, "{}", self.report().sources(sources))
121 }
122}
123
124impl fmt::Debug for AnyError {
125 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
126 if f.alternate() {
127 match &self.0 {
128 Inner::Stack(error) => {
129 write!(f, "Stack({error:#?})")
130 }
131 Inner::Std(error, meta) => {
132 write!(f, "Std({error:#?}, {meta:?})")
133 }
134 }
135 } else {
136 write!(f, "{}", self.report().full())
137 }
138 }
139}
140
141impl StackError for AnyError {
142 fn as_dyn(&self) -> &dyn StackError {
143 self
144 }
145 fn into_std(self: Box<Self>) -> Box<dyn std::error::Error + Send + Sync> {
146 self
147 }
148
149 fn as_std(&self) -> &(dyn std::error::Error + Send + Sync + 'static) {
150 match &self.0 {
151 Inner::Std(err, _) => err.as_ref(),
152 Inner::Stack(err) => err.as_std(),
153 }
154 }
155
156 fn meta(&self) -> Option<&Meta> {
157 match &self.0 {
158 Inner::Std(_, meta) => Some(meta),
159 Inner::Stack(err) => err.meta(),
160 }
161 }
162
163 fn source(&self) -> Option<ErrorRef<'_>> {
164 self.as_ref().source()
165 }
166
167 fn is_transparent(&self) -> bool {
168 self.as_ref().is_transparent()
169 }
170
171 fn as_ref<'a>(&'a self) -> ErrorRef<'a> {
172 match &self.0 {
173 Inner::Stack(error) => ErrorRef::Stack(error.deref()),
174 Inner::Std(error, meta) => ErrorRef::std_with_meta(error.as_ref(), meta),
175 }
176 }
177
178 fn fmt_message(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179 match &self.0 {
180 Inner::Stack(error) => error.fmt_message(f),
181 Inner::Std(error, _) => fmt::Display::fmt(error, f),
182 }
183 }
184}
185
186impl std::error::Error for AnyError {
187 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
188 self.as_std().source()
189 }
190}
191
192impl From<String> for AnyError {
193 #[track_caller]
194 fn from(value: String) -> Self {
195 Self::from_display(value)
196 }
197}
198
199impl From<&str> for AnyError {
200 #[track_caller]
201 fn from(value: &str) -> Self {
202 Self::from_display(value)
203 }
204}
205
206impl From<Box<dyn std::error::Error + Send + Sync>> for AnyError {
207 #[track_caller]
208 fn from(value: Box<dyn std::error::Error + Send + Sync>) -> Self {
209 Self::from_std_box(value)
210 }
211}
212
213#[cfg(feature = "anyhow")]
214impl From<anyhow::Error> for AnyError {
215 #[track_caller]
216 fn from(value: anyhow::Error) -> Self {
217 Self::from_anyhow(value)
218 }
219}
220
221impl From<std::io::Error> for AnyError {
222 #[track_caller]
223 fn from(value: std::io::Error) -> Self {
224 Self::from_std(value)
225 }
226}
227
228impl std::str::FromStr for AnyError {
229 type Err = Infallible;
230
231 #[track_caller]
232 fn from_str(s: &str) -> Result<Self, Self::Err> {
233 Ok(Self::from_display(s))
234 }
235}