axum_macros/with_position.rs
1// this is copied from itertools under the following license
2//
3// Copyright (c) 2015
4//
5// Permission is hereby granted, free of charge, to any
6// person obtaining a copy of this software and associated
7// documentation files (the "Software"), to deal in the
8// Software without restriction, including without
9// limitation the rights to use, copy, modify, merge,
10// publish, distribute, sublicense, and/or sell copies of
11// the Software, and to permit persons to whom the Software
12// is furnished to do so, subject to the following
13// conditions:
14//
15// The above copyright notice and this permission notice
16// shall be included in all copies or substantial portions
17// of the Software.
18//
19// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
20// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
21// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
22// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
23// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
26// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27// DEALINGS IN THE SOFTWARE.
28
29use std::iter::{Fuse, FusedIterator, Peekable};
30
31pub(crate) struct WithPosition<I>
32where
33 I: Iterator,
34{
35 handled_first: bool,
36 peekable: Peekable<Fuse<I>>,
37}
38
39impl<I> WithPosition<I>
40where
41 I: Iterator,
42{
43 pub(crate) fn new(iter: impl IntoIterator<IntoIter = I>) -> WithPosition<I> {
44 WithPosition {
45 handled_first: false,
46 peekable: iter.into_iter().fuse().peekable(),
47 }
48 }
49}
50
51impl<I> Clone for WithPosition<I>
52where
53 I: Clone + Iterator,
54 I::Item: Clone,
55{
56 fn clone(&self) -> Self {
57 Self {
58 handled_first: self.handled_first,
59 peekable: self.peekable.clone(),
60 }
61 }
62}
63
64#[derive(Copy, Clone, Debug, PartialEq)]
65pub(crate) enum Position<T> {
66 First(T),
67 Middle(T),
68 Last(T),
69 Only(T),
70}
71
72impl<T> Position<T> {
73 pub(crate) fn into_inner(self) -> T {
74 match self {
75 Position::First(x) | Position::Middle(x) | Position::Last(x) | Position::Only(x) => x,
76 }
77 }
78}
79
80impl<I: Iterator> Iterator for WithPosition<I> {
81 type Item = Position<I::Item>;
82
83 fn next(&mut self) -> Option<Self::Item> {
84 match self.peekable.next() {
85 Some(item) => {
86 if !self.handled_first {
87 // Haven't seen the first item yet, and there is one to give.
88 self.handled_first = true;
89 // Peek to see if this is also the last item,
90 // in which case tag it as `Only`.
91 match self.peekable.peek() {
92 Some(_) => Some(Position::First(item)),
93 None => Some(Position::Only(item)),
94 }
95 } else {
96 // Have seen the first item, and there's something left.
97 // Peek to see if this is the last item.
98 match self.peekable.peek() {
99 Some(_) => Some(Position::Middle(item)),
100 None => Some(Position::Last(item)),
101 }
102 }
103 }
104 // Iterator is finished.
105 None => None,
106 }
107 }
108
109 fn size_hint(&self) -> (usize, Option<usize>) {
110 self.peekable.size_hint()
111 }
112}
113
114impl<I> ExactSizeIterator for WithPosition<I> where I: ExactSizeIterator {}
115
116impl<I: Iterator> FusedIterator for WithPosition<I> {}