1use std::error::Error;
15use std::fmt;
16
17#[derive(Debug)]
19pub struct Context<C> {
20 context: C,
21 source: Box<dyn Error + Send + Sync>,
22}
23
24impl<C> Context<C> {
25 pub fn new(context: C, source: Box<dyn Error + Send + Sync>) -> Self {
26 Self { context, source }
27 }
28}
29
30impl<C: fmt::Display> fmt::Display for Context<C> {
31 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32 self.context.fmt(f)?;
33 f.write_str(": ")?;
34 self.source.fmt(f)
35 }
36}
37
38impl<C: fmt::Debug + fmt::Display> Error for Context<C> {
39 fn source(&self) -> Option<&(dyn Error + 'static)> {
40 Some(&*self.source)
41 }
42}
43
44pub trait ResultExt<T, E>
45where
46 E: Into<Box<dyn Error + Send + Sync>>,
47{
48 fn ctx<D>(self, context: D) -> Result<T, Context<D>>;
50
51 fn with_ctx<D>(self, f: impl FnOnce(&E) -> D) -> Result<T, Context<D>>;
53}
54
55impl<T, E> ResultExt<T, E> for Result<T, E>
56where
57 E: Into<Box<dyn Error + Send + Sync>>,
58{
59 fn ctx<D>(self, context: D) -> Result<T, Context<D>> {
60 self.map_err(|e| e.ctx(context))
61 }
62
63 fn with_ctx<D>(self, f: impl FnOnce(&E) -> D) -> Result<T, Context<D>> {
64 self.map_err(|e| {
65 let context = f(&e);
66 e.ctx(context)
67 })
68 }
69}
70
71pub trait ErrorExt {
72 fn ctx<D>(self, context: D) -> Context<D>;
74}
75
76impl<T: Into<Box<Error + Send + Sync>>> ErrorExt for T {
77 fn ctx<D>(self, context: D) -> Context<D> {
78 Context {
79 context,
80 source: self.into(),
81 }
82 }
83}