1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use std::fmt::{Debug, Formatter};

/// Iterator type that can wrap any kind of [`Iterator`].
///
/// This `struct` is a wrapper around types that implements `Iterator`
/// trait. Since we do not know which specific type of `Iterator` is
/// used, we `Box` it as a trait-object.
///
/// This iterator yields any type which usually depends on references on the
/// model.  Therefore, the iterator must outlive the wrapped `Iterator`.
///
/// [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html
pub struct DynIter<'iter, V> {
    iter: Box<dyn Iterator<Item = V> + 'iter>,
}

impl<V> Debug for DynIter<'_, V> {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        let size_str = match self.iter.size_hint() {
            (min, None) => format!("{}", min),
            (min, Some(max)) if min == max => format!("{}", min),
            (min, Some(max)) => format!("between {} and {}", min, max),
        };
        write!(f, "{{ iter: [Iterator with {} elements]}}", size_str,)
    }
}

impl<'iter, V> DynIter<'iter, V> {
    /// Instantiates an [`DynIter`] from any kind of [`Iterator`].
    ///
    /// [`DynIter`]: ./struct.DynIter.html
    /// [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html
    pub fn new<I>(iter: I) -> Self
    where
        I: Iterator<Item = V> + 'iter,
    {
        Self {
            iter: Box::new(iter),
        }
    }
}

impl<'iter, V> Iterator for DynIter<'iter, V> {
    type Item = V;
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next()
    }
}

#[cfg(test)]
mod tests {
    use super::DynIter;

    // This test is mostly checking that everything compiles and works as
    // expected.
    #[test]
    fn it_works() {
        let iter = (0..5).skip(2).filter(|n| *n != 3);
        let mut dyn_iter = DynIter::new(iter);
        assert_eq!(dyn_iter.next(), Some(2));
        assert_eq!(dyn_iter.next(), Some(4));
        assert_eq!(dyn_iter.next(), None);
    }
}