devela/code/result/
chain_hook.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
// devela::code::result::traits
//
//! Free function chaining traits helpers.
//
// Based on the code by George Burton, Unlicense licensed.
// https://crates.io/crates/apply/0.3.0

/// Allows chaining transformations by passing values through a sequence of functions.
///
/// Use `Chain` to thread operations where each function takes ownership or
/// references the value and returns a new result.
///
/// # Examples
/// ```
/// use devela::Chain;
///
/// let x = 1
///     .chain(|x| x * 2)
///     .chain(|x| x + 1)
///     .chain(|x: i32| x.to_string());
/// assert_eq![x, 3.to_string()];
/// ```
///
/// ```compile_fail
/// use devela::Chain;
///
/// // We can sort it, but we don't receive the new vec.
/// let v: Vec<i32> = vec![3, 2, 1, 5].chain_mut(|it| it.sort());
/// ```
///
/// See also the [`Hook`][crate::Hook] trait.
pub trait Chain<R> {
    /// Chain a function which takes the parameter by value.
    #[must_use]
    fn chain<F>(self, f: F) -> R
    where
        F: FnOnce(Self) -> R,
        Self: Sized,
    {
        f(self)
    }

    /// Chain a function which takes the parameter by shared reference.
    #[must_use]
    fn chain_ref<F>(&self, f: F) -> R
    where
        F: FnOnce(&Self) -> R,
    {
        f(self)
    }

    /// Chain a function which takes the parameter by exclusive reference.
    #[must_use]
    fn chain_mut<F>(&mut self, f: F) -> R
    where
        F: FnOnce(&mut Self) -> R,
    {
        f(self)
    }
}
impl<T: ?Sized, R> Chain<R> for T {}

/// Allows attaching operations or side effects to a value without breaking its flow.
///
/// Use `Hook` when you want to inspect, log, or modify the value in-place without
/// directly returning a new result from the function.
///
/// Useful for when a method doesn't return the receiver
/// but you want to apply several of them to the object.
///
/// It assumes that each function in the chain modifies the value by exclusive
/// reference and returns the modified value.
///
/// # Examples
/// ```
/// use devela::Hook;
///
/// let v = vec![3, 2, 1, 5]
///     .hook_mut(|v| v.sort())
///     .hook_ref(|v| assert_eq![v, &[1, 2, 3, 5]])
///     .hook_mut(|v| v.push(7));
/// assert_eq![v, vec![1, 2, 3, 5, 7]];
/// ```
///
/// See also the [`Chain`][crate::Chain] trait.
pub trait Hook: Sized {
    /// Applies a function which takes the parameter by shared reference,
    /// and then returns the (possibly) modified owned value.
    ///
    /// Similar to [`chain_ref`], but instead of returning self directly from `f`,
    /// since it has a different signature, returns it indirectly.
    ///
    /// [`chain_ref`]: Chain::chain_ref
    #[must_use]
    fn hook_ref<F>(self, f: F) -> Self
    where
        F: FnOnce(&Self),
    {
        f(&self);
        self
    }

    /// Applies a function which takes the parameter by exclusive reference,
    /// and then returns the (possibly) modified owned value.
    ///
    /// Similar to [`chain_mut`], but instead of returning self directly from `f`,
    /// since it has a different signature, returns it indirectly.
    ///
    /// [`chain_mut`]: Chain::chain_mut
    #[must_use]
    fn hook_mut<F>(mut self, f: F) -> Self
    where
        F: FnOnce(&mut Self),
    {
        f(&mut self);
        self
    }
}
impl<T: Sized> Hook for T {}