1use crate::de;
2use crate::error::{
3 self,
4 Error,
5 ErrorImpl,
6};
7use serde::de::{
8 Unexpected,
9 Visitor,
10};
11use serde::{
12 forward_to_deserialize_any,
13 Deserialize,
14 Deserializer,
15 Serialize,
16 Serializer,
17};
18use std::cmp::Ordering;
19use std::fmt::{
20 self,
21 Display,
22};
23use std::hash::{
24 Hash,
25 Hasher,
26};
27use std::str::FromStr;
28
29#[derive(Clone, PartialEq, PartialOrd)]
31pub struct Number {
32 n: N,
33}
34
35#[allow(clippy::enum_variant_names)]
38#[derive(Copy, Clone)]
39enum N {
40 PosInt(u64),
41 NegInt(i64),
43 Float(f64),
45}
46
47impl Number {
48 #[inline]
74 #[allow(clippy::cast_sign_loss)]
75 pub fn is_i64(&self) -> bool {
76 match self.n {
77 N::PosInt(v) => v <= i64::MAX as u64,
78 N::NegInt(_) => true,
79 N::Float(_) => false,
80 }
81 }
82
83 #[inline]
107 pub fn is_u64(&self) -> bool {
108 match self.n {
109 N::PosInt(_) => true,
110 N::NegInt(_) | N::Float(_) => false,
111 }
112 }
113
114 #[inline]
139 pub fn is_f64(&self) -> bool {
140 match self.n {
141 N::Float(_) => true,
142 N::PosInt(_) | N::NegInt(_) => false,
143 }
144 }
145
146 #[inline]
165 pub fn as_i64(&self) -> Option<i64> {
166 match self.n {
167 N::PosInt(n) => {
168 if n <= i64::MAX as u64 {
169 Some(n as i64)
170 } else {
171 None
172 }
173 },
174 N::NegInt(n) => Some(n),
175 N::Float(_) => None,
176 }
177 }
178
179 #[inline]
197 pub fn as_u64(&self) -> Option<u64> {
198 match self.n {
199 N::PosInt(n) => Some(n),
200 N::NegInt(_) | N::Float(_) => None,
201 }
202 }
203
204 #[inline]
235 pub fn as_f64(&self) -> Option<f64> {
236 match self.n {
237 N::PosInt(n) => Some(n as f64),
238 N::NegInt(n) => Some(n as f64),
239 N::Float(n) => Some(n),
240 }
241 }
242
243 #[inline]
259 pub fn is_nan(&self) -> bool {
260 match self.n {
261 N::PosInt(_) | N::NegInt(_) => false,
262 N::Float(f) => f.is_nan(),
263 }
264 }
265
266 #[inline]
283 pub fn is_infinite(&self) -> bool {
284 match self.n {
285 N::PosInt(_) | N::NegInt(_) => false,
286 N::Float(f) => f.is_infinite(),
287 }
288 }
289
290 #[inline]
306 pub fn is_finite(&self) -> bool {
307 match self.n {
308 N::PosInt(_) | N::NegInt(_) => true,
309 N::Float(f) => f.is_finite(),
310 }
311 }
312}
313
314impl Display for Number {
315 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
316 match self.n {
317 N::PosInt(i) => formatter.write_str(itoa::Buffer::new().format(i)),
318 N::NegInt(i) => formatter.write_str(itoa::Buffer::new().format(i)),
319 N::Float(f) if f.is_nan() => formatter.write_str(".nan"),
320 N::Float(f) if f.is_infinite() => {
321 if f.is_sign_negative() {
322 formatter.write_str("-.inf")
323 } else {
324 formatter.write_str(".inf")
325 }
326 },
327 N::Float(f) => formatter.write_str(ryu::Buffer::new().format_finite(f)),
328 }
329 }
330}
331
332impl FromStr for Number {
333 type Err = Error;
334
335 fn from_str(repr: &str) -> Result<Self, Self::Err> {
336 if let Ok(result) = de::visit_int(NumberVisitor, repr) {
337 return result;
338 }
339 if !de::digits_but_not_number(repr) {
340 if let Some(float) = de::parse_f64(repr) {
341 return Ok(float.into());
342 }
343 }
344 Err(error::new(ErrorImpl::FailedToParseNumber))
345 }
346}
347
348impl PartialEq for N {
349 fn eq(&self, other: &N) -> bool {
350 match (*self, *other) {
351 (N::PosInt(a), N::PosInt(b)) => a == b,
352 (N::NegInt(a), N::NegInt(b)) => a == b,
353 (N::Float(a), N::Float(b)) => {
354 if a.is_nan() && b.is_nan() {
355 true
358 } else {
359 a == b
360 }
361 },
362 _ => false,
363 }
364 }
365}
366
367impl PartialOrd for N {
368 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
369 match (*self, *other) {
370 (N::Float(a), N::Float(b)) => {
371 if a.is_nan() && b.is_nan() {
372 Some(Ordering::Equal)
374 } else {
375 a.partial_cmp(&b)
376 }
377 },
378 _ => Some(self.total_cmp(other)),
379 }
380 }
381}
382
383impl N {
384 fn total_cmp(&self, other: &Self) -> Ordering {
385 match (*self, *other) {
386 (N::PosInt(a), N::PosInt(b)) => a.cmp(&b),
387 (N::NegInt(a), N::NegInt(b)) => a.cmp(&b),
388 (N::NegInt(_), N::PosInt(_)) => Ordering::Less,
390 (N::PosInt(_), N::NegInt(_)) => Ordering::Greater,
391 (N::Float(a), N::Float(b)) => a.partial_cmp(&b).unwrap_or_else(|| {
392 if !a.is_nan() {
394 Ordering::Less
395 } else if !b.is_nan() {
396 Ordering::Greater
397 } else {
398 Ordering::Equal
399 }
400 }),
401 (_, N::Float(_)) => Ordering::Less,
404 (N::Float(_), _) => Ordering::Greater,
405 }
406 }
407}
408
409impl Number {
410 pub(crate) fn total_cmp(&self, other: &Self) -> Ordering {
411 self.n.total_cmp(&other.n)
412 }
413}
414
415impl Serialize for Number {
416 #[inline]
417 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
418 where
419 S: Serializer,
420 {
421 match self.n {
422 N::PosInt(i) => serializer.serialize_u64(i),
423 N::NegInt(i) => serializer.serialize_i64(i),
424 N::Float(f) => serializer.serialize_f64(f),
425 }
426 }
427}
428
429struct NumberVisitor;
430
431impl Visitor<'_> for NumberVisitor {
432 type Value = Number;
433
434 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
435 formatter.write_str("a number")
436 }
437
438 #[inline]
439 fn visit_i64<E>(self, value: i64) -> Result<Number, E> {
440 Ok(value.into())
441 }
442
443 #[inline]
444 fn visit_u64<E>(self, value: u64) -> Result<Number, E> {
445 Ok(value.into())
446 }
447
448 #[inline]
449 fn visit_f64<E>(self, value: f64) -> Result<Number, E> {
450 Ok(value.into())
451 }
452}
453
454impl<'de> Deserialize<'de> for Number {
455 #[inline]
456 fn deserialize<D>(deserializer: D) -> Result<Number, D::Error>
457 where
458 D: Deserializer<'de>,
459 {
460 deserializer.deserialize_any(NumberVisitor)
461 }
462}
463
464impl<'de> Deserializer<'de> for Number {
465 type Error = Error;
466
467 #[inline]
468 fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
469 where
470 V: Visitor<'de>,
471 {
472 match self.n {
473 N::PosInt(i) => visitor.visit_u64(i),
474 N::NegInt(i) => visitor.visit_i64(i),
475 N::Float(f) => visitor.visit_f64(f),
476 }
477 }
478
479 forward_to_deserialize_any! {
480 bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
481 bytes byte_buf option unit unit_struct newtype_struct seq tuple
482 tuple_struct map struct enum identifier ignored_any
483 }
484}
485
486impl<'de> Deserializer<'de> for &Number {
487 type Error = Error;
488
489 #[inline]
490 fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
491 where
492 V: Visitor<'de>,
493 {
494 match self.n {
495 N::PosInt(i) => visitor.visit_u64(i),
496 N::NegInt(i) => visitor.visit_i64(i),
497 N::Float(f) => visitor.visit_f64(f),
498 }
499 }
500
501 forward_to_deserialize_any! {
502 bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
503 bytes byte_buf option unit unit_struct newtype_struct seq tuple
504 tuple_struct map struct enum identifier ignored_any
505 }
506}
507
508macro_rules! from_signed {
509 ($($signed_ty:ident)*) => {
510 $(
511 impl From<$signed_ty> for Number {
512 #[inline]
513 #[allow(clippy::cast_sign_loss)]
514 fn from(i: $signed_ty) -> Self {
515 if i < 0 {
516 Number { n: N::NegInt(i as i64) }
517 } else {
518 Number { n: N::PosInt(i as u64) }
519 }
520 }
521 }
522 )*
523 };
524}
525
526macro_rules! from_unsigned {
527 ($($unsigned_ty:ident)*) => {
528 $(
529 impl From<$unsigned_ty> for Number {
530 #[inline]
531 fn from(u: $unsigned_ty) -> Self {
532 Number { n: N::PosInt(u as u64) }
533 }
534 }
535 )*
536 };
537}
538
539from_signed!(i8 i16 i32 i64 isize);
540from_unsigned!(u8 u16 u32 u64 usize);
541
542impl From<f32> for Number {
543 fn from(f: f32) -> Self {
544 Number::from(f as f64)
545 }
546}
547
548impl From<f64> for Number {
549 fn from(mut f: f64) -> Self {
550 if f.is_nan() {
551 f = f64::NAN.copysign(1.0);
553 }
554 Number { n: N::Float(f) }
555 }
556}
557
558#[allow(clippy::derived_hash_with_manual_eq)]
561impl Hash for Number {
562 fn hash<H: Hasher>(&self, state: &mut H) {
563 match self.n {
564 N::Float(_) => {
565 3.hash(state);
567 },
568 N::PosInt(u) => u.hash(state),
569 N::NegInt(i) => i.hash(state),
570 }
571 }
572}
573
574pub(crate) fn unexpected(number: &Number) -> Unexpected {
575 match number.n {
576 N::PosInt(u) => Unexpected::Unsigned(u),
577 N::NegInt(i) => Unexpected::Signed(i),
578 N::Float(f) => Unexpected::Float(f),
579 }
580}