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
use crate::fun::FunOptRef;
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) -> Option<&Out>` is the transformation.
///
/// It represents the transformation `In -> Option<&Out>`.
///
/// Note that, unlike trait objects of fn-traits, `Capture` auto-implements `Clone` given that captured data is cloneable.
///
/// **Instead of `ClosureOptRef`; this closure variant is particularly useful when we capture the data by value and return an `Option` of 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: ClosureOptRef<[Person; 2], usize, str>
/// let name_of_person_with_id =
/// Capture(people).fun_option_ref(|ppl, id: usize| ppl.get(id).map(|p| p.name.as_str()));
///
/// assert_eq!(Some("john"), name_of_person_with_id.call(0));
/// assert_eq!(None, name_of_person_with_id.call(42));
///
/// // alternatively
/// let fun = name_of_person_with_id.as_fn();
/// assert_eq!(Some("doe"), fun(1));
/// ```
#[derive(Clone)]
pub struct ClosureOptRef<Capture, In, Out: ?Sized> {
capture: Capture,
fun: fn(&Capture, In) -> Option<&Out>,
}
impl<Capture: Debug, In, Out: ?Sized> Debug for ClosureOptRef<Capture, In, Out> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ClosureOptRef")
.field("capture", &self.capture)
.finish()
}
}
impl<Capture, In, Out: ?Sized> ClosureOptRef<Capture, In, Out> {
pub(super) fn new(capture: Capture, fun: fn(&Capture, In) -> Option<&Out>) -> 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: ClosureOptRef<[Person; 2], usize, str>
/// let name_of_person_with_id =
/// Capture(people).fun_option_ref(|ppl, id: usize| ppl.get(id).map(|p| p.name.as_str()));
///
/// assert_eq!(Some("john"), name_of_person_with_id.call(0));
/// assert_eq!(None, name_of_person_with_id.call(42));
/// ```
#[inline(always)]
pub fn call(&self, input: In) -> Option<&Out> {
(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.
///
/// # Example
/// ```rust
/// use orx_closure::Capture;
///
/// struct ExpensiveData(Vec<i32>);
///
/// let data = ExpensiveData(vec![10, 11, 12]);
///
/// let get_number = Capture(data).fun_option_ref(|data, i| data.0.get(i));
///
/// assert_eq!(Some(&10), get_number.call(0));
/// assert_eq!(Some(&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) -> Option<&Out>` 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: ClosureOptRef<[Person; 2], usize, str>
/// let name_of_person_with_id =
/// Capture(people).fun_option_ref(|ppl, id: usize| ppl.get(id).map(|p| p.name.as_str()));
///
/// // alternatively
/// let fun = name_of_person_with_id.as_fn();
/// assert_eq!(Some("doe"), fun(1));
/// ```
pub fn as_fn<'a>(&'a self) -> impl Fn(In) -> Option<&'a Out> {
move |x| self.call(x)
}
}
impl<Capture, In, Out: ?Sized> FunOptRef<In, Out> for ClosureOptRef<Capture, In, Out> {
fn call(&self, input: In) -> Option<&Out> {
ClosureOptRef::call(self, input)
}
}