All of lore.kernel.org
 help / color / mirror / Atom feed
From: Danilo Krummrich <dakr@kernel.org>
To: ojeda@kernel.org, alex.gaynor@gmail.com, wedsonaf@gmail.com,
	boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com,
	benno.lossin@proton.me, a.hindborg@samsung.com,
	aliceryhl@google.com, akpm@linux-foundation.org
Cc: daniel.almeida@collabora.com, faith.ekstrand@collabora.com,
	boris.brezillon@collabora.com, lina@asahilina.net,
	mcanal@igalia.com, zhiw@nvidia.com, cjia@nvidia.com,
	jhubbard@nvidia.com, airlied@redhat.com, ajanulgu@redhat.com,
	lyude@redhat.com, linux-kernel@vger.kernel.org,
	rust-for-linux@vger.kernel.org, linux-mm@kvack.org,
	Danilo Krummrich <dakr@kernel.org>
Subject: [PATCH v7 14/26] rust: alloc: implement `IntoIterator` for `Vec`
Date: Thu, 12 Sep 2024 00:52:50 +0200	[thread overview]
Message-ID: <20240911225449.152928-15-dakr@kernel.org> (raw)
In-Reply-To: <20240911225449.152928-1-dakr@kernel.org>

Implement `IntoIterator` for `Vec`, `Vec`'s `IntoIter` type, as well as
`Iterator` for `IntoIter`.

`Vec::into_iter` disassembles the `Vec` into its raw parts; additionally,
`IntoIter` keeps track of a separate pointer, which is incremented
correspondingsly as the iterator advances, while the length, or the count
of elements, is decremented.

This also means that `IntoIter` takes the ownership of the backing
buffer and is responsible to drop the remaining elements and free the
backing buffer, if it's dropped.

Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/alloc.rs      |   1 +
 rust/kernel/alloc/kvec.rs | 181 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 182 insertions(+)

diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs
index 4fb983b63d46..e8fbae2adadb 100644
--- a/rust/kernel/alloc.rs
+++ b/rust/kernel/alloc.rs
@@ -19,6 +19,7 @@
 pub use self::kbox::KVBox;
 pub use self::kbox::VBox;
 
+pub use self::kvec::IntoIter;
 pub use self::kvec::KVVec;
 pub use self::kvec::KVec;
 pub use self::kvec::VVec;
diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs
index 631a44e19f35..e91761c5c52d 100644
--- a/rust/kernel/alloc/kvec.rs
+++ b/rust/kernel/alloc/kvec.rs
@@ -14,6 +14,7 @@
     ops::DerefMut,
     ops::Index,
     ops::IndexMut,
+    ptr,
     ptr::NonNull,
     slice,
     slice::SliceIndex,
@@ -636,3 +637,183 @@ fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] }
 impl_slice_eq! { [A: Allocator] [T], Vec<U, A> }
 impl_slice_eq! { [A: Allocator, const N: usize] Vec<T, A>, [U; N] }
 impl_slice_eq! { [A: Allocator, const N: usize] Vec<T, A>, &[U; N] }
