lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <Z5K4fPgPBNOJaJGl@boqun-archlinux>
Date: Thu, 23 Jan 2025 13:45:32 -0800
From: Boqun Feng <boqun.feng@...il.com>
To: Alice Ryhl <aliceryhl@...gle.com>
Cc: Miguel Ojeda <ojeda@...nel.org>, Alex Gaynor <alex.gaynor@...il.com>,
	Gary Guo <gary@...yguo.net>,
	Björn Roy Baron <bjorn3_gh@...tonmail.com>,
	Benno Lossin <benno.lossin@...ton.me>,
	Andreas Hindborg <a.hindborg@...nel.org>,
	Trevor Gross <tmgross@...ch.edu>, rust-for-linux@...r.kernel.org,
	linux-kernel@...r.kernel.org
Subject: Re: [PATCH v4 2/2] rust: list: make the cursor point between elements

On Thu, Jan 23, 2025 at 11:01:09AM +0000, Alice Ryhl wrote:
[...]
>  
>  /// A cursor into a [`List`].
>  ///
> +/// A cursor always rests between two elements in the list. This means that a cursor has a previous
> +/// and next element, but no current element. It also means that it's possible to have a cursor
> +/// into an empty list.
> +///
> +/// # Examples
> +///
> +/// ```
> +/// use kernel::prelude::*;
> +/// use kernel::list::{List, ListArc, ListLinks};
> +///
> +/// #[pin_data]
> +/// struct ListItem {
> +///     value: u32,
> +///     #[pin]
> +///     links: ListLinks,
> +/// }
> +///
> +/// impl ListItem {
> +///     fn new(value: u32) -> Result<ListArc<Self>> {
> +///         ListArc::pin_init(try_pin_init!(Self {
> +///             value,
> +///             links <- ListLinks::new(),
> +///         }), GFP_KERNEL)
> +///     }
> +/// }
> +///
> +/// kernel::list::impl_has_list_links! {
> +///     impl HasListLinks<0> for ListItem { self.links }
> +/// }
> +/// kernel::list::impl_list_arc_safe! {
> +///     impl ListArcSafe<0> for ListItem { untracked; }
> +/// }
> +/// kernel::list::impl_list_item! {
> +///     impl ListItem<0> for ListItem { using ListLinks; }
> +/// }
> +///
> +/// // Use a cursor to remove the first element with the given value.
> +/// fn remove_first(list: &mut List<ListItem>, value: u32) -> Option<ListArc<ListItem>> {
> +///     let mut cursor = list.cursor_front();
> +///     while let Some(next) = cursor.peek_next() {
> +///         if next.value == value {
> +///             return Some(next.remove());
> +///         }
> +///         cursor.move_next();
> +///     }
> +///     None
> +/// }
> +///
> +/// // Use a cursor to remove all elements with the given value. The removed elements are moved to
> +/// // a new list.
> +/// fn remove_all(list: &mut List<ListItem>, value: u32) -> List<ListItem> {
> +///     let mut out = List::new();
> +///     let mut cursor = list.cursor_front();
> +///     while let Some(next) = cursor.peek_next() {
> +///         if next.value == value {
> +///             out.push_back(next.remove());
> +///         } else {
> +///             cursor.move_next();
> +///         }
> +///     }
> +///     out
> +/// }
> +///
> +/// // Use a cursor to insert a value at a specific index. Returns an error if the index is out of
> +/// // bounds.
> +/// fn insert_at(list: &mut List<ListItem>, new: ListArc<ListItem>, idx: usize) -> Result {
> +///     let mut cursor = list.cursor_front();
> +///     for _ in 0..idx {
> +///         if !cursor.move_next() {
> +///             return Err(EINVAL);
> +///         }
> +///     }
> +///     cursor.insert_next(new);
> +///     Ok(())
> +/// }
> +///
> +/// // Merge two sorted lists into a single sorted list.
> +/// fn merge_sorted(list: &mut List<ListItem>, merge: List<ListItem>) {
> +///     let mut cursor = list.cursor_front();
> +///     for to_insert in merge {
> +///         while let Some(next) = cursor.peek_next() {
> +///             if to_insert.value < next.value {
> +///                 break;
> +///             }
> +///             cursor.move_next();
> +///         }
> +///         cursor.insert_prev(to_insert);
> +///     }
> +/// }
> +///
> +/// let mut list = List::new();
> +/// list.push_back(ListItem::new(14)?);
> +/// list.push_back(ListItem::new(12)?);
> +/// list.push_back(ListItem::new(10)?);
> +/// list.push_back(ListItem::new(12)?);
> +/// list.push_back(ListItem::new(14)?);
> +/// assert_eq!(remove_all(&mut list, 12).iter().count(), 2);
> +/// // [14, 10, 14]
> +/// assert!(remove_first(&mut list, 14).is_some());
> +/// // [10, 14]
> +/// insert_at(&mut list, ListItem::new(12)?, 1)?;
> +/// // [10, 12, 14]
> +///
> +/// let mut list2 = List::new();
> +/// list.push_back(ListItem::new(11)?);
> +/// list.push_back(ListItem::new(13)?);

