Skip to content

Commit 0e39401

Browse files
committed
core::iter::Flatten: update FlatMap & Flatten according to discussion
1 parent 36be763 commit 0e39401

File tree

4 files changed

+294
-20
lines changed

4 files changed

+294
-20
lines changed

src/libcore/iter/iterator.rs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ use cmp::Ordering;
1212
use ops::Try;
1313

1414
use super::{AlwaysOk, LoopState};
15-
use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, Flatten, FlatMap, Fuse};
15+
use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, Fuse};
16+
use super::{Flatten, FlatMap, flatten_compat};
1617
use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile, Rev};
1718
use super::{Zip, Sum, Product};
1819
use super::{ChainState, FromIterator, ZipImpl};
@@ -997,8 +998,8 @@ pub trait Iterator {
997998
/// an extra layer of indirection. `flat_map()` will remove this extra layer
998999
/// on its own.
9991000
///
1000-
/// You can think of [`flat_map(f)`][flat_map] as the equivalent of
1001-
/// [`map`]ping, and then [`flatten`]ing as in `map(f).flatten()`.
1001+
/// You can think of [`flat_map(f)`][flat_map] as the semantic equivalent
1002+
/// of [`map`]ping, and then [`flatten`]ing as in `map(f).flatten()`.
10021003
///
10031004
/// Another way of thinking about `flat_map()`: [`map`]'s closure returns
10041005
/// one item for each element, and `flat_map()`'s closure returns an
@@ -1025,7 +1026,7 @@ pub trait Iterator {
10251026
fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
10261027
where Self: Sized, U: IntoIterator, F: FnMut(Self::Item) -> U,
10271028
{
1028-
self.map(f).flatten()
1029+
FlatMap { inner: flatten_compat(self.map(f)) }
10291030
}
10301031

10311032
/// Creates an iterator that flattens nested structure.
@@ -1060,11 +1061,24 @@ pub trait Iterator {
10601061
/// .collect();
10611062
/// assert_eq!(merged, "alphabetagamma");
10621063
/// ```
1064+
///
1065+
/// You can also rewrite this in terms of [`flat_map()`] which is preferable
1066+
/// in this case since that conveys intent clearer:
1067+
///
1068+
/// ```
1069+
/// let words = ["alpha", "beta", "gamma"];
1070+
///
1071+
/// // chars() returns an iterator
1072+
/// let merged: String = words.iter()
1073+
/// .flat_map(|s| s.chars())
1074+
/// .collect();
1075+
/// assert_eq!(merged, "alphabetagamma");
1076+
/// ```
10631077
#[inline]
10641078
#[unstable(feature = "iterator_flatten", issue = "0")]
1065-
fn flatten(self) -> Flatten<Self, <Self::Item as IntoIterator>::IntoIter>
1079+
fn flatten(self) -> Flatten<Self>
10661080
where Self: Sized, Self::Item: IntoIterator {
1067-
Flatten { iter: self, frontiter: None, backiter: None }
1081+
Flatten { inner: flatten_compat(self) }
10681082
}
10691083

10701084
/// Creates an iterator which ends after the first [`None`].

src/libcore/iter/mod.rs

Lines changed: 166 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2403,14 +2403,87 @@ impl<B, I, St, F> Iterator for Scan<I, St, F> where
24032403
/// An iterator that maps each element to an iterator, and yields the elements
24042404
/// of the produced iterators.
24052405
///
2406-
/// This `type` is created by the [`flat_map`] method on [`Iterator`]. See its
2406+
/// This `struct` is created by the [`flat_map`] method on [`Iterator`]. See its
24072407
/// documentation for more.
24082408
///
24092409
/// [`flat_map`]: trait.Iterator.html#method.flat_map
24102410
/// [`Iterator`]: trait.Iterator.html
24112411
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
24122412
#[stable(feature = "rust1", since = "1.0.0")]
2413-
type FlatMap<I, U, F> = Flatten<Map<I, F>, <U as IntoIterator>::IntoIter>;
2413+
pub struct FlatMap<I, U: IntoIterator, F> {
2414+
inner: FlattenCompat<Map<I, F>, <U as IntoIterator>::IntoIter>
2415+
}
2416+
2417+
#[stable(feature = "rust1", since = "1.0.0")]
2418+
impl<I: Clone, U: Clone + IntoIterator, F: Clone> Clone for FlatMap<I, U, F>
2419+
where <U as IntoIterator>::IntoIter: Clone
2420+
{
2421+
fn clone(&self) -> Self { FlatMap { inner: self.inner.clone() } }
2422+
}
2423+
2424+
#[stable(feature = "core_impl_debug", since = "1.9.0")]
2425+
impl<I: fmt::Debug, U: IntoIterator, F> fmt::Debug for FlatMap<I, U, F>
2426+
where U::IntoIter: fmt::Debug
2427+
{
2428+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2429+
f.debug_struct("FlatMap").field("inner", &self.inner).finish()
2430+
}
2431+
}
2432+
2433+
#[stable(feature = "rust1", since = "1.0.0")]
2434+
impl<I: Iterator, U: IntoIterator, F> Iterator for FlatMap<I, U, F>
2435+
where F: FnMut(I::Item) -> U,
2436+
{
2437+
type Item = U::Item;
2438+
2439+
#[inline]
2440+
fn next(&mut self) -> Option<U::Item> { self.inner.next() }
2441+
2442+
#[inline]
2443+
fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
2444+
2445+
#[inline]
2446+
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
2447+
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
2448+
{
2449+
self.inner.try_fold(init, fold)
2450+
}
2451+
2452+
#[inline]
2453+
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
2454+
where Fold: FnMut(Acc, Self::Item) -> Acc,
2455+
{
2456+
self.inner.fold(init, fold)
2457+
}
2458+
}
2459+
2460+
#[stable(feature = "rust1", since = "1.0.0")]
2461+
impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F>
2462+
where F: FnMut(I::Item) -> U,
2463+
U: IntoIterator,
2464+
U::IntoIter: DoubleEndedIterator
2465+
{
2466+
#[inline]
2467+
fn next_back(&mut self) -> Option<U::Item> { self.inner.next_back() }
2468+
2469+
#[inline]
2470+
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
2471+
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
2472+
{
2473+
self.inner.try_rfold(init, fold)
2474+
}
2475+
2476+
#[inline]
2477+
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
2478+
where Fold: FnMut(Acc, Self::Item) -> Acc,
2479+
{
2480+
self.inner.rfold(init, fold)
2481+
}
2482+
}
2483+
2484+
#[unstable(feature = "fused", issue = "35602")]
2485+
impl<I, U, F> FusedIterator for FlatMap<I, U, F>
2486+
where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {}
24142487

24152488
/// An iterator that flattens one level of nesting in an iterator of things
24162489
/// that can be turned into iterators.
@@ -2422,16 +2495,102 @@ type FlatMap<I, U, F> = Flatten<Map<I, F>, <U as IntoIterator>::IntoIter>;
24222495
/// [`Iterator`]: trait.Iterator.html
24232496
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
24242497
#[unstable(feature = "iterator_flatten", issue = "0")]
2498+
pub struct Flatten<I: Iterator>
2499+
where I::Item: IntoIterator {
2500+
inner: FlattenCompat<I, <I::Item as IntoIterator>::IntoIter>,
2501+
}
2502+
2503+
#[unstable(feature = "iterator_flatten", issue = "0")]
2504+
impl<I, U> fmt::Debug for Flatten<I>
2505+
where I: Iterator + fmt::Debug, U: Iterator + fmt::Debug,
2506+
I::Item: IntoIterator<IntoIter = U, Item = U::Item>,
2507+
{
2508+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2509+
f.debug_struct("Flatten").field("inner", &self.inner).finish()
2510+
}
2511+
}
2512+
2513+
#[unstable(feature = "iterator_flatten", issue = "0")]
2514+
impl<I, U> Clone for Flatten<I>
2515+
where I: Iterator + Clone, U: Iterator + Clone,
2516+
I::Item: IntoIterator<IntoIter = U, Item = U::Item>,
2517+
{
2518+
fn clone(&self) -> Self { Flatten { inner: self.inner.clone() } }
2519+
}
2520+
2521+
#[unstable(feature = "iterator_flatten", issue = "0")]
2522+
impl<I, U> Iterator for Flatten<I>
2523+
where I: Iterator, U: Iterator,
2524+
I::Item: IntoIterator<IntoIter = U, Item = U::Item>
2525+
{
2526+
type Item = U::Item;
2527+
2528+
#[inline]
2529+
fn next(&mut self) -> Option<U::Item> { self.inner.next() }
2530+
2531+
#[inline]
2532+
fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
2533+
2534+
#[inline]
2535+
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
2536+
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
2537+
{
2538+
self.inner.try_fold(init, fold)
2539+
}
2540+
2541+
#[inline]
2542+
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
2543+
where Fold: FnMut(Acc, Self::Item) -> Acc,
2544+
{
2545+
self.inner.fold(init, fold)
2546+
}
2547+
}
2548+
2549+
#[unstable(feature = "iterator_flatten", issue = "0")]
2550+
impl<I, U> DoubleEndedIterator for Flatten<I>
2551+
where I: DoubleEndedIterator, U: DoubleEndedIterator,
2552+
I::Item: IntoIterator<IntoIter = U, Item = U::Item>
2553+
{
2554+
#[inline]
2555+
fn next_back(&mut self) -> Option<U::Item> { self.inner.next_back() }
2556+
2557+
#[inline]
2558+
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
2559+
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
2560+
{
2561+
self.inner.try_rfold(init, fold)
2562+
}
2563+
2564+
#[inline]
2565+
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
2566+
where Fold: FnMut(Acc, Self::Item) -> Acc,
2567+
{
2568+
self.inner.rfold(init, fold)
2569+
}
2570+
}
2571+
2572+
#[unstable(feature = "fused", issue = "35602")]
2573+
impl<I, U> FusedIterator for Flatten<I>
2574+
where I: FusedIterator, U: Iterator,
2575+
I::Item: IntoIterator<IntoIter = U, Item = U::Item> {}
2576+
2577+
/// Adapts an iterator by flattening it, for use in `flatten()` and `flat_map()`.
2578+
fn flatten_compat<I, U>(iter: I) -> FlattenCompat<I, U> {
2579+
FlattenCompat { iter, frontiter: None, backiter: None }
2580+
}
2581+
2582+
/// Real logic of both `Flatten` and `FlatMap` which simply delegate to
2583+
/// this type.
24252584
#[derive(Clone, Debug)]
2426-
pub struct Flatten<I, U> {
2585+
struct FlattenCompat<I, U> {
24272586
iter: I,
24282587
frontiter: Option<U>,
24292588
backiter: Option<U>,
24302589
}
24312590

2432-
#[unstable(feature = "iterator_flatten", issue = "0")]
2433-
impl<I: Iterator, U: Iterator> Iterator for Flatten<I, U>
2434-
where I::Item: IntoIterator<IntoIter = U, Item = U::Item>
2591+
impl<I, U> Iterator for FlattenCompat<I, U>
2592+
where I: Iterator, U: Iterator,
2593+
I::Item: IntoIterator<IntoIter = U, Item = U::Item>
24352594
{
24362595
type Item = U::Item;
24372596

@@ -2498,8 +2657,7 @@ impl<I: Iterator, U: Iterator> Iterator for Flatten<I, U>
24982657
}
24992658
}
25002659

2501-
#[unstable(feature = "iterator_flatten", issue = "0")]
2502-
impl<I, U> DoubleEndedIterator for Flatten<I, U>
2660+
impl<I, U> DoubleEndedIterator for FlattenCompat<I, U>
25032661
where I: DoubleEndedIterator, U: DoubleEndedIterator,
25042662
I::Item: IntoIterator<IntoIter = U, Item = U::Item>
25052663
{
@@ -2555,10 +2713,6 @@ impl<I, U> DoubleEndedIterator for Flatten<I, U>
25552713
}
25562714
}
25572715

2558-
#[unstable(feature = "fused", issue = "35602")]
2559-
impl<I: FusedIterator, U: Iterator> FusedIterator for Flatten<I, U>
2560-
where I::Item: IntoIterator<IntoIter = U, Item = U::Item> {}
2561-
25622716
/// An iterator that yields `None` forever after the underlying iterator
25632717
/// yields `None` once.
25642718
///

0 commit comments

Comments
 (0)