Skip to main content

fp_library/classes/
par_ref_functor.rs

1//! Parallel by-reference functor mapping.
2//!
3//! **User story:** "I want to map over a collection by reference in parallel."
4//!
5//! This trait combines the by-reference access of [`RefFunctor`](crate::classes::RefFunctor) with
6//! the parallelism of [`ParFunctor`](crate::classes::ParFunctor). The closure receives `&A`
7//! (no consumption of elements) and must be `Send + Sync`. Elements must be `Send + Sync`
8//! for rayon's `par_iter()`.
9//!
10//! ### Examples
11//!
12//! ```
13//! use fp_library::{
14//! 	brands::VecBrand,
15//! 	classes::par_ref_functor::ParRefFunctor,
16//! };
17//!
18//! let v = vec![1, 2, 3];
19//! let result = VecBrand::par_ref_map(|x: &i32| x.to_string(), &v);
20//! assert_eq!(result, vec!["1", "2", "3"]);
21//! ```
22
23#[fp_macros::document_module]
24mod inner {
25	use {
26		crate::kinds::*,
27		fp_macros::*,
28	};
29
30	/// Parallel by-reference functor mapping.
31	///
32	/// Maps a `Send + Sync` function over a structure by reference, potentially
33	/// using rayon for parallel execution. The closure receives `&A` instead
34	/// of consuming `A`.
35	///
36	/// Elements must be `Send + Sync` because rayon's `par_iter()` requires
37	/// `&A: Send`, which is equivalent to `A: Sync`.
38	#[kind(type Of<'a, A: 'a>: 'a;)]
39	pub trait ParRefFunctor: crate::classes::RefFunctor {
40		/// Maps a function over the structure by reference in parallel.
41		#[document_signature]
42		#[document_type_parameters(
43			"The lifetime of the elements.",
44			"The input element type.",
45			"The output element type."
46		)]
47		#[document_parameters(
48			"The function to apply to each element reference. Must be `Send + Sync`.",
49			"The structure to map over."
50		)]
51		#[document_returns("A new structure containing the mapped elements.")]
52		#[document_examples]
53		///
54		/// ```
55		/// use fp_library::{
56		/// 	brands::VecBrand,
57		/// 	classes::par_ref_functor::ParRefFunctor,
58		/// };
59		///
60		/// let v = vec![1, 2, 3];
61		/// let result = VecBrand::par_ref_map(|x: &i32| x * 2, &v);
62		/// assert_eq!(result, vec![2, 4, 6]);
63		/// ```
64		fn par_ref_map<'a, A: Send + Sync + 'a, B: Send + 'a>(
65			f: impl Fn(&A) -> B + Send + Sync + 'a,
66			fa: &Self::Of<'a, A>,
67		) -> Self::Of<'a, B>;
68	}
69
70	/// Maps a function over a structure by reference in parallel.
71	///
72	/// Free function version that dispatches to [the type class' associated function][`ParRefFunctor::par_ref_map`].
73	#[document_signature]
74	#[document_type_parameters(
75		"The lifetime of the elements.",
76		"The brand of the structure.",
77		"The input element type.",
78		"The output element type."
79	)]
80	#[document_parameters(
81		"The function to apply to each element reference. Must be `Send + Sync`.",
82		"The structure to map over."
83	)]
84	#[document_returns("A new structure containing the mapped elements.")]
85	#[document_examples]
86	///
87	/// ```
88	/// use fp_library::{
89	/// 	brands::VecBrand,
90	/// 	functions::*,
91	/// };
92	///
93	/// let v = vec![1, 2, 3];
94	/// let result = par_ref_map::<VecBrand, _, _>(|x: &i32| x * 2, &v);
95	/// assert_eq!(result, vec![2, 4, 6]);
96	/// ```
97	pub fn par_ref_map<'a, Brand: ParRefFunctor, A: Send + Sync + 'a, B: Send + 'a>(
98		f: impl Fn(&A) -> B + Send + Sync + 'a,
99		fa: &Brand::Of<'a, A>,
100	) -> Brand::Of<'a, B> {
101		Brand::par_ref_map(f, fa)
102	}
103}
104
105pub use inner::*;