From 7c574204a8c3c48bdf28c128cbada52e2f4a2391 Mon Sep 17 00:00:00 2001 From: Caleb Sander Date: Fri, 28 Aug 2020 15:51:27 -0400 Subject: [PATCH 1/2] impl ops::Try for Ordering --- library/core/src/cmp.rs | 25 +++++++++++ src/test/ui/ordering-try.rs | 89 +++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 src/test/ui/ordering-try.rs diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 3953c73319fe4..647af1fe0419e 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -23,6 +23,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use self::Ordering::*; +use crate::ops; /// Trait for equality comparisons which are [partial equivalence /// relations](https://en.wikipedia.org/wiki/Partial_equivalence_relation). @@ -679,6 +680,30 @@ impl PartialOrd for Ordering { } } +#[unstable(feature = "try_trait", issue = "42327")] +impl ops::Try for Ordering { + type Ok = (); + type Error = Self; + + #[inline] + fn into_result(self) -> Result<(), Self> { + match self { + Equal => Ok(()), + _ => Err(self), + } + } + + #[inline] + fn from_ok(_: ()) -> Self { + Equal + } + + #[inline] + fn from_error(v: Self) -> Self { + v + } +} + /// Trait for values that can be compared for a sort-order. /// /// The comparison must satisfy, for all `a`, `b` and `c`: diff --git a/src/test/ui/ordering-try.rs b/src/test/ui/ordering-try.rs new file mode 100644 index 0000000000000..cec3c3f65f494 --- /dev/null +++ b/src/test/ui/ordering-try.rs @@ -0,0 +1,89 @@ +// run-pass + +use std::cmp::Ordering; +use std::iter; + +#[derive(Eq, PartialEq)] +struct Test(bool, u8, &'static str); + +const BOOL_VALUES: [bool; 2] = [true, false]; +const U8_VALUES: [u8; 3] = [1, 2, 3]; +const STR_VALUES: [&str; 3] = ["a", "ab", "c"]; + +fn test_values() -> impl Iterator { + BOOL_VALUES.iter().flat_map(|&a| { + U8_VALUES.iter().flat_map(move |&b| { + STR_VALUES.iter().map(move |&c| Test(a, b, c)) + }) + }) +} + +// This Ord implementation should behave the same as #[derive(Ord)], +// but uses the Try operator on Ordering values +impl Ord for Test { + fn cmp(&self, other: &Self) -> Ordering { + self.0.cmp(&other.0)?; + self.1.cmp(&other.1)?; + self.2.cmp(&other.2) + } +} + +impl PartialOrd for Test { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +fn test_struct_cmp() { + for test1 in test_values() { + let test1_alt = (test1.0, test1.1, test1.2); + for test2 in test_values() { + let test2_alt = (test2.0, test2.1, test2.2); + assert_eq!(test1.cmp(&test2), test1_alt.cmp(&test2_alt)); + } + } +} + +// Implement Iterator::cmp() using the Try operator +fn cmp(mut iter1: I1, mut iter2: I2) -> Ordering +where + A: Ord, + I1: Iterator, + I2: Iterator, +{ + loop { + match (iter1.next(), iter2.next()) { + (Some(x), Some(y)) => x.cmp(&y)?, + (x, y) => return x.cmp(&y), + } + } +} + +fn u8_sequences() -> impl Iterator> { + iter::once(vec![]) + .chain(U8_VALUES.iter().map(|&a| vec![a])) + .chain(U8_VALUES.iter().flat_map(|&a| { + U8_VALUES.iter().map(move |&b| vec![a, b]) + })) + .chain(U8_VALUES.iter().flat_map(|&a| { + U8_VALUES.iter().flat_map(move |&b| { + U8_VALUES.iter().map(move |&c| vec![a, b, c]) + }) + })) +} + +fn test_slice_cmp() { + for sequence1 in u8_sequences() { + for sequence2 in u8_sequences() { + assert_eq!( + cmp(sequence1.iter().copied(), sequence2.iter().copied()), + sequence1.iter().copied().cmp(sequence2.iter().copied()), + ); + } + } +} + +fn main() { + test_struct_cmp(); + test_slice_cmp(); +} From 4558600ea95ee545861f1f44ada70b6eada5a23f Mon Sep 17 00:00:00 2001 From: Caleb Sander Date: Wed, 2 Sep 2020 12:56:12 -0400 Subject: [PATCH 2/2] Use UnequalOrdering as Error type of ops::Try --- library/core/src/cmp.rs | 75 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 7 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 647af1fe0419e..3b94bb48d9cd5 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -23,6 +23,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use self::Ordering::*; +use crate::convert::TryFrom; use crate::ops; /// Trait for equality comparisons which are [partial equivalence @@ -680,16 +681,76 @@ impl PartialOrd for Ordering { } } +/// An `UnequalOrdering` is an [`Ordering`] which is either `Less` or `Greater`. +/// It can be obtained from an [`Ordering`] using [`TryFrom`] or [`TryInto`]. +/// It can be converted back to an [`Ordering`] using [`From`] or [`Into`]. +/// +/// # Examples +/// +/// ``` +/// #![feature(try_trait)] +/// +/// use std::cmp::{Ordering, UnequalOrdering}; +/// use std::convert::{TryFrom, TryInto}; +/// +/// assert_eq!(Ordering::Less.try_into(), Ok(UnequalOrdering::Less)); +/// assert_eq!(Ordering::Greater.try_into(), Ok(UnequalOrdering::Greater)); +/// assert!(UnequalOrdering::try_from(Ordering::Equal).is_err()); +/// +/// assert_eq!(Ordering::from(UnequalOrdering::Less), Ordering::Less); +/// assert_eq!(Ordering::from(UnequalOrdering::Greater), Ordering::Greater); +/// ``` +/// +/// [`TryFrom`]: crate::convert::TryFrom +/// [`TryInto`]: crate::convert::TryInto +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[unstable(feature = "try_trait", issue = "42327")] +pub enum UnequalOrdering { + /// An ordering where a compared value is less than another. + Less = -1, + /// An ordering where a compared value is greater than another. + Greater = 1, +} + +/// The error type returned when conversion of [`Ordering::Equal`] into +/// [`UnequalOrdering`] fails. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[unstable(feature = "try_trait", issue = "42327")] +pub struct EqualOrderingError; + +#[unstable(feature = "try_trait", issue = "42327")] +impl TryFrom for UnequalOrdering { + type Error = EqualOrderingError; + + fn try_from(value: Ordering) -> Result { + match value { + Less => Ok(UnequalOrdering::Less), + Equal => Err(EqualOrderingError), + Greater => Ok(UnequalOrdering::Greater), + } + } +} + +#[unstable(feature = "try_trait", issue = "42327")] +impl From for Ordering { + fn from(value: UnequalOrdering) -> Self { + match value { + UnequalOrdering::Less => Less, + UnequalOrdering::Greater => Greater, + } + } +} + #[unstable(feature = "try_trait", issue = "42327")] impl ops::Try for Ordering { type Ok = (); - type Error = Self; + type Error = UnequalOrdering; #[inline] - fn into_result(self) -> Result<(), Self> { - match self { - Equal => Ok(()), - _ => Err(self), + fn into_result(self) -> Result<(), UnequalOrdering> { + match UnequalOrdering::try_from(self) { + Ok(unequal_ordering) => Err(unequal_ordering), + Err(_) => Ok(()), } } @@ -699,8 +760,8 @@ impl ops::Try for Ordering { } #[inline] - fn from_error(v: Self) -> Self { - v + fn from_error(v: UnequalOrdering) -> Self { + Self::from(v) } }