11use crate :: alloc:: { Allocator , Global } ;
22use core:: fmt;
33use core:: iter:: { FusedIterator , TrustedLen } ;
4- use core:: mem:: { self } ;
4+ use core:: mem:: { self , MaybeUninit } ;
55use core:: ptr:: { self , NonNull } ;
66use core:: slice:: { self } ;
77
@@ -102,16 +102,11 @@ impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> {
102102#[ stable( feature = "drain" , since = "1.6.0" ) ]
103103impl < T , A : Allocator > Drop for Drain < ' _ , T , A > {
104104 fn drop ( & mut self ) {
105- /// Continues dropping the remaining elements in the `Drain`, then moves back the
106- /// un-`Drain`ed elements to restore the original `Vec`.
105+ /// Moves back the un-`Drain`ed elements to restore the original `Vec`.
107106 struct DropGuard < ' r , ' a , T , A : Allocator > ( & ' r mut Drain < ' a , T , A > ) ;
108107
109108 impl < ' r , ' a , T , A : Allocator > Drop for DropGuard < ' r , ' a , T , A > {
110109 fn drop ( & mut self ) {
111- // Continue the same loop we have below. If the loop already finished, this does
112- // nothing.
113- self . 0 . for_each ( drop) ;
114-
115110 if self . 0 . tail_len > 0 {
116111 unsafe {
117112 let source_vec = self . 0 . vec . as_mut ( ) ;
@@ -129,15 +124,43 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
129124 }
130125 }
131126
132- // exhaust self first
133- while let Some ( item) = self . next ( ) {
134- let guard = DropGuard ( self ) ;
135- drop ( item) ;
136- mem:: forget ( guard) ;
127+ let iter = mem:: replace ( & mut self . iter , ( & mut [ ] ) . iter ( ) ) ;
128+ let drop_len = iter. len ( ) ;
129+ let drop_ptr = iter. as_slice ( ) . as_ptr ( ) ;
130+
131+ // forget iter so there's no aliasing reference
132+ drop ( iter) ;
133+
134+ let mut vec = self . vec ;
135+
136+ if mem:: size_of :: < T > ( ) == 0 {
137+ // ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount.
138+ // this can be achieved by manipulating the Vec length instead of moving values out from `iter`.
139+ unsafe {
140+ let vec = vec. as_mut ( ) ;
141+ let old_len = vec. len ( ) ;
142+ vec. set_len ( old_len + drop_len + self . tail_len ) ;
143+ vec. truncate ( old_len + self . tail_len ) ;
144+ }
145+
146+ return ;
147+ }
148+
149+ // ensure elements are moved back into their appropriate places, even when drop_in_place panics
150+ let _guard = DropGuard ( self ) ;
151+
152+ if drop_len == 0 {
153+ return ;
137154 }
138155
139- // Drop a `DropGuard` to move back the non-drained tail of `self`.
140- DropGuard ( self ) ;
156+ unsafe {
157+ let vec = vec. as_mut ( ) ;
158+ let spare_capacity = vec. spare_capacity_mut ( ) ;
159+ let drop_offset = drop_ptr. offset_from ( spare_capacity. as_ptr ( ) as * const _ ) as usize ;
160+ let drop_range = drop_offset..( drop_offset + drop_len) ;
161+ let to_drop = & mut spare_capacity[ drop_range] ;
162+ ptr:: drop_in_place ( MaybeUninit :: slice_assume_init_mut ( to_drop) ) ;
163+ }
141164 }
142165}
143166
0 commit comments