Skip to content

Commit 088bf14

Browse files
DarksonnDanilo Krummrich
authored andcommitted
rust: alloc: add Vec::drain_all
This is like the stdlib method drain, except that it's hard-coded to use the entire vector's range. Rust Binder uses it in the range allocator to take ownership of everything in a vector in a case where reusing the vector is desirable. Implementing `DrainAll` in terms of `slice::IterMut` lets us reuse some nice optimizations in core for the case where T is a ZST. Signed-off-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Reviewed-by: Benno Lossin <lossin@kernel.org> Link: https://lore.kernel.org/r/20250502-vec-methods-v5-4-06d20ad9366f@google.com Signed-off-by: Danilo Krummrich <dakr@kernel.org>
1 parent 9def0d0 commit 088bf14

File tree

1 file changed

+59
-0
lines changed

1 file changed

+59
-0
lines changed

rust/kernel/alloc/kvec.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,30 @@ where
586586
unsafe { ptr::drop_in_place(ptr) };
587587
}
588588
}
589+
590+
/// Takes ownership of all items in this vector without consuming the allocation.
591+
///
592+
/// # Examples
593+
///
594+
/// ```
595+
/// let mut v = kernel::kvec![0, 1, 2, 3]?;
596+
///
597+
/// for (i, j) in v.drain_all().enumerate() {
598+
/// assert_eq!(i, j);
599+
/// }
600+
///
601+
/// assert!(v.capacity() >= 4);
602+
/// # Ok::<(), Error>(())
603+
/// ```
604+
pub fn drain_all(&mut self) -> DrainAll<'_, T> {
605+
// SAFETY: This does not underflow the length.
606+
let elems = unsafe { self.dec_len(self.len()) };
607+
// INVARIANT: The first `len` elements of the spare capacity are valid values, and as we
608+
// just set the length to zero, we may transfer ownership to the `DrainAll` object.
609+
DrainAll {
610+
elements: elems.iter_mut(),
611+
}
612+
}
589613
}
590614

591615
impl<T: Clone, A: Allocator> Vec<T, A> {
@@ -1073,3 +1097,38 @@ where
10731097
}
10741098
}
10751099
}
1100+
1101+
/// An iterator that owns all items in a vector, but does not own its allocation.
1102+
///
1103+
/// # Invariants
1104+
///
1105+
/// Every `&mut T` returned by the iterator references a `T` that the iterator may take ownership
1106+
/// of.
1107+
pub struct DrainAll<'vec, T> {
1108+
elements: slice::IterMut<'vec, T>,
1109+
}
1110+
1111+
impl<'vec, T> Iterator for DrainAll<'vec, T> {
1112+
type Item = T;
1113+
1114+
fn next(&mut self) -> Option<T> {
1115+
let elem: *mut T = self.elements.next()?;
1116+
// SAFETY: By the type invariants, we may take ownership of this value.
1117+
Some(unsafe { elem.read() })
1118+
}
1119+
1120+
fn size_hint(&self) -> (usize, Option<usize>) {
1121+
self.elements.size_hint()
1122+
}
1123+
}
1124+
1125+
impl<'vec, T> Drop for DrainAll<'vec, T> {
1126+
fn drop(&mut self) {
1127+
if core::mem::needs_drop::<T>() {
1128+
let iter = core::mem::take(&mut self.elements);
1129+
let ptr: *mut [T] = iter.into_slice();
1130+
// SAFETY: By the type invariants, we own these values so we may destroy them.
1131+
unsafe { ptr::drop_in_place(ptr) };
1132+
}
1133+
}
1134+
}

0 commit comments

Comments
 (0)