Coverage Report

Created: 2024-05-20 06:38

/rust/registry/src/index.crates.io-6f17d22bba15001f/itertools-0.11.0/src/with_position.rs
Line
Count
Source (jump to first uncovered line)
1
use std::iter::{Fuse,Peekable, FusedIterator};
2
3
/// An iterator adaptor that wraps each element in an [`Position`].
4
///
5
/// Iterator element type is `(Position, I::Item)`.
6
///
7
/// See [`.with_position()`](crate::Itertools::with_position) for more information.
8
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
9
pub struct WithPosition<I>
10
    where I: Iterator,
11
{
12
    handled_first: bool,
13
    peekable: Peekable<Fuse<I>>,
14
}
15
16
impl<I> Clone for WithPosition<I>
17
    where I: Clone + Iterator,
18
          I::Item: Clone,
19
{
20
    clone_fields!(handled_first, peekable);
21
}
22
23
/// Create a new `WithPosition` iterator.
24
0
pub fn with_position<I>(iter: I) -> WithPosition<I>
25
0
    where I: Iterator,
26
0
{
27
0
    WithPosition {
28
0
        handled_first: false,
29
0
        peekable: iter.fuse().peekable(),
30
0
    }
31
0
}
32
33
/// The first component of the value yielded by `WithPosition`.
34
/// Indicates the position of this element in the iterator results.
35
///
36
/// See [`.with_position()`](crate::Itertools::with_position) for more information.
37
0
#[derive(Copy, Clone, Debug, PartialEq)]
38
pub enum Position {
39
    /// This is the first element.
40
    First,
41
    /// This is neither the first nor the last element.
42
    Middle,
43
    /// This is the last element.
44
    Last,
45
    /// This is the only element.
46
    Only,
47
}
48
49
impl<I: Iterator> Iterator for WithPosition<I> {
50
    type Item = (Position, I::Item);
51
52
0
    fn next(&mut self) -> Option<Self::Item> {
53
0
        match self.peekable.next() {
54
0
            Some(item) => {
55
0
                if !self.handled_first {
56
                    // Haven't seen the first item yet, and there is one to give.
57
0
                    self.handled_first = true;
58
0
                    // Peek to see if this is also the last item,
59
0
                    // in which case tag it as `Only`.
60
0
                    match self.peekable.peek() {
61
0
                        Some(_) => Some((Position::First, item)),
62
0
                        None => Some((Position::Only, item)),
63
                    }
64
                } else {
65
                    // Have seen the first item, and there's something left.
66
                    // Peek to see if this is the last item.
67
0
                    match self.peekable.peek() {
68
0
                        Some(_) => Some((Position::Middle, item)),
69
0
                        None => Some((Position::Last, item)),
70
                    }
71
                }
72
            }
73
            // Iterator is finished.
74
0
            None => None,
75
        }
76
0
    }
77
78
0
    fn size_hint(&self) -> (usize, Option<usize>) {
79
0
        self.peekable.size_hint()
80
0
    }
81
}
82
83
impl<I> ExactSizeIterator for WithPosition<I>
84
    where I: ExactSizeIterator,
85
{ }
86
87
impl<I: Iterator> FusedIterator for WithPosition<I> 
88
{}