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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// SPDX-License-Identifier: MIT
// Copyright 2024 IROX Contributors
//

//!
//! Iterators adds the [`Itertools`] Trait, which adds a number of additional
//! helper methods to the [`Iterator`] Trait.
//!

use self::join::Joining;
use self::looping_forever::LoopingForever;

extern crate alloc;

use crate::iterators::join::MultiJoining;
use alloc::vec::Vec;

mod join;
pub mod looping_forever;

///
/// Itertools adds helpful additional methods to [`Iterator`]
pub trait Itertools: Iterator {
    ///
    /// Returns an iterator that never ends, sequentially looping over all items in this
    /// iterator forever, unless there are no items in the iterator.
    fn looping_forever(self) -> LoopingForever<Self::Item>
    where
        Self: Sized + Iterator,
        Self::Item: Clone,
    {
        LoopingForever {
            index: 0,
            items: self.collect(),
        }
    }

    ///
    /// Collects a specific amount of items from the iterator.  The underlying iterator may return
    /// more, or less items than the specified count.  Any remaining uncollected items will be
    /// discarded.  If count is greater than the length of the underlying iterator, then the
    /// remainder of the returned vector will be None.
    #[must_use]
    fn collect_exact(mut self, count: usize) -> Vec<Option<Self::Item>>
    where
        Self: Sized + Iterator,
        Self::Item: Clone,
    {
        let mut out: Vec<Option<Self::Item>> = Vec::with_capacity(count);
        for _i in 0..count {
            out.push(self.next())
        }
        out
    }

    ///
    /// Same behavior as [`Itertools::collect_exact`], except rather than returning 'None' after the end, it
    /// returns the specified value
    #[must_use]
    fn collect_exact_or(mut self, count: usize, def: Self::Item) -> Vec<Self::Item>
    where
        Self: Sized + Iterator,
        Self::Item: Clone,
    {
        let mut out: Vec<Self::Item> = Vec::with_capacity(count);
        for _i in 0..count {
            out.push(self.next().unwrap_or(def.clone()))
        }
        out
    }

    ///
    /// Same behavior as [`Itertools::collect_exact`], except rather than returning 'None' after the end, it
    /// returns the default value
    #[must_use]
    fn collect_exact_or_default(mut self, count: usize) -> Vec<Self::Item>
    where
        Self: Sized + Iterator,
        Self::Item: Clone + Default,
    {
        let mut out: Vec<Self::Item> = Vec::with_capacity(count);
        for _i in 0..count {
            out.push(self.next().unwrap_or_default());
        }
        out
    }

    ///
    /// Collects and returns upto 'count' items from this iterator.  If this
    /// iterator is exhausted, the returned vector is empty.  Note, the returned
    /// vector may have *up to* the requested number of items if the iterator
    /// exhausts before filling the chunk.
    #[must_use]
    fn collect_next_chunk(&mut self, count: usize) -> Vec<Self::Item> {
        let mut out: Vec<Self::Item> = Vec::with_capacity(count);
        for _i in 0..count {
            match self.next() {
                Some(e) => out.push(e),
                None => break,
            }
        }
        out
    }

    ///
    /// Returns the elements in this iterator interspersed with the joining delimiter.
    /// For example, if this iterator contains `[A, B, C, D]` and the delimiter is `z`, then the
    /// final iteration sequence will be `[A, z, B, z, C, z, D]`
    #[must_use]
    fn joining(self, delim: Self::Item) -> Joining<Self, Self::Item>
    where
        Self: Sized,
        Self::Item: Clone,
    {
        Joining::new(self, delim)
    }

    ///
    /// Returns the elements in this iterator interspersed with the elements in the joining delimeter.
    /// For example, if this iterator contains `[A, B, C, D]` and the delimiters are `[1, 2]`, then
    /// the final iteration sequence will be `[A, 1, 2, B, 1, 2, C, 1, 2, D]`
    #[must_use]
    fn joining_multi(self, delim: &[Self::Item]) -> MultiJoining<Self, Self::Item>
    where
        Self: Sized,
        Self::Item: Clone,
    {
        MultiJoining::new(self, delim)
    }
}

impl<T: ?Sized> Itertools for T where T: Iterator {}