]> git.lizzy.rs Git - rust.git/blob - library/core/src/iter/adapters/skip.rs
Split iterator adaptors into individual modules
[rust.git] / library / core / src / iter / adapters / skip.rs
1 use crate::{
2     iter::{adapters::SourceIter, FusedIterator, InPlaceIterable},
3     ops::{ControlFlow, Try},
4 };
5
6 /// An iterator that skips over `n` elements of `iter`.
7 ///
8 /// This `struct` is created by the [`skip`] method on [`Iterator`]. See its
9 /// documentation for more.
10 ///
11 /// [`skip`]: Iterator::skip
12 /// [`Iterator`]: trait.Iterator.html
13 #[derive(Clone, Debug)]
14 #[must_use = "iterators are lazy and do nothing unless consumed"]
15 #[stable(feature = "rust1", since = "1.0.0")]
16 pub struct Skip<I> {
17     iter: I,
18     n: usize,
19 }
20
21 impl<I> Skip<I> {
22     pub(in crate::iter) fn new(iter: I, n: usize) -> Skip<I> {
23         Skip { iter, n }
24     }
25 }
26
27 #[stable(feature = "rust1", since = "1.0.0")]
28 impl<I> Iterator for Skip<I>
29 where
30     I: Iterator,
31 {
32     type Item = <I as Iterator>::Item;
33
34     #[inline]
35     fn next(&mut self) -> Option<I::Item> {
36         if self.n == 0 {
37             self.iter.next()
38         } else {
39             let old_n = self.n;
40             self.n = 0;
41             self.iter.nth(old_n)
42         }
43     }
44
45     #[inline]
46     fn nth(&mut self, n: usize) -> Option<I::Item> {
47         // Can't just add n + self.n due to overflow.
48         if self.n > 0 {
49             let to_skip = self.n;
50             self.n = 0;
51             // nth(n) skips n+1
52             self.iter.nth(to_skip - 1)?;
53         }
54         self.iter.nth(n)
55     }
56
57     #[inline]
58     fn count(mut self) -> usize {
59         if self.n > 0 {
60             // nth(n) skips n+1
61             if self.iter.nth(self.n - 1).is_none() {
62                 return 0;
63             }
64         }
65         self.iter.count()
66     }
67
68     #[inline]
69     fn last(mut self) -> Option<I::Item> {
70         if self.n > 0 {
71             // nth(n) skips n+1
72             self.iter.nth(self.n - 1)?;
73         }
74         self.iter.last()
75     }
76
77     #[inline]
78     fn size_hint(&self) -> (usize, Option<usize>) {
79         let (lower, upper) = self.iter.size_hint();
80
81         let lower = lower.saturating_sub(self.n);
82         let upper = match upper {
83             Some(x) => Some(x.saturating_sub(self.n)),
84             None => None,
85         };
86
87         (lower, upper)
88     }
89
90     #[inline]
91     fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
92     where
93         Self: Sized,
94         Fold: FnMut(Acc, Self::Item) -> R,
95         R: Try<Ok = Acc>,
96     {
97         let n = self.n;
98         self.n = 0;
99         if n > 0 {
100             // nth(n) skips n+1
101             if self.iter.nth(n - 1).is_none() {
102                 return try { init };
103             }
104         }
105         self.iter.try_fold(init, fold)
106     }
107
108     #[inline]
109     fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
110     where
111         Fold: FnMut(Acc, Self::Item) -> Acc,
112     {
113         if self.n > 0 {
114             // nth(n) skips n+1
115             if self.iter.nth(self.n - 1).is_none() {
116                 return init;
117             }
118         }
119         self.iter.fold(init, fold)
120     }
121 }
122
123 #[stable(feature = "rust1", since = "1.0.0")]
124 impl<I> ExactSizeIterator for Skip<I> where I: ExactSizeIterator {}
125
126 #[stable(feature = "double_ended_skip_iterator", since = "1.9.0")]
127 impl<I> DoubleEndedIterator for Skip<I>
128 where
129     I: DoubleEndedIterator + ExactSizeIterator,
130 {
131     fn next_back(&mut self) -> Option<Self::Item> {
132         if self.len() > 0 { self.iter.next_back() } else { None }
133     }
134
135     #[inline]
136     fn nth_back(&mut self, n: usize) -> Option<I::Item> {
137         let len = self.len();
138         if n < len {
139             self.iter.nth_back(n)
140         } else {
141             if len > 0 {
142                 // consume the original iterator
143                 self.iter.nth_back(len - 1);
144             }
145             None
146         }
147     }
148
149     fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
150     where
151         Self: Sized,
152         Fold: FnMut(Acc, Self::Item) -> R,
153         R: Try<Ok = Acc>,
154     {
155         fn check<T, Acc, R: Try<Ok = Acc>>(
156             mut n: usize,
157             mut fold: impl FnMut(Acc, T) -> R,
158         ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> {
159             move |acc, x| {
160                 n -= 1;
161                 let r = fold(acc, x);
162                 if n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) }
163             }
164         }
165
166         let n = self.len();
167         if n == 0 { try { init } } else { self.iter.try_rfold(init, check(n, fold)).into_try() }
168     }
169
170     fn rfold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
171     where
172         Fold: FnMut(Acc, Self::Item) -> Acc,
173     {
174         #[inline]
175         fn ok<Acc, T>(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, T) -> Result<Acc, !> {
176             move |acc, x| Ok(f(acc, x))
177         }
178
179         self.try_rfold(init, ok(fold)).unwrap()
180     }
181 }
182
183 #[stable(feature = "fused", since = "1.26.0")]
184 impl<I> FusedIterator for Skip<I> where I: FusedIterator {}
185
186 #[unstable(issue = "none", feature = "inplace_iteration")]
187 unsafe impl<S: Iterator, I: Iterator> SourceIter for Skip<I>
188 where
189     I: SourceIter<Source = S>,
190 {
191     type Source = S;
192
193     #[inline]
194     unsafe fn as_inner(&mut self) -> &mut S {
195         // SAFETY: unsafe function forwarding to unsafe function with the same requirements
196         unsafe { SourceIter::as_inner(&mut self.iter) }
197     }
198 }
199
200 #[unstable(issue = "none", feature = "inplace_iteration")]
201 unsafe impl<I: InPlaceIterable> InPlaceIterable for Skip<I> {}