From: "Alexandre Courbot" <acourbot@nvidia.com>
To: "Joel Fernandes" <joelagnelf@nvidia.com>,
<linux-kernel@vger.kernel.org>, <rust-for-linux@vger.kernel.org>,
<dri-devel@lists.freedesktop.org>,
<nouveau@lists.freedesktop.org>,
"Danilo Krummrich" <dakr@kernel.org>,
"Dave Airlie" <airlied@gmail.com>
Cc: "Alexandre Courbot" <acourbot@nvidia.com>,
"Alistair Popple" <apopple@nvidia.com>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Alex Gaynor" <alex.gaynor@gmail.com>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>, <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Simona Vetter" <simona@ffwll.ch>,
"Maarten Lankhorst" <maarten.lankhorst@linux.intel.com>,
"Maxime Ripard" <mripard@kernel.org>,
"Thomas Zimmermann" <tzimmermann@suse.de>,
"John Hubbard" <jhubbard@nvidia.com>,
"Timur Tabi" <ttabi@nvidia.com>,
"Joel Fernandes" <joel@joelfernandes.org>,
"Lyude Paul" <elle@weathered-steel.dev>,
"Daniel Almeida" <daniel.almeida@collabora.com>,
"Andrea Righi" <arighi@nvidia.com>,
"Philipp Stanner" <phasta@kernel.org>,
"Nouveau" <nouveau-bounces@lists.freedesktop.org>
Subject: Re: [PATCH v3] rust: clist: Add support to interface with C linked lists
Date: Wed, 03 Dec 2025 22:06:52 +0900 [thread overview]
Message-ID: <DEOLRLCZQMBG.1WHBR4YL8SKYR@nvidia.com> (raw)
In-Reply-To: <20251129213056.4021375-1-joelagnelf@nvidia.com>
On Sun Nov 30, 2025 at 6:30 AM JST, Joel Fernandes wrote:
<snip>
> +/// Low-level iterator over `list_head` nodes.
> +///
> +/// An iterator used to iterate over a C intrusive linked list (`list_head`). Caller has to
> +/// perform conversion of returned `ClistHead` to an item (using `container_of` macro or similar).
> +///
> +/// # Invariants
> +///
> +/// `ClistHeadIter` is iterating over an allocated, initialized and valid list.
> +struct ClistHeadIter<'a> {
> + current_head: &'a ClistHead,
> + list_head: &'a ClistHead,
> + exhausted: bool,
Mmm, I suspect `exhausted` is not needed at all - please see below.
> +}
> +
> +impl<'a> Iterator for ClistHeadIter<'a> {
> + type Item = &'a ClistHead;
> +
> + #[inline]
> + fn next(&mut self) -> Option<Self::Item> {
> + if self.exhausted {
> + return None;
> + }
> +
> + // Advance to next node.
> + self.current_head = self.current_head.next();
> +
> + // Check if we've circled back to the sentinel head.
> + if self.current_head == self.list_head {
> + self.exhausted = true;
> + return None;
> + }
> +
> + Some(self.current_head)
> + }
IIUC you could just rewrite this as
let next = self.current_head.next();
if next == self.list_head {
None
} else {
self.current_head = next;
Some(self.current_head)
}
and drop `exhausted` altogether.
> +}
> +
> +impl<'a> FusedIterator for ClistHeadIter<'a> {}
Is there a reason for not implementing `DoubleEndedIterator` as well?
> +
> +/// A typed C linked list with a sentinel head.
> +///
> +/// A sentinel head represents the entire linked list and can be used for
> +/// iteration over items of type `T`, it is not associated with a specific item.
> +///
> +/// # Invariants
> +///
> +/// - `head` is an allocated and valid C `list_head` structure that is the list's sentinel.
> +/// - `offset` is the byte offset of the `list_head` field within the C struct that `T` wraps.
> +///
> +/// # Safety
> +///
> +/// - All the list's `list_head` nodes must be allocated and have valid next/prev pointers.
> +/// - The underlying `list_head` (and entire list) must not be modified by C for the
> +/// lifetime 'a of `Clist`.
> +pub struct Clist<'a, T> {
> + head: &'a ClistHead,
> + offset: usize,
Joining the chorus suggesting to move `offset` to a const generic. Not
only will it make the struct smaller, it is also better because now
every single C `list_head` becomes its own `Clist` type, allowing you to
discriminate between them in the type system! Not that we will ever make
use of that, but still! :)
In my review of v2 I also suggested to use a closure as the generic
argument, and that the offset case could be a specialization, but
looking at this version I realize this was overengineered - just using
the offset should be enough for all cases, and is much more elegant, so
that looks like the right call indeed.
> + _phantom: PhantomData<&'a T>,
> +}
> +
> +impl<'a, T> Clist<'a, T> {
> + /// Create a typed `Clist` from a raw sentinel `list_head` pointer.
> + ///
> + /// The const generic `OFFSET` specifies the byte offset of the `list_head` field within
> + /// the C struct that `T` wraps.
> + ///
> + /// # Safety
> + ///
> + /// - `ptr` must be a valid pointer to an allocated and initialized `list_head` structure
> + /// representing a list sentinel.
> + /// - `ptr` must remain valid and unmodified for the lifetime `'a`.
> + /// - The list must contain items where the `list_head` field is at byte offset `OFFSET`.
> + /// - `T` must be `#[repr(transparent)]` over the C struct.
> + #[inline]
> + pub unsafe fn from_raw_and_offset<const OFFSET: usize>(ptr: *mut bindings::list_head) -> Self {
> + Self {
> + // SAFETY: Caller guarantees `ptr` is a valid, sentinel `list_head` object.
> + head: unsafe { ClistHead::from_raw(ptr) },
> + offset: OFFSET,
> + _phantom: PhantomData,
> + }
> + }
> +
> + /// Get the raw sentinel `list_head` pointer.
> + #[inline]
> + pub fn as_raw(&self) -> *mut bindings::list_head {
> + self.head.as_raw()
> + }
> +
> + /// Check if the list is empty.
> + #[inline]
> + pub fn is_empty(&self) -> bool {
> + let raw = self.as_raw();
> + // SAFETY: self.as_raw() is valid per type invariants.
> + unsafe { (*raw).next == raw }
> + }
> +
> + /// Create an iterator over typed items.
> + #[inline]
> + pub fn iter(&self) -> ClistIter<'a, T> {
> + ClistIter {
> + head_iter: ClistHeadIter {
> + current_head: self.head,
> + list_head: self.head,
> + exhausted: false,
> + },
> + offset: self.offset,
> + _phantom: PhantomData,
> + }
> + }
> +}
> +
> +/// High-level iterator over typed list items.
> +pub struct ClistIter<'a, T> {
> + head_iter: ClistHeadIter<'a>,
> + offset: usize,
Now that Clist's offset has moved to a const generic, let's do the same
here as well.
Overall I think this version looks pretty clean! A nice,
easy to understand wrapper over the C API.
next prev parent reply other threads:[~2025-12-03 13:07 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-29 21:30 [PATCH v3] rust: clist: Add support to interface with C linked lists Joel Fernandes
2025-12-01 0:34 ` John Hubbard
2025-12-01 20:32 ` Joel Fernandes
2025-12-01 20:57 ` Joel Fernandes
2025-12-01 22:17 ` John Hubbard
2025-12-01 22:43 ` Joel Fernandes
2025-12-01 22:52 ` John Hubbard
2025-12-01 23:09 ` Joel Fernandes
2025-12-01 23:15 ` John Hubbard
2025-12-01 23:21 ` Joel Fernandes
2025-12-01 22:58 ` Miguel Ojeda
2025-12-01 22:50 ` Miguel Ojeda
2025-12-01 22:54 ` John Hubbard
2025-12-01 15:25 ` Alice Ryhl
2025-12-01 21:35 ` Joel Fernandes
2025-12-01 16:51 ` Daniel Almeida
2025-12-01 19:35 ` John Hubbard
2025-12-01 20:06 ` Joel Fernandes
2025-12-01 23:01 ` Daniel Almeida
2025-12-01 23:23 ` Joel Fernandes
2025-12-01 22:54 ` Daniel Almeida
2025-12-01 22:58 ` Miguel Ojeda
2025-12-01 21:46 ` Joel Fernandes
2025-12-03 13:06 ` Alexandre Courbot [this message]
2025-12-03 15:08 ` Joel Fernandes
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=DEOLRLCZQMBG.1WHBR4YL8SKYR@nvidia.com \
--to=acourbot@nvidia.com \
--cc=a.hindborg@kernel.org \
--cc=airlied@gmail.com \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=apopple@nvidia.com \
--cc=arighi@nvidia.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=elle@weathered-steel.dev \
--cc=gary@garyguo.net \
--cc=jhubbard@nvidia.com \
--cc=joel@joelfernandes.org \
--cc=joelagnelf@nvidia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=maarten.lankhorst@linux.intel.com \
--cc=mripard@kernel.org \
--cc=nouveau-bounces@lists.freedesktop.org \
--cc=nouveau@lists.freedesktop.org \
--cc=ojeda@kernel.org \
--cc=phasta@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=simona@ffwll.ch \
--cc=tmgross@umich.edu \
--cc=ttabi@nvidia.com \
--cc=tzimmermann@suse.de \
/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.