bump_scope/owned_slice/
drain.rs

1use core::{
2    fmt,
3    iter::FusedIterator,
4    mem::{self, ManuallyDrop},
5    ops::RangeBounds,
6    ptr::{self, NonNull},
7};
8
9use crate::{
10    BumpBox, SizedTypeProperties, owned_slice,
11    polyfill::{non_null, slice},
12};
13
14use super::TakeOwnedSlice;
15
16/// A draining iterator for owned slices.
17///
18/// This struct is created by the `drain` method on
19/// [`BumpBox`](BumpBox::drain),
20/// [`FixedBumpVec`](crate::FixedBumpVec::drain),
21/// [`BumpVec`](crate::BumpVec::drain) and
22/// [`MutBumpVec`](crate::MutBumpVec::drain).
23///
24/// See their documentation for more.
25///
26/// # Example
27///
28/// ```
29/// use bump_scope::{Bump, owned_slice::Drain};
30/// let bump: Bump = Bump::new();
31///
32/// let mut v = bump.alloc_slice_copy(&[0, 1, 2]);
33/// let iter: Drain<'_, _> = v.drain(..);
34/// # _ = iter;
35/// ```
36pub struct Drain<'a, T: 'a> {
37    /// Index of tail to preserve
38    tail_start: usize,
39    /// Length of tail
40    tail_len: usize,
41    /// Current remaining range to remove
42    iter: owned_slice::IntoIter<'a, T>,
43    slice: &'a mut NonNull<[T]>,
44}
45
46impl<T: fmt::Debug> fmt::Debug for Drain<'_, T> {
47    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48        f.debug_tuple("Drain").field(&self.iter.as_slice()).finish()
49    }
50}
51
52impl<'a, T> Drain<'a, T> {
53    pub(crate) fn new(boxed: &'a mut BumpBox<[T]>, range: impl RangeBounds<usize>) -> Drain<'a, T> {
54        // Memory safety
55        //
56        // When the Drain is first created, it shortens the length of
57        // the source slice to make sure no uninitialized or moved-from elements
58        // are accessible at all if the Drain's destructor never gets to run.
59        //
60        // Drain will copy out the values to remove.
61        // When finished, remaining tail of the vec is copied back to cover
62        // the hole, and the vector length is restored to the new length.
63
64        let len = boxed.len();
65        let range = slice::range(range, ..len);
66
67        unsafe {
68            // set self.vec length's to start, to be safe in case Drain is leaked
69            boxed.set_len(range.start);
70
71            Drain {
72                tail_start: range.end,
73                tail_len: len - range.end,
74                iter: owned_slice::IntoIter::new_ranged(boxed.ptr(), range),
75                slice: boxed.mut_ptr(),
76            }
77        }
78    }
79
80    /// Returns the remaining items of this iterator as a slice.
81    ///
82    /// # Examples
83    ///
84    /// ```
85    /// # use bump_scope::{Bump, bump_vec};
86    /// # let bump: Bump = Bump::new();
87    /// let mut vec = bump_vec![in &bump; 'a', 'b', 'c'];
88    /// let mut drain = vec.drain(..);
89    /// assert_eq!(drain.as_slice(), &['a', 'b', 'c']);
90    /// let _ = drain.next().unwrap();
91    /// assert_eq!(drain.as_slice(), &['b', 'c']);
92    /// ```
93    #[must_use]
94    pub fn as_slice(&self) -> &[T] {
95        self.iter.as_slice()
96    }
97
98    /// Keep unyielded elements in the source slice.
99    ///
100    /// # Examples
101    ///
102    /// ```
103    /// # use bump_scope::{Bump, bump_vec};
104    /// # let bump: Bump = Bump::new();
105    /// let mut vec = bump_vec![in &bump; 'a', 'b', 'c'];
106    /// let mut drain = vec.drain(..);
107    ///
108    /// assert_eq!(drain.next().unwrap(), 'a');
109    ///
110    /// // This call keeps 'b' and 'c' in the vec.
111    /// drain.keep_rest();
112    ///
113    /// // If we wouldn't call `keep_rest()`,
114    /// // `vec` would be empty.
115    /// assert_eq!(vec, ['b', 'c']);
116    /// ```
117    pub fn keep_rest(self) {
118        // At this moment layout looks like this:
119        //
120        // [head] [yielded by next] [unyielded] [yielded by next_back] [tail]
121        //        ^-- start         \_________/-- unyielded_len        \____/-- self.tail_len
122        //                          ^-- unyielded_ptr                  ^-- tail
123        //
124        // Normally `Drop` impl would drop [unyielded] and then move [tail] to the `start`.
125        // Here we want to
126        // 1. Move [unyielded] to `start`
127        // 2. Move [tail] to a new start at `start + len(unyielded)`
128        // 3. Update length of the original vec to `len(head) + len(unyielded) + len(tail)`
129        //    a. In case of ZST, this is the only thing we want to do
130        // 4. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do
131        let mut this = ManuallyDrop::new(self);
132
133        unsafe {
134            let slice_ptr = non_null::as_non_null_ptr(*this.slice).as_ptr();
135
136            let start = this.slice.len();
137            let tail = this.tail_start;
138
139            let unyielded_len = this.iter.len();
140            let unyielded_ptr = this.iter.as_slice().as_ptr();
141
142            // ZSTs have no identity, so we don't need to move them around.
143            if !T::IS_ZST {
144                let start_ptr = slice_ptr.add(start);
145
146                // memmove back unyielded elements
147                if unyielded_ptr != start_ptr {
148                    let src = unyielded_ptr;
149                    let dst = start_ptr;
150
151                    ptr::copy(src, dst, unyielded_len);
152                }
153
154                // memmove back untouched tail
155                if tail != (start + unyielded_len) {
156                    let src = slice_ptr.add(tail);
157                    let dst = start_ptr.add(unyielded_len);
158                    ptr::copy(src, dst, this.tail_len);
159                }
160            }
161
162            let new_len = start + unyielded_len + this.tail_len;
163            non_null::set_len(this.slice, new_len);
164        }
165    }
166}
167
168impl<T> AsRef<[T]> for Drain<'_, T> {
169    fn as_ref(&self) -> &[T] {
170        self.as_slice()
171    }
172}
173
174unsafe impl<T: Sync> Sync for Drain<'_, T> {}
175unsafe impl<T: Send> Send for Drain<'_, T> {}
176
177impl<T> Iterator for Drain<'_, T> {
178    type Item = T;
179
180    #[inline]
181    fn next(&mut self) -> Option<T> {
182        self.iter.next()
183    }
184
185    #[inline]
186    fn size_hint(&self) -> (usize, Option<usize>) {
187        self.iter.size_hint()
188    }
189}
190
191impl<T> DoubleEndedIterator for Drain<'_, T> {
192    #[inline]
193    fn next_back(&mut self) -> Option<T> {
194        self.iter.next_back()
195    }
196}
197
198impl<T> Drop for Drain<'_, T> {
199    fn drop(&mut self) {
200        /// Moves back the un-`Drain`ed elements to restore the original slice.
201        struct DropGuard<'r, 'a, T>(&'r mut Drain<'a, T>);
202
203        impl<T> Drop for DropGuard<'_, '_, T> {
204            fn drop(&mut self) {
205                if self.0.tail_len > 0 {
206                    unsafe {
207                        // memmove back untouched tail, update to new length
208                        let slice_ptr = non_null::as_non_null_ptr(*self.0.slice).as_ptr();
209
210                        let start = self.0.slice.len();
211                        let tail = self.0.tail_start;
212
213                        if tail != start {
214                            let src = slice_ptr.add(tail);
215                            let dst = slice_ptr.add(start);
216                            ptr::copy(src, dst, self.0.tail_len);
217                        }
218
219                        non_null::set_len(self.0.slice, start + self.0.tail_len);
220                    }
221                }
222            }
223        }
224
225        let iter = mem::take(&mut self.iter);
226
227        if T::IS_ZST {
228            // ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount.
229            // this can be achieved by manipulating the slice length instead of moving values out from `iter`.
230            unsafe {
231                let old_len = self.slice.len();
232                non_null::set_len(self.slice, old_len + iter.len() + self.tail_len);
233                non_null::truncate(self.slice, old_len + self.tail_len);
234            }
235
236            return;
237        }
238
239        // Ensure elements are moved back into their appropriate places, even when dropping `iter` panics.
240        let _guard = DropGuard(self);
241
242        // Drops the remaining drained elements.
243        drop(iter);
244    }
245}
246
247impl<T> ExactSizeIterator for Drain<'_, T> {
248    #[cfg(feature = "nightly-exact-size-is-empty")]
249    fn is_empty(&self) -> bool {
250        self.iter.is_empty()
251    }
252}
253
254#[cfg(feature = "nightly-trusted-len")]
255unsafe impl<T> core::iter::TrustedLen for Drain<'_, T> {}
256
257impl<T> FusedIterator for Drain<'_, T> {}
258
259unsafe impl<T> TakeOwnedSlice for Drain<'_, T> {
260    type Item = T;
261
262    #[inline]
263    fn owned_slice_ref(&self) -> &[Self::Item] {
264        self.iter.owned_slice_ref()
265    }
266
267    #[inline]
268    fn take_owned_slice(&mut self) {
269        self.iter.take_owned_slice();
270    }
271}
272
273#[cfg(all(test, feature = "std"))]
274mod tests {
275    use std::{string::ToString, vec::Vec};
276
277    use crate::{
278        FixedBumpVec,
279        tests::{Bump, TestWrap},
280    };
281
282    #[test]
283    fn owned_slice() {
284        let bump: Bump = Bump::new();
285        let slice = bump.alloc_iter((0..5).map(|v| v.to_string()).map(TestWrap));
286        assert_eq!(
287            slice.iter().map(|v| v.0.clone()).collect::<Vec<_>>(),
288            &["0", "1", "2", "3", "4"]
289        );
290
291        for start in 0..slice.len() {
292            for end in start..slice.len() {
293                TestWrap::expect().drops(5).clones(5).run(|| {
294                    let mut slice_clone = bump.alloc_slice_clone(&slice);
295
296                    let mut vec = FixedBumpVec::with_capacity_in(10, &bump);
297                    vec.append(slice_clone.drain(start..end));
298
299                    assert_eq!(vec, slice[start..end]);
300
301                    assert_eq!(
302                        TestWrap::peel_slice(slice_clone.as_slice()),
303                        TestWrap::peel_slice(&slice[..start])
304                            .iter()
305                            .chain(TestWrap::peel_slice(&slice[end..]))
306                            .cloned()
307                            .collect::<Vec<_>>()
308                    );
309                });
310            }
311        }
312    }
313
314    #[test]
315    fn owned_slice_zst() {
316        let bump: Bump = Bump::new();
317        let slice = bump.alloc_iter((0..5).map(|v| v.to_string()).map(TestWrap));
318
319        for start in 0..slice.len() {
320            for end in start..slice.len() {
321                TestWrap::expect().drops(5).clones(5).run(|| {
322                    let mut slice_clone = bump.alloc_slice_clone(&slice);
323                    let mut vec = FixedBumpVec::with_capacity_in(10, &bump);
324                    vec.append(slice_clone.drain(start..end));
325
326                    assert_eq!(vec.len(), end - start);
327                    assert_eq!(slice_clone.len(), slice[..start].len() + slice[end..].len());
328                });
329            }
330        }
331    }
332}