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> {}