+
+impl<'a, T, A> IntoIterator for &'a Vec<T, A>
+where
+    A: Allocator,
+{
+    type Item = &'a T;
+    type IntoIter = slice::Iter<'a, T>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter()
+    }
+}
+
+impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec<T, A>
+where
+    A: Allocator,
+{
+    type Item = &'a mut T;
+    type IntoIter = slice::IterMut<'a, T>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter_mut()
+    }
+}
+
+/// An [`Iterator`] implementation for [`Vec`] that moves elements out of a vector.
+///
+/// This structure is created by the [`Vec::into_iter`] method on [`Vec`] (provided by the
+/// [`IntoIterator`] trait).
+///
+/// # Examples
+///
+/// ```
+/// let v = kernel::kvec![0, 1, 2]?;
+/// let iter = v.into_iter();
+///
+/// # Ok::<(), Error>(())
+/// ```
+pub struct IntoIter<T, A: Allocator> {
+    ptr: *mut T,
+    buf: NonNull<T>,
+    len: usize,
+    cap: usize,
+    _p: PhantomData<A>,
+}
+
+impl<T, A> IntoIter<T, A>
+where
+    A: Allocator,
+{
+    fn as_raw_mut_slice(&mut self) -> *mut [T] {
+        ptr::slice_from_raw_parts_mut(self.ptr, self.len)
+    }
+}
+
+impl<T, A> Iterator for IntoIter<T, A>
+where
+    A: Allocator,
+{
+    type Item = T;
+
+    /// # Examples
+    ///
+    /// ```
+    /// let v = kernel::kvec![1, 2, 3]?;
+    /// let mut it = v.into_iter();
+    ///
+    /// assert_eq!(it.next(), Some(1));
+    /// assert_eq!(it.next(), Some(2));
+    /// assert_eq!(it.next(), Some(3));
+    /// assert_eq!(it.next(), None);
+    ///
+    /// # Ok::<(), Error>(())
+    /// ```
+    fn next(&mut self) -> Option<T> {
+        if self.len == 0 {
+            return None;
+        }
+
+        let current = self.ptr;
+
+        // SAFETY: We can't overflow; decreasing `self.len` by one every time we advance `self.ptr`
+        // by one guarantees that.
+        unsafe { self.ptr = self.ptr.add(1) };
+
+        self.len -= 1;
+
+        // SAFETY: `current` is guaranteed to point at a valid element within the buffer.
+        Some(unsafe { current.read() })
+    }
+
+    /// # Examples
+    ///
+    /// ```
+    /// let v: KVec<u32> = kernel::kvec![1, 2, 3]?;
+    /// let mut iter = v.into_iter();
+    /// let size = iter.size_hint().0;
+    ///
+    /// iter.next();
+    /// assert_eq!(iter.size_hint().0, size - 1);
+    ///
+    /// iter.next();
+    /// assert_eq!(iter.size_hint().0, size - 2);
+    ///
+    /// iter.next();
+    /// assert_eq!(iter.size_hint().0, size - 3);
+    ///
+    /// # Ok::<(), Error>(())
+    /// ```
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (self.len, Some(self.len))
+    }
+}
+
+impl<T, A> Drop for IntoIter<T, A>
+where
+    A: Allocator,
+{
+    fn drop(&mut self) {
+        // SAFETY: The pointer in `self.0` is guaranteed to be valid by the type invariant.
+        unsafe { ptr::drop_in_place(self.as_raw_mut_slice()) };
+
+        // If `cap == 0` we never allocated any memory in the first place.
+        if self.cap != 0 {
+            // SAFETY: `self.buf` was previously allocated with `A`.
+            unsafe { A::free(self.buf.cast()) };
+        }
+    }
+}
+
+impl<T, A> IntoIterator for Vec<T, A>
+where
+    A: Allocator,
+{
+    type Item = T;
+    type IntoIter = IntoIter<T, A>;
+
+    /// Consumes the `Vec<T, A>` and creates an `Iterator`, which moves each value out of the
+    /// vector (from start to end).
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let v = kernel::kvec![1, 2]?;
+    /// let mut v_iter = v.into_iter();
+    ///
+    /// let first_element: Option<u32> = v_iter.next();
+    ///
+    /// assert_eq!(first_element, Some(1));
+    /// assert_eq!(v_iter.next(), Some(2));
+    /// assert_eq!(v_iter.next(), None);
+    ///
+    /// # Ok::<(), Error>(())
+    /// ```
+    ///
+    /// ```
+    /// let v = kernel::kvec![];
+    /// let mut v_iter = v.into_iter();
+    ///
+    /// let first_element: Option<u32> = v_iter.next();
+    ///
+    /// assert_eq!(first_element, None);
+    ///
+    /// # Ok::<(), Error>(())
+    /// ```
+    #[inline]
+    fn into_iter(self) -> Self::IntoIter {
+        let (ptr, len, cap) = self.into_raw_parts();
+
+        IntoIter {
+            ptr,
+            // SAFETY: `ptr` is either a dangling pointer or a pointer to a valid memory
+            // allocation, allocated with `A`.
+            buf: unsafe { NonNull::new_unchecked(ptr) },
+            len,
+            cap,
+            _p: PhantomData::<A>,
+        }
+    }
+}
-- 
2.46.0


  parent reply	other threads:[~2024-09-11 22:56 UTC|newest]

