1
use core::{
2
    cmp::{Eq, Ordering},
3
    hash::{Hash, Hasher},
4
};
5

            
6
use serde::{de::Visitor, Serialize, Serializer};
7

            
8
/// A wrapper for any numeric primitive type in Rust.
9
///
10
/// Some varints of the `Number` enum are enabled by features:
11
/// - `Number::I128` and `Number::U128` by the `integer128` feature
12
///
13
/// To ensure that feature unification does not break `match`ing over `Number`,
14
/// the `Number` enum is non-exhaustive.
15
///
16
/// <details>
17
/// <summary>Exhaustively matching on <code>Number</code> in tests</summary>
18
///
19
/// If you want to ensure that you exhaustively handle every variant, you can
20
/// match on the hidden `Number::__NonExhaustive(x)` variant by using the
21
/// `x.never() -> !` method.
22
///
23
/// <div class="warning">
24
/// Matching on this variant means that your code may break when RON is
25
/// upgraded or when feature unification enables further variants in the
26
/// <code>Number</code> enum than your code expects.
27
/// </div>
28
///
29
/// It is your responsibility to only *ever* match on `Number::__NonExhaustive`
30
/// inside tests, e.g. by using `#[cfg(test)]` on the particular match arm, to
31
/// ensure that only your tests break (e.g. in CI) when your code is not
32
/// exhaustively matching on every variant, e.g. after a version upgrade or
33
/// feature unification.
34
/// </details>
35
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Hash, Ord)]
36
#[cfg_attr(doc, non_exhaustive)]
37
pub enum Number {
38
    I8(i8),
39
    I16(i16),
40
    I32(i32),
41
    I64(i64),
42
    #[cfg(feature = "integer128")]
43
    I128(i128),
44
    U8(u8),
45
    U16(u16),
46
    U32(u32),
47
    U64(u64),
48
    #[cfg(feature = "integer128")]
49
    U128(u128),
50
    F32(F32),
51
    F64(F64),
52
    #[cfg(not(doc))]
53
    #[allow(private_interfaces)]
54
    __NonExhaustive(private::Never),
55
}
56

            
57
mod private {
58
    #[derive(Debug, PartialEq, PartialOrd, Eq, Hash, Ord)]
59
    enum _Never {}
60

            
61
    #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Hash, Ord)]
62
    pub struct Never {
63
        never: &'static _Never,
64
    }
65

            
66
    impl Never {
67
        pub fn never(self) -> ! {
68
            match *self.never {}
69
        }
70
    }
71

            
72
    #[cfg(not(feature = "integer128"))]
73
    /// ```compile_fail
74
    /// # use ron::Number;
75
    /// fn match_number(x: Number) {
76
    ///     match x {
77
    ///         Number::I8(v) => println!("i8: {}", v),
78
    ///         Number::I16(v) => println!("i16: {}", v),
79
    ///         Number::I32(v) => println!("i32: {}", v),
80
    ///         Number::I64(v) => println!("i64: {}", v),
81
    ///         Number::U8(v) => println!("u8: {}", v),
82
    ///         Number::U16(v) => println!("u16: {}", v),
83
    ///         Number::U32(v) => println!("u32: {}", v),
84
    ///         Number::U64(v) => println!("u64: {}", v),
85
    ///         Number::F32(v) => println!("f32: {}", v.0),
86
    ///         Number::F64(v) => println!("f64: {}", v.0),
87
    ///     }
88
    /// }
89
    /// ```
90
    fn _assert_non_exhaustive_check_fails_not_integer128() {}
91

            
92
    #[cfg(feature = "integer128")]
93
    /// ```compile_fail
94
    /// # use ron::Number;
95
    /// fn match_number(x: Number) {
96
    ///     match x {
97
    ///         Number::I8(v) => println!("i8: {}", v),
98
    ///         Number::I16(v) => println!("i16: {}", v),
99
    ///         Number::I32(v) => println!("i32: {}", v),
100
    ///         Number::I64(v) => println!("i64: {}", v),
101
    ///         Number::I128(v) => println!("i128: {}", v),
102
    ///         Number::U8(v) => println!("u8: {}", v),
103
    ///         Number::U16(v) => println!("u16: {}", v),
104
    ///         Number::U32(v) => println!("u32: {}", v),
105
    ///         Number::U64(v) => println!("u64: {}", v),
106
    ///         Number::U128(v) => println!("u128: {}", v),
107
    ///         Number::F32(v) => println!("f32: {}", v.0),
108
    ///         Number::F64(v) => println!("f64: {}", v.0),
109
    ///     }
110
    /// }
111
    /// ```
112
    fn _assert_non_exhaustive_check_fails_integer128() {}
113
}
114

            
115
impl Serialize for Number {
116
672
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
117
672
        match self {
118
56
            Self::I8(v) => serializer.serialize_i8(*v),
119
40
            Self::I16(v) => serializer.serialize_i16(*v),
120
40
            Self::I32(v) => serializer.serialize_i32(*v),
121
40
            Self::I64(v) => serializer.serialize_i64(*v),
122
            #[cfg(feature = "integer128")]
123
20
            Self::I128(v) => serializer.serialize_i128(*v),
124
88
            Self::U8(v) => serializer.serialize_u8(*v),
125
40
            Self::U16(v) => serializer.serialize_u16(*v),
126
40
            Self::U32(v) => serializer.serialize_u32(*v),
127
40
            Self::U64(v) => serializer.serialize_u64(*v),
128
            #[cfg(feature = "integer128")]
129
20
            Self::U128(v) => serializer.serialize_u128(*v),
130
168
            Self::F32(v) => serializer.serialize_f32(v.get()),
131
80
            Self::F64(v) => serializer.serialize_f64(v.get()),
132
            #[cfg(not(doc))]
133
            Self::__NonExhaustive(never) => never.never(),
134
        }
135
672
    }
