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
129
130
131
132
133
134
135
136
137
138
139
140
//! Thread-safe cloneable wrappers over closures that carry `Send + Sync` bounds.
//!
//! ### Examples
//!
//! ```
//! use {
//! fp_library::{
//! brands::*,
//! functions::*,
//! },
//! std::thread,
//! };
//!
//! let f = send_cloneable_fn_new::<ArcFnBrand, _, _>(|x: i32| x * 2);
//!
//! // Can be sent to another thread
//! let handle = thread::spawn(move || {
//! assert_eq!(f(5), 10);
//! });
//! handle.join().unwrap();
//! ```
#[fp_macros::document_module]
mod inner {
use {
crate::classes::*,
fp_macros::*,
std::ops::Deref,
};
/// Abstraction for thread-safe cloneable wrappers over closures.
///
/// This trait extends [`CloneableFn`] to enforce `Send + Sync` bounds on the
/// wrapped closure and the wrapper itself. This is implemented by types like
/// [`ArcFnBrand`][crate::brands::ArcFnBrand] but not [`RcFnBrand`][crate::brands::RcFnBrand].
///
/// The lifetime `'a` ensures the function doesn't outlive referenced data,
/// while generic types `A` and `B` represent the input and output types, respectively.
///
/// By explicitly requiring that both type parameters outlive the application lifetime `'a`,
/// we provide the compiler with the necessary guarantees to handle trait objects
/// (like `dyn Fn`) commonly used in thread-safe function wrappers. This resolves potential
/// E0310 errors where the compiler cannot otherwise prove that captured variables in
/// closures satisfy the required lifetime bounds.
pub trait SendCloneableFn: CloneableFn {
/// The type of the thread-safe cloneable function wrapper.
///
/// This associated type represents the concrete type of the wrapper (e.g., `Arc<dyn Fn(A) -> B + Send + Sync>`)
/// that implements `Clone`, `Send`, `Sync` and dereferences to the underlying closure.
type SendOf<'a, A: 'a, B: 'a>: Clone
+ Send
+ Sync
+ Deref<Target = dyn 'a + Fn(A) -> B + Send + Sync>;
/// Creates a new thread-safe cloneable function wrapper.
///
/// This method wraps a closure into a thread-safe cloneable function wrapper.
#[document_signature]
///
#[document_type_parameters(
"The lifetime of the function and its captured data.",
"The input type of the function.",
"The output type of the function."
)]
///
#[document_parameters(
"The closure to wrap. Must be `Send + Sync`.",
"The input value to the function."
)]
#[document_returns("The wrapped thread-safe cloneable function.")]
#[document_examples]
///
/// ```
/// use {
/// fp_library::{
/// brands::*,
/// functions::*,
/// },
/// std::thread,
/// };
///
/// let f = send_cloneable_fn_new::<ArcFnBrand, _, _>(|x: i32| x * 2);
///
/// // Can be sent to another thread
/// let handle = thread::spawn(move || {
/// assert_eq!(f(5), 10);
/// });
/// handle.join().unwrap();
/// ```
fn send_cloneable_fn_new<'a, A: 'a, B: 'a>(
f: impl 'a + Fn(A) -> B + Send + Sync
) -> <Self as SendCloneableFn>::SendOf<'a, A, B>;
}
/// Creates a new thread-safe cloneable function wrapper.
///
/// Free function version that dispatches to [the type class' associated function][`SendCloneableFn::send_cloneable_fn_new`].
#[document_signature]
///
#[document_type_parameters(
"The lifetime of the function and its captured data.",
"The brand of the thread-safe cloneable function wrapper.",
"The input type of the function.",
"The output type of the function."
)]
///
#[document_parameters(
"The closure to wrap. Must be `Send + Sync`.",
"The input value to the function."
)]
#[document_returns("The wrapped thread-safe cloneable function.")]
#[document_examples]
///
/// ```
/// use {
/// fp_library::{
/// brands::*,
/// functions::*,
/// },
/// std::thread,
/// };
///
/// let f = send_cloneable_fn_new::<ArcFnBrand, _, _>(|x: i32| x * 2);
///
/// // Can be sent to another thread
/// let handle = thread::spawn(move || {
/// assert_eq!(f(5), 10);
/// });
/// handle.join().unwrap();
/// ```
pub fn new<'a, Brand, A, B>(
f: impl 'a + Fn(A) -> B + Send + Sync
) -> <Brand as SendCloneableFn>::SendOf<'a, A, B>
where
Brand: SendCloneableFn, {
<Brand as SendCloneableFn>::send_cloneable_fn_new(f)
}
}
pub use inner::*;