orx_closure/
closure_val.rs

1use crate::fun::Fun;
2use core::fmt::Debug;
3
4/// Closure strictly separating the captured data from the function, and hence, having two components:
5///
6/// * `Capture` is any captured data,
7/// * `fn(&Capture, In) -> Out` is the transformation.
8///
9/// It represents the transformation `In -> Out`.
10///
11/// Note that, unlike trait objects of fn-traits, `Closure` auto-implements `Clone` given that captured data is cloneable.
12///
13/// # Example
14///
15/// ```rust
16/// use orx_closure::*;
17///
18/// let name = String::from("morgana");
19///
20/// // nth_char: Closure<String, usize, Option<char>>
21/// let nth_char = Capture(name).fun(|n, i| n.chars().nth(i));
22///
23/// assert_eq!(Some('m'), nth_char.call(0));
24///
25/// // alternatively
26/// let fun = nth_char.as_fn();
27/// assert_eq!(Some('g'), fun(3));
28/// ```
29#[derive(Clone)]
30pub struct Closure<Capture, In, Out> {
31    capture: Capture,
32    fun: fn(&Capture, In) -> Out,
33}
34
35impl<Capture: Debug, In, Out> Debug for Closure<Capture, In, Out> {
36    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
37        f.debug_struct("Closure")
38            .field("capture", &self.capture)
39            .finish()
40    }
41}
42
43impl<Capture, In, Out> Closure<Capture, In, Out> {
44    pub(super) fn new(capture: Capture, fun: fn(&Capture, In) -> Out) -> Self {
45        Self { capture, fun }
46    }
47
48    /// Calls the closure with the given `input`.
49    ///
50    /// # Example
51    ///
52    /// ```rust
53    /// use orx_closure::Capture;
54    ///
55    /// let base = 2;
56    /// let modulo = Capture(base).fun(|b, n| n % b);
57    ///
58    /// assert_eq!(0, modulo.call(42));
59    /// assert_eq!(1, modulo.call(7));
60    /// ```
61    #[inline(always)]
62    pub fn call(&self, input: In) -> Out {
63        (self.fun)(&self.capture, input)
64    }
65
66    /// Returns a reference to the captured data.
67    #[inline(always)]
68    pub fn captured_data(&self) -> &Capture {
69        &self.capture
70    }
71
72    /// Consumes the closure and returns back the captured data.
73    ///
74    /// ```rust
75    /// use orx_closure::Capture;
76    ///
77    /// struct ExpensiveData(Vec<i32>);
78    ///
79    /// let data = ExpensiveData(vec![0, 1, 2]);
80    ///
81    /// let get_number = Capture(data).fun(|data, i| 42 + data.0[i]);
82    ///
83    /// assert_eq!(42, get_number.call(0));
84    /// assert_eq!(44, get_number.call(2));
85    ///
86    /// let _data: ExpensiveData = get_number.into_captured_data();
87    /// ```
88    pub fn into_captured_data(self) -> Capture {
89        self.capture
90    }
91
92    /// Returns the closure as an `impl Fn(In) -> Out` struct, allowing the convenience
93    ///
94    /// * to avoid the `call` method,
95    /// * or pass the closure to functions accepting a function generic over the `Fn`.
96    ///
97    /// # Example
98    ///
99    /// ```rust
100    /// use orx_closure::Capture;
101    ///
102    /// let base = 2;
103    /// let modulo = Capture(base).fun(|b, n| n % b);
104    ///
105    /// // with call method
106    /// assert_eq!(0, modulo.call(42));
107    /// assert_eq!(1, modulo.call(7));
108    ///
109    /// // getting it as 'Fn' and directly calling the closure
110    /// let module_fn = modulo.as_fn();
111    /// assert_eq!(0, module_fn(42));
112    /// assert_eq!(1, module_fn(7));
113    /// ```
114    pub fn as_fn(&self) -> impl Fn(In) -> Out + '_ {
115        |x| (self.fun)(&self.capture, x)
116    }
117}
118
119impl<Capture, In, Out> Fun<In, Out> for Closure<Capture, In, Out> {
120    fn call(&self, input: In) -> Out {
121        Closure::call(self, input)
122    }
123}