fp_library/classes/par_functor.rs
1//! Data structures that can be mapped over in parallel.
2//!
3//! ### Examples
4//!
5//! ```
6//! use fp_library::{
7//! brands::*,
8//! functions::*,
9//! };
10//!
11//! let v = vec![1, 2, 3];
12//! let result: Vec<i32> = par_map::<VecBrand, _, _>(|x| x * 2, v);
13//! assert_eq!(result, vec![2, 4, 6]);
14//! ```
15
16#[fp_macros::document_module]
17mod inner {
18 use {
19 crate::kinds::*,
20 fp_macros::*,
21 };
22
23 /// A type class for data structures that can be mapped over in parallel.
24 ///
25 /// `ParFunctor` is the parallel counterpart to [`Functor`](crate::classes::Functor).
26 /// Implementors define [`par_map`][ParFunctor::par_map] directly: there is no intermediate
27 /// `Vec` conversion imposed by the interface. Types backed by contiguous memory (e.g.,
28 /// [`VecBrand`](crate::brands::VecBrand)) can use rayon's parallel iterators directly;
29 /// other types may collect to `Vec` as an implementation detail.
30 ///
31 /// ### Laws
32 ///
33 /// `ParFunctor` instances must satisfy the same laws as `Functor`:
34 /// * Identity: `par_map(identity, fa) = fa`.
35 /// * Composition: `par_map(|a| f(g(a)), fa) = par_map(f, par_map(g, fa))`.
36 ///
37 /// ### Thread Safety
38 ///
39 /// All `par_*` functions require `A: Send`, `B: Send`, and closures to be `Send + Sync`.
40 /// These bounds apply even when the `rayon` feature is disabled, so that code compiles
41 /// identically in both configurations.
42 ///
43 /// **Note: The `rayon` feature must be enabled to use actual parallel execution. Without
44 /// it, all `par_*` functions fall back to equivalent sequential operations.**
45 #[document_examples]
46 ///
47 /// ParFunctor laws for [`Vec`]:
48 ///
49 /// ```
50 /// use fp_library::{
51 /// brands::VecBrand,
52 /// functions::*,
53 /// };
54 ///
55 /// let xs = vec![1, 2, 3];
56 ///
57 /// // Identity: par_map(identity, fa) = fa
58 /// assert_eq!(par_map::<VecBrand, _, _>(identity, xs.clone()), xs);
59 ///
60 /// // Composition: par_map(|a| f(g(a)), fa) = par_map(f, par_map(g, fa))
61 /// let f = |a: i32| a + 1;
62 /// let g = |a: i32| a * 2;
63 /// assert_eq!(
64 /// par_map::<VecBrand, _, _>(|a| f(g(a)), xs.clone()),
65 /// par_map::<VecBrand, _, _>(f, par_map::<VecBrand, _, _>(g, xs)),
66 /// );
67 /// ```
68 #[kind(type Of<'a, A: 'a>: 'a;)]
69 pub trait ParFunctor {
70 /// Maps a function over a data structure in parallel.
71 ///
72 /// When the `rayon` feature is enabled, elements are processed across multiple threads.
73 /// Otherwise falls back to sequential mapping.
74 #[document_signature]
75 ///
76 #[document_type_parameters(
77 "The lifetime of the elements.",
78 "The input element type.",
79 "The output element type."
80 )]
81 ///
82 #[document_parameters(
83 "The function to apply to each element. Must be `Send + Sync`.",
84 "The data structure to map over."
85 )]
86 ///
87 #[document_returns("A new data structure containing the mapped elements.")]
88 #[document_examples]
89 ///
90 /// ```
91 /// use fp_library::{
92 /// brands::VecBrand,
93 /// classes::par_functor::ParFunctor,
94 /// };
95 ///
96 /// let result = VecBrand::par_map(|x: i32| x * 2, vec![1, 2, 3]);
97 /// assert_eq!(result, vec![2, 4, 6]);
98 /// ```
99 fn par_map<'a, A: 'a + Send, B: 'a + Send>(
100 f: impl Fn(A) -> B + Send + Sync + 'a,
101 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
102 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>);
103 }
104
105 /// Maps a function over a data structure in parallel.
106 ///
107 /// Applies `f` to each element independently. When the `rayon` feature is enabled,
108 /// elements are processed across multiple threads. Otherwise falls back to sequential mapping.
109 ///
110 /// Free function version that dispatches to [`ParFunctor::par_map`].
111 #[document_signature]
112 ///
113 #[document_type_parameters(
114 "The lifetime of the elements.",
115 "The brand of the collection.",
116 "The input element type.",
117 "The output element type."
118 )]
119 ///
120 #[document_parameters(
121 "The function to apply to each element. Must be `Send + Sync`.",
122 "The collection to map over."
123 )]
124 ///
125 #[document_returns("A new collection containing the mapped elements.")]
126 #[document_examples]
127 ///
128 /// ```
129 /// use fp_library::{
130 /// brands::*,
131 /// functions::*,
132 /// };
133 ///
134 /// let v = vec![1, 2, 3];
135 /// let result: Vec<i32> = par_map::<VecBrand, _, _>(|x| x * 2, v);
136 /// assert_eq!(result, vec![2, 4, 6]);
137 /// ```
138 pub fn par_map<'a, Brand: ParFunctor, A: 'a + Send, B: 'a + Send>(
139 f: impl Fn(A) -> B + Send + Sync + 'a,
140 fa: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
141 ) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
142 Brand::par_map(f, fa)
143 }
144}
145
146pub use inner::*;