]> git.proxmox.com Git - rustc.git/blame - library/core/src/iter/adapters/fuse.rs
New upstream version 1.62.1+dfsg1
[rustc.git] / library / core / src / iter / adapters / fuse.rs
CommitLineData
ba9703b0 1use crate::intrinsics;
136023e0 2use crate::iter::adapters::zip::try_get_unchecked;
5869c6ff
XL
3use crate::iter::{
4 DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen, TrustedRandomAccess,
94222f64 5 TrustedRandomAccessNoCoerce,
5869c6ff 6};
ba9703b0
XL
7use crate::ops::Try;
8
9/// An iterator that yields `None` forever after the underlying iterator
10/// yields `None` once.
11///
1b1a35ee
XL
12/// This `struct` is created by [`Iterator::fuse`]. See its documentation
13/// for more.
ba9703b0
XL
14#[derive(Clone, Debug)]
15#[must_use = "iterators are lazy and do nothing unless consumed"]
16#[stable(feature = "rust1", since = "1.0.0")]
17pub struct Fuse<I> {
136023e0
XL
18 // NOTE: for `I: FusedIterator`, we never bother setting `None`, but
19 // we still have to be prepared for that state due to variance.
20 // See rust-lang/rust#85863
ba9703b0
XL
21 iter: Option<I>,
22}
23impl<I> Fuse<I> {
24 pub(in crate::iter) fn new(iter: I) -> Fuse<I> {
25 Fuse { iter: Some(iter) }
26 }
27}
28
29#[stable(feature = "fused", since = "1.26.0")]
30impl<I> FusedIterator for Fuse<I> where I: Iterator {}
31
32/// Fuse the iterator if the expression is `None`.
33macro_rules! fuse {
34 ($self:ident . iter . $($call:tt)+) => {
35 match $self.iter {
36 Some(ref mut iter) => match iter.$($call)+ {
37 None => {
38 $self.iter = None;
39 None
40 }
41 item => item,
42 },
43 None => None,
44 }
45 };
46}
47
136023e0
XL
48/// Specialized macro that doesn't check if the expression is `None`.
49/// (We trust that a `FusedIterator` will fuse itself.)
50macro_rules! spec {
51 ($self:ident . iter . $($call:tt)+) => {
52 match $self.iter {
53 Some(ref mut iter) => iter.$($call)+,
54 None => None,
ba9703b0
XL
55 }
56 };
57}
58
136023e0
XL
59// Any specialized implementation here is made internal
60// to avoid exposing default fns outside this trait.
ba9703b0
XL
61#[stable(feature = "rust1", since = "1.0.0")]
62impl<I> Iterator for Fuse<I>
63where
64 I: Iterator,
65{
66 type Item = <I as Iterator>::Item;
67
68 #[inline]
69 fn next(&mut self) -> Option<Self::Item> {
70 FuseImpl::next(self)
71 }
72
73 #[inline]
74 fn nth(&mut self, n: usize) -> Option<I::Item> {
75 FuseImpl::nth(self, n)
76 }
77
78 #[inline]
79 fn last(self) -> Option<Self::Item> {
136023e0
XL
80 match self.iter {
81 Some(iter) => iter.last(),
82 None => None,
83 }
ba9703b0
XL
84 }
85
86 #[inline]
87 fn count(self) -> usize {
136023e0
XL
88 match self.iter {
89 Some(iter) => iter.count(),
90 None => 0,
91 }
ba9703b0
XL
92 }
93
94 #[inline]
95 fn size_hint(&self) -> (usize, Option<usize>) {
136023e0
XL
96 match self.iter {
97 Some(ref iter) => iter.size_hint(),
98 None => (0, Some(0)),
99 }
ba9703b0
XL
100 }
101
102 #[inline]
103 fn try_fold<Acc, Fold, R>(&mut self, acc: Acc, fold: Fold) -> R
104 where
105 Self: Sized,
106 Fold: FnMut(Acc, Self::Item) -> R,
17df50a5 107 R: Try<Output = Acc>,
ba9703b0
XL
108 {
109 FuseImpl::try_fold(self, acc, fold)
110 }
111
112 #[inline]
136023e0 113 fn fold<Acc, Fold>(self, mut acc: Acc, fold: Fold) -> Acc
ba9703b0
XL
114 where
115 Fold: FnMut(Acc, Self::Item) -> Acc,
116 {
136023e0
XL
117 if let Some(iter) = self.iter {
118 acc = iter.fold(acc, fold);
119 }
120 acc
ba9703b0
XL
121 }
122
123 #[inline]
124 fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
125 where
126 P: FnMut(&Self::Item) -> bool,
127 {
128 FuseImpl::find(self, predicate)
129 }
3dfed10e
XL
130
131 #[inline]
6c58768f 132 unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
3dfed10e 133 where
94222f64 134 Self: TrustedRandomAccessNoCoerce,
3dfed10e
XL
135 {
136 match self.iter {
1b1a35ee
XL
137 // SAFETY: the caller must uphold the contract for
138 // `Iterator::__iterator_get_unchecked`.
3dfed10e
XL
139 Some(ref mut iter) => unsafe { try_get_unchecked(iter, idx) },
140 // SAFETY: the caller asserts there is an item at `i`, so we're not exhausted.
141 None => unsafe { intrinsics::unreachable() },
142 }
143 }
ba9703b0
XL
144}
145
146#[stable(feature = "rust1", since = "1.0.0")]
147impl<I> DoubleEndedIterator for Fuse<I>
148where
149 I: DoubleEndedIterator,
150{
151 #[inline]
152 fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
153 FuseImpl::next_back(self)
154 }
155
156 #[inline]
157 fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
158 FuseImpl::nth_back(self, n)
159 }
160
161 #[inline]
162 fn try_rfold<Acc, Fold, R>(&mut self, acc: Acc, fold: Fold) -> R
163 where
164 Self: Sized,
165 Fold: FnMut(Acc, Self::Item) -> R,
17df50a5 166 R: Try<Output = Acc>,
ba9703b0
XL
167 {
168 FuseImpl::try_rfold(self, acc, fold)
169 }
170
171 #[inline]
136023e0 172 fn rfold<Acc, Fold>(self, mut acc: Acc, fold: Fold) -> Acc
ba9703b0
XL
173 where
174 Fold: FnMut(Acc, Self::Item) -> Acc,
175 {
136023e0
XL
176 if let Some(iter) = self.iter {
177 acc = iter.rfold(acc, fold);
178 }
179 acc
ba9703b0
XL
180 }
181
182 #[inline]
183 fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
184 where
185 P: FnMut(&Self::Item) -> bool,
186 {
187 FuseImpl::rfind(self, predicate)
188 }
189}
190
191#[stable(feature = "rust1", since = "1.0.0")]
192impl<I> ExactSizeIterator for Fuse<I>
193where
194 I: ExactSizeIterator,
195{
196 fn len(&self) -> usize {
136023e0
XL
197 match self.iter {
198 Some(ref iter) => iter.len(),
199 None => 0,
200 }
ba9703b0
XL
201 }
202
203 fn is_empty(&self) -> bool {
136023e0
XL
204 match self.iter {
205 Some(ref iter) => iter.is_empty(),
206 None => true,
207 }
ba9703b0
XL
208 }
209}
210
5869c6ff
XL
211#[unstable(feature = "trusted_len", issue = "37572")]
212// SAFETY: `TrustedLen` requires that an accurate length is reported via `size_hint()`. As `Fuse`
213// is just forwarding this to the wrapped iterator `I` this property is preserved and it is safe to
214// implement `TrustedLen` here.
215unsafe impl<I> TrustedLen for Fuse<I> where I: TrustedLen {}
216
3dfed10e
XL
217#[doc(hidden)]
218#[unstable(feature = "trusted_random_access", issue = "none")]
5869c6ff
XL
219// SAFETY: `TrustedRandomAccess` requires that `size_hint()` must be exact and cheap to call, and
220// `Iterator::__iterator_get_unchecked()` must be implemented accordingly.
221//
222// This is safe to implement as `Fuse` is just forwarding these to the wrapped iterator `I`, which
223// preserves these properties.
94222f64
XL
224unsafe impl<I> TrustedRandomAccess for Fuse<I> where I: TrustedRandomAccess {}
225
226#[doc(hidden)]
227#[unstable(feature = "trusted_random_access", issue = "none")]
228unsafe impl<I> TrustedRandomAccessNoCoerce for Fuse<I>
ba9703b0 229where
94222f64 230 I: TrustedRandomAccessNoCoerce,
ba9703b0 231{
6a06907d 232 const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT;
ba9703b0
XL
233}
234
136023e0
XL
235/// Fuse specialization trait
236///
237/// We only need to worry about `&mut self` methods, which
238/// may exhaust the iterator without consuming it.
ba9703b0
XL
239#[doc(hidden)]
240trait FuseImpl<I> {
241 type Item;
242
243 // Functions specific to any normal Iterators
244 fn next(&mut self) -> Option<Self::Item>;
245 fn nth(&mut self, n: usize) -> Option<Self::Item>;
ba9703b0
XL
246 fn try_fold<Acc, Fold, R>(&mut self, acc: Acc, fold: Fold) -> R
247 where
248 Self: Sized,
249 Fold: FnMut(Acc, Self::Item) -> R,
17df50a5 250 R: Try<Output = Acc>;
ba9703b0
XL
251 fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
252 where
253 P: FnMut(&Self::Item) -> bool;
254
255 // Functions specific to DoubleEndedIterators
256 fn next_back(&mut self) -> Option<Self::Item>
257 where
258 I: DoubleEndedIterator;
259 fn nth_back(&mut self, n: usize) -> Option<Self::Item>
260 where
261 I: DoubleEndedIterator;
262 fn try_rfold<Acc, Fold, R>(&mut self, acc: Acc, fold: Fold) -> R
263 where
264 Self: Sized,
265 Fold: FnMut(Acc, Self::Item) -> R,
17df50a5 266 R: Try<Output = Acc>,
ba9703b0 267 I: DoubleEndedIterator;
ba9703b0
XL
268 fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
269 where
270 P: FnMut(&Self::Item) -> bool,
271 I: DoubleEndedIterator;
ba9703b0
XL
272}
273
136023e0 274/// General `Fuse` impl which sets `iter = None` when exhausted.
ba9703b0
XL
275#[doc(hidden)]
276impl<I> FuseImpl<I> for Fuse<I>
277where
278 I: Iterator,
279{
280 type Item = <I as Iterator>::Item;
281
282 #[inline]
283 default fn next(&mut self) -> Option<<I as Iterator>::Item> {
284 fuse!(self.iter.next())
285 }
286
287 #[inline]
288 default fn nth(&mut self, n: usize) -> Option<I::Item> {
289 fuse!(self.iter.nth(n))
290 }
291
ba9703b0
XL
292 #[inline]
293 default fn try_fold<Acc, Fold, R>(&mut self, mut acc: Acc, fold: Fold) -> R
294 where
295 Self: Sized,
296 Fold: FnMut(Acc, Self::Item) -> R,
17df50a5 297 R: Try<Output = Acc>,
ba9703b0
XL
298 {
299 if let Some(ref mut iter) = self.iter {
300 acc = iter.try_fold(acc, fold)?;
301 self.iter = None;
302 }
29967ef6 303 try { acc }
ba9703b0
XL
304 }
305
ba9703b0
XL
306 #[inline]
307 default fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
308 where
309 P: FnMut(&Self::Item) -> bool,
310 {
311 fuse!(self.iter.find(predicate))
312 }
313
314 #[inline]
315 default fn next_back(&mut self) -> Option<<I as Iterator>::Item>
316 where
317 I: DoubleEndedIterator,
318 {
319 fuse!(self.iter.next_back())
320 }
321
322 #[inline]
323 default fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item>
324 where
325 I: DoubleEndedIterator,
326 {
327 fuse!(self.iter.nth_back(n))
328 }
329
330 #[inline]
331 default fn try_rfold<Acc, Fold, R>(&mut self, mut acc: Acc, fold: Fold) -> R
332 where
333 Self: Sized,
334 Fold: FnMut(Acc, Self::Item) -> R,
17df50a5 335 R: Try<Output = Acc>,
ba9703b0
XL
336 I: DoubleEndedIterator,
337 {
338 if let Some(ref mut iter) = self.iter {
339 acc = iter.try_rfold(acc, fold)?;
340 self.iter = None;
341 }
29967ef6 342 try { acc }
ba9703b0
XL
343 }
344
ba9703b0
XL
345 #[inline]
346 default fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
347 where
348 P: FnMut(&Self::Item) -> bool,
349 I: DoubleEndedIterator,
350 {
351 fuse!(self.iter.rfind(predicate))
352 }
ba9703b0
XL
353}
354
136023e0
XL
355/// Specialized `Fuse` impl which doesn't bother clearing `iter` when exhausted.
356/// However, we must still be prepared for the possibility that it was already cleared!
ba9703b0
XL
357#[doc(hidden)]
358impl<I> FuseImpl<I> for Fuse<I>
359where
360 I: FusedIterator,
361{
362 #[inline]
363 fn next(&mut self) -> Option<<I as Iterator>::Item> {
136023e0 364 spec!(self.iter.next())
ba9703b0
XL
365 }
366
367 #[inline]
368 fn nth(&mut self, n: usize) -> Option<I::Item> {
136023e0 369 spec!(self.iter.nth(n))
ba9703b0
XL
370 }
371
372 #[inline]
136023e0 373 fn try_fold<Acc, Fold, R>(&mut self, mut acc: Acc, fold: Fold) -> R
ba9703b0
XL
374 where
375 Self: Sized,
376 Fold: FnMut(Acc, Self::Item) -> R,
17df50a5 377 R: Try<Output = Acc>,
ba9703b0 378 {
136023e0
XL
379 if let Some(ref mut iter) = self.iter {
380 acc = iter.try_fold(acc, fold)?;
381 }
382 try { acc }
ba9703b0
XL
383 }
384
385 #[inline]
386 fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
387 where
388 P: FnMut(&Self::Item) -> bool,
389 {
136023e0 390 spec!(self.iter.find(predicate))
ba9703b0
XL
391 }
392
393 #[inline]
394 fn next_back(&mut self) -> Option<<I as Iterator>::Item>
395 where
396 I: DoubleEndedIterator,
397 {
136023e0 398 spec!(self.iter.next_back())
ba9703b0
XL
399 }
400
401 #[inline]
402 fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item>
403 where
404 I: DoubleEndedIterator,
405 {
136023e0 406 spec!(self.iter.nth_back(n))
ba9703b0
XL
407 }
408
409 #[inline]
136023e0 410 fn try_rfold<Acc, Fold, R>(&mut self, mut acc: Acc, fold: Fold) -> R
ba9703b0
XL
411 where
412 Self: Sized,
413 Fold: FnMut(Acc, Self::Item) -> R,
17df50a5 414 R: Try<Output = Acc>,
ba9703b0
XL
415 I: DoubleEndedIterator,
416 {
136023e0
XL
417 if let Some(ref mut iter) = self.iter {
418 acc = iter.try_rfold(acc, fold)?;
419 }
420 try { acc }
ba9703b0
XL
421 }
422
423 #[inline]
424 fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
425 where
426 P: FnMut(&Self::Item) -> bool,
427 I: DoubleEndedIterator,
428 {
136023e0 429 spec!(self.iter.rfind(predicate))
ba9703b0
XL
430 }
431}