arch_pkg_db/text/multi/
iter.rs

1use super::MultiTextCollection;
2use crate::{
3    Text, TextCollection,
4    text::iter::{TextIntoIter, TextIter, TextIterMut},
5    value::RepositoryName,
6};
7use core::{iter::FusedIterator, slice};
8use std::vec;
9
10/// [Iterator] over immutable references to all items inside a [`MultiTextCollection`], each paired with
11/// their corresponding [`RepositoryName`].
12#[derive(Debug, Clone)]
13pub struct MultiTextIter<'a> {
14    current: Option<(RepositoryName<'a>, TextIter<'a>)>,
15    remaining: slice::Iter<'a, (RepositoryName<'a>, TextCollection)>,
16}
17
18impl<'a> MultiTextIter<'a> {
19    /// Construct an (effectively) empty iterator.
20    ///
21    /// This iterator requires at least one call to [`MultiTextIter::next_stage`] to become useful (i.e. non-empty).
22    fn blank(collections: &'a Vec<(RepositoryName<'a>, TextCollection)>) -> Self {
23        MultiTextIter {
24            current: None,
25            remaining: collections.iter(),
26        }
27    }
28
29    /// Extract an item from [`MultiTextIter::remaining`] into [`MultiTextIter::current`] after it has been exhausted.
30    fn next_stage(&mut self) {
31        debug_assert!(
32            self.current.is_none(),
33            "next_stage must only be called after current has been exhausted",
34        );
35        self.current = self
36            .remaining
37            .next()
38            .map(|(repository, collection)| (*repository, collection.iter()));
39    }
40}
41
42impl<'a> Iterator for MultiTextIter<'a> {
43    type Item = (RepositoryName<'a>, &'a Text);
44
45    fn next(&mut self) -> Option<Self::Item> {
46        loop {
47            let (repository, text_iter) = self.current.as_mut()?;
48
49            if let Some(text) = text_iter.next() {
50                return Some((*repository, text));
51            }
52
53            self.current = None;
54            self.next_stage();
55        }
56    }
57}
58
59impl FusedIterator for MultiTextIter<'_> {}
60
61impl<'a> MultiTextCollection<'a> {
62    /// Iterate over immutable references to all items inside a [`MultiTextCollection`], each paired with
63    /// their corresponding [`RepositoryName`].
64    pub fn iter(&'a self) -> MultiTextIter<'a> {
65        let mut iter = MultiTextIter::blank(&self.internal);
66        iter.next_stage();
67        iter
68    }
69}
70
71/// [Iterator] over mutable references to all items inside a [`MultiTextCollection`], each paired with
72/// their corresponding [`RepositoryName`].
73#[derive(Debug)]
74pub struct MultiTextIterMut<'a> {
75    current: Option<(RepositoryName<'a>, TextIterMut<'a>)>,
76    remaining: slice::IterMut<'a, (RepositoryName<'a>, TextCollection)>,
77}
78
79impl<'a> MultiTextIterMut<'a> {
80    /// Construct an (effectively) empty iterator.
81    ///
82    /// This iterator requires at least one call to [`MultiTextIterMut::next_stage`] to become useful (i.e. non-empty).
83    fn blank(collections: &'a mut Vec<(RepositoryName<'a>, TextCollection)>) -> Self {
84        MultiTextIterMut {
85            current: None,
86            remaining: collections.iter_mut(),
87        }
88    }
89
90    /// Extract an item from [`MultiTextIterMut::remaining`] into [`MultiTextIterMut::current`] after it has been exhausted.
91    fn next_stage(&mut self) {
92        debug_assert!(
93            self.current.is_none(),
94            "next_stage must only be called after current has been exhausted",
95        );
96        self.current = self
97            .remaining
98            .next()
99            .map(|(repository, collection)| (*repository, collection.iter_mut()));
100    }
101}
102
103impl<'a> Iterator for MultiTextIterMut<'a> {
104    type Item = (RepositoryName<'a>, &'a mut Text);
105
106    fn next(&mut self) -> Option<Self::Item> {
107        loop {
108            let (repository, text_iter) = self.current.as_mut()?;
109
110            if let Some(text) = text_iter.next() {
111                return Some((*repository, text));
112            }
113
114            self.current = None;
115            self.next_stage();
116        }
117    }
118}
119
120impl FusedIterator for MultiTextIterMut<'_> {}
121
122impl<'a> MultiTextCollection<'a> {
123    /// Iterate over mutable references to all items inside a [`MultiTextCollection`], each paired with
124    /// their corresponding [`RepositoryName`].
125    pub fn iter_mut(&'a mut self) -> MultiTextIterMut<'a> {
126        let mut iter = MultiTextIterMut::blank(&mut self.internal);
127        iter.next_stage();
128        iter
129    }
130}
131
132/// [Iterator] over owned items inside a [`MultiTextCollection`], each paired with their corresponding
133/// [`RepositoryName`].
134#[derive(Debug, Clone)]
135pub struct MultiTextIntoIter<'a> {
136    current: Option<(RepositoryName<'a>, TextIntoIter)>,
137    remaining: vec::IntoIter<(RepositoryName<'a>, TextCollection)>,
138}
139
140impl<'a> MultiTextIntoIter<'a> {
141    /// Construct an (effectively) empty iterator.
142    ///
143    /// This iterator requires at least one call to [`MultiTextIntoIter::next_stage`] to become useful (i.e. non-empty).
144    fn blank(collections: Vec<(RepositoryName<'a>, TextCollection)>) -> Self {
145        MultiTextIntoIter {
146            current: None,
147            remaining: collections.into_iter(),
148        }
149    }
150
151    /// Extract an item from [`MultiTextIntoIter::remaining`] into [`MultiTextIntoIter::current`] after it has been exhausted.
152    fn next_stage(&mut self) {
153        debug_assert!(
154            self.current.is_none(),
155            "next_stage must only be called after current has been exhausted",
156        );
157        self.current = self
158            .remaining
159            .next()
160            .map(|(repository, collection)| (repository, collection.into_iter()));
161    }
162}
163
164impl<'a> Iterator for MultiTextIntoIter<'a> {
165    type Item = (RepositoryName<'a>, Text);
166
167    fn next(&mut self) -> Option<Self::Item> {
168        loop {
169            let (repository, text_iter) = self.current.as_mut()?;
170
171            if let Some(text) = text_iter.next() {
172                return Some((*repository, text));
173            }
174
175            self.current = None;
176            self.next_stage();
177        }
178    }
179}
180
181impl FusedIterator for MultiTextIntoIter<'_> {}
182
183impl<'a> IntoIterator for MultiTextCollection<'a> {
184    type Item = (RepositoryName<'a>, Text);
185    type IntoIter = MultiTextIntoIter<'a>;
186
187    fn into_iter(self) -> Self::IntoIter {
188        let mut iter = MultiTextIntoIter::blank(self.internal);
189        iter.next_stage();
190        iter
191    }
192}