sonic_rs/serde/
rawnumber.rs

1use ::serde::{
2    de, de::Visitor, ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer,
3};
4use ::std::fmt;
5use faststr::FastStr;
6
7use super::number::Number;
8use crate::{util::private::Sealed, Error, JsonNumberTrait};
9
10/// Represents a JSON number with arbitrary precision, the underlying representation of a string,
11/// like as Golang `json.Number`.
12///
13/// Example1:
14///
15/// ```
16/// use sonic_rs::RawNumber;
17///
18/// use crate::sonic_rs::JsonNumberTrait;
19///
20/// // RawNumber can be parsed from a JSON number text.
21/// let num: RawNumber = sonic_rs::from_str("123").unwrap();
22/// assert_eq!(num.as_i64(), Some(123));
23/// assert_eq!(num.as_str(), "123");
24///
25/// // RawNumber can be parsed from a JSON string text that contains a number.
26/// let num: RawNumber =
27///     sonic_rs::from_str("\"1.2333333333333333333333333333333333333333\"").unwrap();
28/// assert_eq!(num.as_f64(), Some(1.2333333333333334));
29/// assert_eq!(num.as_str(), "1.2333333333333333333333333333333333333333");
30/// ```
31#[derive(Clone, PartialEq, Eq, Hash, Debug)]
32pub struct RawNumber {
33    n: FastStr,
34}
35
36impl RawNumber {
37    pub(crate) fn new(s: &str) -> Self {
38        Self { n: FastStr::new(s) }
39    }
40
41    pub(crate) fn from_faststr(n: FastStr) -> Self {
42        Self { n }
43    }
44
45    /// as_str returns the underlying string representation of the number.
46    pub fn as_str(&self) -> &str {
47        self.n.as_str()
48    }
49}
50
51pub(crate) const TOKEN: &str = "$sonic_rs::private::JsonNumber";
52
53impl<'de> Deserialize<'de> for RawNumber {
54    #[inline]
55    fn deserialize<D>(deserializer: D) -> Result<RawNumber, D::Error>
56    where
57        D: Deserializer<'de>,
58    {
59        struct JsonNumberVisitor;
60
61        impl<'de> Visitor<'de> for JsonNumberVisitor {
62            type Value = RawNumber;
63
64            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
65                formatter.write_str("a JSON number")
66            }
67
68            fn visit_borrowed_str<E>(self, raw: &'de str) -> Result<Self::Value, E>
69            where
70                E: de::Error,
71            {
72                Ok(RawNumber::new(raw))
73            }
74        }
75
76        deserializer.deserialize_newtype_struct(TOKEN, JsonNumberVisitor)
77    }
78}
79
80impl Serialize for RawNumber {
81    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
82    where
83        S: Serializer,
84    {
85        let mut s = serializer.serialize_struct(TOKEN, 1)?;
86        s.serialize_field(TOKEN, &self.n)?;
87        s.end()
88    }
89}
90
91impl Sealed for RawNumber {}
92
93impl JsonNumberTrait for RawNumber {
94    /// Returns true if the `Number` is an integer between `i64::MIN` and
95    /// `i64::MAX`.
96    ///
97    /// For any Number on which `is_i64` returns true, `as_i64` is guaranteed to
98    /// return the integer value.
99    #[inline]
100    fn is_i64(&self) -> bool {
101        self.as_i64().is_some()
102    }
103
104    /// Returns true if the `Number` is an integer between zero and `u64::MAX`.
105    ///
106    /// For any Number on which `is_u64` returns true, `as_u64` is guaranteed to
107    /// return the integer value.
108    #[inline]
109    fn is_u64(&self) -> bool {
110        self.as_u64().is_some()
111    }
112
113    /// Returns true if the `Number` can be represented by f64.
114    ///
115    /// For any Number on which `is_f64` returns true, `as_f64` is guaranteed to
116    /// return the floating point value.
117    ///
118    /// Currently this function returns true if and only if both `is_i64` and
119    /// `is_u64` return false but this is not a guarantee in the future.
120    #[inline]
121    fn is_f64(&self) -> bool {
122        self.as_f64().is_some()
123    }
124
125    /// If the `Number` is an integer, represent it as i64 if possible. Returns
126    /// None otherwise.
127    #[inline]
128    fn as_i64(&self) -> Option<i64> {
129        self.n.parse().ok()
130    }
131
132    /// If the `Number` is an integer, represent it as u64 if possible. Returns
133    /// None otherwise.
134    #[inline]
135    fn as_u64(&self) -> Option<u64> {
136        self.n.parse().ok()
137    }
138
139    /// Represents the number as finite f64 if possible. Returns None otherwise.
140    #[inline]
141    fn as_f64(&self) -> Option<f64> {
142        self.n.parse::<f64>().ok().filter(|float| float.is_finite())
143    }
144}
145
146impl TryFrom<RawNumber> for Number {
147    type Error = Error;
148
149    fn try_from(value: RawNumber) -> Result<Self, Self::Error> {
150        let num: Number = crate::from_str(value.n.as_str())?;
151        Ok(num)
152    }
153}