rune_alloc/vec_deque/
drain.rs

1use core::fmt;
2use core::iter::FusedIterator;
3use core::marker::PhantomData;
4use core::mem;
5
6use crate::alloc::{Allocator, Global, SizedTypeProperties};
7use crate::ptr::{self, NonNull};
8
9use super::VecDeque;
10
11/// A draining iterator over the elements of a `VecDeque`.
12///
13/// This `struct` is created by the [`drain`] method on [`VecDeque`]. See its
14/// documentation for more.
15///
16/// [`drain`]: VecDeque::drain
17pub struct Drain<'a, T: 'a, A: Allocator = Global> {
18    // We can't just use a &mut VecDeque<T, A>, as that would make Drain invariant over T
19    // and we want it to be covariant instead
20    deque: NonNull<VecDeque<T, A>>,
21    // drain_start is stored in deque.len
22    drain_len: usize,
23    // index into the logical array, not the physical one (always lies in [0..deque.len))
24    idx: usize,
25    // number of elements after the drain range
26    tail_len: usize,
27    remaining: usize,
28    // Needed to make Drain covariant over T
29    _marker: PhantomData<&'a T>,
30}
31
32impl<'a, T, A: Allocator> Drain<'a, T, A> {
33    pub(super) unsafe fn new(
34        deque: &'a mut VecDeque<T, A>,
35        drain_start: usize,
36        drain_len: usize,
37    ) -> Self {
38        let orig_len = mem::replace(&mut deque.len, drain_start);
39        let tail_len = orig_len - drain_start - drain_len;
40        Drain {
41            deque: NonNull::from(deque),
42            drain_len,
43            idx: drain_start,
44            tail_len,
45            remaining: drain_len,
46            _marker: PhantomData,
47        }
48    }
49
50    // Only returns pointers to the slices, as that's all we need
51    // to drop them. May only be called if `self.remaining != 0`.
52    unsafe fn as_slices(&self) -> (*mut [T], *mut [T]) {
53        unsafe {
54            let deque = self.deque.as_ref();
55
56            // We know that `self.idx + self.remaining <= deque.len <= usize::MAX`, so this won't overflow.
57            let logical_remaining_range = self.idx..self.idx + self.remaining;
58
59            // SAFETY: `logical_remaining_range` represents the
60            // range into the logical buffer of elements that
61            // haven't been drained yet, so they're all initialized,
62            // and `slice::range(start..end, end) == start..end`,
63            // so the preconditions for `slice_ranges` are met.
64            let (a_range, b_range) =
65                deque.slice_ranges(logical_remaining_range.clone(), logical_remaining_range.end);
66            (deque.buffer_range(a_range), deque.buffer_range(b_range))
67        }
68    }
69}
70
71impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> {
72    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73        f.debug_tuple("Drain")
74            .field(&self.drain_len)
75            .field(&self.idx)
76            .field(&self.tail_len)
77            .field(&self.remaining)
78            .finish()
79    }
80}
81
82unsafe impl<T: Sync, A: Allocator + Sync> Sync for Drain<'_, T, A> {}
83unsafe impl<T: Send, A: Allocator + Send> Send for Drain<'_, T, A> {}
84
85impl<T, A: Allocator> Drop for Drain<'_, T, A> {
86    fn drop(&mut self) {
87        struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>);
88
89        impl<T, A: Allocator> Drop for DropGuard<'_, '_, T, A> {
90            fn drop(&mut self) {
91                if self.0.remaining != 0 {
92                    unsafe {
93                        // SAFETY: We just checked that `self.remaining != 0`.
94                        let (front, back) = self.0.as_slices();
95                        ptr::drop_in_place(front);
96                        ptr::drop_in_place(back);
97                    }
98                }
99
100                let source_deque = unsafe { self.0.deque.as_mut() };
101
102                let drain_start = source_deque.len();
103                let drain_len = self.0.drain_len;
104                let drain_end = drain_start + drain_len;
105
106                let orig_len = self.0.tail_len + drain_end;
107
108                if T::IS_ZST {
109                    // no need to copy around any memory if T is a ZST
110                    source_deque.len = orig_len - drain_len;
111                    return;
112                }
113
114                let head_len = drain_start;
115                let tail_len = self.0.tail_len;
116
117                match (head_len, tail_len) {
118                    (0, 0) => {
119                        source_deque.head = 0;
120                        source_deque.len = 0;
121                    }
122                    (0, _) => {
123                        source_deque.head = source_deque.to_physical_idx(drain_len);
124                        source_deque.len = orig_len - drain_len;
125                    }
126                    (_, 0) => {
127                        source_deque.len = orig_len - drain_len;
128                    }
129                    _ => unsafe {
130                        if head_len <= tail_len {
131                            source_deque.wrap_copy(
132                                source_deque.head,
133                                source_deque.to_physical_idx(drain_len),
134                                head_len,
135                            );
136                            source_deque.head = source_deque.to_physical_idx(drain_len);
137                            source_deque.len = orig_len - drain_len;
138                        } else {
139                            source_deque.wrap_copy(
140                                source_deque.to_physical_idx(head_len + drain_len),
141                                source_deque.to_physical_idx(head_len),
142                                tail_len,
143                            );
144                            source_deque.len = orig_len - drain_len;
145                        }
146                    },
147                }
148            }
149        }
150
151        let guard = DropGuard(self);
152
153        if guard.0.remaining != 0 {
154            unsafe {
155                // SAFETY: We just checked that `self.remaining != 0`.
156                let (front, back) = guard.0.as_slices();
157                // since idx is a logical index, we don't need to worry about wrapping.
158                guard.0.idx += ptr::slice_len(front);
159                guard.0.remaining -= ptr::slice_len(front);
160                ptr::drop_in_place(front);
161                guard.0.remaining = 0;
162                ptr::drop_in_place(back);
163            }
164        }
165
166        // Dropping `guard` handles moving the remaining elements into place.
167    }
168}
169
170impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
171    type Item = T;
172
173    #[inline]
174    fn next(&mut self) -> Option<T> {
175        if self.remaining == 0 {
176            return None;
177        }
178        let wrapped_idx = unsafe { self.deque.as_ref().to_physical_idx(self.idx) };
179        self.idx += 1;
180        self.remaining -= 1;
181        Some(unsafe { self.deque.as_mut().buffer_read(wrapped_idx) })
182    }
183
184    #[inline]
185    fn size_hint(&self) -> (usize, Option<usize>) {
186        let len = self.remaining;
187        (len, Some(len))
188    }
189}
190
191impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> {
192    #[inline]
193    fn next_back(&mut self) -> Option<T> {
194        if self.remaining == 0 {
195            return None;
196        }
197        self.remaining -= 1;
198        let wrapped_idx = unsafe {
199            self.deque
200                .as_ref()
201                .to_physical_idx(self.idx + self.remaining)
202        };
203        Some(unsafe { self.deque.as_mut().buffer_read(wrapped_idx) })
204    }
205}
206
207impl<T, A: Allocator> ExactSizeIterator for Drain<'_, T, A> {}
208
209impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {}