1- use std:: ptr;
1+ use std:: { mem , ptr} ;
22
33use smallvec:: { Array , SmallVec } ;
44use thin_vec:: ThinVec ;
@@ -13,39 +13,44 @@ pub trait FlatMapInPlace<T>: Sized {
1313// The implementation of this method is syntactically identical for all the
1414// different vector types.
1515macro_rules! flat_map_in_place {
16- ( ) => {
16+ ( $vec : ident $ ( where T : $bound : path ) ? ) => {
1717 fn flat_map_in_place<F , I >( & mut self , mut f: F )
1818 where
1919 F : FnMut ( T ) -> I ,
2020 I : IntoIterator <Item = T >,
2121 {
22+ struct LeakGuard <' a, T $( : $bound) ?>( & ' a mut $vec<T >) ;
23+
24+ impl <' a, T $( : $bound) ?> Drop for LeakGuard <' a, T > {
25+ fn drop( & mut self ) {
26+ unsafe {
27+ self . 0 . set_len( 0 ) ; // make sure we just leak elements in case of panic
28+ }
29+ }
30+ }
31+
32+ let this = LeakGuard ( self ) ;
33+
2234 let mut read_i = 0 ;
2335 let mut write_i = 0 ;
2436 unsafe {
25- let mut old_len = self . len( ) ;
26- self . set_len( 0 ) ; // make sure we just leak elements in case of panic
27-
28- while read_i < old_len {
37+ while read_i < this. 0 . len( ) {
2938 // move the read_i'th item out of the vector and map it
3039 // to an iterator
31- let e = ptr:: read( self . as_ptr( ) . add( read_i) ) ;
40+ let e = ptr:: read( this . 0 . as_ptr( ) . add( read_i) ) ;
3241 let iter = f( e) . into_iter( ) ;
3342 read_i += 1 ;
3443
3544 for e in iter {
3645 if write_i < read_i {
37- ptr:: write( self . as_mut_ptr( ) . add( write_i) , e) ;
46+ ptr:: write( this . 0 . as_mut_ptr( ) . add( write_i) , e) ;
3847 write_i += 1 ;
3948 } else {
4049 // If this is reached we ran out of space
4150 // in the middle of the vector.
4251 // However, the vector is in a valid state here,
4352 // so we just do a somewhat inefficient insert.
44- self . set_len( old_len) ;
45- self . insert( write_i, e) ;
46-
47- old_len = self . len( ) ;
48- self . set_len( 0 ) ;
53+ this. 0 . insert( write_i, e) ;
4954
5055 read_i += 1 ;
5156 write_i += 1 ;
@@ -54,20 +59,23 @@ macro_rules! flat_map_in_place {
5459 }
5560
5661 // write_i tracks the number of actually written new items.
57- self . set_len( write_i) ;
62+ this. 0 . set_len( write_i) ;
63+
64+ // The ThinVec is in a sane state again. Prevent the LeakGuard from leaking the data.
65+ mem:: forget( this) ;
5866 }
5967 }
6068 } ;
6169}
6270
6371impl < T > FlatMapInPlace < T > for Vec < T > {
64- flat_map_in_place ! ( ) ;
72+ flat_map_in_place ! ( Vec ) ;
6573}
6674
6775impl < T , A : Array < Item = T > > FlatMapInPlace < T > for SmallVec < A > {
68- flat_map_in_place ! ( ) ;
76+ flat_map_in_place ! ( SmallVec where T : Array ) ;
6977}
7078
7179impl < T > FlatMapInPlace < T > for ThinVec < T > {
72- flat_map_in_place ! ( ) ;
80+ flat_map_in_place ! ( ThinVec ) ;
7381}
0 commit comments