fp_library/classes/function.rs
1use super::category::Category;
2use crate::make_type_apply;
3use std::ops::Deref;
4
5/// Abstraction for wrappers over closures.
6///
7/// This trait is implemented by "Brand" types (like [`ArcFnBrand`][crate::brands::ArcFnBrand]
8/// and [`RcFnBrand`][crate::brands::RcFnBrand]) to provide a way to construct
9/// and type-check wrappers over closures (`Arc<dyn Fn...>`, `Rc<dyn Fn...>`,
10/// etc.) in a generic context, allowing library users to choose between
11/// implementations at function call sites.
12///
13/// The lifetime `'a` ensures the function doesn't outlive referenced data,
14/// while generic types `A` and `B` represent the input and output types, respectively.
15pub trait Function: Category {
16 type Output<'a, A, B>: Deref<Target = dyn 'a + Fn(A) -> B>;
17
18 /// Creates a new function wrapper.
19 ///
20 /// # Type Signature
21 ///
22 /// `forall a b. Function f => (a -> b) -> f a b`
23 ///
24 /// # Parameters
25 ///
26 /// * `f`: The closure to wrap.
27 ///
28 /// # Returns
29 ///
30 /// The wrapped function.
31 ///
32 /// # Examples
33 ///
34 /// ```
35 /// use fp_library::classes::function::Function;
36 /// use fp_library::brands::RcFnBrand;
37 ///
38 /// let f = <RcFnBrand as Function>::new(|x: i32| x * 2);
39 /// assert_eq!(f(5), 10);
40 /// ```
41 fn new<'a, A, B>(f: impl 'a + Fn(A) -> B) -> ApplyFunction<'a, Self, A, B>;
42}
43
44make_type_apply!(ApplyFunction, Function, ('a), (A, B), "' -> * -> *");
45
46/// Creates a new function wrapper.
47///
48/// Free function version that dispatches to [the type class' associated function][`Function::new`].
49///
50/// # Type Signature
51///
52/// `forall a b. Function f => (a -> b) -> f a b`
53///
54/// # Parameters
55///
56/// * `f`: The closure to wrap.
57///
58/// # Returns
59///
60/// The wrapped function.
61///
62/// # Examples
63///
64/// ```
65/// use fp_library::classes::function::new;
66/// use fp_library::brands::RcFnBrand;
67///
68/// let f = new::<RcFnBrand, _, _>(|x: i32| x * 2);
69/// assert_eq!(f(5), 10);
70/// ```
71pub fn new<'a, F, A, B>(f: impl 'a + Fn(A) -> B) -> ApplyFunction<'a, F, A, B>
72where
73 F: Function,
74{
75 F::new(f)
76}