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}