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,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::UnsignedInt(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::SignedInt(-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    /// Represents `positive fixint`, `uint 8`, `uint 16`, `uint 32` and `uint 64`
29    UnsignedInt(u64),
30    /// Represents `negative fixint`, `int 8`, `int 16`, `int 32` and `int 64`
31    SignedInt(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    pub fn as_unsigned_int(&self) -> Option<u64> {
39        match self {
40            Number::UnsignedInt(v) => Some(*v),
41            _ => None,
42        }
43    }
44
45    /// If the `Number` is signed int, returns `i64`.
46    pub fn as_signed_int(&self) -> Option<i64> {
47        match self {
48            Number::SignedInt(v) => Some(*v),
49            _ => None,
50        }
51    }
52
53    /// If the `Number` is floating number, returns `f64`.
54    pub fn as_float(&self) -> Option<f64> {
55        match self {
56            Number::Float(v) => Some(*v),
57            _ => None,
58        }
59    }
60}
61
62macro_rules! impl_from_num {
63    ($from:ident,$ty:path,$cast:path) => {
64        impl From<$from> for Number {
65            fn from(value: $from) -> Self {
66                $ty(value as $cast)
67            }
68        }
69    };
70}
71
72impl_from_num!(u8, Number::UnsignedInt, u64);
73impl_from_num!(u16, Number::UnsignedInt, u64);
74impl_from_num!(u32, Number::UnsignedInt, u64);
75impl_from_num!(u64, Number::UnsignedInt, u64);
76impl_from_num!(i8, Number::SignedInt, i64);
77impl_from_num!(i16, Number::SignedInt, i64);
78impl_from_num!(i32, Number::SignedInt, i64);
79impl_from_num!(i64, Number::SignedInt, i64);
80impl_from_num!(f32, Number::Float, f64);
81impl_from_num!(f64, Number::Float, f64);
82
83impl Serialize for Number {
84    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
85    where
86        S: Serializer,
87    {
88        match self {
89            Number::UnsignedInt(n) => serializer.serialize_u64(*n),
90            Number::SignedInt(n) => serializer.serialize_i64(*n),
91            Number::Float(n) => serializer.serialize_f64(*n),
92        }
93    }
94}
95
96impl<'de> Deserialize<'de> for Number {
97    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
98    where
99        D: Deserializer<'de>,
100    {
101        struct NumberVisitor;
102        impl Visitor<'_> for NumberVisitor {
103            type Value = Number;
104            fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
105                formatter.write_str("a number")
106            }
107
108            fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
109            where
110                E: serde::de::Error,
111            {
112                Ok(Number::UnsignedInt(v))
113            }
114
115            fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
116            where
117                E: serde::de::Error,
118            {
119                Ok(Number::SignedInt(v))
120            }
121
122            fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
123            where
124                E: serde::de::Error,
125            {
126                Ok(Number::Float(v))
127            }
128        }
129
130        deserializer.deserialize_any(NumberVisitor)
131    }
132}
133
134#[cfg(test)]
135mod tests {
136    use super::*;
137    use crate::from_slice;
138    use rstest::rstest;
139
140    #[rstest]
141    #[case([0x05],5)]
142    #[case([0xcd, 0xff, 0xff],u16::MAX.into())]
143    #[case([0xce, 0xff, 0xff,0xff,0xff],u32::MAX.into())]
144    #[case([0xcf, 0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff],u64::MAX)]
145    fn decode_unsigned_int<Buf: AsRef<[u8]>>(#[case] input: Buf, #[case] expected: u64) {
146        let num = from_slice::<Number>(input.as_ref()).unwrap();
147        assert_eq!(num, Number::UnsignedInt(expected));
148    }
149
150    #[rstest]
151    #[case([0xe0],-32)]
152    #[case([0xd0, 0x7f],i8::MAX.into())]
153    #[case([0xd1, 0x7f, 0xff],i16::MAX.into())]
154    #[case([0xd2, 0x80, 0x00, 0x00, 0x00],i32::MIN.into())]
155    #[case([0xd3, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],i64::MAX)]
156    fn decode_signed_int<Buf: AsRef<[u8]>>(#[case] input: Buf, #[case] expected: i64) {
157        let num = from_slice::<Number>(input.as_ref()).unwrap();
158        assert_eq!(num, Number::SignedInt(expected));
159    }
160
161    #[rstest]
162    #[case([0xca, 0x42, 0xf6, 0xe9, 0x79],123.456)]
163    #[case([0xcb, 0x40, 0xfe, 0x24, 0x0c, 0x9f, 0xcb, 0x0c, 0x02],123456.789012)]
164    fn decode_float<Buf: AsRef<[u8]>>(#[case] input: Buf, #[case] expected: f64) {
165        let num = from_slice::<Number>(input.as_ref()).unwrap();
166        match num {
167            Number::Float(n) => {
168                let diff = (n - expected).abs();
169                assert!(diff < (1e-5))
170            }
171            _ => {
172                panic!("Err")
173            }
174        }
175    }
176}