sonic_rs/serde/
rawnumber.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
use ::serde::{
    de, de::Visitor, ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer,
};
use ::std::fmt;
use faststr::FastStr;

use super::number::Number;
use crate::{util::private::Sealed, Error, JsonNumberTrait};

/// Represents a JSON number with arbitrary precision, the underlying representation of a string,
/// like as Golang `json.Number`.
///
/// Example1:
///
/// ```
/// use sonic_rs::RawNumber;
///
/// use crate::sonic_rs::JsonNumberTrait;
///
/// // RawNumber can be parsed from a JSON number text.
/// let num: RawNumber = sonic_rs::from_str("123").unwrap();
/// assert_eq!(num.as_i64(), Some(123));
/// assert_eq!(num.as_str(), "123");
///
/// // RawNumber can be parsed from a JSON string text that contains a number.
/// let num: RawNumber =
///     sonic_rs::from_str("\"1.2333333333333333333333333333333333333333\"").unwrap();
/// assert_eq!(num.as_f64(), Some(1.2333333333333334));
/// assert_eq!(num.as_str(), "1.2333333333333333333333333333333333333333");
/// ```
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct RawNumber {
    n: FastStr,
}

impl RawNumber {
    pub(crate) fn new(s: &str) -> Self {
        Self { n: FastStr::new(s) }
    }

    pub(crate) fn from_faststr(n: FastStr) -> Self {
        Self { n }
    }

    /// as_str returns the underlying string representation of the number.
    pub fn as_str(&self) -> &str {
        self.n.as_str()
    }
}

pub(crate) const TOKEN: &str = "$sonic_rs::private::JsonNumber";

impl<'de> Deserialize<'de> for RawNumber {
    #[inline]
    fn deserialize<D>(deserializer: D) -> Result<RawNumber, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct JsonNumberVisitor;

        impl<'de> Visitor<'de> for JsonNumberVisitor {
            type Value = RawNumber;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a JSON number")
            }

            fn visit_borrowed_str<E>(self, raw: &'de str) -> Result<Self::Value, E>
            where
                E: de::Error,
            {
                Ok(RawNumber::new(raw))
            }
        }

        deserializer.deserialize_newtype_struct(TOKEN, JsonNumberVisitor)
    }
}

impl Serialize for RawNumber {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut s = serializer.serialize_struct(TOKEN, 1)?;
        s.serialize_field(TOKEN, &self.n)?;
        s.end()
    }
}

impl Sealed for RawNumber {}

impl JsonNumberTrait for RawNumber {
    /// Returns true if the `Number` is an integer between `i64::MIN` and
    /// `i64::MAX`.
    ///
    /// For any Number on which `is_i64` returns true, `as_i64` is guaranteed to
    /// return the integer value.
    #[inline]
    fn is_i64(&self) -> bool {
        self.as_i64().is_some()
    }

    /// Returns true if the `Number` is an integer between zero and `u64::MAX`.
    ///
    /// For any Number on which `is_u64` returns true, `as_u64` is guaranteed to
    /// return the integer value.
    #[inline]
    fn is_u64(&self) -> bool {
        self.as_u64().is_some()
    }

    /// Returns true if the `Number` can be represented by f64.
    ///
    /// For any Number on which `is_f64` returns true, `as_f64` is guaranteed to
    /// return the floating point value.
    ///
    /// Currently this function returns true if and only if both `is_i64` and
    /// `is_u64` return false but this is not a guarantee in the future.
    #[inline]
    fn is_f64(&self) -> bool {
        self.as_f64().is_some()
    }

    /// If the `Number` is an integer, represent it as i64 if possible. Returns
    /// None otherwise.
    #[inline]
    fn as_i64(&self) -> Option<i64> {
        self.n.parse().ok()
    }

    /// If the `Number` is an integer, represent it as u64 if possible. Returns
    /// None otherwise.
    #[inline]
    fn as_u64(&self) -> Option<u64> {
        self.n.parse().ok()
    }

    /// Represents the number as finite f64 if possible. Returns None otherwise.
    #[inline]
    fn as_f64(&self) -> Option<f64> {
        self.n.parse::<f64>().ok().filter(|float| float.is_finite())
    }
}

impl TryFrom<RawNumber> for Number {
    type Error = Error;

    fn try_from(value: RawNumber) -> Result<Self, Self::Error> {
        let num: Number = crate::from_str(value.n.as_str())?;
        Ok(num)
    }
}