Skip to main content

yui_core/ext/
iter.rs

1//! [`IteratorExt`]: iterator helpers, notably `range()` for the min..=max of a
2//! sequence as an `Option<RangeInclusive>`.
3
4use std::ops::RangeInclusive;
5use itertools::{Itertools, MinMaxResult};
6
7/// Extension methods on [`Iterator`].
8pub trait IteratorExt: Iterator + Sized {
9    /// The inclusive range `min..=max` of the items, or `None` if the iterator
10    /// is empty.
11    fn range(self) -> Option<RangeInclusive<Self::Item>>
12    where Self::Item: Ord + Copy {
13        match self.minmax() {
14            MinMaxResult::NoElements       => None,
15            MinMaxResult::OneElement(x)    => Some(x ..= x),
16            MinMaxResult::MinMax(min, max) => Some(min ..= max),
17        }
18    }
19}
20
21impl<I: Iterator> IteratorExt for I {}
22
23#[cfg(test)]
24mod tests {
25    use super::*;
26
27    #[test]
28    fn range_empty() {
29        let r: Option<RangeInclusive<i32>> = std::iter::empty().range();
30        assert_eq!(r, None);
31    }
32
33    #[test]
34    fn range_single() {
35        assert_eq!([7].into_iter().range(), Some(7 ..= 7));
36    }
37
38    #[test]
39    fn range_sorted() {
40        assert_eq!([1, 2, 3, 4, 5].into_iter().range(), Some(1 ..= 5));
41    }
42
43    #[test]
44    fn range_unsorted() {
45        assert_eq!([3, -2, 5, 1, -7, 4].into_iter().range(), Some(-7 ..= 5));
46    }
47
48    #[test]
49    fn range_duplicates() {
50        assert_eq!([2, 2, 2].into_iter().range(), Some(2 ..= 2));
51    }
52}