messagepack_serde/value/
number.rs

1use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Visitor};
2
3/// Represents any number, it could be int or float.
4///
5/// ## Example
6///
7/// ```rust
8/// use serde::{Deserialize, Serialize};
9/// use messagepack_serde::{from_slice,value::Number};
10/// #[derive(Debug, Serialize, Deserialize, PartialEq)]
11/// struct Data{
12///     num: Number
13/// }
14/// let buf:&[u8] = &[0x81,0xa3,0x6e,0x75,0x6d,0x01]; // {"num":1}
15/// let data = from_slice::<Data>(buf).unwrap();
16/// assert_eq!(data.num,Number::PositiveInt(1));
17///
18/// let buf:&[u8] = &[0x81,0xa3,0x6e,0x75,0x6d,0xd0,0x85]; // {"num":-123}
19/// let data = from_slice::<Data>(buf).unwrap();
20/// assert_eq!(data.num,Number::NegativeInt(-123));
21///
22/// let buf:&[u8] = &[0x81,0xa3,0x6e,0x75,0x6d,0xcb,0x3f,0xf8,0x00,0x00,0x00,0x00,0x00,0x00]; // {"num":1.5}
23/// let data = from_slice::<Data>(buf).unwrap();
24/// assert_eq!(data.num,Number::Float(1.5));
25/// ```
26#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
27pub enum Number {
28    /// Always positive
29    PositiveInt(u64),
30    /// Always negative
31    NegativeInt(i64),
32    /// Represents `float 32` and `float 64`
33    Float(f64),
34}
35
36impl Number {
37    /// If the `Number` is unsigned int, returns `u64`.
38    ///
39    /// ```rust
40    /// # use messagepack_serde::value::Number;
41    ///
42    /// let n = Number::from(1);
43    /// assert_eq!(n.as_unsigned_int(),Some(1));
44    ///
45    /// let n = Number::try_from(1isize).unwrap();
46    /// assert_eq!(n.as_unsigned_int(),Some(1));
47    ///
48    /// let n = Number::from(-1);
49    /// assert_eq!(n.as_unsigned_int(),None);
50    /// ```
51    pub fn as_unsigned_int(&self) -> Option<u64> {
52        match self {
53            Number::PositiveInt(v) => Some(*v),
54            Number::NegativeInt(v) => (*v).try_into().ok(),
55            _ => None,
56        }
57    }
58
59    /// If the `Number` is signed int, returns `i64`.
60    ///
61    /// ```rust
62    /// # use messagepack_serde::value::Number;
63    /// let n = Number::from(-1);
64    /// assert_eq!(n.as_signed_int(),Some(-1));
65    ///
66    /// let n = Number::from(1);
67    /// assert_eq!(n.as_signed_int(),Some(1));
68    /// ```
69    pub fn as_signed_int(&self) -> Option<i64> {
70        match self {
71            Number::PositiveInt(v) => i64::try_from(*v).ok(),
72            Number::NegativeInt(v) => Some(*v),
73            _ => None,
74        }
75    }
76
77    /// If the `Number` is floating number, returns `f64`.
78    ///
79    /// ```rust
80    /// # use messagepack_serde::value::Number;
81    /// let n = Number::from(1.5);
82    /// assert_eq!(n.as_float(),Some(1.5));
83    ///
84    /// let n = Number::from(1);
85    /// assert_eq!(n.as_float(),None);
86    /// ```
87    pub fn as_float(&self) -> Option<f64> {
88        match self {
89            Number::Float(v) => Some(*v),
90            _ => None,
91        }
92    }
93}
94
95impl From<u64> for Number {
96    fn from(value: u64) -> Self {
97        Number::PositiveInt(value)
98    }
99}
100
101impl From<i64> for Number {
102    fn from(value: i64) -> Self {
103        u64::try_from(value)
104            .map(Number::PositiveInt)
105            .unwrap_or_else(|_| Number::NegativeInt(value))
106    }
107}
108
109macro_rules! impl_from_num {
110    ($from:ident, $cast:path) => {
111        impl From<$from> for Number {
112            fn from(value: $from) -> Self {
113                Self::from(value as $cast)
114            }
115        }
116    };
117}
118
119impl_from_num!(u8, u64);
120impl_from_num!(u16, u64);
121impl_from_num!(u32, u64);
122impl_from_num!(i8, i64);
123impl_from_num!(i16, i64);
124impl_from_num!(i32, i64);
125
126impl TryFrom<usize> for Number {
127    type Error = core::num::TryFromIntError;
128    fn try_from(value: usize) -> Result<Self, Self::Error> {
129        u64::try_from(value).map(Number::PositiveInt)
130    }
131}
132
133impl TryFrom<isize> for Number {
134    type Error = core::num::TryFromIntError;
135    fn try_from(value: isize) -> Result<Self, Self::Error> {
136        if let Ok(v) = i64::try_from(value) {
137            return Ok(Number::from(v));
138        }
139
140        u64::try_from(value).map(Self::from)
141    }
142}
143
144impl From<f32> for Number {
145    fn from(value: f32) -> Self {
146        Self::from(value as f64)
147    }
148}
149
150impl From<f64> for Number {
151    fn from(value: f64) -> Self {
152        Self::Float(value)
153    }
154}
155
156impl Serialize for Number {
157    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
158    where
159        S: Serializer,
160    {
161        match self {
162            Number::PositiveInt(n) => serializer.serialize_u64(*n),
163            Number::NegativeInt(n) => serializer.serialize_i64(*n),
164            Number::Float(n) => serializer.serialize_f64(*n),
165        }
166    }
167}
168
169impl<'de> Deserialize<'de> for Number {
170    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
171    where
172        D: Deserializer<'de>,
173    {
174        struct NumberVisitor;
175        impl Visitor<'_> for NumberVisitor {
176            type Value = Number;
177            fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
178                formatter.write_str("a number")
179            }
180
181            fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
182            where
183                E: serde::de::Error,
184            {
185                Ok(Number::from(v))
186            }
187
188            fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
189            where
190                E: serde::de::Error,
191            {
192                Ok(Number::from(v))
193            }
194
195            fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
196            where
197                E: serde::de::Error,
198            {
199                Ok(Number::from(v))
200            }
201        }
202
203        deserializer.deserialize_any(NumberVisitor)
204    }
205}
206
207#[cfg(test)]
208mod tests {
209    use super::*;
210    use crate::from_slice;
211    use rstest::rstest;
212
213    #[rstest]
214    #[case([0x05],5)]
215    #[case([0xcd, 0xff, 0xff],u16::MAX.into())]
216    #[case([0xce, 0xff, 0xff,0xff,0xff],u32::MAX.into())]
217    #[case([0xcf, 0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff],u64::MAX)]
218    fn decode_unsigned_int<Buf: AsRef<[u8]>>(#[case] input: Buf, #[case] expected: u64) {
219        let num = from_slice::<Number>(input.as_ref()).unwrap();
220        assert_eq!(num, Number::PositiveInt(expected));
221    }
222
223    #[rstest]
224    #[case([0xe0],-32)]
225    #[case([0xd0, 0x80],i8::MIN.into())]
226    #[case([0xd1, 0x80, 0x00],i16::MIN.into())]
227    #[case([0xd2, 0x80, 0x00, 0x00, 0x00],i32::MIN.into())]
228    #[case([0xd3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],i64::MIN)]
229    fn decode_signed_int<Buf: AsRef<[u8]>>(#[case] input: Buf, #[case] expected: i64) {
230        let num = from_slice::<Number>(input.as_ref()).unwrap();
231        assert_eq!(num, Number::NegativeInt(expected));
232    }
233
234    #[rstest]
235    #[case([0xca, 0x42, 0xf6, 0xe9, 0x79],123.456)]
236    #[case([0xcb, 0x40, 0xfe, 0x24, 0x0c, 0x9f, 0xcb, 0x0c, 0x02],123456.789012)]
237    fn decode_float<Buf: AsRef<[u8]>>(#[case] input: Buf, #[case] expected: f64) {
238        let num = from_slice::<Number>(input.as_ref()).unwrap();
239        match num {
240            Number::Float(n) => {
241                let diff = (n - expected).abs();
242                assert!(diff < (1e-5))
243            }
244            _ => {
245                panic!("Err")
246            }
247        }
248    }
249}