loro_thunderdome/iter/
into_iter.rs

1use core::iter::{ExactSizeIterator, FusedIterator};
2
3use crate::arena::{Arena, Index};
4
5/// Iterator typed used when an Arena is turned [`IntoIterator`].
6pub struct IntoIter<T> {
7    pub(crate) arena: Arena<T>,
8    pub(crate) slot: u32,
9}
10
11impl<T> Iterator for IntoIter<T> {
12    type Item = (Index, T);
13
14    fn next(&mut self) -> Option<Self::Item> {
15        loop {
16            // If there are no entries remaining in the arena, we should always
17            // return None. Using this check instead of comparing with the
18            // arena's size allows us to skip any trailing empty entries.
19            if self.arena.is_empty() {
20                return None;
21            }
22
23            // slot may overflow if the arena's underlying storage contains more
24            // than 2^32 elements, but its internal length value was not
25            // changed, as it overflowing would panic before reaching this code.
26            let slot = self.slot;
27            self.slot = self
28                .slot
29                .checked_add(1)
30                .unwrap_or_else(|| panic!("Overflowed u32 trying to into_iter Arena"));
31
32            // If this entry is occupied, this method will mark it as an empty.
33            // Otherwise, we'll continue looping until we've removed all
34            // occupied entries from the arena.
35            if let Some((index, value)) = self.arena.remove_by_slot(slot) {
36                return Some((index, value));
37            }
38        }
39    }
40
41    fn size_hint(&self) -> (usize, Option<usize>) {
42        (self.arena.len(), Some(self.arena.len()))
43    }
44}
45
46impl<T> FusedIterator for IntoIter<T> {}
47impl<T> ExactSizeIterator for IntoIter<T> {}
48
49#[cfg(all(test, feature = "std"))]
50mod test {
51    use crate::Arena;
52
53    use std::collections::HashSet;
54
55    #[test]
56    fn into_iter() {
57        let mut arena = Arena::with_capacity(2);
58        let one = arena.insert(1);
59        let two = arena.insert(2);
60
61        let mut pairs = HashSet::new();
62        let mut into_iter = arena.into_iter();
63        assert_eq!(into_iter.size_hint(), (2, Some(2)));
64
65        pairs.insert(into_iter.next().unwrap());
66        assert_eq!(into_iter.size_hint(), (1, Some(1)));
67
68        pairs.insert(into_iter.next().unwrap());
69        assert_eq!(into_iter.size_hint(), (0, Some(0)));
70
71        assert_eq!(into_iter.next(), None);
72        assert_eq!(into_iter.next(), None);
73        assert_eq!(into_iter.size_hint(), (0, Some(0)));
74
75        assert_eq!(pairs.len(), 2);
76        assert!(pairs.contains(&(one, 1)));
77        assert!(pairs.contains(&(two, 2)));
78    }
79}