@@ -16,13 +16,13 @@ use serde::de::{IntoDeserializer, MapAccess};
16
16
pub ( crate ) const TOKEN : & str = "$serde_json::private::Number" ;
17
17
18
18
/// Represents a JSON number, whether integer or floating point.
19
- #[ derive( Clone , Eq , PartialEq ) ]
19
+ #[ derive( Clone , PartialEq , Eq , Hash ) ]
20
20
pub struct Number {
21
21
n : N ,
22
22
}
23
23
24
24
#[ cfg( not( feature = "arbitrary_precision" ) ) ]
25
- #[ derive( Copy , Clone , PartialEq ) ]
25
+ #[ derive( Copy , Clone ) ]
26
26
enum N {
27
27
PosInt ( u64 ) ,
28
28
/// Always less than zero.
@@ -31,10 +31,43 @@ enum N {
31
31
Float ( f64 ) ,
32
32
}
33
33
34
+ #[ cfg( not( feature = "arbitrary_precision" ) ) ]
35
+ impl PartialEq for N {
36
+ fn eq ( & self , other : & Self ) -> bool {
37
+ match ( self , other) {
38
+ ( N :: PosInt ( a) , N :: PosInt ( b) ) => a == b,
39
+ ( N :: NegInt ( a) , N :: NegInt ( b) ) => a == b,
40
+ ( N :: Float ( a) , N :: Float ( b) ) => a == b,
41
+ _ => false ,
42
+ }
43
+ }
44
+ }
45
+
34
46
// Implementing Eq is fine since any float values are always finite.
35
47
#[ cfg( not( feature = "arbitrary_precision" ) ) ]
36
48
impl Eq for N { }
37
49
50
+ #[ cfg( not( feature = "arbitrary_precision" ) ) ]
51
+ impl core:: hash:: Hash for N {
52
+ fn hash < H : core:: hash:: Hasher > ( & self , h : & mut H ) {
53
+ match self {
54
+ N :: PosInt ( i) => i. hash ( h) ,
55
+ N :: NegInt ( i) => i. hash ( h) ,
56
+ N :: Float ( f) => {
57
+ // Using `f64::to_bits` here is fine since any float values are never `NaN`.
58
+ if * f == 0.0f64 {
59
+ // The IEEE 754 standard has two representations for zero, +0 and -0,
60
+ // such that +0 == -0.
61
+ // In both cases we use the +0 hash so that hash(+0) == hash(-0).
62
+ 0.0f64 . to_bits ( ) . hash ( h) ;
63
+ } else {
64
+ f. to_bits ( ) . hash ( h) ;
65
+ }
66
+ }
67
+ }
68
+ }
69
+ }
70
+
38
71
#[ cfg( feature = "arbitrary_precision" ) ]
39
72
type N = String ;
40
73
0 commit comments