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
use std::fmt;
use std::iter::{Fuse, FusedIterator, Peekable};
/// An iterator adaptor that wraps each element in an [`Position`].
///
/// Iterator element type is `(Position, I::Item)`.
///
/// See [`.with_position()`](crate::Itertools::with_position) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct WithPosition<I>
where
I: Iterator,
{
handled_first: bool,
peekable: Peekable<Fuse<I>>,
}
impl<I> fmt::Debug for WithPosition<I>
where
I: Iterator,
Peekable<Fuse<I>>: fmt::Debug,
{
debug_fmt_fields!(WithPosition, handled_first, peekable);
}
impl<I> Clone for WithPosition<I>
where
I: Clone + Iterator,
I::Item: Clone,
{
clone_fields!(handled_first, peekable);
}
/// Create a new `WithPosition` iterator.
pub fn with_position<I>(iter: I) -> WithPosition<I>
where
I: Iterator,
{
WithPosition {
handled_first: false,
peekable: iter.fuse().peekable(),
}
}
/// The first component of the value yielded by `WithPosition`.
/// Indicates the position of this element in the iterator results.
///
/// See [`.with_position()`](crate::Itertools::with_position) for more information.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Position {
/// This is the initial element (also true if there's exactly one element)
pub is_first: bool,
/// This is the final element (also true if there's exactly one element)
pub is_last: bool,
}
impl Position {
/// This is the first and the last element at the same time, and there are no more elements
pub fn is_exactly_one(self) -> bool {
self.is_first && self.is_last
}
/// This is neither first nor last element, and there will be more elements
pub fn is_middle(self) -> bool {
!self.is_first && !self.is_last
}
/// This is the initial element (also true if there's exactly one element)
pub fn is_first(self) -> bool {
self.is_first
}
/// This is the final element (also true if there's exactly one element)
pub fn is_last(self) -> bool {
self.is_last
}
}
impl<I: Iterator> Iterator for WithPosition<I> {
type Item = (Position, I::Item);
fn next(&mut self) -> Option<Self::Item> {
let item = self.peekable.next()?;
let is_last = self.peekable.peek().is_none();
let is_first = !self.handled_first;
self.handled_first = true;
Some((Position { is_first, is_last }, item))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.peekable.size_hint()
}
fn fold<B, F>(mut self, mut init: B, mut f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
if let Some(mut head) = self.peekable.next() {
if !self.handled_first {
// The current head is `First` or `Only`,
// it depends if there is another item or not.
match self.peekable.next() {
Some(second) => {
let first = std::mem::replace(&mut head, second);
let position = Position {
is_first: true,
is_last: false,
};
init = f(init, (position, first));
}
None => {
let position = Position {
is_first: true,
is_last: true,
};
return f(init, (position, head));
}
}
}
// Have seen the first item, and there's something left.
init = self.peekable.fold(init, |acc, mut item| {
std::mem::swap(&mut head, &mut item);
let position = Position {
is_first: false,
is_last: false,
};
f(acc, (position, item))
});
let position = Position {
is_first: false,
is_last: true,
};
// The "head" is now the last item.
init = f(init, (position, head));
}
init
}
}
impl<I> ExactSizeIterator for WithPosition<I> where I: ExactSizeIterator {}
impl<I: Iterator> FusedIterator for WithPosition<I> {}