18
18
//! depending on the value of cfg!(parallel_compiler).
19
19
20
20
use crate :: owning_ref:: { Erased , OwningRef } ;
21
+ use std:: any:: Any ;
21
22
use std:: collections:: HashMap ;
22
23
use std:: hash:: { BuildHasher , Hash } ;
23
24
use std:: marker:: PhantomData ;
24
25
use std:: ops:: { Deref , DerefMut } ;
26
+ use std:: panic:: { catch_unwind, resume_unwind, AssertUnwindSafe } ;
25
27
26
28
pub use std:: sync:: atomic:: Ordering ;
27
29
pub use std:: sync:: atomic:: Ordering :: SeqCst ;
28
30
31
+ pub fn catch < R > (
32
+ store : & Lock < Option < Box < dyn Any + std:: marker:: Send + ' static > > > ,
33
+ f : impl FnOnce ( ) -> R ,
34
+ ) -> Option < R > {
35
+ catch_unwind ( AssertUnwindSafe ( f) )
36
+ . map_err ( |err| {
37
+ * store. lock ( ) = Some ( err) ;
38
+ } )
39
+ . ok ( )
40
+ }
41
+
42
+ pub fn resume ( store : Lock < Option < Box < dyn Any + std:: marker:: Send + ' static > > > ) {
43
+ if let Some ( panic) = store. into_inner ( ) {
44
+ resume_unwind ( panic) ;
45
+ }
46
+ }
47
+
29
48
cfg_if ! {
30
49
if #[ cfg( not( parallel_compiler) ) ] {
31
50
pub auto trait Send { }
@@ -42,7 +61,6 @@ cfg_if! {
42
61
}
43
62
44
63
use std:: ops:: Add ;
45
- use std:: panic:: { resume_unwind, catch_unwind, AssertUnwindSafe } ;
46
64
47
65
/// This is a single threaded variant of AtomicCell provided by crossbeam.
48
66
/// Unlike `Atomic` this is intended for all `Copy` types,
@@ -181,46 +199,40 @@ cfg_if! {
181
199
( $( $blocks: tt) , * ) => {
182
200
// We catch panics here ensuring that all the blocks execute.
183
201
// This makes behavior consistent with the parallel compiler.
184
- let mut panic = None ;
202
+ let panic = :: rustc_data_structures :: sync :: Lock :: new ( None ) ;
185
203
$(
186
- if let Err ( p) = :: std:: panic:: catch_unwind(
187
- :: std:: panic:: AssertUnwindSafe ( || $blocks)
188
- ) {
189
- if panic. is_none( ) {
190
- panic = Some ( p) ;
191
- }
192
- }
204
+ :: rustc_data_structures:: sync:: catch( & panic, || $blocks) ;
193
205
) *
194
- if let Some ( panic) = panic {
195
- :: std:: panic:: resume_unwind( panic) ;
196
- }
206
+ :: rustc_data_structures:: sync:: resume( panic) ;
197
207
}
198
208
}
199
209
200
- pub use std:: iter:: Iterator as ParallelIterator ;
210
+ use std:: iter:: { Iterator , IntoIterator , FromIterator } ;
201
211
202
- pub fn par_iter<T : IntoIterator >( t: T ) -> T :: IntoIter {
203
- t. into_iter( )
204
- }
205
-
206
- pub fn par_for_each_in<T : IntoIterator >(
212
+ pub fn par_for_each<T : IntoIterator >(
207
213
t: T ,
208
- for_each:
209
- impl Fn ( <<T as IntoIterator >:: IntoIter as Iterator >:: Item ) + Sync + Send
214
+ mut for_each: impl FnMut ( <<T as IntoIterator >:: IntoIter as Iterator >:: Item ) ,
210
215
) {
211
216
// We catch panics here ensuring that all the loop iterations execute.
212
217
// This makes behavior consistent with the parallel compiler.
213
- let mut panic = None ;
218
+ let panic = Lock :: new ( None ) ;
214
219
t. into_iter( ) . for_each( |i| {
215
- if let Err ( p) = catch_unwind( AssertUnwindSafe ( || for_each( i) ) ) {
216
- if panic. is_none( ) {
217
- panic = Some ( p) ;
218
- }
219
- }
220
+ catch( & panic, || for_each( i) ) ;
220
221
} ) ;
221
- if let Some ( panic) = panic {
222
- resume_unwind( panic) ;
223
- }
222
+ resume( panic) ;
223
+ }
224
+
225
+ pub fn par_map<T : IntoIterator , R , C : FromIterator <R >>(
226
+ t: T ,
227
+ mut map: impl FnMut ( <<T as IntoIterator >:: IntoIter as Iterator >:: Item ) -> R ,
228
+ ) -> C {
229
+ // We catch panics here ensuring that all the loop iterations execute.
230
+ let panic = Lock :: new( None ) ;
231
+ let r = t. into_iter( ) . filter_map( |i| {
232
+ catch( & panic, || map( i) )
233
+ } ) . collect( ) ;
234
+ resume( panic) ;
235
+ r
224
236
}
225
237
226
238
pub type MetadataRef = OwningRef <Box <dyn Erased >, [ u8 ] >;
@@ -388,20 +400,39 @@ cfg_if! {
388
400
389
401
pub use rayon_core:: WorkerLocal ;
390
402
391
- pub use rayon:: iter:: ParallelIterator ;
392
- use rayon:: iter:: IntoParallelIterator ;
393
-
394
- pub fn par_iter<T : IntoParallelIterator >( t: T ) -> T :: Iter {
395
- t. into_par_iter( )
396
- }
403
+ use rayon:: iter:: { ParallelIterator , FromParallelIterator , IntoParallelIterator } ;
397
404
398
- pub fn par_for_each_in <T : IntoParallelIterator >(
405
+ pub fn par_for_each <T : IntoParallelIterator >(
399
406
t: T ,
400
407
for_each: impl Fn (
401
408
<<T as IntoParallelIterator >:: Iter as ParallelIterator >:: Item
402
409
) + Sync + Send
403
410
) {
404
- t. into_par_iter( ) . for_each( for_each)
411
+ // We catch panics here ensuring that all the loop iterations execute.
412
+ let panic = Lock :: new( None ) ;
413
+ t. into_par_iter( ) . for_each( |i| {
414
+ catch( & panic, || for_each( i) ) ;
415
+ } ) ;
416
+ resume( panic) ;
417
+ }
418
+
419
+ pub fn par_map<
420
+ T : IntoParallelIterator ,
421
+ R : Send ,
422
+ C : FromParallelIterator <R >
423
+ >(
424
+ t: T ,
425
+ map: impl Fn (
426
+ <<T as IntoParallelIterator >:: Iter as ParallelIterator >:: Item
427
+ ) -> R + Sync + Send
428
+ ) -> C {
429
+ // We catch panics here ensuring that all the loop iterations execute.
430
+ let panic = Lock :: new( None ) ;
431
+ let r = t. into_par_iter( ) . filter_map( |i| {
432
+ catch( & panic, || map( i) )
433
+ } ) . collect( ) ;
434
+ resume( panic) ;
435
+ r
405
436
}
406
437
407
438
pub type MetadataRef = OwningRef <Box <dyn Erased + Send + Sync >, [ u8 ] >;
0 commit comments