fp_library/classes/send_cloneable_fn.rs
1//! Thread-safe cloneable wrappers over closures that carry `Send + Sync` bounds.
2//!
3//! ### Examples
4//!
5//! ```
6//! use fp_library::{functions::*, brands::*};
7//! use std::thread;
8//!
9//! let f = send_cloneable_fn_new::<ArcFnBrand, _, _>(|x: i32| x * 2);
10//!
11//! // Can be sent to another thread
12//! let handle = thread::spawn(move || {
13//! assert_eq!(f(5), 10);
14//! });
15//! handle.join().unwrap();
16//! ```
17
18use super::cloneable_fn::CloneableFn;
19use fp_macros::doc_params;
20use fp_macros::doc_type_params;
21use fp_macros::hm_signature;
22use std::ops::Deref;
23
24/// Abstraction for thread-safe cloneable wrappers over closures.
25///
26/// This trait extends [`CloneableFn`] to enforce `Send + Sync` bounds on the
27/// wrapped closure and the wrapper itself. This is implemented by types like
28/// [`ArcFnBrand`][crate::brands::ArcFnBrand] but not [`RcFnBrand`][crate::brands::RcFnBrand].
29///
30/// The lifetime `'a` ensures the function doesn't outlive referenced data,
31/// while generic types `A` and `B` represent the input and output types, respectively.
32pub trait SendCloneableFn: CloneableFn {
33 /// The type of the thread-safe cloneable function wrapper.
34 ///
35 /// This associated type represents the concrete type of the wrapper (e.g., `Arc<dyn Fn(A) -> B + Send + Sync>`)
36 /// that implements `Clone`, `Send`, `Sync` and dereferences to the underlying closure.
37 type SendOf<'a, A, B>: Clone + Send + Sync + Deref<Target = dyn 'a + Fn(A) -> B + Send + Sync>;
38
39 /// Creates a new thread-safe cloneable function wrapper.
40 ///
41 /// This method wraps a closure into a thread-safe cloneable function wrapper.
42 ///
43 /// ### Type Signature
44 ///
45 #[hm_signature(SendCloneableFn)]
46 ///
47 /// ### Type Parameters
48 ///
49 #[doc_type_params(
50 "The lifetime of the function and its captured data.",
51 "The input type of the function.",
52 "The output type of the function."
53 )]
54 ///
55 /// ### Parameters
56 ///
57 #[doc_params("The closure to wrap. Must be `Send + Sync`.", "The input value to the function.")]
58 /// ### Returns
59 ///
60 /// The wrapped thread-safe cloneable function.
61 ///
62 /// ### Examples
63 ///
64 /// ```
65 /// use fp_library::{functions::*, brands::*};
66 /// use std::thread;
67 ///
68 /// let f = send_cloneable_fn_new::<ArcFnBrand, _, _>(|x: i32| x * 2);
69 ///
70 /// // Can be sent to another thread
71 /// let handle = thread::spawn(move || {
72 /// assert_eq!(f(5), 10);
73 /// });
74 /// handle.join().unwrap();
75 /// ```
76 fn send_cloneable_fn_new<'a, A, B>(
77 f: impl 'a + Fn(A) -> B + Send + Sync
78 ) -> <Self as SendCloneableFn>::SendOf<'a, A, B>;
79}
80
81/// Creates a new thread-safe cloneable function wrapper.
82///
83/// Free function version that dispatches to [the type class' associated function][`SendCloneableFn::send_cloneable_fn_new`].
84///
85/// ### Type Signature
86///
87#[hm_signature(SendCloneableFn)]
88///
89/// ### Type Parameters
90///
91#[doc_type_params(
92 "The lifetime of the function and its captured data.",
93 "The brand of the thread-safe cloneable function wrapper.",
94 "The input type of the function.",
95 "The output type of the function."
96)]
97///
98/// ### Parameters
99///
100#[doc_params("The closure to wrap. Must be `Send + Sync`.", "The input value to the function.")]
101/// ### Returns
102///
103/// The wrapped thread-safe cloneable function.
104///
105/// ### Examples
106///
107/// ```
108/// use fp_library::{functions::*, brands::*};
109/// use std::thread;
110///
111/// let f = send_cloneable_fn_new::<ArcFnBrand, _, _>(|x: i32| x * 2);
112///
113/// // Can be sent to another thread
114/// let handle = thread::spawn(move || {
115/// assert_eq!(f(5), 10);
116/// });
117/// handle.join().unwrap();
118/// ```
119pub fn new<'a, Brand, A, B>(
120 f: impl 'a + Fn(A) -> B + Send + Sync
121) -> <Brand as SendCloneableFn>::SendOf<'a, A, B>
122where
123 Brand: SendCloneableFn,
124{
125 <Brand as SendCloneableFn>::send_cloneable_fn_new(f)
126}