wee_woo/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#![no_std]
#![doc = env!("CARGO_PKG_DESCRIPTION")]

use core::{error::Error, fmt, iter};

/// An extension trait for [`Error`]s.
pub trait ErrorExt {
    /// Attach a source to the current error.
    ///
    /// The value of `source` will be returned by the [`Error::source`] and
    /// [`Error::cause`] implementations of the returned value. Note that the
    /// latter is deprecated.
    ///
    /// See also [`ErrorExt::caused`]
    fn with_source<Source>(
        self,
        source: Source,
    ) -> ErrorWithSource<Self, Source>
    where
        Self: Sized;

    /// Set `self` as the source of the given error.
    ///
    /// The value of `self` will be returned by the [`Error::source`] and
    /// [`Error::cause`] implementations of the returned value. Note that the
    /// latter is deprecated.
    ///
    /// See also [`ErrorExt::with_source`]
    fn caused<Error>(self, error: Error) -> ErrorWithSource<Error, Self>
    where
        Self: Sized;

    /// [`Display`] an [`Error`] and its [`source`]s with a separator.
    ///
    /// [`Display`]: fmt::Display
    /// [`source`]: Error::source
    fn display_with_sources<I>(&self, infix: I) -> DisplayWithSources<&Self, I>
    where
        Self: Sized;
}

impl<This> ErrorExt for This
where
    This: Error,
{
    fn with_source<Source>(
        self,
        source: Source,
    ) -> ErrorWithSource<Self, Source>
    where
        Self: Sized,
    {
        ErrorWithSource {
            this: self,
            source,
        }
    }

    fn caused<Error>(self, error: Error) -> ErrorWithSource<Error, Self>
    where
        Self: Sized,
    {
        ErrorWithSource {
            this: error,
            source: self,
        }
    }

    fn display_with_sources<I>(&self, infix: I) -> DisplayWithSources<&Self, I>
    where
        Self: Sized,
    {
        DisplayWithSources {
            error: self,
            infix,
        }
    }
}

/// [`Display`] an [`Error`] and its [`source`]s with a separator.
///
/// [`Display`]: fmt::Display
/// [`source`]: Error::source
pub struct DisplayWithSources<E, I> {
    /// The error (and its sources) to write.
    pub error: E,

    /// Separator to write between the error and each subsequent source.
    pub infix: I,
}

impl<E, I> fmt::Display for DisplayWithSources<E, I>
where
    E: Error,
    I: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.error)?;

        let mut source = self.error.source();

        source
            .into_iter()
            .chain(iter::from_fn(|| {
                source = source.and_then(Error::source);
                source
            }))
            .try_for_each(|source| write!(f, "{}{source}", self.infix))
    }
}

/// An [`Error`] with a [`source`] [`Error`].
///
/// This is useful for constructing ad-hoc chains of errors.
///
/// [`source`]: Error::source
#[derive(Debug)]
pub struct ErrorWithSource<This, Source> {
    /// The current error.
    ///
    /// Note that calling [`Error::source`] on an [`ErrorWithSource`] will not
    /// call [`Error::source`] on [`this`]; [`source`] will always be returned
    /// instead.
    ///
    /// [`this`]: ErrorWithSource#structfield.this
    /// [`source`]: ErrorWithSource#structfield.source
    pub this: This,

    /// The error that caused the current error.
    ///
    /// This value will be returned by [`ErrorWithSource`]'s [`Error::source`]
    /// and [`Error::cause`] implementations. Note that the latter is
    /// deprecated.
    pub source: Source,
}

impl<This, Source> Error for ErrorWithSource<This, Source>
where
    This: fmt::Display + fmt::Debug,
    Source: Error + 'static,
{
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        Some(&self.source)
    }

    fn cause(&self) -> Option<&dyn Error> {
        Some(&self.source)
    }
}

impl<This, Source> fmt::Display for ErrorWithSource<This, Source>
where
    This: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.this.fmt(f)
    }
}