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}