136
}
137

            
138
impl Number {
139
267418
    pub fn visit<'de, V: Visitor<'de>, E: serde::de::Error>(
140
267418
        &self,
141
267418
        visitor: V,
142
267418
    ) -> Result<V::Value, E> {
143
267418
        match self {
144
572
            Self::I8(v) => visitor.visit_i8(*v),
145
556
            Self::I16(v) => visitor.visit_i16(*v),
146
568
            Self::I32(v) => visitor.visit_i32(*v),
147
556
            Self::I64(v) => visitor.visit_i64(*v),
148
            #[cfg(feature = "integer128")]
149
282
            Self::I128(v) => visitor.visit_i128(*v),
150
249726
            Self::U8(v) => visitor.visit_u8(*v),
151
568
            Self::U16(v) => visitor.visit_u16(*v),
152
556
            Self::U32(v) => visitor.visit_u32(*v),
153
556
            Self::U64(v) => visitor.visit_u64(*v),
154
            #[cfg(feature = "integer128")]
155
423
            Self::U128(v) => visitor.visit_u128(*v),
156
4957
            Self::F32(v) => visitor.visit_f32(v.get()),
157
8098
            Self::F64(v) => visitor.visit_f64(v.get()),
158
            #[cfg(not(doc))]
159
            Self::__NonExhaustive(never) => never.never(),
160
        }
161
267418
    }
162
}
163

            
164
macro_rules! float_ty {
165
    ($ty:ident($float:ty)) => {
166
        #[doc = concat!(
167
                    "A wrapper for [`", stringify!($float), "`], which implements [`Eq`], ",
168
                    "[`Hash`] and [`Ord`] using [`", stringify!($float), "::total_cmp`] ",
169
                    "for a total order comparison",
170
                )]
171
        #[derive(Copy, Clone, Debug)] // GRCOV_EXCL_LINE
172
        pub struct $ty(pub $float);
173

            
174
        impl $ty {
175
            #[doc = concat!("Construct a new [`", stringify!($ty), "`].")]
176
            #[must_use]
177
13512
            pub fn new(v: $float) -> Self {
178
13512
                Self(v)
179
13512
            }
180

            
181
            #[doc = concat!("Returns the wrapped [`", stringify!($float), "`].")]
182
            #[must_use]
183
22667
            pub fn get(self) -> $float {
184
22667
                self.0
185
22667
            }
186
        }
