Skip to content

Commit 49e4880

Browse files
bors[bot]phimuemue
andauthored
Merge #464
464: Unify convenience map functions r=jswrenn a=phimuemue In response to #283: I think we should employ a uniform architecture for our `map`-specializations (as they already diverged). This PR is meant to unify the implementations so we essentially only need to parametrize the mapping function: * Generalize `MapInto` to `MapSpecialCase` (which can be used as basis for all our map convenience functions) and define `MapInto` in terms of `MapSpecialCase` * Specialize `collect` (was specialized on `MapOk`, so I guess we want to keep it for now) * Define `MapOk` in terms of `MapSpecialCase` * Simple tests for specialized `size_hint`, `fold`, `collect` * As at this point probably all existing PRs involving `map_xyz` are conflicting anyway, move them to an own module (similar to `coalesce`) Co-authored-by: philipp <descpl@yahoo.de>
2 parents 9769e75 + 3068b23 commit 49e4880

File tree

3 files changed

+136
-112
lines changed

3 files changed

+136
-112
lines changed

src/adaptors/map.rs

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
use std::iter::FromIterator;
2+
use std::marker::PhantomData;
3+
4+
#[derive(Clone)]
5+
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
6+
pub struct MapSpecialCase<I, F> {
7+
iter: I,
8+
f: F,
9+
}
10+
11+
pub trait MapSpecialCaseFn<T> {
12+
type Out;
13+
fn call(&mut self, t: T) -> Self::Out;
14+
}
15+
16+
impl<I, R> Iterator for MapSpecialCase<I, R>
17+
where
18+
I: Iterator,
19+
R: MapSpecialCaseFn<I::Item>,
20+
{
21+
type Item = R::Out;
22+
23+
fn next(&mut self) -> Option<Self::Item> {
24+
self.iter.next().map(|i| self.f.call(i))
25+
}
26+
27+
fn size_hint(&self) -> (usize, Option<usize>) {
28+
self.iter.size_hint()
29+
}
30+
31+
fn fold<Acc, Fold>(self, init: Acc, mut fold_f: Fold) -> Acc
32+
where
33+
Fold: FnMut(Acc, Self::Item) -> Acc,
34+
{
35+
let mut f = self.f;
36+
self.iter.fold(init, move |acc, v| fold_f(acc, f.call(v)))
37+
}
38+
39+
fn collect<C>(self) -> C
40+
where
41+
C: FromIterator<Self::Item>,
42+
{
43+
let mut f = self.f;
44+
self.iter.map(move |v| f.call(v)).collect()
45+
}
46+
}
47+
48+
impl<I, R> DoubleEndedIterator for MapSpecialCase<I, R>
49+
where
50+
I: DoubleEndedIterator,
51+
R: MapSpecialCaseFn<I::Item>,
52+
{
53+
fn next_back(&mut self) -> Option<Self::Item> {
54+
self.iter.next_back().map(|i| self.f.call(i))
55+
}
56+
}
57+
58+
impl<I, R> ExactSizeIterator for MapSpecialCase<I, R>
59+
where
60+
I: ExactSizeIterator,
61+
R: MapSpecialCaseFn<I::Item>,
62+
{
63+
}
64+
65+
/// An iterator adapter to apply a transformation within a nested `Result::Ok`.
66+
///
67+
/// See [`.map_ok()`](../trait.Itertools.html#method.map_ok) for more information.
68+
pub type MapOk<I, F> = MapSpecialCase<I, MapSpecialCaseFnOk<F>>;
69+
70+
/// See [`MapOk`](struct.MapOk.html).
71+
#[deprecated(note = "Use MapOk instead", since = "0.10")]
72+
pub type MapResults<I, F> = MapOk<I, F>;
73+
74+
impl<F, T, U, E> MapSpecialCaseFn<Result<T, E>> for MapSpecialCaseFnOk<F>
75+
where
76+
F: FnMut(T) -> U,
77+
{
78+
type Out = Result<U, E>;
79+
fn call(&mut self, t: Result<T, E>) -> Self::Out {
80+
t.map(|v| self.0(v))
81+
}
82+
}
83+
84+
#[derive(Clone)]
85+
pub struct MapSpecialCaseFnOk<F>(F);
86+
87+
/// Create a new `MapOk` iterator.
88+
pub fn map_ok<I, F, T, U, E>(iter: I, f: F) -> MapOk<I, F>
89+
where
90+
I: Iterator<Item = Result<T, E>>,
91+
F: FnMut(T) -> U,
92+
{
93+
MapSpecialCase {
94+
iter,
95+
f: MapSpecialCaseFnOk(f),
96+
}
97+
}
98+
99+
/// An iterator adapter to apply `Into` conversion to each element.
100+
///
101+
/// See [`.map_into()`](../trait.Itertools.html#method.map_into) for more information.
102+
pub type MapInto<I, R> = MapSpecialCase<I, MapSpecialCaseFnInto<R>>;
103+
104+
impl<T: Into<U>, U> MapSpecialCaseFn<T> for MapSpecialCaseFnInto<U> {
105+
type Out = U;
106+
fn call(&mut self, t: T) -> Self::Out {
107+
t.into()
108+
}
109+
}
110+
111+
#[derive(Clone)]
112+
pub struct MapSpecialCaseFnInto<U>(PhantomData<U>);
113+
114+
/// Create a new [`MapInto`](struct.MapInto.html) iterator.
115+
pub fn map_into<I, R>(iter: I) -> MapInto<I, R> {
116+
MapSpecialCase {
117+
iter,
118+
f: MapSpecialCaseFnInto(PhantomData),
119+
}
120+
}

