diff --git a/src/adaptors/map.rs b/src/adaptors/map.rs new file mode 100644 index 000000000..ce7c762cb --- /dev/null +++ b/src/adaptors/map.rs @@ -0,0 +1,120 @@ +use std::iter::FromIterator; +use std::marker::PhantomData; + +#[derive(Clone)] +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct MapSpecialCase { + iter: I, + f: F, +} + +pub trait MapSpecialCaseFn { + type Out; + fn call(&mut self, t: T) -> Self::Out; +} + +impl Iterator for MapSpecialCase +where + I: Iterator, + R: MapSpecialCaseFn, +{ + type Item = R::Out; + + fn next(&mut self) -> Option { + self.iter.next().map(|i| self.f.call(i)) + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + fn fold(self, init: Acc, mut fold_f: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + let mut f = self.f; + self.iter.fold(init, move |acc, v| fold_f(acc, f.call(v))) + } + + fn collect(self) -> C + where + C: FromIterator, + { + let mut f = self.f; + self.iter.map(move |v| f.call(v)).collect() + } +} + +impl DoubleEndedIterator for MapSpecialCase +where + I: DoubleEndedIterator, + R: MapSpecialCaseFn, +{ + fn next_back(&mut self) -> Option { + self.iter.next_back().map(|i| self.f.call(i)) + } +} + +impl ExactSizeIterator for MapSpecialCase +where + I: ExactSizeIterator, + R: MapSpecialCaseFn, +{ +} + +/// An iterator adapter to apply a transformation within a nested `Result::Ok`. +/// +/// See [`.map_ok()`](../trait.Itertools.html#method.map_ok) for more information. +pub type MapOk = MapSpecialCase>; + +/// See [`MapOk`](struct.MapOk.html). +#[deprecated(note = "Use MapOk instead", since = "0.10")] +pub type MapResults = MapOk; + +impl MapSpecialCaseFn> for MapSpecialCaseFnOk +where + F: FnMut(T) -> U, +{ + type Out = Result; + fn call(&mut self, t: Result) -> Self::Out { + t.map(|v| self.0(v)) + } +} + +#[derive(Clone)] +pub struct MapSpecialCaseFnOk(F); + +/// Create a new `MapOk` iterator. +pub fn map_ok(iter: I, f: F) -> MapOk +where + I: Iterator>, + F: FnMut(T) -> U, +{ + MapSpecialCase { + iter, + f: MapSpecialCaseFnOk(f), + } +} + +/// An iterator adapter to apply `Into` conversion to each element. +/// +/// See [`.map_into()`](../trait.Itertools.html#method.map_into) for more information. +pub type MapInto = MapSpecialCase>; + +impl, U> MapSpecialCaseFn for MapSpecialCaseFnInto { + type Out = U; + fn call(&mut self, t: T) -> Self::Out { + t.into() + } +} + +#[derive(Clone)] +pub struct MapSpecialCaseFnInto(PhantomData); + +/// Create a new [`MapInto`](struct.MapInto.html) iterator. +pub fn map_into(iter: I) -> MapInto { + MapSpecialCase { + iter, + f: MapSpecialCaseFnInto(PhantomData), + } +} diff --git a/src/adaptors/mod.rs b/src/adaptors/mod.rs index 794cc6711..d98f6fe7c 100644 --- a/src/adaptors/mod.rs +++ b/src/adaptors/mod.rs @@ -5,8 +5,12 @@ //! except according to those terms. mod coalesce; +mod map; mod multi_product; pub use self::coalesce::*; +pub use self::map::{map_into, map_ok, MapInto, MapOk}; +#[allow(deprecated)] +pub use self::map::MapResults; #[cfg(feature = "use_std")] pub use self::multi_product::*; @@ -806,118 +810,6 @@ impl_tuple_combination!(Tuple2Combination Tuple1Combination ; A, A, A ; a); impl_tuple_combination!(Tuple3Combination Tuple2Combination ; A, A, A, A ; a b); impl_tuple_combination!(Tuple4Combination Tuple3Combination ; A, A, A, A, A; a b c); -/// An iterator adapter to apply `Into` conversion to each element. -/// -/// See [`.map_into()`](../trait.Itertools.html#method.map_into) for more information. -#[derive(Clone)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct MapInto { - iter: I, - _res: PhantomData, -} - -/// Create a new [`MapInto`](struct.MapInto.html) iterator. -pub fn map_into(iter: I) -> MapInto { - MapInto { - iter, - _res: PhantomData, - } -} - -impl Iterator for MapInto - where I: Iterator, - I::Item: Into, -{ - type Item = R; - - fn next(&mut self) -> Option { - self.iter - .next() - .map(|i| i.into()) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - fn fold(self, init: Acc, mut fold_f: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.fold(init, move |acc, v| fold_f(acc, v.into())) - } -} - -impl DoubleEndedIterator for MapInto - where I: DoubleEndedIterator, - I::Item: Into, -{ - fn next_back(&mut self) -> Option { - self.iter - .next_back() - .map(|i| i.into()) - } -} - -impl ExactSizeIterator for MapInto -where - I: ExactSizeIterator, - I::Item: Into, -{} - -/// See [`MapOk`](struct.MapOk.html). -#[deprecated(note="Use MapOk instead", since="0.10")] -pub type MapResults = MapOk; - -/// An iterator adapter to apply a transformation within a nested `Result::Ok`. -/// -/// See [`.map_ok()`](../trait.Itertools.html#method.map_ok) for more information. -#[derive(Clone)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct MapOk { - iter: I, - f: F -} - -/// Create a new `MapOk` iterator. -pub fn map_ok(iter: I, f: F) -> MapOk - where I: Iterator>, - F: FnMut(T) -> U, -{ - MapOk { - iter, - f, - } -} - -impl Iterator for MapOk - where I: Iterator>, - F: FnMut(T) -> U, -{ - type Item = Result; - - fn next(&mut self) -> Option { - self.iter.next().map(|v| v.map(&mut self.f)) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - fn fold(self, init: Acc, mut fold_f: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - let mut f = self.f; - self.iter.fold(init, move |acc, v| fold_f(acc, v.map(&mut f))) - } - - fn collect(self) -> C - where C: FromIterator - { - let mut f = self.f; - self.iter.map(move |v| v.map(&mut f)).collect() - } -} - /// An iterator adapter to filter values within a nested `Result::Ok`. /// /// See [`.filter_ok()`](../trait.Itertools.html#method.filter_ok) for more information. diff --git a/tests/specializations.rs b/tests/specializations.rs index 85d44dd96..bc337c28e 100644 --- a/tests/specializations.rs +++ b/tests/specializations.rs @@ -86,3 +86,15 @@ quickcheck! { test_specializations(&i1.into_iter().merge_join_by(i2.into_iter(), std::cmp::Ord::cmp)); } } + +quickcheck! { + fn map_into(v: Vec) -> () { + test_specializations(&v.into_iter().map_into::()); + } +} + +quickcheck! { + fn map_ok(v: Vec>) -> () { + test_specializations(&v.into_iter().map_ok(|u| u.checked_add(1))); + } +}