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
use core::hash::Hash;
use failure::Fail;

/// The failure of a particular operation.
///
/// Can be attached with a value of type `Val`.
pub trait ErrorBase<Val: ?Sized = ()>: Fail + Into<&'static str> + Copy + Eq + Hash {
    /// This error, attached with a value.
    type With: ?Sized + ErrorWith<Val, Without = Self>;

    /// Attaches a value to this error.
    fn val(self, val: Val) -> Self::With where Val: Sized;
}

/// The failure of a particular operation, with the given operand(s).
///
/// Can be attached with a value of type `Val`, if `Val` is sized.
pub trait ErrorWith<Val: ?Sized> {
    /// This error, without the attached value.
    type Without: Fail;

    /// Gets the underlying error.
    fn as_error(&self) -> Self::Without;

    /// References the attached value.
    fn as_value(&self) -> &Val;

    /// Consumes this error and returns the attached value.
    fn into_value(self) -> Val where Self: Sized, Val: Sized;

    /// Discards the attached value and returns the underlying error.
    fn into_error(self) -> Self::Without where Self: Sized, Val: Sized {
        self.as_error()
    }

    /// Maps a function over the attached value.
    fn map<F, Ret>(self, f: F) -> <Self::Without as ErrorBase<Ret>>::With
    where
        Self: Sized,
        Val: Sized,
        F: Fn(Val) -> Ret,
        Self::Without: ErrorBase<Ret>,
        <Self::Without as ErrorBase<Ret>>::With: Sized,
    {
        let err = self.as_error();
        err.val(f(self.into_value()))
    }
}