Skip to content

Commit 0061b16

Browse files
committed
Add the join! macro
The `join!` macro forks and joins many expressions at once. This is easier to use than deeply nesting calls to `rayon::join`.
1 parent 4d8c9bd commit 0061b16

File tree

1 file changed

+147
-0
lines changed

1 file changed

+147
-0
lines changed

src/lib.rs

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,150 @@ pub use rayon_core::ThreadPool;
4444
pub use rayon_core::join;
4545
pub use rayon_core::{scope, Scope};
4646
pub use rayon_core::spawn;
47+
48+
/// Fork and join many expressions at once.
49+
///
50+
/// The syntax is one or more occurrences of
51+
///
52+
/// ```ignore
53+
/// let <irrefutable pattern> = fork <closure expresssion>;`.
54+
/// ```
55+
///
56+
/// For example,
57+
///
58+
/// ```
59+
/// #[macro_use]
60+
/// extern crate rayon;
61+
///
62+
/// # fn main() {
63+
/// join! {
64+
/// let w = fork || 0;
65+
/// let x = fork || 1;
66+
/// let y = fork || 2;
67+
/// let z = fork || 3;
68+
/// }
69+
///
70+
/// assert_eq!(w, 0);
71+
/// assert_eq!(x, 1);
72+
/// assert_eq!(y, 2);
73+
/// assert_eq!(z, 3);
74+
/// # }
75+
/// ```
76+
///
77+
/// This is equivalent to nesting calls to `rayon::join` like this:
78+
///
79+
/// ```
80+
/// # extern crate rayon;
81+
/// let (w, (x, (y, z))) = rayon::join(
82+
/// || 0,
83+
/// || rayon::join(
84+
/// || 1,
85+
/// || rayon::join(
86+
/// || 2,
87+
/// || 3,
88+
/// )
89+
/// )
90+
/// );
91+
/// ```
92+
///
93+
/// Alternatively, you can just get a flattened tuple of results, without
94+
/// binding the results to any variable inside the macro.
95+
///
96+
/// The syntax is one or more occurrences of `<closure expression> ,` where the
97+
/// last `,` is optional.
98+
///
99+
/// ```rust
100+
/// #[macro_use]
101+
/// extern crate rayon;
102+
///
103+
/// # fn main() {
104+
/// let (w, x, y, z) = join!(|| 0, || 1, || 2, || 3);
105+
///
106+
/// assert_eq!(w, 0);
107+
/// assert_eq!(x, 1);
108+
/// assert_eq!(y, 2);
109+
/// assert_eq!(z, 3);
110+
/// # }
111+
/// ```
112+
#[macro_export]
113+
macro_rules! join {
114+
// Entry point for `let <pat> = fork <closure>;` usage.
115+
( $( let $lhs:pat = fork $rhs:expr ; )+ ) => {
116+
let join!( @left $( $lhs , )+ ) = join!( @right $( $rhs , )+ );
117+
};
118+
119+
// Entry point for `<closure>,` usage.
120+
( $x:expr $( , $xs:expr )* ) => {
121+
join! { @flat $x $( , $xs )* }
122+
};
123+
124+
// Flattening tuples with temporary variables.
125+
( @flat $( let $lhs:ident = $rhs:expr ; )+ ) => {
126+
{
127+
let join!( @left $( $lhs , )+ ) = join!( @right $( $rhs , )+ );
128+
($( $lhs ),+)
129+
}
130+
};
131+
( @flat $( let $lhs:ident = $rhs:expr ; )* $x:expr $( , $xs:expr )*) => {
132+
join! { @flat
133+
$( let $lhs = $rhs ; )*
134+
let lhs = $x;
135+
$($xs),*
136+
}
137+
};
138+
139+
// Left hand side recursion to nest individual patterns into tuple patterns
140+
// like `(x, (y, (z, ...)))`.
141+
( @left $x:pat , ) => {
142+
$x
143+
};
144+
( @left $x:pat , $( $xs:pat , )+ ) => {
145+
( $x , join!( @left $( $xs , )+ ) )
146+
};
147+
148+
// Right hand side recursion to nest exprs into rayon fork-joins
149+
// like:
150+
//
151+
// rayon::join(
152+
// x,
153+
// || rayon::join(
154+
// y,
155+
// || rayon::join(
156+
// z,
157+
// || ...)))
158+
( @right $x:expr , ) => {
159+
($x)()
160+
};
161+
( @right $x:expr , $( $xs:expr , )+ ) => {
162+
::rayon::join( $x , || join!( @right $( $xs , )+ ) )
163+
}
164+
}
165+
166+
// Necessary for the tests using macros that expand to `::rayon::whatever`.
167+
#[cfg(test)]
168+
mod rayon {
169+
pub use super::*;
170+
}
171+
172+
#[cfg(test)]
173+
mod tests {
174+
#[macro_use]
175+
use super::*;
176+
177+
#[test]
178+
fn join_macro_with_more_complex_patterns() {
179+
struct Point(usize, usize);
180+
181+
join! {
182+
let Point(w, x) = fork || Point(1, 2);
183+
let Point(y, z) = fork || Point(3, 4);
184+
let (((((a, _), _), _), _), _) = fork || (((((5, 4), 3), 2), 1), 0);
185+
};
186+
187+
assert_eq!(w, 1);
188+
assert_eq!(x, 2);
189+
assert_eq!(y, 3);
190+
assert_eq!(z, 4);
191+
assert_eq!(a, 5);
192+
}
193+
}

0 commit comments

Comments
 (0)