187

            
188
        impl From<$float> for $ty {
189
13512
            fn from(v: $float) -> Self {
190
13512
                Self::new(v)
191
13512
            }
192
        }
193

            
194
        /// Partial equality comparison
195
        ///
196
        #[doc = concat!(
197
                    "In order to be able to use [`", stringify!($ty), "`] as a mapping key, ",
198
                    "floating values use [`", stringify!($float), "::total_cmp`] for a total ",
199
                    "order comparison.",
200
                )]
201
        ///
202
        /// See the [`Ord`] implementation.
203
        impl PartialEq for $ty {
204
17575
            fn eq(&self, other: &Self) -> bool {
205
17575
                self.cmp(other).is_eq()
206
17575
            }
207
        }
208

            
209
        /// Equality comparison
210
        ///
211
        #[doc = concat!(
212
                    "In order to be able to use [`", stringify!($ty), "`] as a mapping key, ",
213
                    "floating values use [`", stringify!($float), "::total_cmp`] for a total ",
214
                    "order comparison.",
215
                )]
216
        ///
217
        /// See the [`Ord`] implementation.
218
        impl Eq for $ty {}
219

            
220
        impl Hash for $ty {
221
24
            fn hash<H: Hasher>(&self, state: &mut H) {
222
24
                self.0.to_bits().hash(state);
223
24
            }
224
        }
225

            
226
        /// Partial ordering comparison
227
        ///
228
        #[doc = concat!(
229
                    "In order to be able to use [`", stringify!($ty), "`] as a mapping key, ",
230
                    "floating values use [`", stringify!($float), "::total_cmp`] for a total ",
231
                    "order comparison.",
232
                )]
233
        ///
234
        /// See the [`Ord`] implementation.
235
        impl PartialOrd for $ty {
236
8
            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
237
8
                Some(self.cmp(other))
238
8
            }
239
        }
240

            
241
        /// Ordering comparison
242
        ///
243
        #[doc = concat!(
244
                    "In order to be able to use [`", stringify!($ty), "`] as a mapping key, ",
245
                    "floating values use [`", stringify!($float), "::total_cmp`] for a total ",
246
                    "order comparison.",
247
                )]
248
        ///
249
        /// ```
250
        #[doc = concat!("use ron::value::", stringify!($ty), ";")]
251
        #[doc = concat!(
252
                    "assert!(", stringify!($ty), "::new(", stringify!($float), "::NAN) > ",
253
                    stringify!($ty), "::new(", stringify!($float), "::INFINITY));",
254
                )]
255
        #[doc = concat!(
256
                    "assert!(", stringify!($ty), "::new(-", stringify!($float), "::NAN) < ",
257
                    stringify!($ty), "::new(", stringify!($float), "::NEG_INFINITY));",
258
                )]
259
        #[doc = concat!(
260
                    "assert!(", stringify!($ty), "::new(", stringify!($float), "::NAN) == ",
261
                    stringify!($ty), "::new(", stringify!($float), "::NAN));",
262
                )]
263
        /// ```
264
        impl Ord for $ty {
265
17869
            fn cmp(&self, other: &Self) -> Ordering {
266
17869
                self.0.total_cmp(&other.0)
267
17869
            }
268
        }
269
    };