Thread overview: 77+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-09-11 22:52 [PATCH v7 00/26] Generic `Allocator` support for Rust Danilo Krummrich
2024-09-11 22:52 ` [PATCH v7 01/26] rust: alloc: add `Allocator` trait Danilo Krummrich
2024-09-15 15:28   ` Gary Guo
2024-09-15 17:02     ` Danilo Krummrich
2024-09-15 19:22       ` Gary Guo
2024-09-15 20:08         ` Gary Guo
2024-09-15 21:39           ` Danilo Krummrich
2024-09-15 21:37         ` Danilo Krummrich
2024-09-21 15:32   ` [RFC PATCH] rust: alloc: pass `old_layout` to `Allocator` Danilo Krummrich
2024-09-23 13:56     ` Alice Ryhl
2024-09-23 15:20       ` Benno Lossin
2024-09-23 16:13       ` Gary Guo
2024-09-24 13:31         ` Danilo Krummrich
2024-09-24 13:34           ` Danilo Krummrich
2024-09-24 19:58           ` Gary Guo
2024-09-11 22:52 ` [PATCH v7 02/26] rust: alloc: separate `aligned_size` from `krealloc_aligned` Danilo Krummrich
2024-09-11 22:52 ` [PATCH v7 03/26] rust: alloc: rename `KernelAllocator` to `Kmalloc` Danilo Krummrich
2024-09-11 22:52 ` [PATCH v7 04/26] rust: alloc: implement `Allocator` for `Kmalloc` Danilo Krummrich
2024-09-26 13:00   ` Benno Lossin
2024-09-26 13:24     ` Danilo Krummrich
2024-09-26 14:00       ` Benno Lossin
2024-09-11 22:52 ` [PATCH v7 05/26] rust: alloc: add module `allocator_test` Danilo Krummrich
2024-09-11 22:52 ` [PATCH v7 06/26] rust: alloc: implement `Vmalloc` allocator Danilo Krummrich
2024-09-26 13:06   ` Benno Lossin
2024-09-11 22:52 ` [PATCH v7 07/26] rust: alloc: implement `KVmalloc` allocator Danilo Krummrich
2024-09-26 13:07   ` Benno Lossin
2024-09-11 22:52 ` [PATCH v7 08/26] rust: alloc: add __GFP_NOWARN to `Flags` Danilo Krummrich
2024-09-28 18:55   ` Gary Guo
2024-09-11 22:52 ` [PATCH v7 09/26] rust: alloc: implement kernel `Box` Danilo Krummrich
2024-09-26 13:23   ` Benno Lossin
2024-09-28 18:54   ` Gary Guo
2024-09-11 22:52 ` [PATCH v7 10/26] rust: treewide: switch to our kernel `Box` type Danilo Krummrich
2024-09-28 18:59   ` Gary Guo
2024-09-29 14:52     ` Danilo Krummrich
2024-09-11 22:52 ` [PATCH v7 11/26] rust: alloc: remove extension of std's `Box` Danilo Krummrich
2024-09-28 19:00   ` Gary Guo
2024-09-11 22:52 ` [PATCH v7 12/26] rust: alloc: add `Box` to prelude Danilo Krummrich
2024-09-28 19:00   ` Gary Guo
2024-09-11 22:52 ` [PATCH v7 13/26] rust: alloc: implement kernel `Vec` type Danilo Krummrich
2024-09-26 13:47   ` Benno Lossin
2024-09-28 12:43     ` Danilo Krummrich
2024-09-28 13:20       ` Benno Lossin
2024-09-28 19:14   ` Gary Guo
2024-09-11 22:52 ` Danilo Krummrich [this message]
2024-09-26 13:53   ` [PATCH v7 14/26] rust: alloc: implement `IntoIterator` for `Vec` Benno Lossin
2024-09-28 19:20   ` Gary Guo
2024-09-11 22:52 ` [PATCH v7 15/26] rust: alloc: implement `collect` for `IntoIter` Danilo Krummrich
2024-09-26 13:57   ` Benno Lossin
2024-09-28 19:27   ` Gary Guo
2024-09-29 15:12     ` Danilo Krummrich
2024-09-11 22:52 ` [PATCH v7 16/26] rust: treewide: switch to the kernel `Vec` type Danilo Krummrich
2024-09-28 19:28   ` Gary Guo
2024-09-11 22:52 ` [PATCH v7 17/26] rust: alloc: remove `VecExt` extension Danilo Krummrich
2024-09-28 19:29   ` Gary Guo
2024-09-11 22:52 ` [PATCH v7 18/26] rust: alloc: add `Vec` to prelude Danilo Krummrich
2024-09-28 19:29   ` Gary Guo
2024-09-11 22:52 ` [PATCH v7 19/26] rust: error: use `core::alloc::LayoutError` Danilo Krummrich
2024-09-28 19:30   ` Gary Guo
2024-09-11 22:52 ` [PATCH v7 20/26] rust: error: check for config `test` in `Error::name` Danilo Krummrich
2024-09-28 19:30   ` Gary Guo
2024-09-11 22:52 ` [PATCH v7 21/26] rust: alloc: implement `contains` for `Flags` Danilo Krummrich
2024-09-28 19:31   ` Gary Guo
2024-09-11 22:52 ` [PATCH v7 22/26] rust: alloc: implement `Cmalloc` in module allocator_test Danilo Krummrich
2024-09-28 19:35   ` Gary Guo
2024-09-29 15:14     ` Danilo Krummrich
2024-09-11 22:52 ` [PATCH v7 23/26] rust: str: test: replace `alloc::format` Danilo Krummrich
2024-09-28 19:37   ` Gary Guo
2024-09-11 22:53 ` [PATCH v7 24/26] rust: alloc: update module comment of alloc.rs Danilo Krummrich
2024-09-28 19:38   ` Gary Guo
2024-09-11 22:53 ` [PATCH v7 25/26] kbuild: rust: remove the `alloc` crate and `GlobalAlloc` Danilo Krummrich
2024-09-28 19:43   ` Gary Guo
2024-09-29 15:17     ` Danilo Krummrich
2024-10-01 13:27       ` Danilo Krummrich
2024-10-03 21:41     ` Miguel Ojeda
2024-10-03 21:53       ` Danilo Krummrich
2024-10-03 22:49         ` Miguel Ojeda
2024-09-11 22:53 ` [PATCH v7 26/26] MAINTAINERS: add entry for the Rust `alloc` module Danilo Krummrich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240911225449.152928-15-dakr@kernel.org \
    --to=dakr@kernel.org \
    --cc=a.hindborg@samsung.com \
    --cc=airlied@redhat.com \
    --cc=ajanulgu@redhat.com \
    --cc=akpm@linux-foundation.org \
    --cc=alex.gaynor@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=benno.lossin@proton.me \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun.feng@gmail.com \
    --cc=boris.brezillon@collabora.com \
    --cc=cjia@nvidia.com \
    --cc=daniel.almeida@collabora.com \
    --cc=faith.ekstrand@collabora.com \
    --cc=gary@garyguo.net \
    --cc=jhubbard@nvidia.com \
    --cc=lina@asahilina.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=lyude@redhat.com \
    --cc=mcanal@igalia.com \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=wedsonaf@gmail.com \
    --cc=zhiw@nvidia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.