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)
}
}