Skip to main content

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}