Skip to main content

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::*;