1use alloc::{borrow::Cow, boxed::Box, sync::Arc};
2use core::{
3 any::{Any, TypeId, type_name},
4 error::Error,
5 fmt::{Debug, Display},
6 ops::Deref,
7};
8
9use crate::cause::{Cause, CauseInner, Chain, UniDisplay};
10
11pub type UniResult<T, U> = Result<T, UniError<U>>;
15
16pub type SimpleResult<T> = Result<T, SimpleError>;
18
19pub type DynResult<T> = Result<T, DynError>;
21
22pub type SimpleError = UniError<()>;
24
25#[derive(Debug)]
31pub struct DynError(Box<dyn UniErrorOps + Send + Sync>);
32
33impl DynError {
34 pub(crate) fn new<E: UniErrorOps>(err: E) -> Self {
35 Self(Box::new(err))
36 }
37
38 pub fn downcast<T: UniKind>(self) -> Option<UniError<T>> {
40 let err: Box<dyn Any> = self.0;
41 err.downcast().ok().map(|err| *err)
42 }
43}
44
45impl Deref for DynError {
46 type Target = dyn UniErrorOps + Send + Sync;
47
48 fn deref(&self) -> &Self::Target {
49 &*self.0
50 }
51}
52
53pub trait UniKind: Debug + Any + Send + Sync {
57 fn value(&self, _cause: Option<Cause<'_>>) -> Cow<'static, str> {
60 Cow::Borrowed("")
61 }
62
63 fn context(&self, _cause: Option<Cause<'_>>) -> Option<Cow<'static, str>> {
65 None
66 }
67
68 fn code(&self, _cause: Option<Cause<'_>>) -> i32 {
70 -1
71 }
72
73 fn type_name(&self) -> &'static str {
75 type_name::<Self>()
76 }
77
78 fn into_error(self) -> UniError<Self>
80 where
81 Self: Sized,
82 {
83 UniError::from_kind(self)
84 }
85}
86
87impl dyn UniKind {
88 pub fn downcast_ref<T: UniKind>(&self) -> Option<&T> {
90 let err: &dyn Any = self;
91 err.downcast_ref()
92 }
93}
94
95impl UniKind for () {}
96
97#[derive(Debug)]
102pub(crate) struct UniErrorInner<T> {
103 kind: Arc<T>,
104 context: Option<Cow<'static, str>>,
105 cause: Option<Arc<CauseInner>>,
106}
107
108impl<T: UniKind> UniErrorInner<T> {
109 pub fn prev_cause<'e>(&'e self) -> Option<Cause<'e>> {
110 self.cause.as_ref().map(|inner| Cause::from_inner(inner))
111 }
112}
113
114impl<T: UniKind> Display for UniErrorInner<T> {
115 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
116 if let Some(context) = &self.context {
117 write!(f, "{}", context)?;
118 }
119
120 let cause = self.cause.as_ref().map(|inner| Cause::from_inner(inner));
121 let context = self.kind.context(cause);
122 if let Some(context) = context.as_ref() {
123 if self.context.is_some() {
124 write!(f, ": ")?;
125 }
126 write!(f, "{}", context)?;
127 }
128
129 if let Some(cause) = &self.prev_cause() {
130 if self.context.is_some() || context.is_some() {
131 write!(f, ": ")?;
132 }
133 write!(f, "{}", cause)?;
134 }
135
136 Ok(())
137 }
138}
139
140impl<T: UniKind> Error for UniErrorInner<T> {
141 fn source(&self) -> Option<&(dyn Error + 'static)> {
142 match self.prev_cause() {
143 Some(Cause::UniError(err)) => Some(&***err),
144 Some(Cause::UniStdError(err)) => Some(err),
145 Some(Cause::StdError(err)) => Some(err),
146 Some(Cause::UniDisplay(_)) | None => None,
147 }
148 }
149}
150
151#[derive(Debug)]
155pub struct UniError<T> {
156 inner: Box<UniErrorInner<T>>,
157}
158
159impl<T: UniKind + Default> UniError<T> {
160 pub fn from_context(context: impl Into<Cow<'static, str>>) -> Self {
162 Self::new(Default::default(), Some(context.into()), None)
163 }
164
165 pub fn from_boxed(error: Box<dyn Error + Send + Sync>) -> Self {
167 Self::new(
168 Default::default(),
169 None,
170 Some(CauseInner::from_boxed_error(error)),
171 )
172 }
173
174 pub fn from_context_boxed(
176 context: impl Into<Cow<'static, str>>,
177 error: Box<dyn Error + Send + Sync>,
178 ) -> Self {
179 Self::new(
180 Default::default(),
181 Some(context.into()),
182 Some(CauseInner::from_boxed_error(error)),
183 )
184 }
185}
186
187impl<T: UniKind> UniError<T> {
188 pub(crate) fn new(
189 kind: T,
190 context: Option<Cow<'static, str>>,
191 cause: Option<CauseInner>,
192 ) -> Self {
193 Self {
194 inner: Box::new(UniErrorInner {
195 kind: Arc::new(kind),
196 context,
197 cause: cause.map(Arc::new),
198 }),
199 }
200 }
201
202 pub fn from_kind_boxed(kind: T, error: Box<dyn Error + Send + Sync>) -> Self {
204 Self::new(kind, None, Some(CauseInner::from_boxed_error(error)))
205 }
206
207 pub fn from_kind_context_boxed(
209 kind: T,
210 context: impl Into<Cow<'static, str>>,
211 error: Box<dyn Error + Send + Sync>,
212 ) -> Self {
213 Self::new(
214 kind,
215 Some(context.into()),
216 Some(CauseInner::from_boxed_error(error)),
217 )
218 }
219
220 pub fn from_kind(kind: T) -> Self {
222 Self::new(kind, None, None)
223 }
224
225 pub fn from_kind_context(kind: T, context: impl Into<Cow<'static, str>>) -> Self {
227 Self::new(kind, Some(context.into()), None)
228 }
229
230 pub fn kind_ref(&self) -> &T {
232 &self.inner.kind
233 }
234}
235
236impl<T: Clone> UniError<T> {
237 pub fn kind_clone(&self) -> T {
239 (*self.inner.kind).clone()
240 }
241}
242
243pub trait UniErrorOps: UniDisplay + Deref<Target = dyn Error + Send + Sync + 'static> {
245 fn kind_dyn_ref(&self) -> &dyn UniKind;
247
248 fn kind_code(&self) -> i32 {
250 self.kind_dyn_ref().code(self.prev_cause())
251 }
252
253 fn kind_value(&self) -> Cow<'static, str> {
256 self.kind_dyn_ref().value(self.prev_cause())
257 }
258
259 fn kind_context_str(&self) -> Option<Cow<'static, str>> {
261 self.kind_dyn_ref().context(self.prev_cause())
262 }
263
264 fn is_simple(&self) -> bool {
266 self.type_id() == TypeId::of::<SimpleError>()
267 }
268
269 fn prev_cause<'e>(&'e self) -> Option<Cause<'e>>;
271
272 fn chain(&self) -> Chain<'_>;
274
275 fn root_cause(&self) -> Option<Cause<'_>>;
278}
279
280impl dyn UniErrorOps + Send + Sync {
281 pub fn downcast_ref<T: UniKind>(&self) -> Option<&UniError<T>> {
283 let err: &dyn Any = self;
284 err.downcast_ref()
285 }
286}
287
288impl<T: UniKind> UniErrorOps for UniError<T> {
289 fn kind_dyn_ref(&self) -> &dyn UniKind {
290 self.kind_ref()
291 }
292
293 fn prev_cause<'e>(&'e self) -> Option<Cause<'e>> {
294 self.inner.prev_cause()
295 }
296
297 fn chain(&self) -> Chain<'_> {
298 Chain::new(self.prev_cause())
299 }
300
301 fn root_cause(&self) -> Option<Cause<'_>> {
302 let mut chain = self.chain();
303 let mut root = chain.next();
304
305 for next in chain {
306 root = Some(next);
307 }
308 root
309 }
310}
311
312impl<T: UniKind> Display for UniError<T> {
313 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
314 <UniErrorInner<T> as Display>::fmt(&self.inner, f)
315 }
316}
317
318impl<T: UniKind> Clone for UniError<T> {
320 fn clone(&self) -> Self {
321 Self {
322 inner: Box::new(UniErrorInner {
323 kind: self.inner.kind.clone(),
324 context: self.inner.context.clone(),
325 cause: self.inner.cause.clone(),
326 }),
327 }
328 }
329}
330
331impl<T: UniKind + PartialEq + 'static> PartialEq for UniError<T> {
332 fn eq(&self, other: &Self) -> bool {
333 if self.inner.kind == other.inner.kind {
335 if self.is_simple() {
338 self.inner.context == other.inner.context
339 } else {
340 true
341 }
342 } else {
343 false
344 }
345 }
346}
347
348impl<T: UniKind> Deref for UniError<T> {
349 type Target = dyn Error + Sync + Send + 'static;
350
351 fn deref(&self) -> &Self::Target {
352 &self.inner
353 }
354}
355
356impl<T: UniKind> AsRef<dyn Error + Sync + Send> for UniError<T> {
357 fn as_ref(&self) -> &(dyn Error + Sync + Send + 'static) {
358 &**self
359 }
360}