Skip to content

Commit 89d6c86

Browse files
committed
ADD: drain() method and Drain iterator
This add the drain functionality similar to std Vec's drain to HeaderVec. The `with_weakfix()` things are not needed for Drain (I was wrong in a earlier commit message) but they will be required for upcoming Splice functionality. Since vec::Drain depends on a few nightly features internally but we want to stay compatible with stable a few things are backported from nightly in `future_slice`. OTOH we can already stabilize Drain::keep_rest(). Most code was taken from std::vec and minimally adapted to work for HeaderVec.
1 parent efc96c0 commit 89d6c86

File tree

4 files changed

+401
-1
lines changed

4 files changed

+401
-1
lines changed

src/drain.rs

+243
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
#![cfg(any(feature = "std"))]
2+
3+
use core::{
4+
any::type_name,
5+
mem::{self},
6+
ptr::{self, NonNull},
7+
};
8+
9+
use std::{fmt, iter::FusedIterator, mem::ManuallyDrop, slice};
10+
11+
use crate::HeaderVec;
12+
13+
/// A draining iterator for `HeaderVec<H, T>`.
14+
///
15+
/// This `struct` is created by [`HeaderVec::drain`].
16+
/// See its documentation for more.
17+
///
18+
/// # Feature compatibility
19+
///
20+
/// The `drain()` API and [`Drain`] iterator are only available when the `std` feature is
21+
/// enabled.
22+
///
23+
/// # Example
24+
///
25+
/// ```
26+
/// # #[cfg(any(doc, feature = "std"))] {
27+
/// # use header_vec::HeaderVec;
28+
/// let mut hv: HeaderVec<(), _> = HeaderVec::from([0, 1, 2]);
29+
/// let iter: header_vec::Drain<'_, _, _> = hv.drain(..);
30+
/// # }
31+
/// ```
32+
pub struct Drain<'a, H, T> {
33+
/// Index of tail to preserve
34+
pub(super) tail_start: usize,
35+
/// Length of tail
36+
pub(super) tail_len: usize,
37+
/// Current remaining range to remove
38+
pub(super) iter: slice::Iter<'a, T>,
39+
pub(super) vec: NonNull<HeaderVec<H, T>>,
40+
}
41+
42+
impl<H: fmt::Debug, T: fmt::Debug> fmt::Debug for Drain<'_, H, T> {
43+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44+
f.debug_struct(&format!(
45+
"Drain<{}, {}>",
46+
type_name::<H>(),
47+
type_name::<T>()
48+
))
49+
.field("header", unsafe { self.vec.as_ref() })
50+
.field("iter", &self.iter.as_slice())
51+
.finish()
52+
}
53+
}
54+
55+
impl<'a, H, T> Drain<'a, H, T> {
56+
/// Returns the remaining items of this iterator as a slice.
57+
///
58+
/// # Examples
59+
///
60+
/// ```
61+
/// # use header_vec::HeaderVec;
62+
/// let mut hv: HeaderVec<(), _> = HeaderVec::from(['a', 'b', 'c']);
63+
/// let mut drain = hv.drain(..);
64+
/// assert_eq!(drain.as_slice(), &['a', 'b', 'c']);
65+
/// let _ = drain.next().unwrap();
66+
/// assert_eq!(drain.as_slice(), &['b', 'c']);
67+
/// ```
68+
#[must_use]
69+
pub fn as_slice(&self) -> &[T] {
70+
self.iter.as_slice()
71+
}
72+
73+
/// Keep unyielded elements in the source `HeaderVec`.
74+
///
75+
/// # Examples
76+
///
77+
/// ```
78+
/// # use header_vec::HeaderVec;
79+
/// let mut hv: HeaderVec<(), _> = HeaderVec::from(['a', 'b', 'c']);
80+
/// let mut drain = hv.drain(..);
81+
///
82+
/// assert_eq!(drain.next().unwrap(), 'a');
83+
///
84+
/// // This call keeps 'b' and 'c' in the vec.
85+
/// drain.keep_rest();
86+
///
87+
/// // If we wouldn't call `keep_rest()`,
88+
/// // `hv` would be empty.
89+
/// assert_eq!(hv.as_slice(), ['b', 'c']);
90+
/// ```
91+
pub fn keep_rest(self) {
92+
let mut this = ManuallyDrop::new(self);
93+
94+
unsafe {
95+
let source_vec = this.vec.as_mut();
96+
97+
let start = source_vec.len();
98+
let tail = this.tail_start;
99+
100+
let unyielded_len = this.iter.len();
101+
let unyielded_ptr = this.iter.as_slice().as_ptr();
102+
103+
// ZSTs have no identity, so we don't need to move them around.
104+
if std::mem::size_of::<T>() != 0 {
105+
let start_ptr = source_vec.as_mut_ptr().add(start);
106+
107+
// memmove back unyielded elements
108+
if unyielded_ptr != start_ptr {
109+
let src = unyielded_ptr;
110+
let dst = start_ptr;
111+
112+
ptr::copy(src, dst, unyielded_len);
113+
}
114+
115+
// memmove back untouched tail
116+
if tail != (start + unyielded_len) {
117+
let src = source_vec.as_ptr().add(tail);
118+
let dst = start_ptr.add(unyielded_len);
119+
ptr::copy(src, dst, this.tail_len);
120+
}
121+
}
122+
123+
source_vec.set_len(start + unyielded_len + this.tail_len);
124+
}
125+
}
126+
}
127+
128+
impl<'a, H, T> AsRef<[T]> for Drain<'a, H, T> {
129+
fn as_ref(&self) -> &[T] {
130+
self.as_slice()
131+
}
132+
}
133+
134+
unsafe impl<H: Sync, T: Sync> Sync for Drain<'_, H, T> {}
135+
unsafe impl<H: Send, T: Send> Send for Drain<'_, H, T> {}
136+
137+
impl<H, T> Iterator for Drain<'_, H, T> {
138+
type Item = T;
139+
140+
#[inline]
141+
fn next(&mut self) -> Option<T> {
142+
self.iter
143+
.next()
144+
.map(|elt| unsafe { ptr::read(elt as *const _) })
145+
}
146+
147+
fn size_hint(&self) -> (usize, Option<usize>) {
148+
self.iter.size_hint()
149+
}
150+
}
151+
152+
impl<H, T> DoubleEndedIterator for Drain<'_, H, T> {
153+
#[inline]
154+
fn next_back(&mut self) -> Option<T> {
155+
self.iter
156+
.next_back()
157+
.map(|elt| unsafe { ptr::read(elt as *const _) })
158+
}
159+
}
160+
161+
impl<H, T> Drop for Drain<'_, H, T> {
162+
fn drop(&mut self) {
163+
/// Moves back the un-`Drain`ed elements to restore the original `Vec`.
164+
struct DropGuard<'r, 'a, H, T>(&'r mut Drain<'a, H, T>);
165+
166+
impl<'r, 'a, H, T> Drop for DropGuard<'r, 'a, H, T> {
167+
fn drop(&mut self) {
168+
if self.0.tail_len > 0 {
169+
unsafe {
170+
let source_vec = self.0.vec.as_mut();
171+
// memmove back untouched tail, update to new length
172+
let start = source_vec.len();
173+
let tail = self.0.tail_start;
174+
if tail != start {
175+
let src = source_vec.as_ptr().add(tail);
176+
let dst = source_vec.as_mut_ptr().add(start);
177+
ptr::copy(src, dst, self.0.tail_len);
178+
}
179+
source_vec.set_len(start + self.0.tail_len);
180+
}
181+
}
182+
}
183+
}
184+
185+
let iter = mem::take(&mut self.iter);
186+
let drop_len = iter.len();
187+
188+
let mut vec = self.vec;
189+
190+
// unstable: if T::IS_ZST { instead we use size_of
191+
if mem::size_of::<T>() == 0 {
192+
// ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount.
193+
// this can be achieved by manipulating the Vec length instead of moving values out from `iter`.
194+
unsafe {
195+
let vec = vec.as_mut();
196+
let old_len = vec.len();
197+
vec.set_len(old_len + drop_len + self.tail_len);
198+
vec.truncate(old_len + self.tail_len);
199+
}
200+
201+
return;
202+
}
203+
204+
// ensure elements are moved back into their appropriate places, even when drop_in_place panics
205+
let _guard = DropGuard(self);
206+
207+
if drop_len == 0 {
208+
return;
209+
}
210+
211+
// as_slice() must only be called when iter.len() is > 0 because
212+
// it also gets touched by vec::Splice which may turn it into a dangling pointer
213+
// which would make it and the vec pointer point to different allocations which would
214+
// lead to invalid pointer arithmetic below.
215+
let drop_ptr = iter.as_slice().as_ptr();
216+
217+
unsafe {
218+
// drop_ptr comes from a slice::Iter which only gives us a &[T] but for drop_in_place
219+
// a pointer with mutable provenance is necessary. Therefore we must reconstruct
220+
// it from the original vec but also avoid creating a &mut to the front since that could
221+
// invalidate raw pointers to it which some unsafe code might rely on.
222+
let vec_ptr = vec.as_mut().as_mut_ptr();
223+
224+
// PLANNED: let drop_offset = drop_ptr.sub_ptr(vec_ptr); is in nightly
225+
let drop_offset = usize::try_from(drop_ptr.offset_from(vec_ptr)).unwrap_unchecked();
226+
let to_drop = ptr::slice_from_raw_parts_mut(vec_ptr.add(drop_offset), drop_len);
227+
ptr::drop_in_place(to_drop);
228+
}
229+
}
230+
}
231+
232+
impl<H, T> FusedIterator for Drain<'_, H, T> {}
233+
234+
// PLANNED: unstable features
235+
// impl<H, T> ExactSizeIterator for Drain<'_, H, T> {
236+
// fn is_empty(&self) -> bool {
237+
// self.iter.is_empty()
238+
// }
239+
// }
240+
//
241+
// #[unstable(feature = "trusted_len", issue = "37572")]
242+
// unsafe impl<H, T> TrustedLen for Drain<'_, H, T> {}
243+
//

