Skip to main content

zinc_utils/
parallel.rs

1//! Parallel iteration macros that conditionally use rayon when the "parallel"
2//! feature is enabled.
3//!
4//! These macros provide a convenient way to switch between parallel and
5//! sequential iteration without changing the calling code - just enable/disable
6//! the "parallel" cargo feature.
7
8/// Conditionally iterate over a slice in parallel.
9///
10/// When the "parallel" feature is enabled, uses `par_iter()` from rayon.
11/// Otherwise, uses standard `iter()`.
12#[macro_export]
13macro_rules! cfg_iter {
14    ($e:expr, $min_len:expr) => {{
15        #[cfg(feature = "parallel")]
16        let result = $e.par_iter().with_min_len($min_len);
17
18        #[cfg(not(feature = "parallel"))]
19        let result = $e.iter();
20
21        result
22    }};
23    ($e:expr) => {{
24        #[cfg(feature = "parallel")]
25        let result = $e.par_iter();
26
27        #[cfg(not(feature = "parallel"))]
28        let result = $e.iter();
29
30        result
31    }};
32}
33
34/// Conditionally iterate mutably over a slice in parallel.
35///
36/// When the "parallel" feature is enabled, uses `par_iter_mut()` from rayon.
37/// Otherwise, uses standard `iter_mut()`.
38#[macro_export]
39macro_rules! cfg_iter_mut {
40    ($e:expr, $min_len:expr) => {{
41        #[cfg(feature = "parallel")]
42        let result = $e.par_iter_mut().with_min_len($min_len);
43
44        #[cfg(not(feature = "parallel"))]
45        let result = $e.iter_mut();
46
47        result
48    }};
49    ($e:expr) => {{
50        #[cfg(feature = "parallel")]
51        let result = $e.par_iter_mut();
52
53        #[cfg(not(feature = "parallel"))]
54        let result = $e.iter_mut();
55
56        result
57    }};
58}
59
60/// Conditionally consume and iterate over a collection in parallel.
61///
62/// When the "parallel" feature is enabled, uses `into_par_iter()` from rayon.
63/// Otherwise, uses standard `into_iter()`.
64#[macro_export]
65macro_rules! cfg_into_iter {
66    ($e:expr, $min_len:expr) => {{
67        #[cfg(feature = "parallel")]
68        let result = $e.into_par_iter().with_min_len($min_len);
69
70        #[cfg(not(feature = "parallel"))]
71        let result = $e.into_iter();
72
73        result
74    }};
75    ($e:expr) => {{
76        #[cfg(feature = "parallel")]
77        let result = $e.into_par_iter();
78
79        #[cfg(not(feature = "parallel"))]
80        let result = $e.into_iter();
81
82        result
83    }};
84}
85
86/// Conditionally iterate over chunks of a slice in parallel.
87///
88/// When the "parallel" feature is enabled, uses `par_chunks()` from rayon.
89/// Otherwise, uses standard `chunks()`.
90#[macro_export]
91macro_rules! cfg_chunks {
92    ($e:expr, $size:expr) => {{
93        #[cfg(feature = "parallel")]
94        let result = $e.par_chunks($size);
95
96        #[cfg(not(feature = "parallel"))]
97        let result = $e.chunks($size);
98
99        result
100    }};
101}
102
103/// Conditionally iterate mutably over chunks of a slice in parallel.
104///
105/// When the "parallel" feature is enabled, uses `par_chunks_mut()` from rayon.
106/// Otherwise, uses standard `chunks_mut()`.
107#[macro_export]
108macro_rules! cfg_chunks_mut {
109    ($e:expr, $size:expr) => {{
110        #[cfg(feature = "parallel")]
111        let result = $e.par_chunks_mut($size);
112
113        #[cfg(not(feature = "parallel"))]
114        let result = $e.chunks_mut($size);
115
116        result
117    }};
118}
119
120/// Conditionally extend a collection from an iterator.
121///
122/// When the "parallel" feature is enabled, uses `par_extend()` from rayon.
123/// Otherwise, uses standard `extend()`.
124#[macro_export]
125macro_rules! cfg_extend {
126    ($e:expr, $i:expr) => {{
127        #[cfg(feature = "parallel")]
128        let result = $e.par_extend($i);
129
130        #[cfg(not(feature = "parallel"))]
131        let result = $e.extend($i);
132
133        result
134    }};
135}
136
137/// Conditionally fork expressions into parallel tasks using `rayon::join`.
138///
139/// When the "parallel" feature is enabled, uses right-leaning nested
140/// `rayon::join` calls to execute all expressions concurrently. Otherwise,
141/// evaluates them sequentially.
142///
143/// Returns a right-nested pair tree: 2 items → `(A, B)`,
144/// 3 items → `(A, (B, C))`, 4 items → `(A, (B, (C, D)))`, etc.
145/// The shape is identical in both parallel and sequential mode.
146///
147/// (Unfortunately, we can't flatten the result into a tuple of all items using
148/// just `macro_rules`)
149#[macro_export]
150macro_rules! cfg_join {
151    ($a:expr, $b:expr $(,)?) => {{
152        #[cfg(feature = "parallel")]
153        let result = rayon::join(|| $a, || $b);
154
155        #[cfg(not(feature = "parallel"))]
156        let result = ($a, $b);
157
158        result
159    }};
160    ($first:expr, $($rest:expr),+ $(,)?) => {{
161        #[cfg(feature = "parallel")]
162        let result = rayon::join(
163            || $first,
164            || cfg_join!($($rest),+),
165        );
166
167        #[cfg(not(feature = "parallel"))]
168        let result = ($first, cfg_join!($($rest),+));
169
170        result
171    }};
172}