These need to be `list2` instead of `list`, otherwise the doctest will
fail.

> +/// merge_sorted(&mut list, list2);
> +///
> +/// let mut items = list.into_iter();
> +/// assert_eq!(items.next().unwrap().value, 10);
> +/// assert_eq!(items.next().unwrap().value, 11);
> +/// assert_eq!(items.next().unwrap().value, 12);
> +/// assert_eq!(items.next().unwrap().value, 13);
> +/// assert_eq!(items.next().unwrap().value, 14);
> +/// assert!(items.next().is_none());
> +/// # Result::<(), Error>::Ok(())
> +/// ```
> +///
>  /// # Invariants
>  ///
> -/// The `current` pointer points a value in `list`.
> +/// The `next` pointer is null or points a value in `list`.
>  pub struct Cursor<'a, T: ?Sized + ListItem<ID>, const ID: u64 = 0> {
> -    current: *mut ListLinksFields,
>      list: &'a mut List<T, ID>,
> +    /// Points at the element after this cursor, or null if the cursor is after the last element.
> +    next: *mut ListLinksFields,
>  }
>  
[...]

While we are at it, could you also add a doc test that uses
`cursor_back()` and `move_prev()`? Something like below, that would
show (and at least test a bit on) the API for another direction.

With all these, feel free to add:

Reviewed-by: Boqun Feng <boqun.feng@...il.com>

Regards,
Boqun

------>8
diff --git a/rust/kernel/list.rs b/rust/kernel/list.rs
index b83016e5bcd9..2d38fbaf94e3 100644
--- a/rust/kernel/list.rs
+++ b/rust/kernel/list.rs
@@ -625,6 +625,18 @@ fn next(&mut self) -> Option<ArcBorrow<'a, T>> {
 ///     None
 /// }
 ///
+/// // Use a cursor to remove the last element with the given value.
+/// fn remove_last(list: &mut List<ListItem>, value: u32) -> Option<ListArc<ListItem>> {
+///     let mut cursor = list.cursor_back();
+///     while let Some(prev) = cursor.peek_prev() {
+///         if prev.value == value {
+///             return Some(prev.remove());
+///         }
+///         cursor.move_prev();
+///     }
+///     None
+/// }
+///
 /// // Use a cursor to remove all elements with the given value. The removed elements are moved to
 /// // a new list.
 /// fn remove_all(list: &mut List<ListItem>, value: u32) -> List<ListItem> {
@@ -672,12 +684,15 @@ fn next(&mut self) -> Option<ArcBorrow<'a, T>> {
 /// list.push_back(ListItem::new(12)?);
 /// list.push_back(ListItem::new(10)?);
 /// list.push_back(ListItem::new(12)?);
+/// list.push_back(ListItem::new(15)?);
 /// list.push_back(ListItem::new(14)?);
 /// assert_eq!(remove_all(&mut list, 12).iter().count(), 2);
-/// // [14, 10, 14]
+/// // [14, 10, 15, 14]
 /// assert!(remove_first(&mut list, 14).is_some());
+/// // [10, 15, 14]
+/// assert!(remove_last(&mut list, 15).is_some());
 /// // [10, 14]
 /// insert_at(&mut list, ListItem::new(12)?, 1)?;
 /// // [10, 12, 14]
 ///
 /// let mut list2 = List::new();

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