-
Notifications
You must be signed in to change notification settings - Fork 339
Unify convenience map functions #464
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
be65c2e
0d6bb9d
8ef597b
9105061
9346100
3068b23
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -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<I, F> { | ||||||
| iter: I, | ||||||
| f: F, | ||||||
| } | ||||||
|
|
||||||
| pub trait MapSpecialCaseFn<T> { | ||||||
| type Out; | ||||||
| fn call(&mut self, t: T) -> Self::Out; | ||||||
| } | ||||||
|
|
||||||
| impl<I, R> Iterator for MapSpecialCase<I, R> | ||||||
| where | ||||||
| I: Iterator, | ||||||
| R: MapSpecialCaseFn<I::Item>, | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| { | ||||||
| type Item = R::Out; | ||||||
|
|
||||||
| fn next(&mut self) -> Option<Self::Item> { | ||||||
| self.iter.next().map(|i| self.f.call(i)) | ||||||
| } | ||||||
|
|
||||||
| fn size_hint(&self) -> (usize, Option<usize>) { | ||||||
| self.iter.size_hint() | ||||||
| } | ||||||
|
|
||||||
| fn fold<Acc, 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<C>(self) -> C | ||||||
| where | ||||||
| C: FromIterator<Self::Item>, | ||||||
| { | ||||||
| let mut f = self.f; | ||||||
| self.iter.map(move |v| f.call(v)).collect() | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| impl<I, R> DoubleEndedIterator for MapSpecialCase<I, R> | ||||||
| where | ||||||
| I: DoubleEndedIterator, | ||||||
| R: MapSpecialCaseFn<I::Item>, | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| { | ||||||
| fn next_back(&mut self) -> Option<Self::Item> { | ||||||
| self.iter.next_back().map(|i| self.f.call(i)) | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| impl<I, R> ExactSizeIterator for MapSpecialCase<I, R> | ||||||
| where | ||||||
| I: ExactSizeIterator, | ||||||
| R: MapSpecialCaseFn<I::Item>, | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| { | ||||||
| } | ||||||
|
|
||||||
| /// 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<I, F> = MapSpecialCase<I, MapSpecialCaseFnOk<F>>; | ||||||
|
|
||||||
| /// See [`MapOk`](struct.MapOk.html). | ||||||
| #[deprecated(note = "Use MapOk instead", since = "0.10")] | ||||||
| pub type MapResults<I, F> = MapOk<I, F>; | ||||||
|
|
||||||
| impl<F, T, U, E> MapSpecialCaseFn<Result<T, E>> for MapSpecialCaseFnOk<F> | ||||||
| where | ||||||
| F: FnMut(T) -> U, | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| { | ||||||
| type Out = Result<U, E>; | ||||||
| fn call(&mut self, t: Result<T, E>) -> Self::Out { | ||||||
| t.map(|v| self.0(v)) | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| #[derive(Clone)] | ||||||
| pub struct MapSpecialCaseFnOk<F>(F); | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| /// Create a new `MapOk` iterator. | ||||||
| pub fn map_ok<I, F, T, U, E>(iter: I, f: F) -> MapOk<I, F> | ||||||
| where | ||||||
| I: Iterator<Item = Result<T, E>>, | ||||||
| F: FnMut(T) -> U, | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| { | ||||||
| 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<I, R> = MapSpecialCase<I, MapSpecialCaseFnInto<R>>; | ||||||
|
|
||||||
| impl<T: Into<U>, U> MapSpecialCaseFn<T> for MapSpecialCaseFnInto<U> { | ||||||
| type Out = U; | ||||||
| fn call(&mut self, t: T) -> Self::Out { | ||||||
| t.into() | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| #[derive(Clone)] | ||||||
| pub struct MapSpecialCaseFnInto<U>(PhantomData<U>); | ||||||
|
|
||||||
| /// Create a new [`MapInto`](struct.MapInto.html) iterator. | ||||||
| pub fn map_into<I, R>(iter: I) -> MapInto<I, R> { | ||||||
| MapSpecialCase { | ||||||
| iter, | ||||||
| f: MapSpecialCaseFnInto(PhantomData), | ||||||
| } | ||||||
| } | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This way unsized “special functions” can be used, including trait objects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good observation! Are unsized functions common? Alternatively, we could reverse the order of fields in
MapSpecialCaseand makeI: ?Sized, thereby supporting iterator trait objects. (Unfortunately, it's one or the other.)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this nice idea. In general, I am leaning to incorporate changes that generalize functionality.
However, I'd like to postpone this one and - if we decide to accept
?Sizedfunctions - do it uniformly throughout itertools. I think my changes did not change behavior in this regard, so I hope postponing is ok.@pthariensflame As I'm no expert in this area: Could you showcase a situation that requires
F: ?Sized?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure! If we have an unsized trait object
dyn Fn(X) -> Y, then we get an unsizedMapSpecialCaseFnOk<dyn Fn(X) -> Y>, which is then your example of an unsizedF.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fine by me!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pthariensflame I'm curious about the actual use-case
dyn Fnmight appear in. I've never needed to dynamically dispatched function objects before.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I'm fine with waiting too. This isn't essential functionality, just mildly helpful at best.
As far as
dyn Fn, I can't point to any specific code, but it might come up when abstracting over dynamically swappable actions. For example: imagine a pipeline of scriptable blocks that the user can specify in a GUI, and it gets compiled down to functions that invoke the scripts and munge the values flowing through as necessary. The whole pipeline is then composed and boxed up as adyn Fnso that it can be altered on the fly as the application runs.