devela/code/result/
chain_hook.rs

1// devela::code::result::traits
2//
3//! Free function chaining traits helpers.
4//
5// Based on the code by George Burton, Unlicense licensed.
6// https://crates.io/crates/apply/0.3.0
7
8/// Allows chaining transformations by passing values through a sequence of functions.
9///
10/// Use `Chain` to thread operations where each function takes ownership or
11/// references the value and returns a new result.
12///
13/// # Examples
14/// ```
15/// use devela::Chain;
16///
17/// let x = 1
18///     .chain(|x| x * 2)
19///     .chain(|x| x + 1)
20///     .chain(|x: i32| x.to_string());
21/// assert_eq![x, 3.to_string()];
22/// ```
23///
24/// ```compile_fail
25/// use devela::Chain;
26///
27/// // We can sort it, but we don't receive the new vec.
28/// let v: Vec<i32> = vec![3, 2, 1, 5].chain_mut(|it| it.sort());
29/// ```
30/// See also the [`Hook`][crate::Hook] trait.
31///
32#[doc = crate::doc_!(vendor: "apply")]
33pub trait Chain<R> {
34    /// Chain a function which takes the parameter by value.
35    #[must_use]
36    fn chain<F>(self, f: F) -> R
37    where
38        F: FnOnce(Self) -> R,
39        Self: Sized,
40    {
41        f(self)
42    }
43
44    /// Chain a function which takes the parameter by shared reference.
45    #[must_use]
46    fn chain_ref<F>(&self, f: F) -> R
47    where
48        F: FnOnce(&Self) -> R,
49    {
50        f(self)
51    }
52
53    /// Chain a function which takes the parameter by exclusive reference.
54    #[must_use]
55    fn chain_mut<F>(&mut self, f: F) -> R
56    where
57        F: FnOnce(&mut Self) -> R,
58    {
59        f(self)
60    }
61}
62impl<T: ?Sized, R> Chain<R> for T {}
63
64/// Allows attaching operations or side effects to a value without breaking its flow.
65///
66/// Use `Hook` when you want to inspect, log, or modify the value in-place without
67/// directly returning a new result from the function.
68///
69/// Useful for when a method doesn't return the receiver
70/// but you want to apply several of them to the object.
71///
72/// It assumes that each function in the chain modifies the value by exclusive
73/// reference and returns the modified value.
74///
75/// # Examples
76/// ```
77/// use devela::Hook;
78///
79/// let v = vec![3, 2, 1, 5]
80///     .hook_mut(|v| v.sort())
81///     .hook_ref(|v| assert_eq![v, &[1, 2, 3, 5]])
82///     .hook_mut(|v| v.push(7));
83/// assert_eq![v, vec![1, 2, 3, 5, 7]];
84/// ```
85/// See also the [`Chain`][crate::Chain] trait.
86///
87#[doc = crate::doc_!(vendor: "apply")]
88pub trait Hook: Sized {
89    /// Applies a function which takes the parameter by shared reference,
90    /// and then returns the (possibly) modified owned value.
91    ///
92    /// Similar to [`chain_ref`], but instead of returning self directly from `f`,
93    /// since it has a different signature, returns it indirectly.
94    ///
95    /// [`chain_ref`]: Chain::chain_ref
96    #[must_use]
97    fn hook_ref<F>(self, f: F) -> Self
98    where
99        F: FnOnce(&Self),
100    {
101        f(&self);
102        self
103    }
104
105    /// Applies a function which takes the parameter by exclusive reference,
106    /// and then returns the (possibly) modified owned value.
107    ///
108    /// Similar to [`chain_mut`], but instead of returning self directly from `f`,
109    /// since it has a different signature, returns it indirectly.
110    ///
111    /// [`chain_mut`]: Chain::chain_mut
112    #[must_use]
113    fn hook_mut<F>(mut self, f: F) -> Self
114    where
115        F: FnOnce(&mut Self),
116    {
117        f(&mut self);
118        self
119    }
120}
121impl<T: Sized> Hook for T {}