@@ -45,49 +45,48 @@ where
45
45
/// The first component of the value yielded by `WithPosition`.
46
46
/// Indicates the position of this element in the iterator results.
47
47
///
48
- /// When handling the first or last position,
49
- /// remember to consider the special case of [`Position::Only`].
50
- ///
51
48
/// See [`.with_position()`](crate::Itertools::with_position) for more information.
52
49
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
53
- pub enum Position {
54
- /// This is the first element, and there is more than one element.
55
- First,
56
- /// This is neither the first nor the last element.
57
- Middle,
58
- /// This is the last element, and there was more than one element.
59
- Last,
60
- /// This is the only element.
61
- Only,
50
+ pub struct Position {
51
+ /// This is the initial element (also true if there's exactly one element)
52
+ pub is_first: bool,
53
+ /// This is the final element (also true if there's exactly one element)
54
+ pub is_last: bool,
55
+ }
56
+
57
+ impl Position {
58
+ /// This is the first and the last element at the same time, and there are no more elements
59
+ pub fn is_exactly_one(self) -> bool {
60
+ self.is_first && self.is_last
61
+ }
62
+
63
+ /// This is neither first nor last element, and there will be more elements
64
+ pub fn is_middle(self) -> bool {
65
+ !self.is_first && !self.is_last
66
+ }
67
+
68
+ /// This is the initial element (also true if there's exactly one element)
69
+ pub fn is_first(self) -> bool {
70
+ self.is_first
71
+ }
72
+
73
+ /// This is the final element (also true if there's exactly one element)
74
+ pub fn is_last(self) -> bool {
75
+ self.is_last
76
+ }
62
77
}
63
78
64
79
impl<I: Iterator> Iterator for WithPosition<I> {
65
80
type Item = (Position, I::Item);
66
81
67
82
fn next(&mut self) -> Option<Self::Item> {
68
- match self.peekable.next() {
69
- Some(item) => {
70
- if !self.handled_first {
71
- // Haven't seen the first item yet, and there is one to give.
72
- self.handled_first = true;
73
- // Peek to see if this is also the last item,
74
- // in which case tag it as `Only`.
75
- match self.peekable.peek() {
76
- Some(_) => Some((Position::First, item)),
77
- None => Some((Position::Only, item)),
78
- }
79
- } else {
80
- // Have seen the first item, and there's something left.
81
- // Peek to see if this is the last item.
82
- match self.peekable.peek() {
83
- Some(_) => Some((Position::Middle, item)),
84
- None => Some((Position::Last, item)),
85
- }
86
- }
87
- }
88
- // Iterator is finished.
89
- None => None,
90
- }
83
+ let item = self.peekable.next()?;
84
+
85
+ let is_last = self.peekable.peek().is_none();
86
+ let is_first = !self.handled_first;
87
+ self.handled_first = true;
88
+
89
+ Some((Position { is_first, is_last }, item))
91
90
}
92
91
93
92
fn size_hint(&self) -> (usize, Option<usize>) {
@@ -105,18 +104,36 @@ impl<I: Iterator> Iterator for WithPosition<I> {
105
104
match self.peekable.next() {
106
105
Some(second) => {
107
106
let first = std::mem::replace(&mut head, second);
108
- init = f(init, (Position::First, first));
107
+ let position = Position {
108
+ is_first: true,
109
+ is_last: false,
110
+ };
111
+ init = f(init, (position, first));
112
+ }
113
+ None => {
114
+ let position = Position {
115
+ is_first: true,
116
+ is_last: true,
117
+ };
118
+ return f(init, (position, head));
109
119
}
110
- None => return f(init, (Position::Only, head)),
111
120
}
112
121
}
113
122
// Have seen the first item, and there's something left.
114
123
init = self.peekable.fold(init, |acc, mut item| {
115
124
std::mem::swap(&mut head, &mut item);
116
- f(acc, (Position::Middle, item))
125
+ let position = Position {
126
+ is_first: false,
127
+ is_last: false,
128
+ };
129
+ f(acc, (position, item))
117
130
});
131
+ let position = Position {
132
+ is_first: false,
133
+ is_last: true,
134
+ };
118
135
// The "head" is now the last item.
119
- init = f(init, (Position::Last , head));
136
+ init = f(init, (position , head));
120
137
}
121
138
init
122
139
}
0 commit comments