Skip to main content

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