drasi_core/evaluation/variable_value/
integer.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::float::Float;
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, PartialEq, Hash)]
22pub struct Integer {
23    n: N,
24}
25
26#[derive(Copy, Clone)]
27enum N {
28    PosInt(u64), //why do we do this?
29    NegInt(i64),
30}
31
32impl PartialEq for N {
33    fn eq(&self, other: &Self) -> bool {
34        match (self, other) {
35            (N::PosInt(a), N::PosInt(b)) => a == b,
36            (N::NegInt(a), N::NegInt(b)) => a == b,
37            _ => false,
38        }
39    }
40}
41
42impl PartialEq<Float> for N {
43    fn eq(&self, other: &Float) -> bool {
44        match (self, other.as_f64()) {
45            (N::PosInt(a), Some(b)) => *a as f64 == b,
46            (N::NegInt(a), Some(b)) => *a as f64 == b,
47            _ => false,
48        }
49    }
50}
51
52impl Hash for N {
53    fn hash<H: Hasher>(&self, h: &mut H) {
54        match *self {
55            N::PosInt(i) => i.hash(h),
56            N::NegInt(i) => i.hash(h),
57        }
58    }
59}
60
61impl Integer {
62    #[inline]
63    pub fn is_i64(&self) -> bool {
64        match self.n {
65            N::PosInt(v) => v <= i64::MAX as u64,
66            N::NegInt(_) => true,
67        }
68    }
69
70    #[inline]
71    pub fn is_u64(&self) -> bool {
72        match self.n {
73            N::PosInt(_) => true,
74            N::NegInt(_) => false,
75        }
76    }
77
78    #[inline]
79    pub fn as_i64(&self) -> Option<i64> {
80        match self.n {
81            N::PosInt(n) => {
82                if n <= i64::MAX as u64 {
83                    Some(n as i64)
84                } else {
85                    None
86                }
87            }
88            N::NegInt(n) => Some(n),
89        }
90    }
91
92    #[inline]
93    pub fn as_u64(&self) -> Option<u64> {
94        match self.n {
95            N::PosInt(n) => Some(n),
96            _ => None,
97        }
98    }
99}
100
101impl From<Integer> for Number {
102    fn from(val: Integer) -> Self {
103        match val.n {
104            N::PosInt(u) => Number::from(u),
105            N::NegInt(i) => Number::from(i),
106        }
107    }
108}
109
110impl Eq for Integer {}
111
112impl Display for Integer {
113    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
114        match self.n {
115            N::PosInt(u) => formatter.write_str(itoa::Buffer::new().format(u)),
116            N::NegInt(i) => formatter.write_str(itoa::Buffer::new().format(i)),
117        }
118    }
119}
120
121impl Debug for Integer {
122    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
123        write!(formatter, "Integer({})", self)
124    }
125}
126
127macro_rules! impl_from_unsigned {
128    (
129        $($ty:ty),*
130    ) => {
131        $(
132            impl From<$ty> for Integer {
133                #[inline]
134                fn from(u: $ty) -> Self {
135                    let n = {
136                        { N::PosInt(u as u64) }
137                    };
138                    Integer { n }
139                }
140            }
141        )*
142    };
143}
144
145macro_rules! impl_from_signed {
146    (
147        $($ty:ty),*
148    ) => {
149        $(
150            impl From<$ty> for Integer {
151                #[inline]
152                fn from(i: $ty) -> Self {
153                    let n = {
154                        {
155                            if i < 0 {
156                                N::NegInt(i as i64)
157                            } else {
158                                N::PosInt(i as u64)
159                            }
160                        }
161                    };
162                    Integer { n }
163                }
164            }
165        )*
166    };
167}
168
169macro_rules! impl_from_float {
170    ($ty:ty) => {
171        impl From<$ty> for Integer {
172            fn from(n: $ty) -> Self {
173                let n = {
174                    if n.fract() == 0.0 {
175                        N::PosInt(n as u64).into()
176                    } else {
177                        panic!("Invalid conversion: Cannot convert {} to Integer", n);
178                    }
179                };
180                Integer { n }
181            }
182        }
183    };
184}
185
186impl_from_unsigned!(u8, u16, u32, u64, usize);
187impl_from_signed!(i8, i16, i32, i64, isize);
188impl_from_float!(f32);
189impl_from_float!(f64);
190
191impl PartialEq<Float> for Integer {
192    fn eq(&self, other: &Float) -> bool {
193        match (self.n, other.as_f64()) {
194            (N::PosInt(a), Some(b)) => a as f64 == b,
195            (N::NegInt(a), Some(b)) => a as f64 == b,
196            _ => false,
197        }
198    }
199}
200
201impl<'de> Deserialize<'de> for Integer {
202    #[inline]
203    fn deserialize<D>(deserializer: D) -> Result<Integer, D::Error>
204    where
205        D: Deserializer<'de>,
206    {
207        struct NumberVisitor;
208
209        impl<'de> Visitor<'de> for NumberVisitor {
210            type Value = Integer;
211
212            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
213                formatter.write_str("a JSON number")
214            }
215
216            #[inline]
217            fn visit_i64<E>(self, value: i64) -> Result<Integer, E> {
218                Ok(value.into())
219            }
220
221            #[inline]
222            fn visit_u64<E>(self, value: u64) -> Result<Integer, E> {
223                Ok(value.into())
224            }
225
226            #[inline]
227            fn visit_f64<E>(self, value: f64) -> Result<Integer, E>
228            where
229                E: de::Error,
230            {
231                Ok(Integer::from(value))
232            }
233        }
234
235        deserializer.deserialize_any(NumberVisitor)
236    }
237}