rust-for-linux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: [PATCH 4/5] rust: alloc: add Vec::drain_all
@ 2025-03-20 22:06 Benno Lossin
  2025-03-21  7:54 ` Alice Ryhl
  0 siblings, 1 reply; 7+ messages in thread
From: Benno Lossin @ 2025-03-20 22:06 UTC (permalink / raw)
  To: Alice Ryhl, Danilo Krummrich; +Cc: rust-for-linux, linux-kernel

On Thu Mar 20, 2025 at 2:52 PM CET, Alice Ryhl wrote:
> 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.

Is the reason for not implementing `drain` complexity?

> 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>

The code is good, but I'd like to know the answer to the above question
before giving my RB.

> ---
>  rust/kernel/alloc/kvec.rs | 57 +++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 57 insertions(+)
>
> diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs
> index df930ff0d0b85b8b03c9b7932a2b31dfb62612ed..303198509885f5e24b74da5a92382b518de3e1c0 100644
> --- a/rust/kernel/alloc/kvec.rs
> +++ b/rust/kernel/alloc/kvec.rs
> @@ -564,6 +564,30 @@ pub fn truncate(&mut self, len: usize) {
>          //   len, therefore we have exclusive access to [`new_len`, `old_len`)
>          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);
> +    /// ```
> +    pub fn drain_all(&mut self) -> DrainAll<'_, T> {
> +        let len = self.len();
> +        // INVARIANT: The first 0 elements are valid.
> +        self.len = 0;

Why not `set_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: self.spare_capacity_mut()[..len].iter_mut(),
> +        }
> +    }
>  }
>  
>  impl<T: Clone, A: Allocator> Vec<T, A> {
> @@ -1049,3 +1073,36 @@ fn into_iter(self) -> Self::IntoIter {
>          }
>      }
>  }
> +
> +/// An iterator that owns all items in a vector, but does not own its allocation.
> +///
> +/// # Invariants
> +///
> +/// Every `&mut MaybeUninit<T>` returned by the iterator contains a valid `T` owned by this
> +/// `DrainAll`.
> +pub struct DrainAll<'vec, T> {
> +    elements: slice::IterMut<'vec, MaybeUninit<T>>,
> +}
> +
> +impl<'vec, T> Iterator for DrainAll<'vec, T> {
> +    type Item = T;
> +
> +    fn next(&mut self) -> Option<T> {
> +        let elem = self.elements.next()?;
> +        // SAFETY: By the type invariants, we may take ownership of the value in this
> +        // `MaybeUninit<T>`.
> +        Some(unsafe { elem.assume_init_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>() {

This is neat!

---
Cheers,
Benno

> +            while self.next().is_some() {}
> +        }
> +    }
> +}



^ permalink raw reply	[flat|nested] 7+ messages in thread
* Re: [PATCH 4/5] rust: alloc: add Vec::drain_all
@ 2025-03-21  9:53 Benno Lossin
  0 siblings, 0 replies; 7+ messages in thread
From: Benno Lossin @ 2025-03-21  9:53 UTC (permalink / raw)
  To: Alice Ryhl, Danilo Krummrich; +Cc: rust-for-linux, linux-kernel

On Thu Mar 20, 2025 at 2:52 PM CET, Alice Ryhl wrote:
> 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>
> ---
>  rust/kernel/alloc/kvec.rs | 57 +++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 57 insertions(+)
>
> diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs
> index df930ff0d0b85b8b03c9b7932a2b31dfb62612ed..303198509885f5e24b74da5a92382b518de3e1c0 100644
> --- a/rust/kernel/alloc/kvec.rs
> +++ b/rust/kernel/alloc/kvec.rs
> @@ -564,6 +564,30 @@ pub fn truncate(&mut self, len: usize) {
>          //   len, therefore we have exclusive access to [`new_len`, `old_len`)
>          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);
> +    /// ```
> +    pub fn drain_all(&mut self) -> DrainAll<'_, T> {
> +        let len = self.len();
> +        // INVARIANT: The first 0 elements are valid.
> +        self.len = 0;

With this changed to `set_len` (or `dec_len` if only that is available):

Reviewed-by: Benno Lossin <benno.lossin@proton.me>

---
Cheers,
Benno

> +        // 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: self.spare_capacity_mut()[..len].iter_mut(),
> +        }
> +    }
>  }
>  
>  impl<T: Clone, A: Allocator> Vec<T, A> {


^ permalink raw reply	[flat|nested] 7+ messages in thread
* [PATCH 0/5] Additional methods for Vec
@ 2025-03-20 13:52 Alice Ryhl
  2025-03-20 13:52 ` [PATCH 4/5] rust: alloc: add Vec::drain_all Alice Ryhl
  0 siblings, 1 reply; 7+ messages in thread
From: Alice Ryhl @ 2025-03-20 13:52 UTC (permalink / raw)
  To: Danilo Krummrich; +Cc: rust-for-linux, linux-kernel, Alice Ryhl

This adds various Vec methods. Some of them are needed by Rust Binder,
and others are needed in other places. Each commit explains where it is
needed.

I'm not sure what we concluded on the set_len / dec_len changes, so I
don't depend on that series for now.

This series is based on top of Vec::truncate from
https://lore.kernel.org/rust-for-linux/20250316111644.154602-1-andrewjballance@gmail.com/

Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
Alice Ryhl (5):
      rust: alloc: add Vec::clear
      rust: alloc: add Vec::pop
      rust: alloc: add Vec::push_within_capacity
      rust: alloc: add Vec::drain_all
      rust: alloc: add Vec::retain

 rust/kernel/alloc/kvec.rs | 147 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 147 insertions(+)
---
base-commit: a337a03281efc4553191b432d757d4c04884bf4c
change-id: 20250320-vec-methods-adfa41e55311

Best regards,
-- 
Alice Ryhl <aliceryhl@google.com>


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2025-03-21  9:53 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-20 22:06 [PATCH 4/5] rust: alloc: add Vec::drain_all Benno Lossin
2025-03-21  7:54 ` Alice Ryhl
2025-03-21  9:52   ` Benno Lossin
  -- strict thread matches above, loose matches on Subject: below --
2025-03-21  9:53 Benno Lossin
2025-03-20 13:52 [PATCH 0/5] Additional methods for Vec Alice Ryhl
2025-03-20 13:52 ` [PATCH 4/5] rust: alloc: add Vec::drain_all Alice Ryhl
2025-03-20 22:12   ` Tamir Duberstein
2025-03-21  7:41     ` Alice Ryhl

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).