Skip to content

Commit 7b279fa

Browse files
authored
Rollup merge of rust-lang#70366 - cuviper:option-fuse, r=dtolnay
Implement Fuse with Option The former `done` flag was roughly similar to an `Option` tag, but left the possibity of misuse. By using a real `Option`, we can set `None` when the iterator is exhausted, removing any way to call it again. We also allow niche layout this way, so the `Fuse` may be smaller. The `FusedIterator` specialization does want to ignore the possibility of exhaustion though, so it uses `unsafe { intrinsics::unreachable() }` to optimize that branch away. The entire `Fuse` implementation is now isolated in its own module to contain that unsafety. r? @scottmcm
2 parents f63798a + 4f429c0 commit 7b279fa

File tree

2 files changed

+344
-255
lines changed

2 files changed

+344
-255
lines changed

src/libcore/iter/adapters/fuse.rs

+342
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
use crate::intrinsics;
2+
use crate::iter::{
3+
DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator, TrustedRandomAccess,
4+
};
5+
use crate::ops::Try;
6+
7+
/// An iterator that yields `None` forever after the underlying iterator
8+
/// yields `None` once.
9+
///
10+
/// This `struct` is created by the [`fuse`] method on [`Iterator`]. See its
11+
/// documentation for more.
12+
///
13+
/// [`fuse`]: trait.Iterator.html#method.fuse
14+
/// [`Iterator`]: trait.Iterator.html
15+
#[derive(Clone, Debug)]
16+
#[must_use = "iterators are lazy and do nothing unless consumed"]
17+
#[stable(feature = "rust1", since = "1.0.0")]
18+
pub struct Fuse<I> {
19+
// NOTE: for `I: FusedIterator`, this is always assumed `Some`!
20+
iter: Option<I>,
21+
}
22+
impl<I> Fuse<I> {
23+
pub(in crate::iter) fn new(iter: I) -> Fuse<I> {
24+
Fuse { iter: Some(iter) }
25+
}
26+
}
27+
28+
#[stable(feature = "fused", since = "1.26.0")]
29+
impl<I> FusedIterator for Fuse<I> where I: Iterator {}
30+
31+
#[stable(feature = "rust1", since = "1.0.0")]
32+
impl<I> Iterator for Fuse<I>
33+
where
34+
I: Iterator,
35+
{
36+
type Item = <I as Iterator>::Item;
37+
38+
#[inline]
39+
default fn next(&mut self) -> Option<<I as Iterator>::Item> {
40+
let next = self.iter.as_mut()?.next();
41+
if next.is_none() {
42+
self.iter = None;
43+
}
44+
next
45+
}
46+
47+
#[inline]
48+
default fn nth(&mut self, n: usize) -> Option<I::Item> {
49+
let nth = self.iter.as_mut()?.nth(n);
50+
if nth.is_none() {
51+
self.iter = None;
52+
}
53+
nth
54+
}
55+
56+
#[inline]
57+
default fn last(self) -> Option<I::Item> {
58+
self.iter?.last()
59+
}
60+
61+
#[inline]
62+
default fn count(self) -> usize {
63+
self.iter.map_or(0, I::count)
64+
}
65+
66+
#[inline]
67+
default fn size_hint(&self) -> (usize, Option<usize>) {
68+
self.iter.as_ref().map_or((0, Some(0)), I::size_hint)
69+
}
70+
71+
#[inline]
72+
default fn try_fold<Acc, Fold, R>(&mut self, mut acc: Acc, fold: Fold) -> R
73+
where
74+
Self: Sized,
75+
Fold: FnMut(Acc, Self::Item) -> R,
76+
R: Try<Ok = Acc>,
77+
{
78+
if let Some(ref mut iter) = self.iter {
79+
acc = iter.try_fold(acc, fold)?;
80+
self.iter = None;
81+
}
82+
Try::from_ok(acc)
83+
}
84+
85+
#[inline]
86+
default fn fold<Acc, Fold>(self, mut acc: Acc, fold: Fold) -> Acc
87+
where
88+
Fold: FnMut(Acc, Self::Item) -> Acc,
89+
{
90+
if let Some(iter) = self.iter {
91+
acc = iter.fold(acc, fold);
92+
}
93+
acc
94+
}
95+
96+
#[inline]
97+
default fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
98+
where
99+
P: FnMut(&Self::Item) -> bool,
100+
{
101+
let found = self.iter.as_mut()?.find(predicate);
102+
if found.is_none() {
103+
self.iter = None;
104+
}
105+
found
106+
}
107+
}
108+
109+
#[stable(feature = "rust1", since = "1.0.0")]
110+
impl<I> DoubleEndedIterator for Fuse<I>
111+
where
112+
I: DoubleEndedIterator,
113+
{
114+
#[inline]
115+
default fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
116+
let next = self.iter.as_mut()?.next_back();
117+
if next.is_none() {
118+
self.iter = None;
119+
}
120+
next
121+
}
122+
123+
#[inline]
124+
default fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
125+
let nth = self.iter.as_mut()?.nth_back(n);
126+
if nth.is_none() {
127+
self.iter = None;
128+
}
129+
nth
130+
}
131+
132+
#[inline]
133+
default fn try_rfold<Acc, Fold, R>(&mut self, mut acc: Acc, fold: Fold) -> R
134+
where
135+
Self: Sized,
136+
Fold: FnMut(Acc, Self::Item) -> R,
137+
R: Try<Ok = Acc>,
138+
{
139+
if let Some(ref mut iter) = self.iter {
140+
acc = iter.try_rfold(acc, fold)?;
141+
self.iter = None;
142+
}
143+
Try::from_ok(acc)
144+
}
145+
146+
#[inline]
147+
default fn rfold<Acc, Fold>(self, mut acc: Acc, fold: Fold) -> Acc
148+
where
149+
Fold: FnMut(Acc, Self::Item) -> Acc,
150+
{
151+
if let Some(iter) = self.iter {
152+
acc = iter.rfold(acc, fold);
153+
}
154+
acc
155+
}
156+
157+
#[inline]
158+
default fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
159+
where
160+
P: FnMut(&Self::Item) -> bool,
161+
{
162+
let found = self.iter.as_mut()?.rfind(predicate);
163+
if found.is_none() {
164+
self.iter = None;
165+
}
166+
found
167+
}
168+
}
169+
170+
#[stable(feature = "rust1", since = "1.0.0")]
171+
impl<I> ExactSizeIterator for Fuse<I>
172+
where
173+
I: ExactSizeIterator,
174+
{
175+
default fn len(&self) -> usize {
176+
self.iter.as_ref().map_or(0, I::len)
177+
}
178+
179+
default fn is_empty(&self) -> bool {
180+
self.iter.as_ref().map_or(true, I::is_empty)
181+
}
182+
}
183+
184+
// NOTE: for `I: FusedIterator`, we assume that the iterator is always `Some`
185+
impl<I: FusedIterator> Fuse<I> {
186+
#[inline(always)]
187+
fn as_inner(&self) -> &I {
188+
match self.iter {
189+
Some(ref iter) => iter,
190+
// SAFETY: the specialized iterator never sets `None`
191+
None => unsafe { intrinsics::unreachable() },
192+
}
193+
}
194+
195+
#[inline(always)]
196+
fn as_inner_mut(&mut self) -> &mut I {
197+
match self.iter {
198+
Some(ref mut iter) => iter,
199+
// SAFETY: the specialized iterator never sets `None`
200+
None => unsafe { intrinsics::unreachable() },
201+
}
202+
}
203+
204+
#[inline(always)]
205+
fn into_inner(self) -> I {
206+
match self.iter {
207+
Some(iter) => iter,
208+
// SAFETY: the specialized iterator never sets `None`
209+
None => unsafe { intrinsics::unreachable() },
210+
}
211+
}
212+
}
213+
214+
#[stable(feature = "fused", since = "1.26.0")]
215+
impl<I> Iterator for Fuse<I>
216+
where
217+
I: FusedIterator,
218+
{
219+
#[inline]
220+
fn next(&mut self) -> Option<<I as Iterator>::Item> {
221+
self.as_inner_mut().next()
222+
}
223+
224+
#[inline]
225+
fn nth(&mut self, n: usize) -> Option<I::Item> {
226+
self.as_inner_mut().nth(n)
227+
}
228+
229+
#[inline]
230+
fn last(self) -> Option<I::Item> {
231+
self.into_inner().last()
232+
}
233+
234+
#[inline]
235+
fn count(self) -> usize {
236+
self.into_inner().count()
237+
}
238+
239+
#[inline]
240+
fn size_hint(&self) -> (usize, Option<usize>) {
241+
self.as_inner().size_hint()
242+
}
243+
244+
#[inline]
245+
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
246+
where
247+
Self: Sized,
248+
Fold: FnMut(Acc, Self::Item) -> R,
249+
R: Try<Ok = Acc>,
250+
{
251+
self.as_inner_mut().try_fold(init, fold)
252+
}
253+
254+
#[inline]
255+
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
256+
where
257+
Fold: FnMut(Acc, Self::Item) -> Acc,
258+
{
259+
self.into_inner().fold(init, fold)
260+
}
261+
262+
#[inline]
263+
fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
264+
where
265+
P: FnMut(&Self::Item) -> bool,
266+
{
267+
self.as_inner_mut().find(predicate)
268+
}
269+
}
270+
271+
#[stable(feature = "fused", since = "1.26.0")]
272+
impl<I> DoubleEndedIterator for Fuse<I>
273+
where
274+
I: DoubleEndedIterator + FusedIterator,
275+
{
276+
#[inline]
277+
fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
278+
self.as_inner_mut().next_back()
279+
}
280+
281+
#[inline]
282+
fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
283+
self.as_inner_mut().nth_back(n)
284+
}
285+
286+
#[inline]
287+
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
288+
where
289+
Self: Sized,
290+
Fold: FnMut(Acc, Self::Item) -> R,
291+
R: Try<Ok = Acc>,
292+
{
293+
self.as_inner_mut().try_rfold(init, fold)
294+
}
295+
296+
#[inline]
297+
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
298+
where
299+
Fold: FnMut(Acc, Self::Item) -> Acc,
300+
{
301+
self.into_inner().rfold(init, fold)
302+
}
303+
304+
#[inline]
305+
fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
306+
where
307+
P: FnMut(&Self::Item) -> bool,
308+
{
309+
self.as_inner_mut().rfind(predicate)
310+
}
311+
}
312+
313+
#[stable(feature = "rust1", since = "1.0.0")]
314+
impl<I> ExactSizeIterator for Fuse<I>
315+
where
316+
I: ExactSizeIterator + FusedIterator,
317+
{
318+
fn len(&self) -> usize {
319+
self.as_inner().len()
320+
}
321+
322+
fn is_empty(&self) -> bool {
323+
self.as_inner().is_empty()
324+
}
325+
}
326+
327+
unsafe impl<I> TrustedRandomAccess for Fuse<I>
328+
where
329+
I: TrustedRandomAccess,
330+
{
331+
unsafe fn get_unchecked(&mut self, i: usize) -> I::Item {
332+
match self.iter {
333+
Some(ref mut iter) => iter.get_unchecked(i),
334+
// SAFETY: the caller asserts there is an item at `i`, so we're not exhausted.
335+
None => intrinsics::unreachable(),
336+
}
337+
}
338+
339+
fn may_have_side_effect() -> bool {
340+
I::may_have_side_effect()
341+
}
342+
}

0 commit comments

Comments
 (0)