Skip to content

Commit deeecc9

Browse files
Darksonnojeda
authored andcommitted
rust: list: add iterators
Rust Binder has lists containing stuff such as all contexts or all processes, and sometimes needs to iterate over them. This patch enables Rust Binder to do that using a normal for loop. The iterator returns the ArcBorrow type, so it is possible to grab a refcount to values while iterating. Reviewed-by: Benno Lossin <benno.lossin@proton.me> Signed-off-by: Alice Ryhl <aliceryhl@google.com> Link: https://lore.kernel.org/r/20240814-linked-list-v5-7-f5f5e8075da0@google.com Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
1 parent db84186 commit deeecc9

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed

rust/kernel/list.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
//! A linked list implementation.
66
77
use crate::init::PinInit;
8+
use crate::sync::ArcBorrow;
89
use crate::types::Opaque;
10+
use core::iter::{DoubleEndedIterator, FusedIterator};
911
use core::marker::PhantomData;
1012
use core::ptr;
1113

@@ -437,6 +439,17 @@ impl<T: ?Sized + ListItem<ID>, const ID: u64> List<T, ID> {
437439
// INVARIANT: The other list is now empty, so update its pointer.
438440
other.first = ptr::null_mut();
439441
}
442+
443+
/// Creates an iterator over the list.
444+
pub fn iter(&self) -> Iter<'_, T, ID> {
445+
// INVARIANT: If the list is empty, both pointers are null. Otherwise, both pointers point
446+
// at the first element of the same list.
447+
Iter {
448+
current: self.first,
449+
stop: self.first,
450+
_ty: PhantomData,
451+
}
452+
}
440453
}
441454

442455
impl<T: ?Sized + ListItem<ID>, const ID: u64> Default for List<T, ID> {
@@ -452,3 +465,92 @@ impl<T: ?Sized + ListItem<ID>, const ID: u64> Drop for List<T, ID> {
452465
}
453466
}
454467
}
468+
469+
/// An iterator over a [`List`].
470+
///
471+
/// # Invariants
472+
///
473+
/// * There must be a [`List`] that is immutably borrowed for the duration of `'a`.
474+
/// * The `current` pointer is null or points at a value in that [`List`].
475+
/// * The `stop` pointer is equal to the `first` field of that [`List`].
476+
#[derive(Clone)]
477+
pub struct Iter<'a, T: ?Sized + ListItem<ID>, const ID: u64 = 0> {
478+
current: *mut ListLinksFields,
479+
stop: *mut ListLinksFields,
480+
_ty: PhantomData<&'a ListArc<T, ID>>,
481+
}
482+
483+
impl<'a, T: ?Sized + ListItem<ID>, const ID: u64> Iterator for Iter<'a, T, ID> {
484+
type Item = ArcBorrow<'a, T>;
485+
486+
fn next(&mut self) -> Option<ArcBorrow<'a, T>> {
487+
if self.current.is_null() {
488+
return None;
489+
}
490+
491+
let current = self.current;
492+
493+
// SAFETY: We just checked that `current` is not null, so it is in a list, and hence not
494+
// dangling. There's no race because the iterator holds an immutable borrow to the list.
495+
let next = unsafe { (*current).next };
496+
// INVARIANT: If `current` was the last element of the list, then this updates it to null.
497+
// Otherwise, we update it to the next element.
498+
self.current = if next != self.stop {
499+
next
500+
} else {
501+
ptr::null_mut()
502+
};
503+
504+
// SAFETY: The `current` pointer points at a value in the list.
505+
let item = unsafe { T::view_value(ListLinks::from_fields(current)) };
506+
// SAFETY:
507+
// * All values in a list are stored in an `Arc`.
508+
// * The value cannot be removed from the list for the duration of the lifetime annotated
509+
// on the returned `ArcBorrow`, because removing it from the list would require mutable
510+
// access to the list. However, the `ArcBorrow` is annotated with the iterator's
511+
// lifetime, and the list is immutably borrowed for that lifetime.
512+
// * Values in a list never have a `UniqueArc` reference.
513+
Some(unsafe { ArcBorrow::from_raw(item) })
514+
}
515+
}
516+
517+
impl<'a, T: ?Sized + ListItem<ID>, const ID: u64> FusedIterator for Iter<'a, T, ID> {}
518+
519+
impl<'a, T: ?Sized + ListItem<ID>, const ID: u64> IntoIterator for &'a List<T, ID> {
520+
type IntoIter = Iter<'a, T, ID>;
521+
type Item = ArcBorrow<'a, T>;
522+
523+
fn into_iter(self) -> Iter<'a, T, ID> {
524+
self.iter()
525+
}
526+
}
527+
528+
/// An owning iterator into a [`List`].
529+
pub struct IntoIter<T: ?Sized + ListItem<ID>, const ID: u64 = 0> {
530+
list: List<T, ID>,
531+
}
532+
533+
impl<T: ?Sized + ListItem<ID>, const ID: u64> Iterator for IntoIter<T, ID> {
534+
type Item = ListArc<T, ID>;
535+
536+
fn next(&mut self) -> Option<ListArc<T, ID>> {
537+
self.list.pop_front()
538+
}
539+
}
540+
541+
impl<T: ?Sized + ListItem<ID>, const ID: u64> FusedIterator for IntoIter<T, ID> {}
542+
543+
impl<T: ?Sized + ListItem<ID>, const ID: u64> DoubleEndedIterator for IntoIter<T, ID> {
544+
fn next_back(&mut self) -> Option<ListArc<T, ID>> {
545+
self.list.pop_back()
546+
}
547+
}
548+
549+
impl<T: ?Sized + ListItem<ID>, const ID: u64> IntoIterator for List<T, ID> {
550+
type IntoIter = IntoIter<T, ID>;
551+
type Item = ListArc<T, ID>;
552+
553+
fn into_iter(self) -> IntoIter<T, ID> {
554+
IntoIter { list: self }
555+
}
556+
}

0 commit comments

Comments
 (0)