fp_library/classes/cloneable_fn.rs
1//! Cloneable wrappers over closures for generic handling of functions in higher-kinded contexts.
2//!
3//! ### Examples
4//!
5//! ```
6//! use fp_library::{brands::*, functions::*};
7//!
8//! let f = cloneable_fn_new::<RcFnBrand, _, _>(|x: i32| x * 2);
9//! assert_eq!(f(5), 10);
10//! ```
11
12use super::function::Function;
13use fp_macros::doc_params;
14use fp_macros::doc_type_params;
15use fp_macros::hm_signature;
16use std::ops::Deref;
17
18/// A trait for cloneable wrappers over closures, allowing for generic handling of cloneable functions in higher-kinded contexts.
19///
20/// This trait is implemented by "Brand" types (like [`ArcFnBrand`][crate::brands::ArcFnBrand]
21/// and [`RcFnBrand`][crate::brands::RcFnBrand]) to provide a way to construct
22/// and type-check cloneable wrappers over closures (`Arc<dyn Fn...>` or
23/// `Rc<dyn Fn...>`) in a generic context, allowing library users to choose
24/// between implementations at function call sites.
25///
26/// The lifetime `'a` ensures the function doesn't outlive referenced data,
27/// while generic types `A` and `B` represent the input and output types, respectively.
28pub trait CloneableFn: Function {
29 /// The type of the cloneable function wrapper.
30 ///
31 /// This associated type represents the concrete type of the wrapper (e.g., `Rc<dyn Fn(A) -> B>`)
32 /// that implements `Clone` and dereferences to the underlying closure.
33 type Of<'a, A, B>: Clone + Deref<Target = dyn 'a + Fn(A) -> B>;
34
35 /// Creates a new cloneable function wrapper.
36 ///
37 /// This function wraps the provided closure `f` into a cloneable function.
38 ///
39 /// ### Type Signature
40 ///
41 #[hm_signature(CloneableFn)]
42 ///
43 /// ### Type Parameters
44 ///
45 #[doc_type_params(
46 "The lifetime of the function and its captured data.",
47 "The input type of the function.",
48 "The output type of the function."
49 )]
50 ///
51 /// ### Parameters
52 ///
53 #[doc_params("The closure to wrap.", "The input value to the function.")]
54 /// ### Returns
55 ///
56 /// The wrapped cloneable function.
57 ///
58 /// ### Examples
59 ///
60 /// ```
61 /// use fp_library::{brands::*, functions::*};
62 ///
63 /// let f = cloneable_fn_new::<RcFnBrand, _, _>(|x: i32| x * 2);
64 /// assert_eq!(f(5), 10);
65 /// ```
66 fn new<'a, A, B>(f: impl 'a + Fn(A) -> B) -> <Self as CloneableFn>::Of<'a, A, B>;
67}
68
69/// Creates a new cloneable function wrapper.
70///
71/// Free function version that dispatches to [the type class' associated function][`CloneableFn::new`].
72///
73/// ### Type Signature
74///
75#[hm_signature(CloneableFn)]
76///
77/// ### Type Parameters
78///
79#[doc_type_params(
80 "The lifetime of the function and its captured data.",
81 "The brand of the cloneable function wrapper.",
82 "The input type of the function.",
83 "The output type of the function."
84)]
85///
86/// ### Parameters
87///
88#[doc_params("The closure to wrap.", "The input value to the function.")]
89/// ### Returns
90///
91/// The wrapped cloneable function.
92///
93/// ### Examples
94///
95/// ```
96/// use fp_library::{brands::*, functions::*};
97///
98/// let f = cloneable_fn_new::<RcFnBrand, _, _>(|x: i32| x * 2);
99/// assert_eq!(f(5), 10);
100/// ```
101pub fn new<'a, Brand, A, B>(f: impl 'a + Fn(A) -> B) -> <Brand as CloneableFn>::Of<'a, A, B>
102where
103 Brand: CloneableFn,
104{
105 <Brand as CloneableFn>::new(f)
106}