From 2896278313ede1b24b47c88bafe684adabbc92d4 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 29 Oct 2014 20:11:16 -0500 Subject: [PATCH] DSTify PartialEq, PartialOrd, Eq, Ord --- src/libcore/cmp.rs | 222 +++++++++++++++++++++++++++++++++++++++++++ src/libcore/slice.rs | 62 ++++++++++++ src/libcore/str.rs | 45 +++++++++ 3 files changed, 329 insertions(+) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index d7c2b52b8de..6e87fe4ced0 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -55,6 +55,8 @@ use option::{Option, Some, None}; /// /// Eventually, this will be implemented by default for types that implement /// `Eq`. +// NOTE(stage0): remove trait after a snapshot +#[cfg(stage0)] #[lang="eq"] #[unstable = "Definition may change slightly after trait reform"] pub trait PartialEq { @@ -66,6 +68,31 @@ pub trait PartialEq { fn ne(&self, other: &Self) -> bool { !self.eq(other) } } +/// Trait for values that can be compared for equality and inequality. +/// +/// This trait allows for partial equality, for types that do not have an +/// equivalence relation. For example, in floating point numbers `NaN != NaN`, +/// so floating point types implement `PartialEq` but not `Eq`. +/// +/// PartialEq only requires the `eq` method to be implemented; `ne` is defined +/// in terms of it by default. Any manual implementation of `ne` *must* respect +/// the rule that `eq` is a strict inverse of `ne`; that is, `!(a == b)` if and +/// only if `a != b`. +/// +/// Eventually, this will be implemented by default for types that implement +/// `Eq`. +#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[lang="eq"] +#[unstable = "Definition may change slightly after trait reform"] +pub trait PartialEq for Sized? { + /// This method tests for `self` and `other` values to be equal, and is used by `==`. + fn eq(&self, other: &Self) -> bool; + + /// This method tests for `!=`. + #[inline] + fn ne(&self, other: &Self) -> bool { !self.eq(other) } +} + /// Trait for equality comparisons which are [equivalence relations]( /// https://en.wikipedia.org/wiki/Equivalence_relation). /// @@ -75,6 +102,8 @@ pub trait PartialEq { /// - reflexive: `a == a`; /// - symmetric: `a == b` implies `b == a`; and /// - transitive: `a == b` and `b == c` implies `a == c`. +// NOTE(stage0): remove trait after a snapshot +#[cfg(stage0)] #[unstable = "Definition may change slightly after trait reform"] pub trait Eq: PartialEq { // FIXME #13101: this method is used solely by #[deriving] to @@ -89,6 +118,30 @@ pub trait Eq: PartialEq { fn assert_receiver_is_total_eq(&self) {} } +/// Trait for equality comparisons which are [equivalence relations]( +/// https://en.wikipedia.org/wiki/Equivalence_relation). +/// +/// This means, that in addition to `a == b` and `a != b` being strict +/// inverses, the equality must be (for all `a`, `b` and `c`): +/// +/// - reflexive: `a == a`; +/// - symmetric: `a == b` implies `b == a`; and +/// - transitive: `a == b` and `b == c` implies `a == c`. +#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[unstable = "Definition may change slightly after trait reform"] +pub trait Eq for Sized?: PartialEq { + // FIXME #13101: this method is used solely by #[deriving] to + // assert that every component of a type implements #[deriving] + // itself, the current deriving infrastructure means doing this + // assertion without using a method on this trait is nearly + // impossible. + // + // This should never be implemented by hand. + #[doc(hidden)] + #[inline(always)] + fn assert_receiver_is_total_eq(&self) {} +} + /// An ordering is, e.g, a result of a comparison between two values. #[deriving(Clone, PartialEq, Show)] #[stable] @@ -145,6 +198,8 @@ impl Ordering { /// true; and /// - transitive, `a < b` and `b < c` implies `a < c`. The same must hold for /// both `==` and `>`. +// NOTE(stage0): remove trait after a snapshot +#[cfg(stage0)] #[unstable = "Definition may change slightly after trait reform"] pub trait Ord: Eq + PartialOrd { /// This method returns an ordering between `self` and `other` values. @@ -160,6 +215,31 @@ pub trait Ord: Eq + PartialOrd { fn cmp(&self, other: &Self) -> Ordering; } +/// Trait for types that form a [total order]( +/// https://en.wikipedia.org/wiki/Total_order). +/// +/// An order is a total order if it is (for all `a`, `b` and `c`): +/// +/// - total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is +/// true; and +/// - transitive, `a < b` and `b < c` implies `a < c`. The same must hold for +/// both `==` and `>`. +#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[unstable = "Definition may change slightly after trait reform"] +pub trait Ord for Sized?: Eq + PartialOrd { + /// This method returns an ordering between `self` and `other` values. + /// + /// By convention, `self.cmp(&other)` returns the ordering matching + /// the expression `self other` if true. For example: + /// + /// ``` + /// assert_eq!( 5u.cmp(&10), Less); // because 5 < 10 + /// assert_eq!(10u.cmp(&5), Greater); // because 10 > 5 + /// assert_eq!( 5u.cmp(&5), Equal); // because 5 == 5 + /// ``` + fn cmp(&self, other: &Self) -> Ordering; +} + #[unstable = "Trait is unstable."] impl Eq for Ordering {} @@ -188,6 +268,8 @@ impl PartialOrd for Ordering { /// which do not have a total order. For example, for floating point numbers, /// `NaN < 0 == false` and `NaN >= 0 == false` (cf. IEEE 754-2008 section /// 5.11). +// NOTE(stage0): remove trait after a snapshot +#[cfg(stage0)] #[lang="ord"] #[unstable = "Definition may change slightly after trait reform"] pub trait PartialOrd: PartialEq { @@ -232,6 +314,60 @@ pub trait PartialOrd: PartialEq { } } +/// Trait for values that can be compared for a sort-order. +/// +/// PartialOrd only requires implementation of the `partial_cmp` method, +/// with the others generated from default implementations. +/// +/// However it remains possible to implement the others separately for types +/// which do not have a total order. For example, for floating point numbers, +/// `NaN < 0 == false` and `NaN >= 0 == false` (cf. IEEE 754-2008 section +/// 5.11). +#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[lang="ord"] +#[unstable = "Definition may change slightly after trait reform"] +pub trait PartialOrd for Sized?: PartialEq { + /// This method returns an ordering between `self` and `other` values + /// if one exists. + fn partial_cmp(&self, other: &Self) -> Option; + + /// This method tests less than (for `self` and `other`) and is used by the `<` operator. + #[inline] + fn lt(&self, other: &Self) -> bool { + match self.partial_cmp(other) { + Some(Less) => true, + _ => false, + } + } + + /// This method tests less than or equal to (`<=`). + #[inline] + fn le(&self, other: &Self) -> bool { + match self.partial_cmp(other) { + Some(Less) | Some(Equal) => true, + _ => false, + } + } + + /// This method tests greater than (`>`). + #[inline] + fn gt(&self, other: &Self) -> bool { + match self.partial_cmp(other) { + Some(Greater) => true, + _ => false, + } + } + + /// This method tests greater than or equal to (`>=`). + #[inline] + fn ge(&self, other: &Self) -> bool { + match self.partial_cmp(other) { + Some(Greater) | Some(Equal) => true, + _ => false, + } + } +} + /// The equivalence relation. Two values may be equivalent even if they are /// of different types. The most common use case for this relation is /// container types; e.g. it is often desirable to be able to use `&str` @@ -286,6 +422,8 @@ pub fn partial_max(v1: T, v2: T) -> Option { mod impls { use cmp::{PartialOrd, Ord, PartialEq, Eq, Ordering, Less, Greater, Equal}; + #[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot + use kinds::Sized; use option::{Option, Some, None}; macro_rules! partial_eq_impl( @@ -393,6 +531,8 @@ mod impls { ord_impl!(char uint u8 u16 u32 u64 int i8 i16 i32 i64) // & pointers + // NOTE(stage0): remove impl after a snapshot + #[cfg(stage0)] #[unstable = "Trait is unstable."] impl<'a, T: PartialEq> PartialEq for &'a T { #[inline] @@ -400,6 +540,8 @@ mod impls { #[inline] fn ne(&self, other: & &'a T) -> bool { *(*self) != *(*other) } } + // NOTE(stage0): remove impl after a snapshot + #[cfg(stage0)] #[unstable = "Trait is unstable."] impl<'a, T: PartialOrd> PartialOrd for &'a T { #[inline] @@ -415,15 +557,55 @@ mod impls { #[inline] fn gt(&self, other: & &'a T) -> bool { *(*self) > *(*other) } } + // NOTE(stage0): remove impl after a snapshot + #[cfg(stage0)] #[unstable = "Trait is unstable."] impl<'a, T: Ord> Ord for &'a T { #[inline] fn cmp(&self, other: & &'a T) -> Ordering { (**self).cmp(*other) } } + // NOTE(stage0): remove impl after a snapshot + #[cfg(stage0)] #[unstable = "Trait is unstable."] impl<'a, T: Eq> Eq for &'a T {} + #[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot + #[unstable = "Trait is unstable."] + impl<'a, Sized? T: PartialEq> PartialEq for &'a T { + #[inline] + fn eq(&self, other: & &'a T) -> bool { PartialEq::eq(*self, *other) } + #[inline] + fn ne(&self, other: & &'a T) -> bool { PartialEq::ne(*self, *other) } + } + #[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot + #[unstable = "Trait is unstable."] + impl<'a, Sized? T: PartialOrd> PartialOrd for &'a T { + #[inline] + fn partial_cmp(&self, other: &&'a T) -> Option { + PartialOrd::partial_cmp(*self, *other) + } + #[inline] + fn lt(&self, other: & &'a T) -> bool { PartialOrd::lt(*self, *other) } + #[inline] + fn le(&self, other: & &'a T) -> bool { PartialOrd::le(*self, *other) } + #[inline] + fn ge(&self, other: & &'a T) -> bool { PartialOrd::ge(*self, *other) } + #[inline] + fn gt(&self, other: & &'a T) -> bool { PartialOrd::gt(*self, *other) } + } + #[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot + #[unstable = "Trait is unstable."] + impl<'a, Sized? T: Ord> Ord for &'a T { + #[inline] + fn cmp(&self, other: & &'a T) -> Ordering { Ord::cmp(*self, *other) } + } + #[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot + #[unstable = "Trait is unstable."] + impl<'a, Sized? T: Eq> Eq for &'a T {} + // &mut pointers + // NOTE(stage0): remove impl after a snapshot + #[cfg(stage0)] #[unstable = "Trait is unstable."] impl<'a, T: PartialEq> PartialEq for &'a mut T { #[inline] @@ -431,6 +613,8 @@ mod impls { #[inline] fn ne(&self, other: &&'a mut T) -> bool { **self != *(*other) } } + // NOTE(stage0): remove impl after a snapshot + #[cfg(stage0)] #[unstable = "Trait is unstable."] impl<'a, T: PartialOrd> PartialOrd for &'a mut T { #[inline] @@ -446,11 +630,49 @@ mod impls { #[inline] fn gt(&self, other: &&'a mut T) -> bool { **self > **other } } + // NOTE(stage0): remove impl after a snapshot + #[cfg(stage0)] #[unstable = "Trait is unstable."] impl<'a, T: Ord> Ord for &'a mut T { #[inline] fn cmp(&self, other: &&'a mut T) -> Ordering { (**self).cmp(*other) } } + // NOTE(stage0): remove impl after a snapshot + #[cfg(stage0)] #[unstable = "Trait is unstable."] impl<'a, T: Eq> Eq for &'a mut T {} + + #[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot + #[unstable = "Trait is unstable."] + impl<'a, Sized? T: PartialEq> PartialEq for &'a mut T { + #[inline] + fn eq(&self, other: &&'a mut T) -> bool { PartialEq::eq(*self, *other) } + #[inline] + fn ne(&self, other: &&'a mut T) -> bool { PartialEq::ne(*self, *other) } + } + #[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot + #[unstable = "Trait is unstable."] + impl<'a, Sized? T: PartialOrd> PartialOrd for &'a mut T { + #[inline] + fn partial_cmp(&self, other: &&'a mut T) -> Option { + PartialOrd::partial_cmp(*self, *other) + } + #[inline] + fn lt(&self, other: &&'a mut T) -> bool { PartialOrd::lt(*self, *other) } + #[inline] + fn le(&self, other: &&'a mut T) -> bool { PartialOrd::le(*self, *other) } + #[inline] + fn ge(&self, other: &&'a mut T) -> bool { PartialOrd::ge(*self, *other) } + #[inline] + fn gt(&self, other: &&'a mut T) -> bool { PartialOrd::gt(*self, *other) } + } + #[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot + #[unstable = "Trait is unstable."] + impl<'a, Sized? T: Ord> Ord for &'a mut T { + #[inline] + fn cmp(&self, other: &&'a mut T) -> Ordering { Ord::cmp(*self, *other) } + } + #[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot + #[unstable = "Trait is unstable."] + impl<'a, Sized? T: Eq> Eq for &'a mut T {} } diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 317a6e224bc..3cc904162a1 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -1555,6 +1555,8 @@ pub mod bytes { // Boilerplate traits // +// NOTE(stage0): remove impl after a snapshot +#[cfg(stage0)] #[unstable = "waiting for DST"] impl<'a,T:PartialEq> PartialEq for &'a [T] { fn eq(&self, other: & &'a [T]) -> bool { @@ -1567,15 +1569,36 @@ impl<'a,T:PartialEq> PartialEq for &'a [T] { } } +#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[unstable = "waiting for DST"] +impl PartialEq for [T] { + fn eq(&self, other: &[T]) -> bool { + self.len() == other.len() && + order::eq(self.iter(), other.iter()) + } + fn ne(&self, other: &[T]) -> bool { + self.len() != other.len() || + order::ne(self.iter(), other.iter()) + } +} + +// NOTE(stage0): remove impl after a snapshot +#[cfg(stage0)] #[unstable = "waiting for DST"] impl<'a,T:Eq> Eq for &'a [T] {} +#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[unstable = "waiting for DST"] +impl Eq for [T] {} + #[unstable = "waiting for DST"] impl> Equiv for [T] { #[inline] fn equiv(&self, other: &V) -> bool { self.as_slice() == other.as_slice() } } +// NOTE(stage0): remove impl after a snapshot +#[cfg(stage0)] #[unstable = "waiting for DST"] impl<'a,T:PartialEq> PartialEq for &'a mut [T] { fn eq(&self, other: & &'a mut [T]) -> bool { @@ -1588,6 +1611,8 @@ impl<'a,T:PartialEq> PartialEq for &'a mut [T] { } } +// NOTE(stage0): remove impl after a snapshot +#[cfg(stage0)] #[unstable = "waiting for DST"] impl<'a,T:Eq> Eq for &'a mut [T] {} @@ -1597,6 +1622,8 @@ impl<'a,T:PartialEq, V: AsSlice> Equiv for &'a mut [T] { fn equiv(&self, other: &V) -> bool { self.as_slice() == other.as_slice() } } +// NOTE(stage0): remove impl after a snapshot +#[cfg(stage0)] #[unstable = "waiting for DST"] impl<'a,T:Ord> Ord for &'a [T] { fn cmp(&self, other: & &'a [T]) -> Ordering { @@ -1604,6 +1631,16 @@ impl<'a,T:Ord> Ord for &'a [T] { } } +#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[unstable = "waiting for DST"] +impl Ord for [T] { + fn cmp(&self, other: &[T]) -> Ordering { + order::cmp(self.iter(), other.iter()) + } +} + +// NOTE(stage0): remove impl after a snapshot +#[cfg(stage0)] #[unstable = "waiting for DST"] impl<'a, T: PartialOrd> PartialOrd for &'a [T] { #[inline] @@ -1628,6 +1665,31 @@ impl<'a, T: PartialOrd> PartialOrd for &'a [T] { } } +#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +#[unstable = "waiting for DST"] +impl PartialOrd for [T] { + #[inline] + fn partial_cmp(&self, other: &[T]) -> Option { + order::partial_cmp(self.iter(), other.iter()) + } + #[inline] + fn lt(&self, other: &[T]) -> bool { + order::lt(self.iter(), other.iter()) + } + #[inline] + fn le(&self, other: &[T]) -> bool { + order::le(self.iter(), other.iter()) + } + #[inline] + fn ge(&self, other: &[T]) -> bool { + order::ge(self.iter(), other.iter()) + } + #[inline] + fn gt(&self, other: &[T]) -> bool { + order::gt(self.iter(), other.iter()) + } +} + /// Extension methods for immutable slices containing integers. #[experimental] pub trait ImmutableIntSlice for Sized? { diff --git a/src/libcore/str.rs b/src/libcore/str.rs index 10c0f68dd5d..175f9f3f577 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -1122,6 +1122,8 @@ pub mod traits { use ops; use str::{Str, StrSlice, eq_slice}; + // NOTE(stage0): remove impl after a snapshot + #[cfg(stage0)] impl<'a> Ord for &'a str { #[inline] fn cmp(&self, other: & &'a str) -> Ordering { @@ -1137,6 +1139,24 @@ pub mod traits { } } + #[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot + impl Ord for str { + #[inline] + fn cmp(&self, other: &str) -> Ordering { + for (s_b, o_b) in self.bytes().zip(other.bytes()) { + match s_b.cmp(&o_b) { + Greater => return Greater, + Less => return Less, + Equal => () + } + } + + self.len().cmp(&other.len()) + } + } + + // NOTE(stage0): remove impl after a snapshot + #[cfg(stage0)] impl<'a> PartialEq for &'a str { #[inline] fn eq(&self, other: & &'a str) -> bool { @@ -1146,8 +1166,25 @@ pub mod traits { fn ne(&self, other: & &'a str) -> bool { !(*self).eq(other) } } + #[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot + impl PartialEq for str { + #[inline] + fn eq(&self, other: &str) -> bool { + eq_slice(self, other) + } + #[inline] + fn ne(&self, other: &str) -> bool { !(*self).eq(other) } + } + + // NOTE(stage0): remove impl after a snapshot + #[cfg(stage0)] impl<'a> Eq for &'a str {} + #[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot + impl Eq for str {} + + // NOTE(stage0): remove impl after a snapshot + #[cfg(stage0)] impl<'a> PartialOrd for &'a str { #[inline] fn partial_cmp(&self, other: &&'a str) -> Option { @@ -1155,6 +1192,14 @@ pub mod traits { } } + #[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot + impl PartialOrd for str { + #[inline] + fn partial_cmp(&self, other: &str) -> Option { + Some(self.cmp(other)) + } + } + impl Equiv for str { #[inline] fn equiv(&self, other: &S) -> bool { eq_slice(self, other.as_slice()) }