1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
use crate::fun::FunResRef;
use std::fmt::Debug;

/// Closure strictly separating the captured data from the function, and hence, having two components:
///
/// * `Capture` is any captured data,
/// * `fn(&Capture, In) -> Result<&Out, Error>` is the transformation.
///
/// It represents the transformation `In -> Result<&Out, Error>`.
///
/// Note that, unlike trait objects of fn-traits, `Capture` auto-implements `Clone` given that captured data is cloneable.
///
/// **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.**
///
/// # Example
///
/// ```rust
/// use orx_closure::Capture;
///
/// struct Person { name: String }
/// let people = [Person { name: "john".to_string() }, Person { name: "doe".to_string() }];
/// // name_of_person_with_id: ClosureResRef<[Person; 2], usize, str, String>
/// let name_of_person_with_id = Capture(people).fun_result_ref(|ppl, id: usize| {
///     ppl.get(id)
///         .map(|p| p.name.as_str())
///         .ok_or_else(|| "unknown id".to_string())
/// });
///
/// assert_eq!(Ok("john"), name_of_person_with_id.call(0));
/// assert_eq!(Err("unknown id".to_string()), name_of_person_with_id.call(42));
///
/// // alternatively
/// let fun = name_of_person_with_id.as_fn();
/// assert_eq!(Ok("doe"), fun(1));
/// ```
#[derive(Clone)]
pub struct ClosureResRef<Capture, In, Out: ?Sized, Error> {
    capture: Capture,
    fun: fn(&Capture, In) -> Result<&Out, Error>,
}

impl<Capture: Debug, In, Out: ?Sized, Error> Debug for ClosureResRef<Capture, In, Out, Error> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("ClosureResRef")
            .field("capture", &self.capture)
            .finish()
    }
}

impl<Capture, In, Out: ?Sized, Error> ClosureResRef<Capture, In, Out, Error> {
    pub(super) fn new(capture: Capture, fun: fn(&Capture, In) -> Result<&Out, Error>) -> Self {
        Self { capture, fun }
    }

    /// Calls the closure with the given `input`.
    ///
    /// # Example
    ///
    /// ```rust
    /// use orx_closure::Capture;
    ///
    /// struct Person { name: String }
    /// let people = [Person { name: "john".to_string() }, Person { name: "doe".to_string() }];
    /// // name_of_person_with_id: ClosureResRef<[Person; 2], usize, str, String>
    /// let name_of_person_with_id = Capture(people).fun_result_ref(|ppl, id: usize| {
    ///     ppl.get(id)
    ///         .map(|p| p.name.as_str())
    ///         .ok_or_else(|| "unknown id".to_string())
    /// });
    ///
    /// assert_eq!(Ok("john"), name_of_person_with_id.call(0));
    /// assert_eq!(Err("unknown id".to_string()), name_of_person_with_id.call(42));
    /// ```
    #[inline(always)]
    pub fn call(&self, input: In) -> Result<&Out, Error> {
        (self.fun)(&self.capture, input)
    }

    /// Returns a reference to the captured data.
    pub fn captured_data(&self) -> &Capture {
        &self.capture
    }

    /// Consumes the closure and returns back the captured data.
    ///
    /// ```rust
    /// use orx_closure::Capture;
    ///
    /// struct ExpensiveData(Vec<i32>);
    ///
    /// let data = ExpensiveData(vec![10, 11, 12]);
    ///
    /// let get_number = Capture(data).fun_result_ref(|data, i| data.0.get(i).ok_or("!!"));
    ///
    /// assert_eq!(Ok(&10), get_number.call(0));
    /// assert_eq!(Ok(&12), get_number.call(2));
    ///
    /// let _data: ExpensiveData = get_number.into_captured_data();
    /// ```
    pub fn into_captured_data(self) -> Capture {
        self.capture
    }

    /// Returns the closure as an `impl Fn(In) -> Result<&Out, String>` struct, allowing the convenience
    ///
    /// * to avoid the `call` method,
    /// * or pass the closure to functions accepting a function generic over the `Fn`.
    ///
    /// # Example
    ///
    /// ```rust
    /// use orx_closure::Capture;
    ///
    /// struct Person { name: String }
    /// let people = [Person { name: "john".to_string() }, Person { name: "doe".to_string() }];
    /// // name_of_person_with_id: ClosureResRef<[Person; 2], usize, str, String>
    /// let name_of_person_with_id = Capture(people).fun_result_ref(|ppl, id: usize| {
    ///     ppl.get(id)
    ///         .map(|p| p.name.as_str())
    ///         .ok_or_else(|| "unknown id".to_string())
    /// });
    ///
    /// let fun = name_of_person_with_id.as_fn();
    /// assert_eq!(Ok("doe"), fun(1));
    /// ```
    pub fn as_fn<'a>(&'a self) -> impl Fn(In) -> Result<&'a Out, Error> {
        move |x| self.call(x)
    }
}

impl<Capture, In, Out: ?Sized, Error> FunResRef<In, Out, Error>
    for ClosureResRef<Capture, In, Out, Error>
{
    fn call(&self, input: In) -> Result<&Out, Error> {
        ClosureResRef::call(self, input)
    }
}