270
}
271

            
272
float_ty! { F32(f32) }
273
float_ty! { F64(f64) }
274

            
275
impl Number {
276
    /// Construct a new number.
277
240402
    pub fn new(v: impl Into<Number>) -> Self {
278
240402
        v.into()
279
240402
    }
280

            
281
    /// Returns the [`f64`] representation of the [`Number`] regardless of
282
    /// whether the number is stored as a float or integer.
283
    ///
284
    /// # Example
285
    ///
286
    /// ```
287
    /// # use ron::value::Number;
288
    /// let i = Number::new(5);
289
    /// let f = Number::new(2.0);
290
    /// assert_eq!(i.into_f64(), 5.0);
291
    /// assert_eq!(f.into_f64(), 2.0);
292
    /// ```
293
    #[must_use]
294
8340
    pub fn into_f64(self) -> f64 {
295
        #[allow(clippy::cast_precision_loss)]
296
8340
        match self {
297
556
            Self::I8(v) => f64::from(v),
298
556
            Self::I16(v) => f64::from(v),
299
556
            Self::I32(v) => f64::from(v),
300
556
            Self::I64(v) => v as f64,
301
            #[cfg(feature = "integer128")]
302
278
            Self::I128(v) => v as f64,
303
556
            Self::U8(v) => f64::from(v),
304
556
            Self::U16(v) => f64::from(v),
305
556
            Self::U32(v) => f64::from(v),
306
556
            Self::U64(v) => v as f64,
307
            #[cfg(feature = "integer128")]
308
278
            Self::U128(v) => v as f64,
309
1668
            Self::F32(v) => f64::from(v.get()),
310
1668
            Self::F64(v) => v.get(),
311
            #[cfg(not(doc))]
312
            Self::__NonExhaustive(never) => never.never(),
313
        }
314
8340
    }
315
}
316

            
317
macro_rules! number_from_impl {
318
    (Number::$variant:ident($wrap:ident($ty:ty))) => {
319
        impl From<$ty> for Number {
320
36881
            fn from(v: $ty) -> Number {
321
36881
                Number::$variant($wrap(v))
322
36881
            }
323
        }
324
    };
325
    (Number::$variant:ident($ty:ty)) => {
326
        impl From<$ty> for Number {
327
237773
            fn from(v: $ty) -> Number {
328
237773
                Number::$variant(v)
329
237773
            }
330
        }
331
    };
332
}
333

            
334
number_from_impl! { Number::I8(i8) }
335
number_from_impl! { Number::I16(i16) }
336
number_from_impl! { Number::I32(i32) }
337
number_from_impl! { Number::I64(i64) }
338
#[cfg(feature = "integer128")]
339
number_from_impl! { Number::I128(i128) }
340
number_from_impl! { Number::U8(u8) }
341
number_from_impl! { Number::U16(u16) }
342
number_from_impl! { Number::U32(u32) }
343
number_from_impl! { Number::U64(u64) }
344
#[cfg(feature = "integer128")]
345
number_from_impl! { Number::U128(u128) }
346
number_from_impl! { Number::F32(F32(f32)) }
347
number_from_impl! { Number::F64(F64(f64)) }
348

            
349
#[cfg(test)]
350
mod tests {
351
    use super::*;
352

            
353
    #[test]
354
4
    fn test_nan() {
355
4
        assert_eq!(F32(f32::NAN), F32(f32::NAN));
356
4
        assert_eq!(F32(-f32::NAN), F32(-f32::NAN));
357
4
        assert_ne!(F32(f32::NAN), F32(-f32::NAN));
358
4
    }
359

            
360
    #[cfg(feature = "std")]
361
    #[test]
362
4
    fn test_nan_hash() {
363
        use std::collections::hash_map::DefaultHasher;
364
        use std::hash::{Hash, Hasher};
365

            
366
24
        fn hash<T: Hash>(v: &T) -> u64 {
367
24
            let mut state = DefaultHasher::new();
368
24
            v.hash(&mut state);
369
24
            state.finish()
370
24
        }
371

            
372
4
        assert_eq!(hash(&F32(f32::NAN)), hash(&F32(f32::NAN)));
373
4
        assert_eq!(hash(&F32(-f32::NAN)), hash(&F32(-f32::NAN)));
374
4
        assert_ne!(hash(&F32(f32::NAN)), hash(&F32(-f32::NAN)));
375
4
    }
376

            
377
    #[test]
378
4
    fn test_partial_ord() {
379
4
        assert!(F32(f32::NAN) > F32(f32::INFINITY));
380
4
        assert!(F32(-f32::NAN) < F32(f32::NEG_INFINITY));
381
4
        assert!(F32(f32::NAN) == F32(f32::NAN));
382
4
    }
383
}