graphql_query/ast/
ast_util.rs

1// TODO: Replace with print comparison (See FloatValue's write_to_buffer)
2// This is here *just* so we can have PartialEq on other nodes, but we shouldn't ever actually compare
3// floats
4
5// See: https://github.com/reem/rust-ordered-float/blob/8962ffc/src/lib.rs
6use super::ast::FloatValue;
7use core::hash::{Hash, Hasher};
8
9// masks for the parts of the IEEE 754 float
10const SIGN_MASK: u64 = 0x8000_0000_0000_0000_u64;
11const EXP_MASK: u64 = 0x7ff0_0000_0000_0000_u64;
12const MAN_MASK: u64 = 0x000f_ffff_ffff_ffff_u64;
13
14// canonical raw bit patterns (for hashing)
15const CANONICAL_NAN_BITS: u64 = 0x7ff8_0000_0000_0000_u64;
16const CANONICAL_ZERO_BITS: u64 = 0x0u64;
17
18#[inline]
19fn raw_double_bits(f: &f64) -> u64 {
20    if f.is_nan() {
21        return CANONICAL_NAN_BITS;
22    }
23
24    // See: https://github.com/rust-num/num-traits/blob/edb4821/src/float.rs#L2027-L2041
25    let bits: u64 = f.to_bits();
26    let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
27    let mut exp: i16 = ((bits >> 52) & 0x7ff) as i16;
28    let man = if exp == 0 {
29        (bits & 0x000f_ffff_ffff_ffff) << 1
30    } else {
31        (bits & 0x000f_ffff_ffff_ffff) | 0x0010_0000_0000_0000
32    };
33    // Exponent bias + mantissa shift
34    exp -= 1023 + 52;
35
36    if man == 0 {
37        return CANONICAL_ZERO_BITS;
38    }
39
40    let man_u64 = man;
41    let exp_u64 = u64::from(exp as u16);
42    let sign_u64 = if sign > 0 { 1u64 } else { 0u64 };
43    (man_u64 & MAN_MASK) | ((exp_u64 << 52) & EXP_MASK) | ((sign_u64 << 63) & SIGN_MASK)
44}
45
46impl<'a> Hash for FloatValue<'a> {
47    fn hash<H: Hasher>(&self, state: &mut H) {
48        let float = self.value.parse::<f64>().unwrap_or(0.0);
49        if float.is_nan() {
50            raw_double_bits(&f64::NAN).hash(state);
51        } else {
52            raw_double_bits(&float).hash(state);
53        }
54    }
55}
56
57impl<'a> PartialEq for FloatValue<'a> {
58    fn eq(&self, other: &Self) -> bool {
59        self.value == other.value
60    }
61}
62
63impl<'a> Eq for FloatValue<'a> {}