1use core::{
2 cmp::{Eq, Ordering},
3 hash::{Hash, Hasher},
4};
5
6use serde::{de::Visitor, Serialize, Serializer};
7
8#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Hash, Ord)]
36#[cfg_attr(doc, non_exhaustive)]
37pub 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
57mod 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 fn _assert_non_exhaustive_check_fails_not_integer128() {}
91
92 #[cfg(feature = "integer128")]
93 fn _assert_non_exhaustive_check_fails_integer128() {}
113}
114
115impl Serialize for Number {
116 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
117 match self {
118 Self::I8(v) => serializer.serialize_i8(*v),
119 Self::I16(v) => serializer.serialize_i16(*v),
120 Self::I32(v) => serializer.serialize_i32(*v),
121 Self::I64(v) => serializer.serialize_i64(*v),
122 #[cfg(feature = "integer128")]
123 Self::I128(v) => serializer.serialize_i128(*v),
124 Self::U8(v) => serializer.serialize_u8(*v),
125 Self::U16(v) => serializer.serialize_u16(*v),
126 Self::U32(v) => serializer.serialize_u32(*v),
127 Self::U64(v) => serializer.serialize_u64(*v),
128 #[cfg(feature = "integer128")]
129 Self::U128(v) => serializer.serialize_u128(*v),
130 Self::F32(v) => serializer.serialize_f32(v.get()),
131 Self::F64(v) => serializer.serialize_f64(v.get()),
132 #[cfg(not(doc))]
133 Self::__NonExhaustive(never) => never.never(),
134 }
135 }
136}
137
138impl Number {
139 pub fn visit<'de, V: Visitor<'de>, E: serde::de::Error>(
140 &self,
141 visitor: V,
142 ) -> Result<V::Value, E> {
143 match self {
144 Self::I8(v) => visitor.visit_i8(*v),
145 Self::I16(v) => visitor.visit_i16(*v),
146 Self::I32(v) => visitor.visit_i32(*v),
147 Self::I64(v) => visitor.visit_i64(*v),
148 #[cfg(feature = "integer128")]
149 Self::I128(v) => visitor.visit_i128(*v),
150 Self::U8(v) => visitor.visit_u8(*v),
151 Self::U16(v) => visitor.visit_u16(*v),
152 Self::U32(v) => visitor.visit_u32(*v),
153 Self::U64(v) => visitor.visit_u64(*v),
154 #[cfg(feature = "integer128")]
155 Self::U128(v) => visitor.visit_u128(*v),
156 Self::F32(v) => visitor.visit_f32(v.get()),
157 Self::F64(v) => visitor.visit_f64(v.get()),
158 #[cfg(not(doc))]
159 Self::__NonExhaustive(never) => never.never(),
160 }
161 }
162}
163
164macro_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)] pub struct $ty(pub $float);
173
174 impl $ty {
175 #[doc = concat!("Construct a new [`", stringify!($ty), "`].")]
176 #[must_use]
177 pub fn new(v: $float) -> Self {
178 Self(v)
179 }
180
181 #[doc = concat!("Returns the wrapped [`", stringify!($float), "`].")]
182 #[must_use]
183 pub fn get(self) -> $float {
184 self.0
185 }
186 }
187
188 impl From<$float> for $ty {
189 fn from(v: $float) -> Self {
190 Self::new(v)
191 }
192 }
193
194 #[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 impl PartialEq for $ty {
204 fn eq(&self, other: &Self) -> bool {
205 self.cmp(other).is_eq()
206 }
207 }
208
209 #[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 impl Eq for $ty {}
219
220 impl Hash for $ty {
221 fn hash<H: Hasher>(&self, state: &mut H) {
222 self.0.to_bits().hash(state);
223 }
224 }
225
226 #[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 impl PartialOrd for $ty {
236 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
237 Some(self.cmp(other))
238 }
239 }
240
241 #[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 #[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 impl Ord for $ty {
265 fn cmp(&self, other: &Self) -> Ordering {
266 self.0.total_cmp(&other.0)
267 }
268 }
269 };
270}
271
272float_ty! { F32(f32) }
273float_ty! { F64(f64) }
274
275impl Number {
276 pub fn new(v: impl Into<Number>) -> Self {
278 v.into()
279 }
280
281 #[must_use]
294 pub fn into_f64(self) -> f64 {
295 #[allow(clippy::cast_precision_loss)]
296 match self {
297 Self::I8(v) => f64::from(v),
298 Self::I16(v) => f64::from(v),
299 Self::I32(v) => f64::from(v),
300 Self::I64(v) => v as f64,
301 #[cfg(feature = "integer128")]
302 Self::I128(v) => v as f64,
303 Self::U8(v) => f64::from(v),
304 Self::U16(v) => f64::from(v),
305 Self::U32(v) => f64::from(v),
306 Self::U64(v) => v as f64,
307 #[cfg(feature = "integer128")]
308 Self::U128(v) => v as f64,
309 Self::F32(v) => f64::from(v.get()),
310 Self::F64(v) => v.get(),
311 #[cfg(not(doc))]
312 Self::__NonExhaustive(never) => never.never(),
313 }
314 }
315}
316
317macro_rules! number_from_impl {
318 (Number::$variant:ident($wrap:ident($ty:ty))) => {
319 impl From<$ty> for Number {
320 fn from(v: $ty) -> Number {
321 Number::$variant($wrap(v))
322 }
323 }
324 };
325 (Number::$variant:ident($ty:ty)) => {
326 impl From<$ty> for Number {
327 fn from(v: $ty) -> Number {
328 Number::$variant(v)
329 }
330 }
331 };
332}
333
334number_from_impl! { Number::I8(i8) }
335number_from_impl! { Number::I16(i16) }
336number_from_impl! { Number::I32(i32) }
337number_from_impl! { Number::I64(i64) }
338#[cfg(feature = "integer128")]
339number_from_impl! { Number::I128(i128) }
340number_from_impl! { Number::U8(u8) }
341number_from_impl! { Number::U16(u16) }
342number_from_impl! { Number::U32(u32) }
343number_from_impl! { Number::U64(u64) }
344#[cfg(feature = "integer128")]
345number_from_impl! { Number::U128(u128) }
346number_from_impl! { Number::F32(F32(f32)) }
347number_from_impl! { Number::F64(F64(f64)) }
348
349#[cfg(test)]
350mod tests {
351 use super::*;
352
353 #[test]
354 fn test_nan() {
355 assert_eq!(F32(f32::NAN), F32(f32::NAN));
356 assert_eq!(F32(-f32::NAN), F32(-f32::NAN));
357 assert_ne!(F32(f32::NAN), F32(-f32::NAN));
358 }
359
360 #[cfg(feature = "std")]
361 #[test]
362 fn test_nan_hash() {
363 use std::collections::hash_map::DefaultHasher;
364 use std::hash::{Hash, Hasher};
365
366 fn hash<T: Hash>(v: &T) -> u64 {
367 let mut state = DefaultHasher::new();
368 v.hash(&mut state);
369 state.finish()
370 }
371
372 assert_eq!(hash(&F32(f32::NAN)), hash(&F32(f32::NAN)));
373 assert_eq!(hash(&F32(-f32::NAN)), hash(&F32(-f32::NAN)));
374 assert_ne!(hash(&F32(f32::NAN)), hash(&F32(-f32::NAN)));
375 }
376
377 #[test]
378 fn test_partial_ord() {
379 assert!(F32(f32::NAN) > F32(f32::INFINITY));
380 assert!(F32(-f32::NAN) < F32(f32::NEG_INFINITY));
381 assert!(F32(f32::NAN) == F32(f32::NAN));
382 }
383}