diff options
Diffstat (limited to 'src/number.rs')
-rw-r--r-- | src/number.rs | 44 |
1 files changed, 39 insertions, 5 deletions
diff --git a/src/number.rs b/src/number.rs index c147618..b965271 100644 --- a/src/number.rs +++ b/src/number.rs @@ -1,6 +1,8 @@ use crate::de::ParserNumber; use crate::error::Error; -use crate::lib::*; +use core::fmt::{self, Debug, Display}; +#[cfg(not(feature = "arbitrary_precision"))] +use core::hash::{Hash, Hasher}; use serde::de::{self, Unexpected, Visitor}; use serde::{ forward_to_deserialize_any, serde_if_integer128, Deserialize, Deserializer, Serialize, @@ -16,13 +18,13 @@ use serde::de::{IntoDeserializer, MapAccess}; pub(crate) const TOKEN: &str = "$serde_json::private::Number"; /// Represents a JSON number, whether integer or floating point. -#[derive(Clone, Eq, PartialEq)] +#[derive(Clone, PartialEq, Eq, Hash)] pub struct Number { n: N, } #[cfg(not(feature = "arbitrary_precision"))] -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, Clone)] enum N { PosInt(u64), /// Always less than zero. @@ -31,10 +33,42 @@ enum N { Float(f64), } +#[cfg(not(feature = "arbitrary_precision"))] +impl PartialEq for N { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (N::PosInt(a), N::PosInt(b)) => a == b, + (N::NegInt(a), N::NegInt(b)) => a == b, + (N::Float(a), N::Float(b)) => a == b, + _ => false, + } + } +} + // Implementing Eq is fine since any float values are always finite. #[cfg(not(feature = "arbitrary_precision"))] impl Eq for N {} +#[cfg(not(feature = "arbitrary_precision"))] +impl Hash for N { + fn hash<H: Hasher>(&self, h: &mut H) { + match *self { + N::PosInt(i) => i.hash(h), + N::NegInt(i) => i.hash(h), + N::Float(f) => { + if f == 0.0f64 { + // There are 2 zero representations, +0 and -0, which + // compare equal but have different bits. We use the +0 hash + // for both so that hash(+0) == hash(-0). + 0.0f64.to_bits().hash(h); + } else { + f.to_bits().hash(h); + } + } + } + } +} + #[cfg(feature = "arbitrary_precision")] type N = String; @@ -130,7 +164,7 @@ impl Number { { for c in self.n.chars() { if c == '.' || c == 'e' || c == 'E' { - return self.n.parse::<f64>().ok().map_or(false, |f| f.is_finite()); + return self.n.parse::<f64>().ok().map_or(false, f64::is_finite); } } false @@ -254,7 +288,7 @@ impl Number { } } -impl fmt::Display for Number { +impl Display for Number { #[cfg(not(feature = "arbitrary_precision"))] fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { match self.n { |