orx_closure/
closure_ref.rs

1use crate::fun::FunRef;
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, `Capture` auto-implements `Clone` given that captured data is cloneable.
12///
13/// **Instead of `ClosureRef`; this closure variant is particularly useful when we capture the data by value and return a reference.**
14///
15/// # Example
16///
17/// ```rust
18/// use orx_closure::Capture;
19///
20/// struct Person { name: String }
21/// let people = [Person { name: "john".to_string() }, Person { name: "doe".to_string() }];
22/// // name_of_person_with_id: ClosureRef<[Person; 2], usize, str>
23/// let name_of_person_with_id =
24///     Capture(people).fun_ref(|ppl, id: usize| ppl[id].name.as_str());
25///
26/// assert_eq!("john", name_of_person_with_id.call(0));
27///
28/// // alternatively
29/// let fun = name_of_person_with_id.as_fn();
30/// assert_eq!("doe", fun(1));
31/// ```
32#[derive(Clone)]
33pub struct ClosureRef<Capture, In, Out: ?Sized> {
34    capture: Capture,
35    fun: fn(&Capture, In) -> &Out,
36}
37
38impl<Capture: Debug, In, Out: ?Sized> Debug for ClosureRef<Capture, In, Out> {
39    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
40        f.debug_struct("ClosureRef")
41            .field("capture", &self.capture)
42            .finish()
43    }
44}
45
46impl<Capture, In, Out: ?Sized> ClosureRef<Capture, In, Out> {
47    pub(super) fn new(capture: Capture, fun: fn(&Capture, In) -> &Out) -> Self {
48        Self { capture, fun }
49    }
50
51    /// Calls the closure with the given `input`.
52    ///
53    /// # Example
54    ///
55    /// ```rust
56    /// use orx_closure::Capture;
57    ///
58    /// struct Person { name: String }
59    /// let people = [Person { name: "john".to_string() }, Person { name: "doe".to_string() }];
60    /// // name_of_person_with_id: ClosureRef<[Person; 2], usize, str>
61    /// let name_of_person_with_id =
62    ///     Capture(people).fun_ref(|ppl, id: usize| ppl[id].name.as_str());
63    ///
64    /// assert_eq!("john", name_of_person_with_id.call(0));
65    /// ```
66    #[inline(always)]
67    pub fn call(&self, input: In) -> &Out {
68        (self.fun)(&self.capture, input)
69    }
70
71    /// Returns a reference to the captured data.
72    #[inline(always)]
73    pub fn captured_data(&self) -> &Capture {
74        &self.capture
75    }
76
77    /// Consumes the closure and returns back the captured data.
78    ///
79    /// ```rust
80    /// use orx_closure::Capture;
81    ///
82    /// struct ExpensiveData(Vec<i32>);
83    ///
84    /// let data = ExpensiveData(vec![10, 11, 12]);
85    ///
86    /// let get_number = Capture(data).fun_ref(|data, i| &data.0[i]);
87    ///
88    /// assert_eq!(&10, get_number.call(0));
89    /// assert_eq!(&12, get_number.call(2));
90    ///
91    /// let _data: ExpensiveData = get_number.into_captured_data();
92    /// ```
93    pub fn into_captured_data(self) -> Capture {
94        self.capture
95    }
96
97    /// Returns the closure as an `impl Fn(In) -> &Out` struct, allowing the convenience
98    ///
99    /// * to avoid the `call` method,
100    /// * or pass the closure to functions accepting a function generic over the `Fn`.
101    ///
102    /// ```rust
103    /// use orx_closure::Capture;
104    ///
105    /// struct Person { name: String }
106    /// let people = [Person { name: "john".to_string() }, Person { name: "doe".to_string() }];
107    /// // name_of_person_with_id: ClosureRef<[Person; 2], usize, str>
108    /// let name_of_person_with_id =
109    ///     Capture(people).fun_ref(|ppl, id: usize| ppl[id].name.as_str());
110    ///
111    /// let fun = name_of_person_with_id.as_fn();
112    /// assert_eq!("doe", fun(1));
113    /// ```
114    pub fn as_fn<'a>(&'a self) -> impl Fn(In) -> &'a Out {
115        move |x| self.call(x)
116    }
117}
118
119impl<Capture, In, Out: ?Sized> FunRef<In, Out> for ClosureRef<Capture, In, Out> {
120    fn call(&self, input: In) -> &Out {
121        ClosureRef::call(self, input)
122    }
123}