src/adaptors/mod.rs

+4-112
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@
55
//! except according to those terms.
66
77
mod coalesce;
8+
mod map;
89
mod multi_product;
910
pub use self::coalesce::*;
11+
pub use self::map::{map_into, map_ok, MapInto, MapOk};
12+
#[allow(deprecated)]
13+
pub use self::map::MapResults;
1014
#[cfg(feature = "use_std")]
1115
pub use self::multi_product::*;
1216

@@ -806,118 +810,6 @@ impl_tuple_combination!(Tuple2Combination Tuple1Combination ; A, A, A ; a);
806810
impl_tuple_combination!(Tuple3Combination Tuple2Combination ; A, A, A, A ; a b);
807811
impl_tuple_combination!(Tuple4Combination Tuple3Combination ; A, A, A, A, A; a b c);
808812

809-
/// An iterator adapter to apply `Into` conversion to each element.
810-
///
811-
/// See [`.map_into()`](../trait.Itertools.html#method.map_into) for more information.
812-
#[derive(Clone)]
813-
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
814-
pub struct MapInto<I, R> {
815-
iter: I,
816-
_res: PhantomData<R>,
817-
}
818-
819-
/// Create a new [`MapInto`](struct.MapInto.html) iterator.
820-
pub fn map_into<I, R>(iter: I) -> MapInto<I, R> {
821-
MapInto {
822-
iter,
823-
_res: PhantomData,
824-
}
825-
}
826-
827-
impl<I, R> Iterator for MapInto<I, R>
828-
where I: Iterator,
829-
I::Item: Into<R>,
830-
{
831-
type Item = R;
832-
833-
fn next(&mut self) -> Option<Self::Item> {
834-
self.iter
835-
.next()
836-
.map(|i| i.into())
837-
}
838-
839-
fn size_hint(&self) -> (usize, Option<usize>) {
840-
self.iter.size_hint()
841-
}
842-
843-
fn fold<Acc, Fold>(self, init: Acc, mut fold_f: Fold) -> Acc
844-
where Fold: FnMut(Acc, Self::Item) -> Acc,
845-
{
846-
self.iter.fold(init, move |acc, v| fold_f(acc, v.into()))
847-
}
848-
}
849-
850-
impl<I, R> DoubleEndedIterator for MapInto<I, R>
851-
where I: DoubleEndedIterator,
852-
I::Item: Into<R>,
853-
{
854-
fn next_back(&mut self) -> Option<Self::Item> {
855-
self.iter
856-
.next_back()
857-
.map(|i| i.into())
858-
}
859-
}
860-
861-
impl<I, R> ExactSizeIterator for MapInto<I, R>
862-
where
863-
I: ExactSizeIterator,
864-
I::Item: Into<R>,
865-
{}
866-
867-
/// See [`MapOk`](struct.MapOk.html).
868-
#[deprecated(note="Use MapOk instead", since="0.10")]
869-
pub type MapResults<I, F> = MapOk<I, F>;
870-
871-
/// An iterator adapter to apply a transformation within a nested `Result::Ok`.
872-
///
873-
/// See [`.map_ok()`](../trait.Itertools.html#method.map_ok) for more information.
874-
#[derive(Clone)]
875-
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
876-
pub struct MapOk<I, F> {
877-
iter: I,
878-
f: F
879-
}
880-
881-
/// Create a new `MapOk` iterator.
882-
pub fn map_ok<I, F, T, U, E>(iter: I, f: F) -> MapOk<I, F>
883-
where I: Iterator<Item = Result<T, E>>,
884-
F: FnMut(T) -> U,
885-
{
886-
MapOk {
887-
iter,
888-
f,
889-
}
890-
}
891-
892-
impl<I, F, T, U, E> Iterator for MapOk<I, F>
893-
where I: Iterator<Item = Result<T, E>>,
894-
F: FnMut(T) -> U,
895-
{
896-
type Item = Result<U, E>;
897-
898-
fn next(&mut self) -> Option<Self::Item> {
899-
self.iter.next().map(|v| v.map(&mut self.f))
900-
}
901-
902-
fn size_hint(&self) -> (usize, Option<usize>) {
903-
self.iter.size_hint()
904-
}
905-
906-
fn fold<Acc, Fold>(self, init: Acc, mut fold_f: Fold) -> Acc
907-
where Fold: FnMut(Acc, Self::Item) -> Acc,
908-
{
909-
let mut f = self.f;
910-
self.iter.fold(init, move |acc, v| fold_f(acc, v.map(&mut f)))
911-
}
912-
913-
fn collect<C>(self) -> C
914-
where C: FromIterator<Self::Item>
915-
{
916-
let mut f = self.f;
917-
self.iter.map(move |v| v.map(&mut f)).collect()
918-
}
919-
}
920-
921813
/// An iterator adapter to filter values within a nested `Result::Ok`.
922814
///
923815
/// See [`.filter_ok()`](../trait.Itertools.html#method.filter_ok) for more information.

tests/specializations.rs

+12
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,15 @@ quickcheck! {
8686
test_specializations(&i1.into_iter().merge_join_by(i2.into_iter(), std::cmp::Ord::cmp));
8787
}
8888
}
89+
90+
quickcheck! {
91+
fn map_into(v: Vec<u8>) -> () {
92+
test_specializations(&v.into_iter().map_into::<u32>());
93+
}
94+
}
95+
96+
quickcheck! {
97+
fn map_ok(v: Vec<Result<u8, char>>) -> () {
98+
test_specializations(&v.into_iter().map_ok(|u| u.checked_add(1)));
99+
}
100+
}

0 commit comments

Comments
 (0)