fp_library/classes/par_compactable.rs
1//! Data structures that can be compacted and separated in parallel.
2//!
3//! ### Examples
4//!
5//! ```
6//! use fp_library::{
7//! brands::*,
8//! functions::*,
9//! };
10//!
11//! let v = vec![Some(1), None, Some(3)];
12//! let result: Vec<i32> = par_compact::<VecBrand, _>(v);
13//! assert_eq!(result, vec![1, 3]);
14//! ```
15
16#[fp_macros::document_module]
17mod inner {
18 use {
19 crate::{
20 brands::*,
21 kinds::*,
22 },
23 fp_macros::*,
24 };
25
26 /// A type class for data structures that can be compacted and separated in parallel.
27 ///
28 /// `ParCompactable` is the parallel counterpart to [`Compactable`](crate::classes::Compactable).
29 /// Implementors define [`par_compact`][ParCompactable::par_compact] and
30 /// [`par_separate`][ParCompactable::par_separate] directly: there is no intermediate `Vec`
31 /// conversion imposed by the interface.
32 ///
33 /// ### Thread Safety
34 ///
35 /// All `par_*` functions require `Send` bounds on element types.
36 /// These bounds apply even when the `rayon` feature is disabled, so that code compiles
37 /// identically in both configurations.
38 ///
39 /// **Note: The `rayon` feature must be enabled to use actual parallel execution. Without
40 /// it, all `par_*` functions fall back to equivalent sequential operations.**
41 #[document_examples]
42 ///
43 /// ```
44 /// use fp_library::{
45 /// brands::VecBrand,
46 /// functions::*,
47 /// };
48 ///
49 /// let v = vec![Some(1), None, Some(3)];
50 /// let result: Vec<i32> = par_compact::<VecBrand, _>(v);
51 /// assert_eq!(result, vec![1, 3]);
52 ///
53 /// let v2: Vec<Result<i32, &str>> = vec![Ok(1), Err("e"), Ok(3)];
54 /// let (errs, oks): (Vec<&str>, Vec<i32>) = par_separate::<VecBrand, _, _>(v2);
55 /// assert_eq!(errs, vec!["e"]);
56 /// assert_eq!(oks, vec![1, 3]);
57 /// ```
58 #[kind(type Of<'a, A: 'a>: 'a;)]
59 pub trait ParCompactable {
60 /// Compacts a data structure of [`Option`]s in parallel, discarding [`None`] values and
61 /// keeping [`Some`] values.
62 ///
63 /// When the `rayon` feature is enabled, elements are processed across multiple threads.
64 /// Otherwise falls back to sequential compaction.
65 #[document_signature]
66 ///
67 #[document_type_parameters(
68 "The lifetime of the elements.",
69 "The type of the elements in the [`Option`]."
70 )]
71 ///
72 #[document_parameters("The data structure containing [`Option`] values.")]
73 ///
74 #[document_returns(
75 "A new data structure containing only the values from the [`Some`] variants."
76 )]
77 #[document_examples]
78 ///
79 /// ```
80 /// use fp_library::{
81 /// brands::VecBrand,
82 /// classes::par_compactable::ParCompactable,
83 /// };
84 ///
85 /// let v = vec![Some(1), None, Some(3)];
86 /// let result: Vec<i32> = VecBrand::par_compact(v);
87 /// assert_eq!(result, vec![1, 3]);
88 /// ```
89 fn par_compact<'a, A: 'a + Send>(
90 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<
91 'a,
92 Apply!(<OptionBrand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
93 >)
94 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>);
95
96 /// Separates a data structure of [`Result`]s into two data structures in parallel.
97 ///
98 /// When the `rayon` feature is enabled, elements are processed across multiple threads.
99 /// Otherwise falls back to sequential separation.
100 #[document_signature]
101 ///
102 #[document_type_parameters(
103 "The lifetime of the elements.",
104 "The type of the error values.",
105 "The type of the success values."
106 )]
107 ///
108 #[document_parameters("The data structure containing [`Result`] values.")]
109 ///
110 #[document_returns(
111 "A pair of data structures: the first containing the [`Err`] values, and the second containing the [`Ok`] values."
112 )]
113 #[document_examples]
114 ///
115 /// ```
116 /// use fp_library::{
117 /// brands::VecBrand,
118 /// classes::par_compactable::ParCompactable,
119 /// };
120 ///
121 /// let v: Vec<Result<i32, &str>> = vec![Ok(1), Err("e"), Ok(3)];
122 /// let (errs, oks): (Vec<&str>, Vec<i32>) = VecBrand::par_separate(v);
123 /// assert_eq!(errs, vec!["e"]);
124 /// assert_eq!(oks, vec![1, 3]);
125 /// ```
126 fn par_separate<'a, E: 'a + Send, O: 'a + Send>(
127 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>)
128 ) -> (
129 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
130 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
131 );
132 }
133
134 /// Compacts a data structure of [`Option`]s in parallel, discarding [`None`] values and
135 /// keeping [`Some`] values.
136 ///
137 /// Free function version that dispatches to [`ParCompactable::par_compact`].
138 #[document_signature]
139 ///
140 #[document_type_parameters(
141 "The lifetime of the elements.",
142 "The brand of the compactable structure.",
143 "The type of the elements in the [`Option`]."
144 )]
145 ///
146 #[document_parameters("The data structure containing [`Option`] values.")]
147 ///
148 #[document_returns(
149 "A new data structure containing only the values from the [`Some`] variants."
150 )]
151 #[document_examples]
152 ///
153 /// ```
154 /// use fp_library::{
155 /// brands::*,
156 /// functions::*,
157 /// };
158 ///
159 /// let v = vec![Some(1), None, Some(3)];
160 /// let result: Vec<i32> = par_compact::<VecBrand, _>(v);
161 /// assert_eq!(result, vec![1, 3]);
162 /// ```
163 pub fn par_compact<'a, Brand: ParCompactable, A: 'a + Send>(
164 fa: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<
165 'a,
166 Apply!(<OptionBrand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
167 >)
168 ) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
169 Brand::par_compact(fa)
170 }
171
172 /// Separates a data structure of [`Result`]s into two data structures in parallel.
173 ///
174 /// Free function version that dispatches to [`ParCompactable::par_separate`].
175 #[document_signature]
176 ///
177 #[document_type_parameters(
178 "The lifetime of the elements.",
179 "The brand of the compactable structure.",
180 "The type of the error values.",
181 "The type of the success values."
182 )]
183 ///
184 #[document_parameters("The data structure containing [`Result`] values.")]
185 ///
186 #[document_returns(
187 "A pair of data structures: the first containing the [`Err`] values, and the second containing the [`Ok`] values."
188 )]
189 #[document_examples]
190 ///
191 /// ```
192 /// use fp_library::{
193 /// brands::*,
194 /// functions::*,
195 /// };
196 ///
197 /// let v: Vec<Result<i32, &str>> = vec![Ok(1), Err("e"), Ok(3)];
198 /// let (errs, oks): (Vec<&str>, Vec<i32>) = par_separate::<VecBrand, _, _>(v);
199 /// assert_eq!(errs, vec!["e"]);
200 /// assert_eq!(oks, vec![1, 3]);
201 /// ```
202 pub fn par_separate<'a, Brand: ParCompactable, E: 'a + Send, O: 'a + Send>(
203 fa: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>)
204 ) -> (
205 Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
206 Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
207 ) {
208 Brand::par_separate::<E, O>(fa)
209 }
210}
211
212pub use inner::*;