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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Copyright Materialize, Inc. and contributors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License in the LICENSE file at the
// root of this repository, or online at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Iterator utilities.

use std::fmt::Debug;
use std::iter::{self, Chain, Once, Peekable};

/// Extension methods for iterators.
pub trait IteratorExt
where
    Self: Iterator + Sized,
{
    /// Chains a single `item` onto the end of this iterator.
    ///
    /// Equivalent to `self.chain(iter::once(item))`.
    fn chain_one(self, item: Self::Item) -> Chain<Self, Once<Self::Item>> {
        self.chain(iter::once(item))
    }

    /// Reports whether all the elements of the iterator are the same.
    ///
    /// This condition is trivially true for iterators with zero or one elements.
    fn all_equal(mut self) -> bool
    where
        Self::Item: PartialEq,
    {
        match self.next() {
            None => true,
            Some(v1) => self.all(|v2| v1 == v2),
        }
    }

    /// Converts the the iterator into an `ExactSizeIterator` reporting the given size.
    ///
    /// The caller is responsible for providing the correct size of the iterator! Providing an
    /// incorrect size value will lead to panics and/or incorrect responses to size queries.
    ///
    /// # Panics
    ///
    /// Panics if the given length is not consistent with this iterator's `size_hint`.
    fn exact_size(self, len: usize) -> ExactSize<Self> {
        let (lower, upper) = self.size_hint();
        assert!(
            lower <= len && upper.map_or(true, |upper| upper >= len),
            "provided length {len} inconsistent with `size_hint`: {:?}",
            (lower, upper)
        );

        ExactSize { inner: self, len }
    }

    /// Wrap this iterator with one that yields a tuple of the iterator element and the extra
    /// value on each iteration. The extra value is cloned for each but the last `Some` element
    /// returned.
    ///
    /// This is useful to provide an owned extra value to each iteration, but only clone it
    /// when necessary.
    ///
    /// NOTE: Once the iterator starts producing `None` values, the extra value will be consumed
    /// and no longer be available. This should not be used for iterators that may produce
    /// `Some` values after producing `None`.
    fn repeat_clone<A: Clone>(self, extra_val: A) -> RepeatClone<Self, A> {
        RepeatClone {
            iter: self.peekable(),
            extra_val: Some(extra_val),
        }
    }
}

impl<I> IteratorExt for I where I: Iterator {}

/// Iterator type returned by [`IteratorExt::exact_size`].
#[derive(Debug)]
pub struct ExactSize<I> {
    inner: I,
    len: usize,
}

impl<I: Iterator> Iterator for ExactSize<I> {
    type Item = I::Item;

    fn next(&mut self) -> Option<Self::Item> {
        self.len = self.len.saturating_sub(1);
        self.inner.next()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.len, Some(self.len))
    }
}

impl<I: Iterator> ExactSizeIterator for ExactSize<I> {}

/// Iterator type returned by [`IteratorExt::repeat_clone`].
pub struct RepeatClone<I: Iterator, A> {
    iter: Peekable<I>,
    extra_val: Option<A>,
}

impl<I: Iterator, A: Clone> Iterator for RepeatClone<I, A> {
    type Item = (I::Item, A);

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.iter.next()?;

        // Clone the extra_val only if there is an item to return on the next call to `next`.
        let val = match self.iter.peek() {
            Some(_) => self.extra_val.clone(),
            None => self.extra_val.take(),
        };

        // We should always return a value if there is a current element.
        Some((next, val.expect("RepeatClone invariant violated")))
    }
}

impl<I: Iterator<Item: Debug> + Debug, A: Debug> Debug for RepeatClone<I, A> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("RepeatClone")
            .field("iter", &self.iter)
            .field("extra_val", &self.extra_val)
            .finish()
    }
}

#[cfg(test)]
mod tests {
    use crate::iter::IteratorExt;

    #[crate::test]
    fn test_all_equal() {
        let empty: [i64; 0] = [];
        assert!(empty.iter().all_equal());
        assert!([1].iter().all_equal());
        assert!([1, 1].iter().all_equal());
        assert!(![1, 2].iter().all_equal());
    }
}