Skip to main content

drasi_core/evaluation/variable_value/
float.rs

1// Copyright 2024 The Drasi Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::evaluation::variable_value::integer::Integer;
16use core::fmt::{self, Debug, Display};
17use core::hash::{Hash, Hasher};
18use serde::de::{self, Deserialize, Deserializer, Visitor};
19use serde_json::Number;
20
21#[derive(Clone, Default)]
22pub struct Float {
23    value: f64,
24}
25
26impl PartialEq for Float {
27    fn eq(&self, other: &Self) -> bool {
28        let (a, b) = (self.value, other.value);
29        a == b
30    }
31}
32
33impl PartialEq<f64> for Float {
34    fn eq(&self, other: &f64) -> bool {
35        let (a, b) = (self.value, *other);
36        a == b
37    }
38}
39
40impl PartialEq<Integer> for Float {
41    fn eq(&self, other: &Integer) -> bool {
42        match (self.value, other.as_i64()) {
43            (a, Some(b)) => a == b as f64,
44            _ => false,
45        }
46    }
47}
48
49impl Eq for Float {}
50
51impl Hash for Float {
52    fn hash<H: Hasher>(&self, h: &mut H) {
53        // There are 2 zero representations, +0 and -0, which
54        // compare equal but have different bits. We use the +0 hash
55        // for both so that hash(+0) == hash(-0).
56        if self.value == 0.0f64 {
57            0.0f64.to_bits().hash(h);
58        } else {
59            self.value.to_bits().hash(h);
60        }
61    }
62}
63
64impl Float {
65    #[inline]
66    pub fn is_f64(&self) -> bool {
67        self.value.is_finite()
68    }
69
70    pub(crate) fn as_f64(&self) -> Option<f64> {
71        match self.value {
72            n if n.is_finite() => Some(n),
73            _ => None,
74        }
75    }
76
77    pub(crate) fn as_f32(&self) -> Option<f32> {
78        match self.value {
79            n if n.is_finite() => Some(n as f32),
80            _ => None,
81        }
82    }
83
84    #[inline]
85    pub fn from_f64(f: f64) -> Option<Float> {
86        if f.is_finite() {
87            Some(Float { value: f })
88        } else {
89            None
90        }
91    }
92
93    #[inline]
94    pub(crate) fn from_f32(f: f32) -> Option<Float> {
95        if f.is_finite() {
96            Some(Float { value: f as f64 })
97        } else {
98            None
99        }
100    }
101}
102
103impl From<Float> for Number {
104    fn from(val: Float) -> Self {
105        Number::from_f64(val.value).expect("a finite float")
106    }
107}
108
109impl Debug for Float {
110    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
111        write!(formatter, "Float({self})")
112    }
113}
114
115impl Display for Float {
116    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
117        {
118            let value = &self.value;
119            formatter.write_str(&value.to_string())
120        }
121    }
122}
123
124impl<'de> Deserialize<'de> for Float {
125    #[inline]
126    fn deserialize<D>(deserializer: D) -> Result<Float, D::Error>
127    where
128        D: Deserializer<'de>,
129    {
130        struct NumberVisitor;
131
132        impl Visitor<'_> for NumberVisitor {
133            type Value = Float;
134
135            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
136                formatter.write_str("a JSON number")
137            }
138
139            #[inline]
140            fn visit_f64<E>(self, value: f64) -> Result<Float, E>
141            where
142                E: de::Error,
143            {
144                Ok(Float::from(value))
145            }
146
147            #[inline]
148            fn visit_f32<E>(self, value: f32) -> Result<Float, E>
149            where
150                E: de::Error,
151            {
152                Ok(Float::from(value))
153            }
154        }
155
156        deserializer.deserialize_any(NumberVisitor)
157    }
158}
159
160macro_rules! impl_from_float {
161    (
162        $($ty:ty),*
163    ) => {
164        $(
165            impl From<$ty> for Float {
166                #[inline]
167                fn from(i: $ty) -> Self {
168                    let n = {
169                        {
170                            i as f64
171                        }
172                    };
173                    Float { value: n }
174                }
175            }
176        )*
177    };
178}
179
180impl_from_float!(f32, f64, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);