Re: [PATCH 6/9] rust: list: add iterators

From: Benno Lossin
Date: Thu Apr 04 2024 - 10:37:06 EST


On 02.04.24 14:17, Alice Ryhl wrote:
> @@ -414,3 +427,92 @@ fn drop(&mut self) {
> }
> }
> }
> +
> +/// An iterator into a [`List`].
> +///
> +/// # Invariants
> +///
> +/// The `current` pointer points at a value in a list, or it is null if the iterator has reached

I think "list" should link to [`List`].

> +/// the end of the list. The `stop` pointer points at the first value in the same list, or it is
> +/// null if the list is empty.
> +#[derive(Clone)]
> +pub struct Iter<'a, T: ?Sized + ListItem<ID>, const ID: u64 = 0> {
> + current: *mut ListLinksFields,
> + stop: *mut ListLinksFields,
> + _ty: PhantomData<&'a ListArc<T, ID>>,
> +}
> +
> +impl<'a, T: ?Sized + ListItem<ID>, const ID: u64> Iterator for Iter<'a, T, ID> {
> + type Item = ArcBorrow<'a, T>;
> +
> + fn next(&mut self) -> Option<ArcBorrow<'a, T>> {
> + if self.current.is_null() {
> + return None;
> + }
> +
> + let current = self.current;
> +
> + // SAFETY: We just checked that `current` is not null, so it is in a list, and hence not
> + // dangling. There's no race because the iterator holds an immutable borrow to the list.

This (that the iterator holds an immutable borrow) is not true (there
is no `&List` field in `Iter`), but you can make that an invariant
instead.

> + let next = unsafe { (*current).next };
> + // INVARIANT: If `current` was the last element of the list, then this updates it to null.
> + // Otherwise, we update it to the next element.
> + self.current = if next != self.stop {
> + next
> + } else {
> + ptr::null_mut()
> + };
> +
> + // SAFETY: The `current` pointer points a value in the list.

Typo: "points a value" -> "points at a value"

I think you should also use consistent naming when referring to the
elements/items/values of a list.

--
Cheers,
Benno

> + let item = unsafe { T::view_value(ListLinks::from_fields(current)) };
> + // SAFETY:
> + // * All values in a list are stored in an `Arc`.
> + // * The value cannot be removed from the list for the duration of the lifetime annotated
> + // on the returned `ArcBorrow`, because removing it from the list would require mutable
> + // access to the list. However, the `ArcBorrow` is annotated with the iterator's
> + // lifetime, and the list is immutably borrowed for that lifetime.
> + // * Values in a list never have a `UniqueArc` reference.
> + Some(unsafe { ArcBorrow::from_raw(item) })
> + }
> +}