@@ -430,6 +430,93 @@ mod from_liballoc {
430
430
d
431
431
}
432
432
}
433
+
434
+ // old binaryheap failed this test
435
+ //
436
+ // Integrity means that all elements are present after a comparison panics,
437
+ // even if the order might not be correct.
438
+ //
439
+ // Destructors must be called exactly once per element.
440
+ // FIXME: re-enable emscripten once it can unwind again
441
+ #[ test]
442
+ #[ cfg( not( target_os = "emscripten" ) ) ]
443
+ fn panic_safe ( ) {
444
+ use std:: cmp;
445
+ use std:: panic:: { self , AssertUnwindSafe } ;
446
+ use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
447
+
448
+ use rand:: { seq:: SliceRandom , thread_rng} ;
449
+
450
+ static DROP_COUNTER : AtomicUsize = AtomicUsize :: new ( 0 ) ;
451
+
452
+ #[ derive( Eq , PartialEq , PartialOrd , Clone , Debug ) ]
453
+ struct PanicOrd < T > ( T , bool ) ;
454
+
455
+ impl < T > Drop for PanicOrd < T > {
456
+ fn drop ( & mut self ) {
457
+ // update global drop count
458
+ DROP_COUNTER . fetch_add ( 1 , Ordering :: SeqCst ) ;
459
+ }
460
+ }
461
+
462
+ impl < T : Ord > Ord for PanicOrd < T > {
463
+ fn cmp ( & self , other : & Self ) -> cmp:: Ordering {
464
+ if self . 1 || other. 1 {
465
+ panic ! ( "Panicking comparison" ) ;
466
+ }
467
+ self . 0 . cmp ( & other. 0 )
468
+ }
469
+ }
470
+ let mut rng = thread_rng ( ) ;
471
+ const DATASZ : usize = 32 ;
472
+ // Miri is too slow
473
+ let ntest = if cfg ! ( miri) { 1 } else { 10 } ;
474
+
475
+ // don't use 0 in the data -- we want to catch the zeroed-out case.
476
+ let data = ( 1 ..=DATASZ ) . collect :: < Vec < _ > > ( ) ;
477
+
478
+ // since it's a fuzzy test, run several tries.
479
+ for _ in 0 ..ntest {
480
+ for i in 1 ..=DATASZ {
481
+ DROP_COUNTER . store ( 0 , Ordering :: SeqCst ) ;
482
+
483
+ let mut panic_ords: Vec < _ > = data
484
+ . iter ( )
485
+ . filter ( |& & x| x != i)
486
+ . map ( |& x| PanicOrd ( x, false ) )
487
+ . collect ( ) ;
488
+ let panic_item = PanicOrd ( i, true ) ;
489
+
490
+ // heapify the sane items
491
+ panic_ords. shuffle ( & mut rng) ;
492
+ let mut heap = BinaryHeap :: from ( panic_ords) ;
493
+ let inner_data;
494
+
495
+ {
496
+ // push the panicking item to the heap and catch the panic
497
+ let thread_result = {
498
+ let mut heap_ref = AssertUnwindSafe ( & mut heap) ;
499
+ panic:: catch_unwind ( move || {
500
+ heap_ref. push ( panic_item) ;
501
+ } )
502
+ } ;
503
+ assert ! ( thread_result. is_err( ) ) ;
504
+
505
+ // Assert no elements were dropped
506
+ let drops = DROP_COUNTER . load ( Ordering :: SeqCst ) ;
507
+ assert ! ( drops == 0 , "Must not drop items. drops={}" , drops) ;
508
+ inner_data = heap. clone ( ) . into_vec ( ) ;
509
+ drop ( heap) ;
510
+ }
511
+ let drops = DROP_COUNTER . load ( Ordering :: SeqCst ) ;
512
+ assert_eq ! ( drops, DATASZ ) ;
513
+
514
+ let mut data_sorted = inner_data. into_iter ( ) . map ( |p| p. 0 ) . collect :: < Vec < _ > > ( ) ;
515
+ data_sorted. sort ( ) ;
516
+ assert_eq ! ( data_sorted, data) ;
517
+ }
518
+ }
519
+ }
433
520
}
434
521
435
522
#[ cfg( feature = "serde" ) ]
0 commit comments