5
5
//! A linked list implementation.
6
6
7
7
use crate :: init:: PinInit ;
8
+ use crate :: sync:: ArcBorrow ;
8
9
use crate :: types:: Opaque ;
10
+ use core:: iter:: { DoubleEndedIterator , FusedIterator } ;
9
11
use core:: marker:: PhantomData ;
10
12
use core:: ptr;
11
13
@@ -437,6 +439,17 @@ impl<T: ?Sized + ListItem<ID>, const ID: u64> List<T, ID> {
437
439
// INVARIANT: The other list is now empty, so update its pointer.
438
440
other. first = ptr:: null_mut ( ) ;
439
441
}
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
+ }
440
453
}
441
454
442
455
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> {
452
465
}
453
466
}
454
467
}
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