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>
This commit is contained in:
Alice Ryhl 2025-05-02 13:19:32 +00:00 committed by Danilo Krummrich
parent 9def0d0a2a
commit 088bf14a88

View File

@ -586,6 +586,30 @@ where
unsafe { ptr::drop_in_place(ptr) };
}
}
/// Takes ownership of all items in this vector without consuming the allocation.
///
/// # Examples
///
/// ```
/// let mut v = kernel::kvec![0, 1, 2, 3]?;
///
/// for (i, j) in v.drain_all().enumerate() {
/// assert_eq!(i, j);
/// }
///
/// assert!(v.capacity() >= 4);
/// # Ok::<(), Error>(())
/// ```
pub fn drain_all(&mut self) -> DrainAll<'_, T> {
// SAFETY: This does not underflow the length.
let elems = unsafe { self.dec_len(self.len()) };
// INVARIANT: The first `len` elements of the spare capacity are valid values, and as we
// just set the length to zero, we may transfer ownership to the `DrainAll` object.
DrainAll {
elements: elems.iter_mut(),
}
}
}
impl<T: Clone, A: Allocator> Vec<T, A> {
@ -1073,3 +1097,38 @@ where
}
}
}
/// An iterator that owns all items in a vector, but does not own its allocation.
///
/// # Invariants
///
/// Every `&mut T` returned by the iterator references a `T` that the iterator may take ownership
/// of.
pub struct DrainAll<'vec, T> {
elements: slice::IterMut<'vec, T>,
}
impl<'vec, T> Iterator for DrainAll<'vec, T> {
type Item = T;
fn next(&mut self) -> Option<T> {
let elem: *mut T = self.elements.next()?;
// SAFETY: By the type invariants, we may take ownership of this value.
Some(unsafe { elem.read() })
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.elements.size_hint()
}
}
impl<'vec, T> Drop for DrainAll<'vec, T> {
fn drop(&mut self) {
if core::mem::needs_drop::<T>() {
let iter = core::mem::take(&mut self.elements);
let ptr: *mut [T] = iter.into_slice();
// SAFETY: By the type invariants, we own these values so we may destroy them.
unsafe { ptr::drop_in_place(ptr) };
}
}
}