From d3c238df92bd78758ba55708c648d360c63ff1cc Mon Sep 17 00:00:00 2001 From: Luro02 <24826124+Luro02@users.noreply.github.com> Date: Sun, 16 Feb 2020 17:09:40 +0100 Subject: [PATCH] impl Ord, Eq and Hash for (U)Float --- src/types/float.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++ src/types/ufloat.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/src/types/float.rs b/src/types/float.rs index d8c8ed9..c118f69 100644 --- a/src/types/float.rs +++ b/src/types/float.rs @@ -1,3 +1,4 @@ +use core::cmp::Ordering; use core::convert::TryFrom; use core::str::FromStr; @@ -99,6 +100,47 @@ impl PartialEq for Float { fn eq(&self, other: &f32) -> bool { &self.0 == other } } +// In order to implement `Eq` a struct has to satisfy +// the following requirements: +// - reflexive: a == a; +// - symmetric: a == b implies b == a; and +// - transitive: a == b and b == c implies a == c. +// +// The symmetric and transitive parts are already satisfied +// through `PartialEq`. The reflexive part is not satisfied for f32, +// because `f32::NAN` never equals `f32::NAN`. (`assert!(f32::NAN, f32::NAN)`) +// +// It is ensured, that this struct can not be constructed +// with NaN so all of the above requirements are satisfied and therefore Eq can +// be soundly implemented. +impl Eq for Float {} + +impl Ord for Float { + #[inline] + #[must_use] + fn cmp(&self, other: &Self) -> Ordering { + if *self < *other { + Ordering::Less + } else if *self == *other { + Ordering::Equal + } else { + Ordering::Greater + } + } +} + +#[doc(hidden)] +impl ::core::hash::Hash for Float { + fn hash(&self, state: &mut H) + where + H: ::core::hash::Hasher, + { + // this should be totally fine (definitely not the most + // efficient implementation as this requires an allocation) + state.write(self.to_string().as_bytes()) + } +} + #[cfg(test)] mod tests { use super::*; @@ -170,4 +212,11 @@ mod tests { assert!(Float::try_from(::core::f32::NAN).is_err()); assert!(Float::try_from(::core::f32::NEG_INFINITY).is_err()); } + + #[test] + fn test_eq() { + struct _AssertEq + where + Float: Eq; + } } diff --git a/src/types/ufloat.rs b/src/types/ufloat.rs index 3eb2f44..a954810 100644 --- a/src/types/ufloat.rs +++ b/src/types/ufloat.rs @@ -1,3 +1,4 @@ +use core::cmp::Ordering; use core::convert::TryFrom; use core::str::FromStr; @@ -110,6 +111,47 @@ impl PartialEq for UFloat { fn eq(&self, other: &f32) -> bool { &self.0 == other } } +// In order to implement `Eq` a struct has to satisfy +// the following requirements: +// - reflexive: a == a; +// - symmetric: a == b implies b == a; and +// - transitive: a == b and b == c implies a == c. +// +// The symmetric and transitive parts are already satisfied +// through `PartialEq`. The reflexive part is not satisfied for f32, +// because `f32::NAN` never equals `f32::NAN`. (`assert!(f32::NAN, f32::NAN)`) +// +// It is ensured, that this struct can not be constructed +// with NaN so all of the above requirements are satisfied and therefore Eq can +// be soundly implemented. +impl Eq for UFloat {} + +impl Ord for UFloat { + #[inline] + #[must_use] + fn cmp(&self, other: &Self) -> Ordering { + if *self < *other { + Ordering::Less + } else if *self == *other { + Ordering::Equal + } else { + Ordering::Greater + } + } +} + +#[doc(hidden)] +impl ::core::hash::Hash for UFloat { + fn hash(&self, state: &mut H) + where + H: ::core::hash::Hasher, + { + // this should be totally fine (definitely not the most + // efficient implementation as this requires an allocation) + state.write(self.to_string().as_bytes()) + } +} + #[cfg(test)] mod tests { use super::*; @@ -179,4 +221,11 @@ mod tests { assert!(UFloat::try_from(::core::f32::NAN).is_err()); assert!(UFloat::try_from(::core::f32::NEG_INFINITY).is_err()); } + + #[test] + fn test_eq() { + struct _AssertEq + where + UFloat: Eq; + } }