55//! A linked list implementation.
66
77use crate :: init:: PinInit ;
8+ use crate :: sync:: ArcBorrow ;
89use crate :: types:: Opaque ;
10+ use core:: iter:: { DoubleEndedIterator , FusedIterator } ;
911use core:: marker:: PhantomData ;
1012use 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
442455impl < 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