src/future_slice.rs

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//! This module re-implements a unstable slice functions, these should be removed once they
2+
//! are stabilized. These is copy-pasted with slight modifications from std::slice for
3+
//! functions that do not need language magic.
4+
5+
use std::ops;
6+
7+
#[track_caller]
8+
#[must_use]
9+
pub(crate) fn range<R>(range: R, bounds: ops::RangeTo<usize>) -> ops::Range<usize>
10+
where
11+
R: ops::RangeBounds<usize>,
12+
{
13+
let len = bounds.end;
14+
15+
let start = match range.start_bound() {
16+
ops::Bound::Included(&start) => start,
17+
ops::Bound::Excluded(start) => start
18+
.checked_add(1)
19+
.unwrap_or_else(|| slice_start_index_overflow_fail()),
20+
ops::Bound::Unbounded => 0,
21+
};
22+
23+
let end = match range.end_bound() {
24+
ops::Bound::Included(end) => end
25+
.checked_add(1)
26+
.unwrap_or_else(|| slice_end_index_overflow_fail()),
27+
ops::Bound::Excluded(&end) => end,
28+
ops::Bound::Unbounded => len,
29+
};
30+
31+
if start > end {
32+
slice_index_order_fail(start, end);
33+
}
34+
if end > len {
35+
slice_end_index_len_fail(end, len);
36+
}
37+
38+
ops::Range { start, end }
39+
}
40+
41+
#[track_caller]
42+
const fn slice_start_index_overflow_fail() -> ! {
43+
panic!("attempted to index slice from after maximum usize");
44+
}
45+
46+
#[track_caller]
47+
const fn slice_end_index_overflow_fail() -> ! {
48+
panic!("attempted to index slice up to maximum usize");
49+
}
50+
51+
#[track_caller]
52+
fn slice_index_order_fail(index: usize, end: usize) -> ! {
53+
panic!("slice index start is larger than end, slice index starts at {index} but ends at {end}")
54+
}
55+
56+
#[track_caller]
57+
fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
58+
panic!(
59+
"slice end index is out of range for slice, range end index {index} out of range for slice of length {len}"
60+
)
61+
}

0 commit comments

Comments
 (0)