Skip to main content

ron/value/
number.rs

1use core::{
2    cmp::{Eq, Ordering},
3    hash::{Hash, Hasher},
4};
5
6use crate::error::{Error, Result};
7use serde::{de::Visitor, Serialize, Serializer};
8
9/// A wrapper for any numeric primitive type in Rust.
10///
11/// Some varints of the `Number` enum are enabled by features:
12/// - `Number::I128` and `Number::U128` by the `integer128` feature
13///
14/// To ensure that feature unification does not break `match`ing over `Number`,
15/// the `Number` enum is non-exhaustive.
16///
17/// <details>
18/// <summary>Exhaustively matching on <code>Number</code> in tests</summary>
19///
20/// If you want to ensure that you exhaustively handle every variant, you can
21/// match on the hidden `Number::__NonExhaustive(x)` variant by using the
22/// `x.never() -> !` method.
23///
24/// <div class="warning">
25/// Matching on this variant means that your code may break when RON is
26/// upgraded or when feature unification enables further variants in the
27/// <code>Number</code> enum than your code expects.
28/// </div>
29///
30/// It is your responsibility to only *ever* match on `Number::__NonExhaustive`
31/// inside tests, e.g. by using `#[cfg(test)]` on the particular match arm, to
32/// ensure that only your tests break (e.g. in CI) when your code is not
33/// exhaustively matching on every variant, e.g. after a version upgrade or
34/// feature unification.
35/// </details>
36#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Hash, Ord)]
37#[cfg_attr(doc, non_exhaustive)]
38pub enum Number {
39    I8(i8),
40    I16(i16),
41    I32(i32),
42    I64(i64),
43    #[cfg(feature = "integer128")]
44    I128(i128),
45    U8(u8),
46    U16(u16),
47    U32(u32),
48    U64(u64),
49    #[cfg(feature = "integer128")]
50    U128(u128),
51    F32(F32),
52    F64(F64),
53    #[cfg(not(doc))]
54    #[allow(private_interfaces)]
55    __NonExhaustive(private::Never),
56}
57
58mod private {
59    #[derive(Debug, PartialEq, PartialOrd, Eq, Hash, Ord)]
60    enum _Never {}
61
62    #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Hash, Ord)]
63    pub struct Never {
64        never: &'static _Never,
65    }
66
67    impl Never {
68        pub fn never(self) -> ! {
69            match *self.never {}
70        }
71    }
72
73    #[cfg(not(feature = "integer128"))]
74    /// ```compile_fail
75    /// # use ron::Number;
76    /// fn match_number(x: Number) {
77    ///     match x {
78    ///         Number::I8(v) => println!("i8: {}", v),
79    ///         Number::I16(v) => println!("i16: {}", v),
80    ///         Number::I32(v) => println!("i32: {}", v),
81    ///         Number::I64(v) => println!("i64: {}", v),
82    ///         Number::U8(v) => println!("u8: {}", v),
83    ///         Number::U16(v) => println!("u16: {}", v),
84    ///         Number::U32(v) => println!("u32: {}", v),
85    ///         Number::U64(v) => println!("u64: {}", v),
86    ///         Number::F32(v) => println!("f32: {}", v.0),
87    ///         Number::F64(v) => println!("f64: {}", v.0),
88    ///     }
89    /// }
90    /// ```
91    fn _assert_non_exhaustive_check_fails_not_integer128() {}
92
93    #[cfg(feature = "integer128")]
94    /// ```compile_fail
95    /// # use ron::Number;
96    /// fn match_number(x: Number) {
97    ///     match x {
98    ///         Number::I8(v) => println!("i8: {}", v),
99    ///         Number::I16(v) => println!("i16: {}", v),
100    ///         Number::I32(v) => println!("i32: {}", v),
101    ///         Number::I64(v) => println!("i64: {}", v),
102    ///         Number::I128(v) => println!("i128: {}", v),
103    ///         Number::U8(v) => println!("u8: {}", v),
104    ///         Number::U16(v) => println!("u16: {}", v),
105    ///         Number::U32(v) => println!("u32: {}", v),
106    ///         Number::U64(v) => println!("u64: {}", v),
107    ///         Number::U128(v) => println!("u128: {}", v),
108    ///         Number::F32(v) => println!("f32: {}", v.0),
109    ///         Number::F64(v) => println!("f64: {}", v.0),
110    ///     }
111    /// }
112    /// ```
113    fn _assert_non_exhaustive_check_fails_integer128() {}
114}
115
116impl Serialize for Number {
117    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
118        match self {
119            Self::I8(v) => serializer.serialize_i8(*v),
120            Self::I16(v) => serializer.serialize_i16(*v),
121            Self::I32(v) => serializer.serialize_i32(*v),
122            Self::I64(v) => serializer.serialize_i64(*v),
123            #[cfg(feature = "integer128")]
124            Self::I128(v) => serializer.serialize_i128(*v),
125            Self::U8(v) => serializer.serialize_u8(*v),
126            Self::U16(v) => serializer.serialize_u16(*v),
127            Self::U32(v) => serializer.serialize_u32(*v),
128            Self::U64(v) => serializer.serialize_u64(*v),
129            #[cfg(feature = "integer128")]
130            Self::U128(v) => serializer.serialize_u128(*v),
131            Self::F32(v) => serializer.serialize_f32(v.get()),
132            Self::F64(v) => serializer.serialize_f64(v.get()),
133            #[cfg(not(doc))]
134            Self::__NonExhaustive(never) => never.never(),
135        }
136    }
137}
138
139impl Number {
140    pub fn visit<'de, V: Visitor<'de>, E: serde::de::Error>(
141        &self,
142        visitor: V,
143    ) -> Result<V::Value, E> {
144        match self {
145            Self::I8(v) => visitor.visit_i8(*v),
146            Self::I16(v) => visitor.visit_i16(*v),
147            Self::I32(v) => visitor.visit_i32(*v),
148            Self::I64(v) => visitor.visit_i64(*v),
149            #[cfg(feature = "integer128")]
150            Self::I128(v) => visitor.visit_i128(*v),
151            Self::U8(v) => visitor.visit_u8(*v),
152            Self::U16(v) => visitor.visit_u16(*v),
153            Self::U32(v) => visitor.visit_u32(*v),
154            Self::U64(v) => visitor.visit_u64(*v),
155            #[cfg(feature = "integer128")]
156            Self::U128(v) => visitor.visit_u128(*v),
157            Self::F32(v) => visitor.visit_f32(v.get()),
158            Self::F64(v) => visitor.visit_f64(v.get()),
159            #[cfg(not(doc))]
160            Self::__NonExhaustive(never) => never.never(),
161        }
162    }
163}
164
165macro_rules! float_ty {
166    ($ty:ident($float:ty)) => {
167        #[doc = concat!(
168                    "A wrapper for [`", stringify!($float), "`], which implements [`Eq`], ",
169                    "[`Hash`] and [`Ord`] using [`", stringify!($float), "::total_cmp`] ",
170                    "for a total order comparison",
171                )]
172        #[derive(Copy, Clone, Debug)] // GRCOV_EXCL_LINE
173        pub struct $ty(pub $float);
174
175        impl $ty {
176            #[doc = concat!("Construct a new [`", stringify!($ty), "`].")]
177            #[must_use]
178            pub fn new(v: $float) -> Self {
179                Self(v)
180            }
181
182            #[doc = concat!("Returns the wrapped [`", stringify!($float), "`].")]
183            #[must_use]
184            pub fn get(self) -> $float {
185                self.0
186            }
187        }
188
189        impl From<$float> for $ty {
190            fn from(v: $float) -> Self {
191                Self::new(v)
192            }
193        }
194
195        /// Partial equality comparison
196        ///
197        #[doc = concat!(
198                    "In order to be able to use [`", stringify!($ty), "`] as a mapping key, ",
199                    "floating values use [`", stringify!($float), "::total_cmp`] for a total ",
200                    "order comparison.",
201                )]
202        ///
203        /// See the [`Ord`] implementation.
204        impl PartialEq for $ty {
205            fn eq(&self, other: &Self) -> bool {
206                self.cmp(other).is_eq()
207            }
208        }
209
210        /// Equality comparison
211        ///
212        #[doc = concat!(
213                    "In order to be able to use [`", stringify!($ty), "`] as a mapping key, ",
214                    "floating values use [`", stringify!($float), "::total_cmp`] for a total ",
215                    "order comparison.",
216                )]
217        ///
218        /// See the [`Ord`] implementation.
219        impl Eq for $ty {}
220
221        impl Hash for $ty {
222            fn hash<H: Hasher>(&self, state: &mut H) {
223                self.0.to_bits().hash(state);
224            }
225        }
226
227        /// Partial ordering comparison
228        ///
229        #[doc = concat!(
230                    "In order to be able to use [`", stringify!($ty), "`] as a mapping key, ",
231                    "floating values use [`", stringify!($float), "::total_cmp`] for a total ",
232                    "order comparison.",
233                )]
234        ///
235        /// See the [`Ord`] implementation.
236        impl PartialOrd for $ty {
237            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
238                Some(self.cmp(other))
239            }
240        }
241
242        /// Ordering comparison
243        ///
244        #[doc = concat!(
245                    "In order to be able to use [`", stringify!($ty), "`] as a mapping key, ",
246                    "floating values use [`", stringify!($float), "::total_cmp`] for a total ",
247                    "order comparison.",
248                )]
249        ///
250        /// ```
251        #[doc = concat!("use ron::value::", stringify!($ty), ";")]
252        #[doc = concat!(
253                    "assert!(", stringify!($ty), "::new(", stringify!($float), "::NAN) > ",
254                    stringify!($ty), "::new(", stringify!($float), "::INFINITY));",
255                )]
256        #[doc = concat!(
257                    "assert!(", stringify!($ty), "::new(-", stringify!($float), "::NAN) < ",
258                    stringify!($ty), "::new(", stringify!($float), "::NEG_INFINITY));",
259                )]
260        #[doc = concat!(
261                    "assert!(", stringify!($ty), "::new(", stringify!($float), "::NAN) == ",
262                    stringify!($ty), "::new(", stringify!($float), "::NAN));",
263                )]
264        /// ```
265        impl Ord for $ty {
266            fn cmp(&self, other: &Self) -> Ordering {
267                self.0.total_cmp(&other.0)
268            }
269        }
270    };
271}
272
273float_ty! { F32(f32) }
274float_ty! { F64(f64) }
275
276impl Number {
277    /// Construct a new number.
278    pub fn new(v: impl Into<Number>) -> Self {
279        v.into()
280    }
281
282    /// Returns the [`f64`] representation of the [`Number`] regardless of
283    /// whether the number is stored as a float or integer.
284    ///
285    /// # Example
286    ///
287    /// ```
288    /// # use ron::value::Number;
289    /// let i = Number::new(5);
290    /// let f = Number::new(2.0);
291    /// assert_eq!(i.into_f64(), 5.0);
292    /// assert_eq!(f.into_f64(), 2.0);
293    /// ```
294    #[must_use]
295    pub fn into_f64(self) -> f64 {
296        #[allow(clippy::cast_precision_loss)]
297        match self {
298            Self::I8(v) => f64::from(v),
299            Self::I16(v) => f64::from(v),
300            Self::I32(v) => f64::from(v),
301            Self::I64(v) => v as f64,
302            #[cfg(feature = "integer128")]
303            Self::I128(v) => v as f64,
304            Self::U8(v) => f64::from(v),
305            Self::U16(v) => f64::from(v),
306            Self::U32(v) => f64::from(v),
307            Self::U64(v) => v as f64,
308            #[cfg(feature = "integer128")]
309            Self::U128(v) => v as f64,
310            Self::F32(v) => f64::from(v.get()),
311            Self::F64(v) => v.get(),
312            #[cfg(not(doc))]
313            Self::__NonExhaustive(never) => never.never(),
314        }
315    }
316}
317
318macro_rules! number_from_impl {
319    (Number::$variant:ident($wrap:ident($ty:ty))) => {
320        impl From<$ty> for Number {
321            fn from(v: $ty) -> Number {
322                Number::$variant($wrap(v))
323            }
324        }
325    };
326    (Number::$variant:ident($ty:ty)) => {
327        impl From<$ty> for Number {
328            fn from(v: $ty) -> Number {
329                Number::$variant(v)
330            }
331        }
332    };
333}
334
335number_from_impl! { Number::I8(i8) }
336number_from_impl! { Number::I16(i16) }
337number_from_impl! { Number::I32(i32) }
338number_from_impl! { Number::I64(i64) }
339#[cfg(feature = "integer128")]
340number_from_impl! { Number::I128(i128) }
341number_from_impl! { Number::U8(u8) }
342number_from_impl! { Number::U16(u16) }
343number_from_impl! { Number::U32(u32) }
344number_from_impl! { Number::U64(u64) }
345#[cfg(feature = "integer128")]
346number_from_impl! { Number::U128(u128) }
347number_from_impl! { Number::F32(F32(f32)) }
348number_from_impl! { Number::F64(F64(f64)) }
349
350/// A serializer that only accepts numeric values, returning a [`Number`].
351/// Used by [`crate::ser::RangeCompound`] to detect whether range bounds are numeric.
352#[allow(clippy::module_name_repetitions)]
353pub struct NumberSerializer;
354
355impl serde::Serializer for NumberSerializer {
356    type Ok = Number;
357    type Error = Error;
358    type SerializeSeq = serde::ser::Impossible<Number, Error>;
359    type SerializeTuple = serde::ser::Impossible<Number, Error>;
360    type SerializeTupleStruct = serde::ser::Impossible<Number, Error>;
361    type SerializeTupleVariant = serde::ser::Impossible<Number, Error>;
362    type SerializeMap = serde::ser::Impossible<Number, Error>;
363    type SerializeStruct = serde::ser::Impossible<Number, Error>;
364    type SerializeStructVariant = serde::ser::Impossible<Number, Error>;
365
366    fn serialize_i8(self, v: i8) -> Result<Number> {
367        Ok(Number::new(v))
368    }
369    fn serialize_i16(self, v: i16) -> Result<Number> {
370        Ok(Number::new(v))
371    }
372    fn serialize_i32(self, v: i32) -> Result<Number> {
373        Ok(Number::new(v))
374    }
375    fn serialize_i64(self, v: i64) -> Result<Number> {
376        Ok(Number::new(v))
377    }
378    fn serialize_u8(self, v: u8) -> Result<Number> {
379        Ok(Number::new(v))
380    }
381    fn serialize_u16(self, v: u16) -> Result<Number> {
382        Ok(Number::new(v))
383    }
384    fn serialize_u32(self, v: u32) -> Result<Number> {
385        Ok(Number::new(v))
386    }
387    fn serialize_u64(self, v: u64) -> Result<Number> {
388        Ok(Number::new(v))
389    }
390    fn serialize_f32(self, v: f32) -> Result<Number> {
391        Ok(Number::new(v))
392    }
393    fn serialize_f64(self, v: f64) -> Result<Number> {
394        Ok(Number::new(v))
395    }
396    #[cfg(feature = "integer128")]
397    fn serialize_i128(self, v: i128) -> Result<Number> {
398        Ok(Number::new(v))
399    }
400    #[cfg(feature = "integer128")]
401    fn serialize_u128(self, v: u128) -> Result<Number> {
402        Ok(Number::new(v))
403    }
404
405    fn serialize_bool(self, _: bool) -> Result<Number> {
406        Err(Error::InvalidValueForType {
407            expected: alloc::string::String::from("number"),
408            found: alloc::string::String::from("bool"),
409        })
410    }
411    fn serialize_char(self, _: char) -> Result<Number> {
412        Err(Error::InvalidValueForType {
413            expected: alloc::string::String::from("number"),
414            found: alloc::string::String::from("char"),
415        })
416    }
417    fn serialize_str(self, _: &str) -> Result<Number> {
418        Err(Error::InvalidValueForType {
419            expected: alloc::string::String::from("number"),
420            found: alloc::string::String::from("string"),
421        })
422    }
423    fn serialize_bytes(self, _: &[u8]) -> Result<Number> {
424        Err(Error::InvalidValueForType {
425            expected: alloc::string::String::from("number"),
426            found: alloc::string::String::from("bytes"),
427        })
428    }
429    fn serialize_none(self) -> Result<Number> {
430        Err(Error::InvalidValueForType {
431            expected: alloc::string::String::from("number"),
432            found: alloc::string::String::from("None"),
433        })
434    }
435    fn serialize_some<T: ?Sized + Serialize>(self, _: &T) -> Result<Number> {
436        Err(Error::InvalidValueForType {
437            expected: alloc::string::String::from("number"),
438            found: alloc::string::String::from("Some"),
439        })
440    }
441    fn serialize_unit(self) -> Result<Number> {
442        Err(Error::InvalidValueForType {
443            expected: alloc::string::String::from("number"),
444            found: alloc::string::String::from("unit"),
445        })
446    }
447    fn serialize_unit_struct(self, _: &'static str) -> Result<Number> {
448        Err(Error::InvalidValueForType {
449            expected: alloc::string::String::from("number"),
450            found: alloc::string::String::from("unit struct"),
451        })
452    }
453    fn serialize_unit_variant(self, _: &'static str, _: u32, _: &'static str) -> Result<Number> {
454        Err(Error::InvalidValueForType {
455            expected: alloc::string::String::from("number"),
456            found: alloc::string::String::from("unit variant"),
457        })
458    }
459    fn serialize_newtype_struct<T: ?Sized + Serialize>(
460        self,
461        _: &'static str,
462        _: &T,
463    ) -> Result<Number> {
464        Err(Error::InvalidValueForType {
465            expected: alloc::string::String::from("number"),
466            found: alloc::string::String::from("newtype struct"),
467        })
468    }
469    fn serialize_newtype_variant<T: ?Sized + Serialize>(
470        self,
471        _: &'static str,
472        _: u32,
473        _: &'static str,
474        _: &T,
475    ) -> Result<Number> {
476        Err(Error::InvalidValueForType {
477            expected: alloc::string::String::from("number"),
478            found: alloc::string::String::from("newtype variant"),
479        })
480    }
481    fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq> {
482        Err(Error::InvalidValueForType {
483            expected: alloc::string::String::from("number"),
484            found: alloc::string::String::from("seq"),
485        })
486    }
487    fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple> {
488        Err(Error::InvalidValueForType {
489            expected: alloc::string::String::from("number"),
490            found: alloc::string::String::from("tuple"),
491        })
492    }
493    fn serialize_tuple_struct(
494        self,
495        _: &'static str,
496        _: usize,
497    ) -> Result<Self::SerializeTupleStruct> {
498        Err(Error::InvalidValueForType {
499            expected: alloc::string::String::from("number"),
500            found: alloc::string::String::from("tuple struct"),
501        })
502    }
503    fn serialize_tuple_variant(
504        self,
505        _: &'static str,
506        _: u32,
507        _: &'static str,
508        _: usize,
509    ) -> Result<Self::SerializeTupleVariant> {
510        Err(Error::InvalidValueForType {
511            expected: alloc::string::String::from("number"),
512            found: alloc::string::String::from("tuple variant"),
513        })
514    }
515    fn serialize_map(self, _: Option<usize>) -> Result<Self::SerializeMap> {
516        Err(Error::InvalidValueForType {
517            expected: alloc::string::String::from("number"),
518            found: alloc::string::String::from("map"),
519        })
520    }
521    fn serialize_struct(self, _: &'static str, _: usize) -> Result<Self::SerializeStruct> {
522        Err(Error::InvalidValueForType {
523            expected: alloc::string::String::from("number"),
524            found: alloc::string::String::from("struct"),
525        })
526    }
527    fn serialize_struct_variant(
528        self,
529        _: &'static str,
530        _: u32,
531        _: &'static str,
532        _: usize,
533    ) -> Result<Self::SerializeStructVariant> {
534        Err(Error::InvalidValueForType {
535            expected: alloc::string::String::from("number"),
536            found: alloc::string::String::from("struct variant"),
537        })
538    }
539}
540
541pub(crate) struct NumberDeserializer(pub(crate) Number);
542
543impl<'de> serde::de::Deserializer<'de> for NumberDeserializer {
544    type Error = crate::error::Error;
545
546    fn deserialize_any<V: serde::de::Visitor<'de>>(
547        self,
548        visitor: V,
549    ) -> crate::error::Result<V::Value> {
550        self.0.visit(visitor)
551    }
552
553    serde::forward_to_deserialize_any! {
554        bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64
555        char str string bytes byte_buf option unit unit_struct
556        newtype_struct seq tuple tuple_struct map struct enum identifier ignored_any
557    }
558}
559
560#[cfg(test)]
561mod tests {
562    use super::*;
563
564    #[test]
565    fn test_nan() {
566        assert_eq!(F32(f32::NAN), F32(f32::NAN));
567        assert_eq!(F32(-f32::NAN), F32(-f32::NAN));
568        assert_ne!(F32(f32::NAN), F32(-f32::NAN));
569    }
570
571    #[cfg(feature = "std")]
572    #[test]
573    fn test_nan_hash() {
574        use std::collections::hash_map::DefaultHasher;
575        use std::hash::{Hash, Hasher};
576
577        fn hash<T: Hash>(v: &T) -> u64 {
578            let mut state = DefaultHasher::new();
579            v.hash(&mut state);
580            state.finish()
581        }
582
583        assert_eq!(hash(&F32(f32::NAN)), hash(&F32(f32::NAN)));
584        assert_eq!(hash(&F32(-f32::NAN)), hash(&F32(-f32::NAN)));
585        assert_ne!(hash(&F32(f32::NAN)), hash(&F32(-f32::NAN)));
586    }
587
588    #[test]
589    fn test_partial_ord() {
590        assert!(F32(f32::NAN) > F32(f32::INFINITY));
591        assert!(F32(-f32::NAN) < F32(f32::NEG_INFINITY));
592        assert!(F32(f32::NAN) == F32(f32::NAN));
593    }
594}