@@ -53,27 +53,36 @@ impl<'a, T, A: Allocator> Drain<'a, T, A> {
5353 }
5454
5555 // Only returns pointers to the slices, as that's
56- // all we need to drop them
57- fn as_slices ( & self ) -> ( * mut [ T ] , * mut [ T ] ) {
56+ // all we need to drop them. May only be called if `self.remaining != 0`.
57+ unsafe fn as_slices ( & self ) -> ( * mut [ T ] , * mut [ T ] ) {
5858 unsafe {
5959 let deque = self . deque . as_ref ( ) ;
60- let wrapped_start = deque. wrap_idx ( self . idx ) ;
61-
62- if self . remaining <= deque. capacity ( ) - wrapped_start {
63- // there's only one contigous slice
64- (
65- ptr:: slice_from_raw_parts_mut ( deque. ptr ( ) . add ( wrapped_start) , self . remaining ) ,
66- & mut [ ] as * mut [ T ] ,
67- )
60+ // FIXME: This is doing almost exactly the same thing as the else branch in `VecDeque::slice_ranges`.
61+ // Unfortunately, we can't just call `slice_ranges` here, as the deque's `len` is currently
62+ // just `drain_start`, so the range check would (almost) always panic. Between temporarily
63+ // adjusting the deques `len` to call `slice_ranges`, and just copy pasting the `slice_ranges`
64+ // implementation, this seemed like the less hacky solution, though it might be good to
65+ // find a better one in the future.
66+
67+ // because `self.remaining != 0`, we know that `self.idx < deque.original_len`, so it's a valid
68+ // logical index.
69+ let wrapped_start = deque. to_physical_idx ( self . idx ) ;
70+
71+ let head_len = deque. capacity ( ) - wrapped_start;
72+
73+ let ( a_range, b_range) = if head_len >= self . remaining {
74+ ( wrapped_start..wrapped_start + self . remaining , 0 ..0 )
6875 } else {
69- let head_len = deque. capacity ( ) - wrapped_start;
70- // this will never overflow due to the if condition
7176 let tail_len = self . remaining - head_len;
72- (
73- ptr:: slice_from_raw_parts_mut ( deque. ptr ( ) . add ( wrapped_start) , head_len) ,
74- ptr:: slice_from_raw_parts_mut ( deque. ptr ( ) , tail_len) ,
75- )
76- }
77+ ( wrapped_start..deque. capacity ( ) , 0 ..tail_len)
78+ } ;
79+
80+ // SAFETY: the range `self.idx..self.idx+self.remaining` lies strictly inside
81+ // the range `0..deque.original_len`. because of this, and because of the fact
82+ // that we acquire `a_range` and `b_range` exactly like `slice_ranges` would,
83+ // it's guaranteed that `a_range` and `b_range` represent valid ranges into
84+ // the deques buffer.
85+ ( deque. buffer_range ( a_range) , deque. buffer_range ( b_range) )
7786 }
7887 }
7988}
@@ -103,8 +112,9 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
103112 impl < ' r , ' a , T , A : Allocator > Drop for DropGuard < ' r , ' a , T , A > {
104113 fn drop ( & mut self ) {
105114 if self . 0 . remaining != 0 {
106- let ( front, back) = self . 0 . as_slices ( ) ;
107115 unsafe {
116+ // SAFETY: We just checked that `self.remaining != 0`.
117+ let ( front, back) = self . 0 . as_slices ( ) ;
108118 ptr:: drop_in_place ( front) ;
109119 ptr:: drop_in_place ( back) ;
110120 }
@@ -133,7 +143,7 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
133143 source_deque. len = 0 ;
134144 }
135145 ( 0 , _) => {
136- source_deque. head = source_deque. wrap_idx ( drain_len) ;
146+ source_deque. head = source_deque. to_physical_idx ( drain_len) ;
137147 source_deque. len = orig_len - drain_len;
138148 }
139149 ( _, 0 ) => {
@@ -143,15 +153,15 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
143153 if head_len <= tail_len {
144154 source_deque. wrap_copy (
145155 source_deque. head ,
146- source_deque. wrap_idx ( drain_len) ,
156+ source_deque. to_physical_idx ( drain_len) ,
147157 head_len,
148158 ) ;
149- source_deque. head = source_deque. wrap_idx ( drain_len) ;
159+ source_deque. head = source_deque. to_physical_idx ( drain_len) ;
150160 source_deque. len = orig_len - drain_len;
151161 } else {
152162 source_deque. wrap_copy (
153- source_deque. wrap_idx ( head_len + drain_len) ,
154- source_deque. wrap_idx ( head_len) ,
163+ source_deque. to_physical_idx ( head_len + drain_len) ,
164+ source_deque. to_physical_idx ( head_len) ,
155165 tail_len,
156166 ) ;
157167 source_deque. len = orig_len - drain_len;
@@ -162,14 +172,17 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
162172 }
163173
164174 let guard = DropGuard ( self ) ;
165- let ( front, back) = guard. 0 . as_slices ( ) ;
166- unsafe {
167- // since idx is a logical index, we don't need to worry about wrapping.
168- guard. 0 . idx += front. len ( ) ;
169- guard. 0 . remaining -= front. len ( ) ;
170- ptr:: drop_in_place ( front) ;
171- guard. 0 . remaining = 0 ;
172- ptr:: drop_in_place ( back) ;
175+ if guard. 0 . remaining != 0 {
176+ unsafe {
177+ // SAFETY: We just checked that `self.remaining != 0`.
178+ let ( front, back) = guard. 0 . as_slices ( ) ;
179+ // since idx is a logical index, we don't need to worry about wrapping.
180+ guard. 0 . idx += front. len ( ) ;
181+ guard. 0 . remaining -= front. len ( ) ;
182+ ptr:: drop_in_place ( front) ;
183+ guard. 0 . remaining = 0 ;
184+ ptr:: drop_in_place ( back) ;
185+ }
173186 }
174187
175188 // Dropping `guard` handles moving the remaining elements into place.
@@ -185,7 +198,7 @@ impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
185198 if self . remaining == 0 {
186199 return None ;
187200 }
188- let wrapped_idx = unsafe { self . deque . as_ref ( ) . wrap_idx ( self . idx ) } ;
201+ let wrapped_idx = unsafe { self . deque . as_ref ( ) . to_physical_idx ( self . idx ) } ;
189202 self . idx += 1 ;
190203 self . remaining -= 1 ;
191204 Some ( unsafe { self . deque . as_mut ( ) . buffer_read ( wrapped_idx) } )
@@ -206,7 +219,7 @@ impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> {
206219 return None ;
207220 }
208221 self . remaining -= 1 ;
209- let wrapped_idx = unsafe { self . deque . as_ref ( ) . wrap_idx ( self . idx + self . remaining ) } ;
222+ let wrapped_idx = unsafe { self . deque . as_ref ( ) . to_physical_idx ( self . idx + self . remaining ) } ;
210223 Some ( unsafe { self . deque . as_mut ( ) . buffer_read ( wrapped_idx) } )
211224 }
212225}
0 commit comments