tower_sesh/value/
number.rs

1// Adapted from https://github.com/serde-rs/json.
2
3use std::{fmt, hash::Hash};
4
5use serde::{
6    de::{self, Unexpected, Visitor},
7    forward_to_deserialize_any, Deserialize, Serialize,
8};
9
10use super::error::Error;
11
12/// Represents a number, whether integer or floating point.
13///
14/// May only represent values which are representable by [`i64`], [`u64`], or
15/// [finite] [`f64`].
16///
17/// [finite]: f64::is_finite
18#[derive(Clone, PartialEq, Eq, Hash)]
19pub struct Number {
20    n: NumberImpl,
21}
22
23#[derive(Copy, Clone)]
24enum NumberImpl {
25    PosInt(u64),
26    /// Always less than zero.
27    NegInt(i64),
28    /// Always finite.
29    Float(f64),
30}
31
32impl PartialEq for NumberImpl {
33    fn eq(&self, other: &Self) -> bool {
34        use NumberImpl::*;
35        match (self, other) {
36            (PosInt(a), PosInt(b)) => a.eq(b),
37            (NegInt(a), NegInt(b)) => a.eq(b),
38            (Float(a), Float(b)) => a.eq(b),
39            _ => false,
40        }
41    }
42}
43
44// NaN cannot be represented, so this is valid
45impl Eq for NumberImpl {}
46
47impl Hash for NumberImpl {
48    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
49        use NumberImpl::*;
50        match *self {
51            PosInt(i) => i.hash(state),
52            NegInt(i) => i.hash(state),
53            Float(f) => {
54                if f == 0.0f64 {
55                    0.0f64.to_bits().hash(state)
56                } else {
57                    f.to_bits().hash(state)
58                }
59            }
60        }
61    }
62}
63
64impl Number {
65    /// Returns `true` if the `Number` is an integer between [`i64::MIN`] and
66    /// [`i64::MAX`].
67    ///
68    /// For any `Number` on which `is_i64` returns `true`, [`as_i64`] is
69    /// guaranteed to return the integer value.
70    ///
71    /// [`as_i64`]: Number::as_i64
72    pub fn is_i64(&self) -> bool {
73        use NumberImpl::*;
74        match self.n {
75            PosInt(v) => v <= i64::MAX as u64,
76            NegInt(_) => true,
77            Float(_) => false,
78        }
79    }
80
81    /// Returns `true` if the `Number` is an integer between `0` and
82    /// [`u64::MAX`].
83    ///
84    /// For any `Number` on which `is_u64` returns `true`, [`as_u64`] is
85    /// guaranteed to return the integer value.
86    ///
87    /// [`as_u64`]: Number::as_u64
88    pub fn is_u64(&self) -> bool {
89        use NumberImpl::*;
90        match self.n {
91            PosInt(_) => true,
92            NegInt(_) | Float(_) => false,
93        }
94    }
95
96    /// Returns `true` if the `Number` can be represented by [`f64`].
97    ///
98    /// For any `Number` on which `is_f64` returns `true`, [`as_f64`] is
99    /// guaranteed to return the floating point value.
100    ///
101    /// This function returns `true` if and only if both [`is_i64`] and
102    /// [`is_u64`] return `false`.
103    ///
104    /// [`as_f64`]: Number::as_f64
105    /// [`is_i64`]: Number::is_i64
106    /// [`is_u64`]: Number::is_u64
107    pub fn is_f64(&self) -> bool {
108        use NumberImpl::*;
109        match self.n {
110            Float(_) => true,
111            PosInt(_) | NegInt(_) => false,
112        }
113    }
114
115    /// If the `Number` is an integer, represent it as [`i64`] if possible.
116    /// Returns `None` otherwise.
117    pub fn as_i64(&self) -> Option<i64> {
118        use NumberImpl::*;
119        match self.n {
120            PosInt(n) => {
121                if n <= i64::MAX as u64 {
122                    Some(n as i64)
123                } else {
124                    None
125                }
126            }
127            NegInt(n) => Some(n),
128            Float(_) => None,
129        }
130    }
131
132    /// If the `Number` is an integer, represent it as [`u64`] if possible.
133    /// Returns `None` otherwise.
134    pub fn as_u64(&self) -> Option<u64> {
135        use NumberImpl::*;
136        match self.n {
137            PosInt(n) => Some(n),
138            NegInt(_) | Float(_) => None,
139        }
140    }
141
142    /// Represents the number as [`f64`] if possible. Returns `None` otherwise.
143    pub fn as_f64(&self) -> Option<f64> {
144        use NumberImpl::*;
145        match self.n {
146            PosInt(n) => Some(n as f64),
147            NegInt(n) => Some(n as f64),
148            Float(n) => Some(n),
149        }
150    }
151
152    /// Converts a [finite] [`f64`] to a `Number`. Infinite or NaN values are
153    /// not valid `Number`s.
154    ///
155    /// [finite]: f64::is_finite
156    ///
157    /// ```
158    /// # use tower_sesh::value::Number;
159    /// #
160    /// assert!(Number::from_f64(256.0).is_some());
161    ///
162    /// assert!(Number::from_f64(f64::NAN).is_none());
163    /// ```
164    pub fn from_f64(f: f64) -> Option<Number> {
165        if f.is_finite() {
166            let n = NumberImpl::Float(f);
167            Some(Number { n })
168        } else {
169            None
170        }
171    }
172
173    /// Converts an [`i128`] to a `Number`. Returns `None` for numbers smaller
174    /// than [`i64::MIN`] or larger than [`u64::MAX`].
175    ///
176    /// ```
177    /// # use tower_sesh::value::Number;
178    /// #
179    /// assert!(Number::from_i128(256).is_some());
180    /// ```
181    pub fn from_i128(i: i128) -> Option<Number> {
182        let n = if let Ok(u) = u64::try_from(i) {
183            NumberImpl::PosInt(u)
184        } else if let Ok(i) = i64::try_from(i) {
185            NumberImpl::NegInt(i)
186        } else {
187            return None;
188        };
189        Some(Number { n })
190    }
191
192    /// Converts a [`u128`] to a `Number`. Returns `None` for numbers larger
193    /// than [`u64::MAX`].
194    ///
195    /// ```
196    /// # use tower_sesh::value::Number;
197    /// #
198    /// assert!(Number::from_u128(256).is_some());
199    /// ```
200    pub fn from_u128(u: u128) -> Option<Number> {
201        let n = if let Ok(u) = u64::try_from(u) {
202            NumberImpl::PosInt(u)
203        } else {
204            return None;
205        };
206        Some(Number { n })
207    }
208
209    pub(super) fn as_f32(&self) -> Option<f32> {
210        use NumberImpl::*;
211        match self.n {
212            PosInt(n) => Some(n as f32),
213            NegInt(n) => Some(n as f32),
214            Float(n) => Some(n as f32),
215        }
216    }
217
218    pub(super) fn from_f32(f: f32) -> Option<Number> {
219        if f.is_finite() {
220            let n = NumberImpl::Float(f as f64);
221            Some(Number { n })
222        } else {
223            None
224        }
225    }
226}
227
228impl fmt::Display for Number {
229    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
230        use NumberImpl::*;
231        match self.n {
232            PosInt(u) => formatter.write_str(itoa::Buffer::new().format(u)),
233            NegInt(i) => formatter.write_str(itoa::Buffer::new().format(i)),
234            Float(f) => formatter.write_str(ryu::Buffer::new().format_finite(f)),
235        }
236    }
237}
238
239impl fmt::Debug for Number {
240    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241        write!(f, "Number({})", self)
242    }
243}
244
245impl Serialize for Number {
246    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
247    where
248        S: serde::Serializer,
249    {
250        use NumberImpl::*;
251        match self.n {
252            PosInt(u) => serializer.serialize_u64(u),
253            NegInt(i) => serializer.serialize_i64(i),
254            Float(f) => serializer.serialize_f64(f),
255        }
256    }
257}
258
259impl<'de> Deserialize<'de> for Number {
260    #[inline]
261    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
262    where
263        D: serde::Deserializer<'de>,
264    {
265        struct NumberVisitor;
266
267        impl Visitor<'_> for NumberVisitor {
268            type Value = Number;
269
270            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
271                formatter.write_str("a number")
272            }
273
274            fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E> {
275                Ok(v.into())
276            }
277
278            fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
279            where
280                E: serde::de::Error,
281            {
282                Number::from_i128(v).ok_or_else(|| de::Error::custom("number out of range"))
283            }
284
285            fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> {
286                Ok(v.into())
287            }
288
289            fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
290            where
291                E: de::Error,
292            {
293                Number::from_u128(v).ok_or_else(|| de::Error::custom("number out of range"))
294            }
295
296            fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E>
297            where
298                E: de::Error,
299            {
300                Number::from_f32(v).ok_or_else(|| de::Error::custom("not a valid number"))
301            }
302
303            fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
304            where
305                E: de::Error,
306            {
307                Number::from_f64(v).ok_or_else(|| de::Error::custom("not a valid number"))
308            }
309        }
310
311        deserializer.deserialize_any(NumberVisitor)
312    }
313}
314
315macro_rules! deserialize_any {
316    () => {
317        fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
318        where
319            V: Visitor<'de>,
320        {
321            match self.n {
322                NumberImpl::PosInt(u) => visitor.visit_u64(u),
323                NumberImpl::NegInt(i) => visitor.visit_i64(i),
324                NumberImpl::Float(f) => visitor.visit_f64(f),
325            }
326        }
327    };
328}
329
330impl<'de> serde::Deserializer<'de> for Number {
331    type Error = Error;
332
333    deserialize_any!();
334
335    forward_to_deserialize_any! {
336        i8 i16 i32 i64 i128
337        u8 u16 u32 u64 u128 f32 f64
338        bool char str string bytes byte_buf option unit unit_struct
339        newtype_struct seq tuple tuple_struct map struct enum identifier
340        ignored_any
341    }
342}
343
344impl<'de> serde::Deserializer<'de> for &Number {
345    type Error = Error;
346
347    deserialize_any!();
348
349    forward_to_deserialize_any! {
350        i8 i16 i32 i64 i128
351        u8 u16 u32 u64 u128 f32 f64
352        bool char str string bytes byte_buf option unit unit_struct
353        newtype_struct seq tuple tuple_struct map struct enum identifier
354        ignored_any
355    }
356}
357
358macro_rules! from_unsigned {
359    ($($ty:ty)*) => {
360        $(
361            impl From<$ty> for Number {
362                fn from(u: $ty) -> Self {
363                    let n = NumberImpl::PosInt(u as u64);
364                    Number { n }
365                }
366            }
367        )*
368    };
369}
370
371macro_rules! from_signed {
372    ($($ty:ty)*) => {
373        $(
374            impl From<$ty> for Number {
375                fn from(i: $ty) -> Self {
376                    let n = if i < 0 {
377                        NumberImpl::NegInt(i as i64)
378                    } else {
379                        NumberImpl::PosInt(i as u64)
380                    };
381                    Number { n }
382                }
383            }
384        )*
385    };
386}
387
388from_unsigned! {
389    u8 u16 u32 u64 usize
390}
391from_signed! {
392    i8 i16 i32 i64 isize
393}
394
395impl Number {
396    #[cold]
397    pub(crate) fn unexpected(&self) -> Unexpected {
398        use NumberImpl::*;
399        match self.n {
400            PosInt(u) => Unexpected::Unsigned(u),
401            NegInt(i) => Unexpected::Signed(i),
402            Float(f) => Unexpected::Float(f),
403        }
404    }
405}