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
use std::{error::Error, marker::PhantomData};

/// Sink to which the non-fatal errors of type `E` can be written
pub trait Warn<E: Error> {
    /// Push the error `error` to the sink
    fn warn(&mut self, error: E);
}

/// Sink adapter that is able to convert from different error types via [`From`] trait
pub struct Adapt<'a, E, W>(&'a mut W, PhantomData<E>);

/// Sink adapter that applies some function before passing the value to the wrapped sink
pub struct AdaptMap<'a, D, E, F, W>(&'a mut W, F, PhantomData<D>, PhantomData<E>);

mod sealed {
    use std::error::Error;

    pub trait WarnExt<E> {}

    impl<E: Error, W: super::Warn<E>> WarnExt<E> for W {}
}

/// Extension methods for trait [`Warn`]
///
/// This trait is implemented for all the traits which implement [`Warn`]. Note that this
/// trait is sealed, so you cannot implement it for anything else.
pub trait WarnExt<E: Error>: Warn<E> + sealed::WarnExt<E> {
    /// Wraps the sink into the adapter, which is able to convert from different error
    /// types via [`From`] trait
    ///
    /// This is especially useful when you try to pass the sink into a subfunction,
    /// which yields different errors. See the [example](#example) below.
    ///
    /// # Example
    ///
    /// ```
    /// use thiserror::Error;
    /// use wurm::prelude::*;
    /// use wurm::CollectAll;
    ///
    /// // First error type
    /// #[derive(Debug, Error, PartialEq, Eq)]
    /// #[error("first error")]
    /// struct FooError;
    ///
    /// // Second error type, which is converible from `FooError`
    /// #[derive(Debug, Error, PartialEq, Eq)]
    /// #[error("second error: {0}")]
    /// struct BarError(#[from] FooError);
    ///
    /// // This function yields errors of type `FooError`
    /// fn foo(warn: &mut impl Warn<FooError>) {
    ///     warn.warn(FooError);
    /// }
    ///
    /// // This function yields errors of type `FooError`
    /// // So, we need the adapter to call `foo()`
    /// fn bar(warn: &mut impl Warn<BarError>) {
    ///     foo(&mut warn.adapt());
    /// }
    ///
    /// let mut warn = CollectAll::default();
    /// bar(&mut warn);
    /// // We get exactly one error of type `BarError` after calling `bar()`.
    /// // Note that the error is originally coming from `foo()` and is wrapped.
    /// assert_eq!(warn.0.len(), 1);
    /// ```
    #[inline]
    fn adapt(&mut self) -> Adapt<'_, E, Self>
    where
        Self: Sized,
    {
        Adapt(self, PhantomData)
    }

    /// Like [`WarnExt::adapt()`], but applies function `func` instead of converting errors via [`From`]
    #[inline]
    fn adapt_map<D, F>(&mut self, func: F) -> AdaptMap<'_, D, E, F, Self>
    where
        Self: Sized,
        D: Error,
        F: FnMut(D) -> E,
    {
        AdaptMap(self, func, PhantomData, PhantomData)
    }
}

impl<E: Error, W: Warn<E>> WarnExt<E> for W {}

impl<'a, D, E, W> Warn<D> for Adapt<'a, E, W>
where
    D: Error,
    E: Error + From<D>,
    W: Warn<E>,
{
    #[inline]
    fn warn(&mut self, error: D) {
        self.0.warn(E::from(error))
    }
}

impl<'a, D, E, F, W> Warn<D> for AdaptMap<'a, D, E, F, W>
where
    D: Error,
    E: Error,
    F: FnMut(D) -> E,
    W: Warn<E>,
{
    #[inline]
    fn warn(&mut self, error: D) {
        self.0.warn(self.1(error))
    }
}