libdd_trace_utils/msgpack_decoder/decode/
number.rs

1// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::msgpack_decoder::decode::error::DecodeError;
5use rmp::{decode::RmpRead, Marker};
6use std::fmt;
7
8#[derive(Debug, PartialEq)]
9pub enum Number {
10    Unsigned(u64),
11    Signed(i64),
12    Float(f64),
13}
14
15impl fmt::Display for Number {
16    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17        match self {
18            Number::Signed(val) => write!(f, "{val}"),
19            Number::Unsigned(val) => write!(f, "{val}"),
20            Number::Float(val) => write!(f, "{val}"),
21        }
22    }
23}
24
25impl Number {
26    pub fn bounded_int_conversion<T>(
27        self,
28        lower_bound: T,
29        upper_bound: Option<T>,
30    ) -> Result<T, DecodeError>
31    where
32        T: TryInto<i64> + TryInto<u64> + TryInto<i32> + Copy + fmt::Display,
33        i64: TryInto<T>,
34        u64: TryInto<T>,
35        <T as TryInto<i64>>::Error: fmt::Debug,
36        <T as TryInto<u64>>::Error: fmt::Debug,
37        <i64 as TryInto<T>>::Error: fmt::Debug,
38        <u64 as TryInto<T>>::Error: fmt::Debug,
39    {
40        #[allow(clippy::unwrap_used)]
41        match self {
42            Number::Signed(val) => {
43                let upper_bound_check = if let Some(upper_bound) = upper_bound {
44                    val <= upper_bound.try_into().unwrap()
45                } else {
46                    true
47                };
48                if val >= lower_bound.try_into().unwrap() && upper_bound_check {
49                    val.try_into()
50                        .map_err(|e| DecodeError::InvalidConversion(format!("{e:?}")))
51                } else {
52                    Err(DecodeError::InvalidConversion(format!(
53                        "{val} is out of bounds for conversion"
54                    )))
55                }
56            }
57            Number::Unsigned(val) => {
58                let upper_bound_check = if let Some(upper_bound) = upper_bound {
59                    val <= upper_bound.try_into().unwrap()
60                } else {
61                    true
62                };
63
64                if upper_bound_check {
65                    val.try_into()
66                        .map_err(|e| DecodeError::InvalidConversion(format!("{e:?}")))
67                } else {
68                    Err(DecodeError::InvalidConversion(format!(
69                        "{val} is out of bounds for conversion"
70                    )))
71                }
72            }
73            _ => Err(DecodeError::InvalidConversion(
74                "Cannot convert float to int".to_owned(),
75            )),
76        }
77    }
78}
79
80impl TryFrom<Number> for i8 {
81    type Error = DecodeError;
82    fn try_from(value: Number) -> Result<Self, Self::Error> {
83        value.bounded_int_conversion(i8::MIN, Some(i8::MAX))
84    }
85}
86
87impl TryFrom<Number> for i32 {
88    type Error = DecodeError;
89    fn try_from(value: Number) -> Result<Self, Self::Error> {
90        value.bounded_int_conversion(i32::MIN, Some(i32::MAX))
91    }
92}
93
94impl TryFrom<Number> for i64 {
95    type Error = DecodeError;
96    fn try_from(value: Number) -> Result<Self, Self::Error> {
97        value.bounded_int_conversion(i64::MIN, Some(i64::MAX))
98    }
99}
100
101impl TryFrom<Number> for u8 {
102    type Error = DecodeError;
103    fn try_from(value: Number) -> Result<Self, Self::Error> {
104        value.bounded_int_conversion(u8::MIN, Some(u8::MAX))
105    }
106}
107
108impl TryFrom<Number> for u32 {
109    type Error = DecodeError;
110    fn try_from(value: Number) -> Result<Self, Self::Error> {
111        value.bounded_int_conversion(u32::MIN, Some(u32::MAX))
112    }
113}
114
115impl TryFrom<Number> for u64 {
116    type Error = DecodeError;
117    fn try_from(value: Number) -> Result<Self, Self::Error> {
118        value.bounded_int_conversion(u64::MIN, None)
119    }
120}
121
122impl TryFrom<Number> for f64 {
123    type Error = DecodeError;
124    fn try_from(value: Number) -> Result<Self, Self::Error> {
125        match value {
126            Number::Unsigned(val) => {
127                if val <= f64::MAX as u64 {
128                    Ok(val as f64)
129                } else {
130                    Err(DecodeError::InvalidConversion(format!(
131                        "{val} is out of bounds for conversion"
132                    )))
133                }
134            }
135            Number::Signed(val) => {
136                if val >= f64::MIN as i64 && val <= f64::MAX as i64 {
137                    Ok(val as f64)
138                } else {
139                    Err(DecodeError::InvalidConversion(format!(
140                        "{val} is out of bounds for conversion"
141                    )))
142                }
143            }
144            Number::Float(val) => Ok(val),
145        }
146    }
147}
148
149fn read_number(buf: &mut &[u8], allow_null: bool) -> Result<Number, DecodeError> {
150    match rmp::decode::read_marker(buf)
151        .map_err(|_| DecodeError::InvalidFormat("Unable to read marker for number".to_owned()))?
152    {
153        Marker::FixPos(val) => Ok(Number::Unsigned(val as u64)),
154        Marker::FixNeg(val) => Ok(Number::Signed(val as i64)),
155        Marker::U8 => Ok(Number::Unsigned(
156            buf.read_data_u8().map_err(|_| DecodeError::IOError)? as u64,
157        )),
158        Marker::U16 => Ok(Number::Unsigned(
159            buf.read_data_u16().map_err(|_| DecodeError::IOError)? as u64,
160        )),
161        Marker::U32 => Ok(Number::Unsigned(
162            buf.read_data_u32().map_err(|_| DecodeError::IOError)? as u64,
163        )),
164        Marker::U64 => Ok(Number::Unsigned(
165            buf.read_data_u64().map_err(|_| DecodeError::IOError)?,
166        )),
167        Marker::I8 => Ok(Number::Signed(
168            buf.read_data_i8().map_err(|_| DecodeError::IOError)? as i64,
169        )),
170        Marker::I16 => Ok(Number::Signed(
171            buf.read_data_i16().map_err(|_| DecodeError::IOError)? as i64,
172        )),
173        Marker::I32 => Ok(Number::Signed(
174            buf.read_data_i32().map_err(|_| DecodeError::IOError)? as i64,
175        )),
176        Marker::I64 => Ok(Number::Signed(
177            buf.read_data_i64().map_err(|_| DecodeError::IOError)?,
178        )),
179        Marker::F32 => Ok(Number::Float(
180            buf.read_data_f32().map_err(|_| DecodeError::IOError)? as f64,
181        )),
182        Marker::F64 => Ok(Number::Float(
183            buf.read_data_f64().map_err(|_| DecodeError::IOError)?,
184        )),
185        Marker::Null => {
186            if allow_null {
187                Ok(Number::Unsigned(0))
188            } else {
189                Err(DecodeError::InvalidType("Invalid number type".to_owned()))
190            }
191        }
192        _ => Err(DecodeError::InvalidType("Invalid number type".to_owned())),
193    }
194}
195
196/// Read a msgpack encoded number from `buf`.
197pub fn read_number_slice<T: TryFrom<Number, Error = DecodeError>>(
198    buf: &mut &[u8],
199) -> Result<T, DecodeError> {
200    read_number(buf, false)?.try_into()
201}
202
203/// Read a msgpack encoded number from `buf` and return 0 if null.
204pub fn read_nullable_number_slice<T: TryFrom<Number, Error = DecodeError>>(
205    buf: &mut &[u8],
206) -> Result<T, DecodeError> {
207    read_number(buf, true)?.try_into()
208}
209
210#[cfg(test)]
211mod tests {
212    use super::*;
213    use serde_json::json;
214    use std::f64;
215
216    #[test]
217    fn test_decoding_not_nullable_slice_to_unsigned() {
218        let mut buf = Vec::new();
219        let expected_value = 42;
220        let val = json!(expected_value);
221        rmp_serde::encode::write_named(&mut buf, &val).unwrap();
222        let mut slice = buf.as_slice();
223        let result: u8 = read_number_slice(&mut slice).unwrap();
224        assert_eq!(result, expected_value);
225    }
226
227    #[test]
228    fn test_decoding_not_nullable_slice_to_signed() {
229        let mut buf = Vec::new();
230        let expected_value = 42;
231        let val = json!(expected_value);
232        rmp_serde::encode::write_named(&mut buf, &val).unwrap();
233        let mut slice = buf.as_slice();
234        let result: i8 = read_number_slice(&mut slice).unwrap();
235        assert_eq!(result, expected_value);
236    }
237
238    #[test]
239    fn test_decoding_not_nullable_slice_to_float() {
240        let mut buf = Vec::new();
241        let expected_value = 42.98;
242        let val = json!(expected_value);
243        rmp_serde::encode::write_named(&mut buf, &val).unwrap();
244        let mut slice = buf.as_slice();
245        let result: f64 = read_number_slice(&mut slice).unwrap();
246        assert_eq!(result, expected_value);
247    }
248
249    #[test]
250    fn test_decoding_null_through_read_number_slice_raises_exception() {
251        let mut buf = Vec::new();
252        let val = json!(null);
253        rmp_serde::encode::write_named(&mut buf, &val).unwrap();
254        let mut slice = buf.as_slice();
255        let result: Result<u8, DecodeError> = read_number_slice(&mut slice);
256        assert!(matches!(result, Err(DecodeError::InvalidType(_))));
257
258        assert_eq!(
259            result.unwrap_err().to_string(),
260            "Invalid type encountered: Invalid number type".to_owned()
261        );
262    }
263
264    #[test]
265    fn test_decoding_null_slice_to_unsigned() {
266        let mut buf = Vec::new();
267        let val = json!(null);
268        rmp_serde::encode::write_named(&mut buf, &val).unwrap();
269        let mut slice = buf.as_slice();
270        let result: u8 = read_nullable_number_slice(&mut slice).unwrap();
271        assert_eq!(result, 0);
272    }
273
274    #[test]
275    fn test_decoding_null_slice_to_signed() {
276        let mut buf = Vec::new();
277        let val = json!(null);
278        rmp_serde::encode::write_named(&mut buf, &val).unwrap();
279        let mut slice = buf.as_slice();
280        let result: i8 = read_nullable_number_slice(&mut slice).unwrap();
281        assert_eq!(result, 0);
282    }
283
284    #[test]
285    fn test_decoding_null_slice_to_float() {
286        let mut buf = Vec::new();
287        let val = json!(null);
288        rmp_serde::encode::write_named(&mut buf, &val).unwrap();
289        let mut slice = buf.as_slice();
290        let result: f64 = read_nullable_number_slice(&mut slice).unwrap();
291        assert_eq!(result, 0.0);
292    }
293
294    #[test]
295    fn test_i64_conversions() {
296        let valid_max = i64::MAX;
297        let valid_unsigned_number = Number::Unsigned(valid_max as u64);
298        let zero_unsigned = Number::Unsigned(0u64);
299        let zero_signed = Number::Signed(0);
300        let valid_signed_number = Number::Signed(valid_max);
301        let invalid_float_number = Number::Float(4.14);
302        let invalid_unsigned = u64::MAX;
303        let invalid_unsigned_number = Number::Unsigned(invalid_unsigned);
304
305        assert_eq!(
306            valid_max,
307            TryInto::<i64>::try_into(valid_unsigned_number).unwrap()
308        );
309        assert_eq!(
310            valid_max,
311            TryInto::<i64>::try_into(valid_signed_number).unwrap()
312        );
313        assert_eq!(0, TryInto::<i64>::try_into(zero_signed).unwrap());
314        assert_eq!(0, TryInto::<i64>::try_into(zero_unsigned).unwrap());
315        assert_eq!(
316            Err(DecodeError::InvalidConversion(
317                "Cannot convert float to int".to_owned()
318            )),
319            TryInto::<i64>::try_into(invalid_float_number)
320        );
321        assert_eq!(
322            Err(DecodeError::InvalidConversion(format!(
323                "{invalid_unsigned} is out of bounds for conversion"
324            ))),
325            TryInto::<i64>::try_into(invalid_unsigned_number)
326        );
327    }
328    #[test]
329    fn test_i32_conversions() {
330        let valid_signed_upper = i32::MAX;
331        let valid_unsigned_number = Number::Unsigned(valid_signed_upper as u64);
332        let zero_unsigned = Number::Unsigned(0u64);
333        let zero_signed = Number::Signed(0);
334        let valid_signed_number_upper = Number::Signed(valid_signed_upper as i64);
335        let valid_signed_lower = i32::MIN;
336        let valid_signed_number_lower = Number::Signed(valid_signed_lower as i64);
337        let invalid_float_number = Number::Float(4.14);
338        let invalid_unsigned = u64::MAX;
339        let invalid_unsigned_number = Number::Unsigned(invalid_unsigned);
340        let invalid_signed_upper = i32::MAX as i64 + 1;
341        let invalid_signed_number_upper = Number::Signed(invalid_signed_upper);
342        let invalid_signed_lower = i32::MIN as i64 - 1;
343        let invalid_signed_number_lower = Number::Signed(invalid_signed_lower);
344
345        assert_eq!(
346            valid_signed_upper,
347            TryInto::<i32>::try_into(valid_unsigned_number).unwrap()
348        );
349        assert_eq!(
350            valid_signed_upper,
351            TryInto::<i32>::try_into(valid_signed_number_upper).unwrap()
352        );
353        assert_eq!(
354            valid_signed_lower,
355            TryInto::<i32>::try_into(valid_signed_number_lower).unwrap()
356        );
357        assert_eq!(0, TryInto::<i32>::try_into(zero_signed).unwrap());
358        assert_eq!(0, TryInto::<i32>::try_into(zero_unsigned).unwrap());
359        assert_eq!(
360            Err(DecodeError::InvalidConversion(
361                "Cannot convert float to int".to_owned()
362            )),
363            TryInto::<i32>::try_into(invalid_float_number)
364        );
365        assert_eq!(
366            Err(DecodeError::InvalidConversion(format!(
367                "{invalid_unsigned} is out of bounds for conversion"
368            ))),
369            TryInto::<i32>::try_into(invalid_unsigned_number)
370        );
371        assert_eq!(
372            Err(DecodeError::InvalidConversion(format!(
373                "{invalid_signed_upper} is out of bounds for conversion"
374            ))),
375            TryInto::<i32>::try_into(invalid_signed_number_upper)
376        );
377        assert_eq!(
378            Err(DecodeError::InvalidConversion(format!(
379                "{invalid_signed_lower} is out of bounds for conversion"
380            ))),
381            TryInto::<i32>::try_into(invalid_signed_number_lower)
382        );
383    }
384
385    #[test]
386    fn test_i8_null_conversions() {
387        let valid_signed_upper = i8::MAX;
388        let valid_unsigned_number = Number::Unsigned(valid_signed_upper as u64);
389        let zero_unsigned = Number::Unsigned(0u64);
390        let zero_signed = Number::Signed(0);
391        let valid_signed_number_upper = Number::Signed(valid_signed_upper as i64);
392        let valid_signed_lower = i8::MIN;
393        let valid_signed_number_lower = Number::Signed(valid_signed_lower as i64);
394        let invalid_float_number = Number::Float(4.14);
395        let invalid_unsigned = u8::MAX;
396        let invalid_unsigned_number = Number::Unsigned(invalid_unsigned as u64);
397        let invalid_signed_upper = i8::MAX as i64 + 1;
398        let invalid_signed_number_upper = Number::Signed(invalid_signed_upper);
399        let invalid_signed_lower = i8::MIN as i64 - 1;
400        let invalid_signed_number_lower = Number::Signed(invalid_signed_lower);
401
402        assert_eq!(
403            valid_signed_upper,
404            TryInto::<i8>::try_into(valid_unsigned_number).unwrap()
405        );
406        assert_eq!(
407            valid_signed_upper,
408            TryInto::<i8>::try_into(valid_signed_number_upper).unwrap()
409        );
410        assert_eq!(
411            valid_signed_lower,
412            TryInto::<i8>::try_into(valid_signed_number_lower).unwrap()
413        );
414        assert_eq!(0, TryInto::<i8>::try_into(zero_signed).unwrap());
415        assert_eq!(0, TryInto::<i8>::try_into(zero_unsigned).unwrap());
416        assert_eq!(
417            Err(DecodeError::InvalidConversion(
418                "Cannot convert float to int".to_owned()
419            )),
420            TryInto::<i8>::try_into(invalid_float_number)
421        );
422        assert_eq!(
423            Err(DecodeError::InvalidConversion(format!(
424                "{invalid_unsigned} is out of bounds for conversion"
425            ))),
426            TryInto::<i8>::try_into(invalid_unsigned_number)
427        );
428        assert_eq!(
429            Err(DecodeError::InvalidConversion(format!(
430                "{invalid_signed_upper} is out of bounds for conversion"
431            ))),
432            TryInto::<i8>::try_into(invalid_signed_number_upper)
433        );
434        assert_eq!(
435            Err(DecodeError::InvalidConversion(format!(
436                "{invalid_signed_lower} is out of bounds for conversion"
437            ))),
438            TryInto::<i8>::try_into(invalid_signed_number_lower)
439        );
440    }
441
442    #[test]
443    fn test_i8_conversions() {
444        let valid_signed_upper = i8::MAX;
445        let valid_unsigned_number = Number::Unsigned(valid_signed_upper as u64);
446        let zero_unsigned = Number::Unsigned(0u64);
447        let zero_signed = Number::Signed(0);
448        let valid_signed_number_upper = Number::Signed(valid_signed_upper as i64);
449        let valid_signed_lower = i8::MIN;
450        let valid_signed_number_lower = Number::Signed(valid_signed_lower as i64);
451        let invalid_float_number = Number::Float(4.14);
452        let invalid_unsigned = u8::MAX;
453        let invalid_unsigned_number = Number::Unsigned(invalid_unsigned as u64);
454        let invalid_signed_upper = i8::MAX as i64 + 1;
455        let invalid_signed_number_upper = Number::Signed(invalid_signed_upper);
456        let invalid_signed_lower = i8::MIN as i64 - 1;
457        let invalid_signed_number_lower = Number::Signed(invalid_signed_lower);
458
459        assert_eq!(
460            valid_signed_upper,
461            TryInto::<i8>::try_into(valid_unsigned_number).unwrap()
462        );
463        assert_eq!(
464            valid_signed_upper,
465            TryInto::<i8>::try_into(valid_signed_number_upper).unwrap()
466        );
467        assert_eq!(
468            valid_signed_lower,
469            TryInto::<i8>::try_into(valid_signed_number_lower).unwrap()
470        );
471        assert_eq!(0, TryInto::<i8>::try_into(zero_signed).unwrap());
472        assert_eq!(0, TryInto::<i8>::try_into(zero_unsigned).unwrap());
473        assert_eq!(
474            Err(DecodeError::InvalidConversion(
475                "Cannot convert float to int".to_owned()
476            )),
477            TryInto::<i8>::try_into(invalid_float_number)
478        );
479        assert_eq!(
480            Err(DecodeError::InvalidConversion(format!(
481                "{invalid_unsigned} is out of bounds for conversion"
482            ))),
483            TryInto::<i8>::try_into(invalid_unsigned_number)
484        );
485        assert_eq!(
486            Err(DecodeError::InvalidConversion(format!(
487                "{invalid_signed_upper} is out of bounds for conversion"
488            ))),
489            TryInto::<i8>::try_into(invalid_signed_number_upper)
490        );
491        assert_eq!(
492            Err(DecodeError::InvalidConversion(format!(
493                "{invalid_signed_lower} is out of bounds for conversion"
494            ))),
495            TryInto::<i8>::try_into(invalid_signed_number_lower)
496        );
497    }
498
499    #[test]
500    fn test_u8_conversions() {
501        let valid_signed_upper = u8::MAX;
502        let valid_unsigned_number = Number::Unsigned(valid_signed_upper as u64);
503        let zero_unsigned = Number::Unsigned(0u64);
504        let zero_signed = Number::Signed(0);
505        let valid_signed_number_upper = Number::Signed(valid_signed_upper as i64);
506        let valid_signed_lower = u8::MIN;
507        let valid_signed_number_lower = Number::Signed(valid_signed_lower as i64);
508        let invalid_float_number = Number::Float(4.14);
509        let invalid_unsigned = (u8::MAX as u64) + 1;
510        let invalid_unsigned_number = Number::Unsigned(invalid_unsigned);
511        let invalid_signed_upper = i32::MAX as i64 + 1;
512        let invalid_signed_number_upper = Number::Signed(invalid_signed_upper);
513        let invalid_signed_lower = i8::MIN as i64;
514        let invalid_signed_number_lower = Number::Signed(invalid_signed_lower);
515
516        assert_eq!(
517            valid_signed_upper,
518            TryInto::<u8>::try_into(valid_unsigned_number).unwrap()
519        );
520        assert_eq!(
521            valid_signed_upper,
522            TryInto::<u8>::try_into(valid_signed_number_upper).unwrap()
523        );
524        assert_eq!(
525            valid_signed_lower,
526            TryInto::<u8>::try_into(valid_signed_number_lower).unwrap()
527        );
528        assert_eq!(0, TryInto::<u8>::try_into(zero_signed).unwrap());
529        assert_eq!(0, TryInto::<u8>::try_into(zero_unsigned).unwrap());
530        assert_eq!(
531            Err(DecodeError::InvalidConversion(
532                "Cannot convert float to int".to_owned()
533            )),
534            TryInto::<u8>::try_into(invalid_float_number)
535        );
536        assert_eq!(
537            Err(DecodeError::InvalidConversion(format!(
538                "{invalid_unsigned} is out of bounds for conversion"
539            ))),
540            TryInto::<u8>::try_into(invalid_unsigned_number)
541        );
542        assert_eq!(
543            Err(DecodeError::InvalidConversion(format!(
544                "{invalid_signed_upper} is out of bounds for conversion"
545            ))),
546            TryInto::<u8>::try_into(invalid_signed_number_upper)
547        );
548        assert_eq!(
549            Err(DecodeError::InvalidConversion(format!(
550                "{invalid_signed_lower} is out of bounds for conversion"
551            ))),
552            TryInto::<u8>::try_into(invalid_signed_number_lower)
553        );
554    }
555
556    #[test]
557    fn test_u32_conversions() {
558        let valid_signed_upper = u32::MAX;
559        let valid_unsigned_number = Number::Unsigned(valid_signed_upper as u64);
560        let zero_unsigned = Number::Unsigned(0u64);
561        let zero_signed = Number::Signed(0);
562        let valid_signed_number_upper = Number::Signed(valid_signed_upper as i64);
563        let valid_signed_lower = u32::MIN;
564        let valid_signed_number_lower = Number::Signed(valid_signed_lower as i64);
565        let invalid_float_number = Number::Float(4.14);
566        let invalid_unsigned = (u32::MAX as u64) + 1;
567        let invalid_unsigned_number = Number::Unsigned(invalid_unsigned);
568        let invalid_signed_upper = i64::MAX;
569        let invalid_signed_number_upper = Number::Signed(invalid_signed_upper);
570        let invalid_signed_lower = i8::MIN as i64;
571        let invalid_signed_number_lower = Number::Signed(invalid_signed_lower);
572
573        assert_eq!(
574            valid_signed_upper,
575            TryInto::<u32>::try_into(valid_unsigned_number).unwrap()
576        );
577        assert_eq!(
578            valid_signed_upper,
579            TryInto::<u32>::try_into(valid_signed_number_upper).unwrap()
580        );
581        assert_eq!(
582            valid_signed_lower,
583            TryInto::<u32>::try_into(valid_signed_number_lower).unwrap()
584        );
585        assert_eq!(0, TryInto::<u32>::try_into(zero_signed).unwrap());
586        assert_eq!(0, TryInto::<u32>::try_into(zero_unsigned).unwrap());
587        assert_eq!(
588            Err(DecodeError::InvalidConversion(
589                "Cannot convert float to int".to_owned()
590            )),
591            TryInto::<u32>::try_into(invalid_float_number)
592        );
593        assert_eq!(
594            Err(DecodeError::InvalidConversion(format!(
595                "{invalid_unsigned} is out of bounds for conversion"
596            ))),
597            TryInto::<u32>::try_into(invalid_unsigned_number)
598        );
599        assert_eq!(
600            Err(DecodeError::InvalidConversion(format!(
601                "{invalid_signed_upper} is out of bounds for conversion"
602            ))),
603            TryInto::<u32>::try_into(invalid_signed_number_upper)
604        );
605        assert_eq!(
606            Err(DecodeError::InvalidConversion(format!(
607                "{invalid_signed_lower} is out of bounds for conversion"
608            ))),
609            TryInto::<u32>::try_into(invalid_signed_number_lower)
610        );
611    }
612
613    #[test]
614    fn test_u64_conversions() {
615        let valid_unsigned = u64::MAX;
616        let valid_unsigned_number = Number::Unsigned(valid_unsigned);
617        let zero_unsigned = Number::Unsigned(0u64);
618        let zero_signed = Number::Signed(0);
619        let valid_signed_upper = i64::MAX as u64;
620        let valid_signed_number_upper = Number::Signed(valid_signed_upper as i64);
621        let valid_signed_lower = u32::MIN as u64;
622        let valid_signed_number_lower = Number::Signed(valid_signed_lower as i64);
623        let invalid_float_number = Number::Float(4.14);
624        let invalid_signed_lower = i8::MIN as i64;
625        let invalid_signed_number_lower = Number::Signed(invalid_signed_lower);
626
627        assert_eq!(
628            valid_unsigned,
629            TryInto::<u64>::try_into(valid_unsigned_number).unwrap()
630        );
631        assert_eq!(
632            valid_signed_upper,
633            TryInto::<u64>::try_into(valid_signed_number_upper).unwrap()
634        );
635        assert_eq!(
636            valid_signed_lower,
637            TryInto::<u64>::try_into(valid_signed_number_lower).unwrap()
638        );
639        assert_eq!(0, TryInto::<u64>::try_into(zero_signed).unwrap());
640        assert_eq!(0, TryInto::<u64>::try_into(zero_unsigned).unwrap());
641        assert_eq!(
642            Err(DecodeError::InvalidConversion(
643                "Cannot convert float to int".to_owned()
644            )),
645            TryInto::<u64>::try_into(invalid_float_number)
646        );
647        assert_eq!(
648            Err(DecodeError::InvalidConversion(format!(
649                "{invalid_signed_lower} is out of bounds for conversion"
650            ))),
651            TryInto::<u64>::try_into(invalid_signed_number_lower)
652        );
653    }
654
655    #[test]
656    fn test_f64_conversions() {
657        let valid_signed_upper = i64::MAX;
658        let valid_unsigned_upper = u64::MAX;
659        let valid_signed_number_upper = Number::Signed(valid_signed_upper);
660        let valid_signed_lower = i64::MIN;
661        let valid_signed_number_lower = Number::Signed(valid_signed_lower);
662        let valid_unsigned_number = Number::Unsigned(valid_unsigned_upper);
663        let zero_unsigned = Number::Unsigned(0u64);
664        let zero_signed = Number::Signed(0);
665        let invalid_unsigned = u64::MAX;
666        let invalid_unsigned_number = Number::Unsigned(invalid_unsigned);
667
668        assert_eq!(
669            valid_unsigned_upper as f64,
670            TryInto::<f64>::try_into(valid_unsigned_number).unwrap()
671        );
672        assert_eq!(
673            valid_signed_upper as f64,
674            TryInto::<f64>::try_into(valid_signed_number_upper).unwrap()
675        );
676        assert_eq!(
677            valid_signed_lower as f64,
678            TryInto::<f64>::try_into(valid_signed_number_lower).unwrap()
679        );
680        assert_eq!(0f64, TryInto::<f64>::try_into(zero_signed).unwrap());
681        assert_eq!(0f64, TryInto::<f64>::try_into(zero_unsigned).unwrap());
682        assert_eq!(
683            Err(DecodeError::InvalidConversion(format!(
684                "{invalid_unsigned} is out of bounds for conversion"
685            ))),
686            TryInto::<i64>::try_into(invalid_unsigned_number)
687        );
688    }
689}