1use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Visitor};
2
3#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
27pub enum Number {
28 PositiveInt(u64),
30 NegativeInt(i64),
32 Float(f64),
34}
35
36impl Number {
37 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 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 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}