@@ -44,3 +44,150 @@ pub use rayon_core::ThreadPool;
4444pub use rayon_core:: join;
4545pub use rayon_core:: { scope, Scope } ;
4646pub 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