From 117a065eda9c91fc3cbbdb9cec472ec98c47ff93 Mon Sep 17 00:00:00 2001 From: Felipe Sere Date: Sun, 20 Oct 2019 19:24:58 +0200 Subject: [PATCH 1/9] Introduce the notion of direction for the min_by func --- src/stream/stream/min_by.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/stream/stream/min_by.rs b/src/stream/stream/min_by.rs index ab12aa05b..626b67029 100644 --- a/src/stream/stream/min_by.rs +++ b/src/stream/stream/min_by.rs @@ -15,8 +15,13 @@ pin_project! { stream: S, compare: F, min: Option, + direction: Direction, } } +enum Direction { + Maximizing, + Minimizing, +} impl MinByFuture { pub(super) fn new(stream: S, compare: F) -> Self { @@ -24,6 +29,7 @@ impl MinByFuture { stream, compare, min: None, + direction: Direction::Minimizing, } } } From ef4480136a6dc90ca37518c18d1a09ac61c12b0d Mon Sep 17 00:00:00 2001 From: Felipe Sere Date: Sun, 20 Oct 2019 19:28:05 +0200 Subject: [PATCH 2/9] Rename to MinMax --- src/stream/stream/min_by.rs | 9 +++++---- src/stream/stream/mod.rs | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/stream/stream/min_by.rs b/src/stream/stream/min_by.rs index 626b67029..02fe3e355 100644 --- a/src/stream/stream/min_by.rs +++ b/src/stream/stream/min_by.rs @@ -10,7 +10,7 @@ use crate::task::{Context, Poll}; pin_project! { #[doc(hidden)] #[allow(missing_debug_implementations)] - pub struct MinByFuture { + pub struct MinMaxByFuture { #[pin] stream: S, compare: F, @@ -23,9 +23,10 @@ enum Direction { Minimizing, } -impl MinByFuture { + +impl MinMaxByFuture { pub(super) fn new(stream: S, compare: F) -> Self { - MinByFuture { + MinMaxByFuture { stream, compare, min: None, @@ -34,7 +35,7 @@ impl MinByFuture { } } -impl Future for MinByFuture +impl Future for MinMaxByFuture where S: Stream + Unpin + Sized, S::Item: Copy, diff --git a/src/stream/stream/mod.rs b/src/stream/stream/mod.rs index 501ece1b2..9c6b254d3 100644 --- a/src/stream/stream/mod.rs +++ b/src/stream/stream/mod.rs @@ -68,7 +68,7 @@ use gt::GtFuture; use last::LastFuture; use le::LeFuture; use lt::LtFuture; -use min_by::MinByFuture; +use min_by::MinMaxByFuture; use next::NextFuture; use nth::NthFuture; use partial_cmp::PartialCmpFuture; @@ -631,12 +631,12 @@ extension_trait! { fn min_by( self, compare: F, - ) -> impl Future> [MinByFuture] + ) -> impl Future> [MinMaxByFuture] where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering, { - MinByFuture::new(self, compare) + MinMaxByFuture::new(self, compare) } #[doc = r#" From 05143e026dd4edf5a86413df558f031c4a71a4f9 Mon Sep 17 00:00:00 2001 From: Felipe Sere Date: Sun, 20 Oct 2019 19:31:06 +0200 Subject: [PATCH 3/9] Rename content to value as its no longer min/max --- src/stream/stream/min_by.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/stream/stream/min_by.rs b/src/stream/stream/min_by.rs index 02fe3e355..4ce0a3252 100644 --- a/src/stream/stream/min_by.rs +++ b/src/stream/stream/min_by.rs @@ -14,7 +14,7 @@ pin_project! { #[pin] stream: S, compare: F, - min: Option, + value: Option, direction: Direction, } } @@ -29,7 +29,7 @@ impl MinMaxByFuture { MinMaxByFuture { stream, compare, - min: None, + value: None, direction: Direction::Minimizing, } } @@ -50,16 +50,16 @@ where match next { Some(new) => { cx.waker().wake_by_ref(); - match this.min.take() { - None => *this.min = Some(new), + match this.value.take() { + None => this.value.replace(new), Some(old) => match (this.compare)(&new, &old) { - Ordering::Less => *this.min = Some(new), - _ => *this.min = Some(old), + Ordering::Less => this.value.replace(new), + _ => this.value.replace(old), }, - } + }; Poll::Pending } - None => Poll::Ready(*this.min), + None => Poll::Ready(*this.value), } } } From 68685019fb7d8f58e21381de7f7bf2b9b482407a Mon Sep 17 00:00:00 2001 From: Felipe Sere Date: Sun, 20 Oct 2019 19:38:41 +0200 Subject: [PATCH 4/9] Use the direction for existing minimize --- src/stream/stream/min_by.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/stream/stream/min_by.rs b/src/stream/stream/min_by.rs index 4ce0a3252..3adab4dda 100644 --- a/src/stream/stream/min_by.rs +++ b/src/stream/stream/min_by.rs @@ -18,6 +18,8 @@ pin_project! { direction: Direction, } } + +#[derive(PartialEq, Eq)] enum Direction { Maximizing, Minimizing, @@ -53,7 +55,7 @@ where match this.value.take() { None => this.value.replace(new), Some(old) => match (this.compare)(&new, &old) { - Ordering::Less => this.value.replace(new), + Ordering::Less if Direction::Minimizing == *this.direction => this.value.replace(new), _ => this.value.replace(old), }, }; From df03a7f3a9fafb3f6ae0ed5e1c7d847cbe7395c2 Mon Sep 17 00:00:00 2001 From: Felipe Sere Date: Sun, 20 Oct 2019 20:28:35 +0200 Subject: [PATCH 5/9] Add maximizing function --- src/stream/stream/min_by.rs | 8 +++++--- src/stream/stream/mod.rs | 41 ++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/stream/stream/min_by.rs b/src/stream/stream/min_by.rs index 3adab4dda..e57ac2d1c 100644 --- a/src/stream/stream/min_by.rs +++ b/src/stream/stream/min_by.rs @@ -20,19 +20,19 @@ pin_project! { } #[derive(PartialEq, Eq)] -enum Direction { +pub(crate) enum Direction { Maximizing, Minimizing, } impl MinMaxByFuture { - pub(super) fn new(stream: S, compare: F) -> Self { + pub(super) fn new(stream: S, compare: F, direction: Direction) -> Self { MinMaxByFuture { stream, compare, value: None, - direction: Direction::Minimizing, + direction, } } } @@ -52,10 +52,12 @@ where match next { Some(new) => { cx.waker().wake_by_ref(); + match this.value.take() { None => this.value.replace(new), Some(old) => match (this.compare)(&new, &old) { Ordering::Less if Direction::Minimizing == *this.direction => this.value.replace(new), + Ordering::Greater if Direction::Maximizing == *this.direction => this.value.replace(new), _ => this.value.replace(old), }, }; diff --git a/src/stream/stream/mod.rs b/src/stream/stream/mod.rs index 9c6b254d3..e13a54373 100644 --- a/src/stream/stream/mod.rs +++ b/src/stream/stream/mod.rs @@ -600,6 +600,45 @@ extension_trait! { FilterMap::new(self, f) } + #[doc = r#" + Returns the element that gives the maximum value with respect to the + specified comparison function. If several elements are equally maximum, + the first element is returned. If the stream is empty, `None` is returned. + + # Examples + + ``` + # fn main() { async_std::task::block_on(async { + # + use std::collections::VecDeque; + + use async_std::prelude::*; + + let s: VecDeque = vec![1, 2, 3].into_iter().collect(); + + let min = s.clone().max_by(|x, y| x.cmp(y)).await; + assert_eq!(min, Some(3)); + + let min = s.max_by(|x, y| y.cmp(x)).await; + assert_eq!(min, Some(1)); + + let min = VecDeque::::new().max_by(|x, y| x.cmp(y)).await; + assert_eq!(min, None); + # + # }) } + ``` + "#] + fn max_by( + self, + compare: F, + ) -> impl Future> [MinMaxByFuture] + where + Self: Sized, + F: FnMut(&Self::Item, &Self::Item) -> Ordering, + { + MinMaxByFuture::new(self, compare, min_by::Direction::Maximizing) + } + #[doc = r#" Returns the element that gives the minimum value with respect to the specified comparison function. If several elements are equally minimum, @@ -636,7 +675,7 @@ extension_trait! { Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering, { - MinMaxByFuture::new(self, compare) + MinMaxByFuture::new(self, compare, min_by::Direction::Minimizing) } #[doc = r#" From da23e73d2aad506813da1078389b93775352e972 Mon Sep 17 00:00:00 2001 From: Felipe Sere Date: Sun, 20 Oct 2019 20:31:44 +0200 Subject: [PATCH 6/9] Don't expose Direction, just expose to fns --- src/stream/stream/min_by.rs | 15 ++++++++++++--- src/stream/stream/mod.rs | 4 ++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/stream/stream/min_by.rs b/src/stream/stream/min_by.rs index e57ac2d1c..b68b640f3 100644 --- a/src/stream/stream/min_by.rs +++ b/src/stream/stream/min_by.rs @@ -20,19 +20,28 @@ pin_project! { } #[derive(PartialEq, Eq)] -pub(crate) enum Direction { +enum Direction { Maximizing, Minimizing, } impl MinMaxByFuture { - pub(super) fn new(stream: S, compare: F, direction: Direction) -> Self { + pub(super) fn new_min(stream: S, compare: F) -> Self { MinMaxByFuture { stream, compare, value: None, - direction, + direction: Direction::Minimizing, + } + } + + pub(super) fn new_max(stream: S, compare: F) -> Self { + MinMaxByFuture { + stream, + compare, + value: None, + direction: Direction::Maximizing, } } } diff --git a/src/stream/stream/mod.rs b/src/stream/stream/mod.rs index e13a54373..8355b81c2 100644 --- a/src/stream/stream/mod.rs +++ b/src/stream/stream/mod.rs @@ -636,7 +636,7 @@ extension_trait! { Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering, { - MinMaxByFuture::new(self, compare, min_by::Direction::Maximizing) + MinMaxByFuture::new_max(self, compare) } #[doc = r#" @@ -675,7 +675,7 @@ extension_trait! { Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering, { - MinMaxByFuture::new(self, compare, min_by::Direction::Minimizing) + MinMaxByFuture::new_min(self, compare) } #[doc = r#" From 89519f0e2424d2d11567f4831f12c2f3e0048d54 Mon Sep 17 00:00:00 2001 From: Felipe Sere Date: Sun, 20 Oct 2019 20:40:54 +0200 Subject: [PATCH 7/9] Shrink the match arms to make the intent clearer --- src/stream/stream/min_by.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/stream/stream/min_by.rs b/src/stream/stream/min_by.rs index b68b640f3..adb54e807 100644 --- a/src/stream/stream/min_by.rs +++ b/src/stream/stream/min_by.rs @@ -55,6 +55,9 @@ where type Output = Option; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + use Direction::*; + use Ordering::*; + let this = self.project(); let next = futures_core::ready!(this.stream.poll_next(cx)); @@ -64,9 +67,8 @@ where match this.value.take() { None => this.value.replace(new), - Some(old) => match (this.compare)(&new, &old) { - Ordering::Less if Direction::Minimizing == *this.direction => this.value.replace(new), - Ordering::Greater if Direction::Maximizing == *this.direction => this.value.replace(new), + Some(old) => match ((this.compare)(&new, &old), this.direction) { + (Less, Minimizing) | (Greater, Maximizing) => this.value.replace(new), _ => this.value.replace(old), }, }; From 3d69a5c8f54e74a7e519568def350d3d7664c694 Mon Sep 17 00:00:00 2001 From: Felipe Sere Date: Sun, 20 Oct 2019 20:46:54 +0200 Subject: [PATCH 8/9] Only have one construtor parametrized over all values --- src/stream/stream/min_by.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/stream/stream/min_by.rs b/src/stream/stream/min_by.rs index adb54e807..f579a3241 100644 --- a/src/stream/stream/min_by.rs +++ b/src/stream/stream/min_by.rs @@ -28,20 +28,19 @@ enum Direction { impl MinMaxByFuture { pub(super) fn new_min(stream: S, compare: F) -> Self { - MinMaxByFuture { - stream, - compare, - value: None, - direction: Direction::Minimizing, - } + MinMaxByFuture::new(stream, compare, Direction::Minimizing) } pub(super) fn new_max(stream: S, compare: F) -> Self { + MinMaxByFuture::new(stream, compare, Direction::Maximizing) + } + + fn new(stream: S, compare: F, direction: Direction) -> Self { MinMaxByFuture { stream, compare, value: None, - direction: Direction::Maximizing, + direction, } } } From b7c79aa22d99686c147fa36f1a5f75f61fdb6552 Mon Sep 17 00:00:00 2001 From: Felipe Sere Date: Tue, 22 Oct 2019 06:49:06 -0500 Subject: [PATCH 9/9] Run fmt --- src/stream/stream/min_by.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/stream/stream/min_by.rs b/src/stream/stream/min_by.rs index f579a3241..806e75416 100644 --- a/src/stream/stream/min_by.rs +++ b/src/stream/stream/min_by.rs @@ -25,7 +25,6 @@ enum Direction { Minimizing, } - impl MinMaxByFuture { pub(super) fn new_min(stream: S, compare: F) -> Self { MinMaxByFuture::new(stream, compare, Direction::Minimizing)