1818//! depending on the value of cfg!(parallel_compiler).
1919
2020use crate :: owning_ref:: { Erased , OwningRef } ;
21+ use std:: any:: Any ;
2122use std:: collections:: HashMap ;
2223use std:: hash:: { BuildHasher , Hash } ;
2324use std:: marker:: PhantomData ;
2425use std:: ops:: { Deref , DerefMut } ;
26+ use std:: panic:: { catch_unwind, resume_unwind, AssertUnwindSafe } ;
2527
2628pub use std:: sync:: atomic:: Ordering ;
2729pub use std:: sync:: atomic:: Ordering :: SeqCst ;
2830
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+
2948cfg_if ! {
3049 if #[ cfg( not( parallel_compiler) ) ] {
3150 pub auto trait Send { }
@@ -42,7 +61,6 @@ cfg_if! {
4261 }
4362
4463 use std:: ops:: Add ;
45- use std:: panic:: { resume_unwind, catch_unwind, AssertUnwindSafe } ;
4664
4765 /// This is a single threaded variant of AtomicCell provided by crossbeam.
4866 /// Unlike `Atomic` this is intended for all `Copy` types,
@@ -181,46 +199,40 @@ cfg_if! {
181199 ( $( $blocks: tt) , * ) => {
182200 // We catch panics here ensuring that all the blocks execute.
183201 // This makes behavior consistent with the parallel compiler.
184- let mut panic = None ;
202+ let panic = :: rustc_data_structures :: sync :: Lock :: new ( None ) ;
185203 $(
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) ;
193205 ) *
194- if let Some ( panic) = panic {
195- :: std:: panic:: resume_unwind( panic) ;
196- }
206+ :: rustc_data_structures:: sync:: resume( panic) ;
197207 }
198208 }
199209
200- pub use std:: iter:: Iterator as ParallelIterator ;
210+ use std:: iter:: { Iterator , IntoIterator , FromIterator } ;
201211
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 >(
207213 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 ) ,
210215 ) {
211216 // We catch panics here ensuring that all the loop iterations execute.
212217 // This makes behavior consistent with the parallel compiler.
213- let mut panic = None ;
218+ let panic = Lock :: new ( None ) ;
214219 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) ) ;
220221 } ) ;
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
224236 }
225237
226238 pub type MetadataRef = OwningRef <Box <dyn Erased >, [ u8 ] >;
@@ -388,20 +400,39 @@ cfg_if! {
388400
389401 pub use rayon_core:: WorkerLocal ;
390402
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 } ;
397404
398- pub fn par_for_each_in <T : IntoParallelIterator >(
405+ pub fn par_for_each <T : IntoParallelIterator >(
399406 t: T ,
400407 for_each: impl Fn (
401408 <<T as IntoParallelIterator >:: Iter as ParallelIterator >:: Item
402409 ) + Sync + Send
403410 ) {
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
405436 }
406437
407438 pub type MetadataRef = OwningRef <Box <dyn Erased + Send + Sync >, [ u8 ] >;
0 commit comments