1 use std::iter::{Fuse,Peekable};
2 
3 /// An iterator adaptor that wraps each element in an [`Position`](../enum.Position.html).
4 ///
5 /// Iterator element type is `Position<I::Item>`.
6 ///
7 /// See [`.with_position()`](../trait.Itertools.html#method.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.
with_position<I>(iter: I) -> WithPosition<I> where I: Iterator,24 pub fn with_position<I>(iter: I) -> WithPosition<I>
25     where I: Iterator,
26 {
27     WithPosition {
28         handled_first: false,
29         peekable: iter.fuse().peekable(),
30     }
31 }
32 
33 /// A value yielded by `WithPosition`.
34 /// Indicates the position of this element in the iterator results.
35 ///
36 /// See [`.with_position()`](trait.Itertools.html#method.with_position) for more information.
37 #[derive(Copy, Clone, Debug, PartialEq)]
38 pub enum Position<T> {
39     /// This is the first element.
40     First(T),
41     /// This is neither the first nor the last element.
42     Middle(T),
43     /// This is the last element.
44     Last(T),
45     /// This is the only element.
46     Only(T),
47 }
48 
49 impl<T> Position<T> {
50     /// Return the inner value.
into_inner(self) -> T51     pub fn into_inner(self) -> T {
52         match self {
53             Position::First(x) |
54             Position::Middle(x) |
55             Position::Last(x) |
56             Position::Only(x) => x,
57         }
58     }
59 }
60 
61 impl<I: Iterator> Iterator for WithPosition<I> {
62     type Item = Position<I::Item>;
63 
next(&mut self) -> Option<Self::Item>64     fn next(&mut self) -> Option<Self::Item> {
65         match self.peekable.next() {
66             Some(item) => {
67                 if !self.handled_first {
68                     // Haven't seen the first item yet, and there is one to give.
69                     self.handled_first = true;
70                     // Peek to see if this is also the last item,
71                     // in which case tag it as `Only`.
72                     match self.peekable.peek() {
73                         Some(_) => Some(Position::First(item)),
74                         None => Some(Position::Only(item)),
75                     }
76                 } else {
77                     // Have seen the first item, and there's something left.
78                     // Peek to see if this is the last item.
79                     match self.peekable.peek() {
80                         Some(_) => Some(Position::Middle(item)),
81                         None => Some(Position::Last(item)),
82                     }
83                 }
84             }
85             // Iterator is finished.
86             None => None,
87         }
88     }
89 
size_hint(&self) -> (usize, Option<usize>)90     fn size_hint(&self) -> (usize, Option<usize>) {
91         self.peekable.size_hint()
92     }
93 }
94 
95 impl<I> ExactSizeIterator for WithPosition<I>
96     where I: ExactSizeIterator,
97 { }
98