combin_iterator/altern/
vec_altern.rs

1//! # VecAltern
2//!
3//! The `vec_altern` module provides an iterator, `VecAltern`, for alternately traversing multiple iterators.
4//!
5//! ## Usage
6//!
7//! To use `VecAltern`, create a new instance with `VecAltern::new()` and add iterators using the `add` method (or `add_and` for a build pattern).
8//! You can also use the macro `altern` for more concise syntax and little performance optimization.
9//! The `next` method will then yield elements from the added iterators in a round-robin fashion until all iterators are exhausted.
10//!
11//! ## Examples
12//!
13//! ```rust
14//! use combin_iterator::altern::VecAltern;
15//! let vec1 = vec![1, 4, 7, 9];
16//! let vec2 = vec![2, 5];
17//! let vec3 = vec![3, 6, 8];
18//!
19//! // // Create a VecAltern iterator and add individual iterators, with a build pattern.
20//! let mut iter = VecAltern::new();
21//! iter.add(vec1.iter());
22//! iter.add(vec2.iter());
23//! iter.add(vec3.iter());
24//!
25//! assert_eq!(iter.collect::<Vec<_>>(), vec![&1, &2, &3, &4, &5, &6, &7, &8, &9]);
26//!
27//! // You can also use a build pattern:
28//! let iter = VecAltern::new().add_and(vec1.iter()).add_and(vec2.iter()).add_and(vec3.iter());
29//! assert_eq!(iter.collect::<Vec<_>>(), vec![&1, &2, &3, &4, &5, &6, &7, &8, &9]);
30//!
31//! // Alternatively, use the `altern!` macro for a more concise syntax, and some perfomance optimization
32//! use combin_iterator::altern;
33//! let iter_macro = altern!(vec1.iter(), vec2.iter(), vec3.iter());
34//!
35//! // Both iterators should yield the same results
36//! assert_eq!(iter_macro.collect::<Vec<_>>(), vec![&1, &2, &3, &4, &5, &6, &7, &8, &9]);
37//! ```
38//!
39//! ## Notes
40//!
41//! - The `altern!` macro provides a convenient way to create an `Altern` iterator with a cleaner syntax, and
42//!   a little performance optimization (with the function: `with_capacity`, like in `Vec`). If you know at
43//!   compile time how many iter you will altern between, then use the `altern!` macro.
44
45
46/// Struct to altern between several iterator
47pub struct VecAltern<'a, A> {
48    iters: Vec<Box<dyn Iterator<Item = A> + 'a>>,
49    current: usize,
50}
51
52impl<'a, A> VecAltern<'a, A> {
53    /// Creates a new instance of an `Altern` iterator.
54    pub fn new() -> Self {
55        Self {
56            iters: vec![],
57            current: 0,
58        }
59    }
60
61    /// Prepare the capacity, like `vec::with_capacity` does.
62    pub fn with_capacity(capacity : usize) -> Self {
63        Self {
64            iters: Vec::with_capacity(capacity),
65            current: 0
66        }
67    }
68
69    /// Adds an iterator to the `Altern` instance.
70    ///
71    /// # Arguments
72    ///
73    /// * `iterator` - An iterator of references to elements of type `A`.
74    ///
75    /// # Returns
76    ///
77    /// The updated `Altern` instance with the added iterator, to use like a builder.
78    pub fn add_and(mut self, iterator: impl Iterator<Item = A> + 'a) -> Self {
79        self.iters.push(Box::new(iterator));
80        self
81    }
82
83    /// Adds an iterator to the `Altern` instance.
84    ///
85    /// # Arguments
86    ///
87    /// * `iterator` - An iterator of references to elements of type `A`.
88    ///
89    /// # Returns
90    pub fn add(&mut self, iterator: impl Iterator<Item = A> + 'a){
91        self.iters.push(Box::new(iterator));
92    }
93}
94
95impl<'a, A> Iterator for VecAltern<'a, A>
96{
97    type Item = A;
98
99
100    /// Returns the next element in the iteration sequence.
101    ///
102    /// The `next` method alternates between the added iterators in a round-robin fashion.
103    fn next(&mut self) -> Option<A> {
104        loop {
105            if self.iters.is_empty() {
106                return None;
107            } else {
108                let next;
109                match self.iters.get_mut(self.current) {
110                    Some(iter) => {
111                        next = (*iter).next()
112                    },
113                    None => {
114                        panic!("altern.current out of bound for altern.iters ")
115                    },
116                }
117
118                match next {
119                    Some(value) => {
120                        self.current = (self.current + 1) % self.iters.len();
121                        return Some(value)
122                    },
123                    None => {
124                        let _ = self.iters.remove(self.current);
125                        let n = self.iters.len().max(1);
126                        self.current = self.current % n;
127                    }
128                }
129            }
130        }
131    }
132}
133
134#[cfg(test)]
135mod tests {
136    use super::VecAltern;
137
138    #[test]
139    fn vec_altern() {
140        let vec1 = vec![1, 4, 7, 9];
141        let vec2 = vec![2, 5];
142        let vec3 = vec![3, 6, 8];
143
144        let iter = VecAltern::new().add_and(vec1.iter()).add_and(vec2.iter()).add_and(vec3.iter());
145
146        assert_eq!(iter.collect::<Vec<_>>(), vec![&1,&2,&3,&4,&5,&6,&7,&8, &9]);
147    }
148
149    #[test]
150    fn empty_vec_altern() {
151        let vec1 : Vec<u8> = vec![];
152        let vec2: Vec<u8> = vec![];
153        let vec3: Vec<u8> = vec![];
154
155        let mut iter = VecAltern::new().add_and(vec1.iter()).add_and(vec2.iter()).add_and(vec3.iter());
156
157        assert_eq!(iter.next(), None);
158    }
159
160    use crate::altern;
161    #[test]
162    fn macro_altern() {
163        let vec1 = vec![1, 4, 7, 9];
164        let vec2 = vec![2, 5];
165        let vec3 = vec![3, 6, 8];
166        let iter = altern!(vec1.iter(), vec2.iter(), vec3.iter());
167        assert_eq!(iter.collect::<Vec<_>>(), vec![&1,&2,&3,&4,&5,&6,&7,&8, &9]);
168    }
169}