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