elrond_codec/impl_for_types/
impl_num_signed.rs

1use crate::{
2    dep_encode_num_mimic, num_conv::universal_decode_number, DecodeError, DecodeErrorHandler,
3    EncodeErrorHandler, NestedDecode, NestedDecodeInput, NestedEncode, NestedEncodeOutput,
4    TopDecode, TopDecodeInput, TopEncode, TopEncodeOutput,
5};
6
7macro_rules! top_encode_num_signed {
8    ($num_type:ty, $size_in_bits:expr) => {
9        impl TopEncode for $num_type {
10            #[inline]
11            fn top_encode_or_handle_err<O, H>(&self, output: O, _h: H) -> Result<(), H::HandledErr>
12            where
13                O: TopEncodeOutput,
14                H: EncodeErrorHandler,
15            {
16                output.set_i64(*self as i64);
17                Ok(())
18            }
19        }
20    };
21}
22
23top_encode_num_signed! {i64, 64}
24top_encode_num_signed! {i32, 32}
25top_encode_num_signed! {isize, 32}
26top_encode_num_signed! {i16, 16}
27top_encode_num_signed! {i8, 8}
28
29dep_encode_num_mimic! {i64, u64}
30dep_encode_num_mimic! {i32, u32}
31dep_encode_num_mimic! {isize, u32}
32dep_encode_num_mimic! {i16, u16}
33dep_encode_num_mimic! {i8, u8}
34
35macro_rules! dep_decode_num_signed {
36    ($ty:ty, $num_bytes:expr) => {
37        impl NestedDecode for $ty {
38            fn dep_decode_or_handle_err<I, H>(input: &mut I, h: H) -> Result<Self, H::HandledErr>
39            where
40                I: NestedDecodeInput,
41                H: DecodeErrorHandler,
42            {
43                let mut bytes = [0u8; $num_bytes];
44                input.read_into(&mut bytes[..], h)?;
45                let num = universal_decode_number(&bytes[..], true) as $ty;
46                Ok(num)
47            }
48        }
49    };
50}
51
52dep_decode_num_signed!(i8, 1);
53dep_decode_num_signed!(i16, 2);
54dep_decode_num_signed!(i32, 4);
55dep_decode_num_signed!(isize, 4);
56dep_decode_num_signed!(i64, 8);
57
58macro_rules! top_decode_num_signed {
59    ($ty:ty, $bounds_ty:ty) => {
60        impl TopDecode for $ty {
61            fn top_decode_or_handle_err<I, H>(input: I, h: H) -> Result<Self, H::HandledErr>
62            where
63                I: TopDecodeInput,
64                H: DecodeErrorHandler,
65            {
66                let arg_i64 = input.into_i64(h)?;
67                let min = <$bounds_ty>::MIN as i64;
68                let max = <$bounds_ty>::MAX as i64;
69                if arg_i64 < min || arg_i64 > max {
70                    Err(h.handle_error(DecodeError::INPUT_OUT_OF_RANGE))
71                } else {
72                    Ok(arg_i64 as $ty)
73                }
74            }
75        }
76    };
77}
78
79top_decode_num_signed!(i8, i8);
80top_decode_num_signed!(i16, i16);
81top_decode_num_signed!(i32, i32);
82top_decode_num_signed!(isize, i32); // even if isize can be 64 bits on some platforms, we always deserialize as max 32 bits
83top_decode_num_signed!(i64, i64);
84
85#[cfg(test)]
86pub mod tests {
87    use crate::test_util::{check_dep_encode_decode, check_top_encode_decode};
88
89    #[test]
90    fn test_top() {
91        // signed zero
92        check_top_encode_decode(0i8, &[]);
93        check_top_encode_decode(0i16, &[]);
94        check_top_encode_decode(0i32, &[]);
95        check_top_encode_decode(0i64, &[]);
96        check_top_encode_decode(0isize, &[]);
97        // signed positive
98        check_top_encode_decode(5i8, &[5]);
99        check_top_encode_decode(5i16, &[5]);
100        check_top_encode_decode(5i32, &[5]);
101        check_top_encode_decode(5i64, &[5]);
102        check_top_encode_decode(5isize, &[5]);
103        // signed negative
104        check_top_encode_decode(-5i8, &[251]);
105        check_top_encode_decode(-5i16, &[251]);
106        check_top_encode_decode(-5i32, &[251]);
107        check_top_encode_decode(-5i64, &[251]);
108        check_top_encode_decode(-5isize, &[251]);
109    }
110
111    #[test]
112    fn test_dep() {
113        // signed zero
114        check_dep_encode_decode(0i8, &[0]);
115        check_dep_encode_decode(0i16, &[0, 0]);
116        check_dep_encode_decode(0i32, &[0, 0, 0, 0]);
117        check_dep_encode_decode(0isize, &[0, 0, 0, 0]);
118        check_dep_encode_decode(0i64, &[0, 0, 0, 0, 0, 0, 0, 0]);
119        // signed positive
120        check_dep_encode_decode(5i8, &[5]);
121        check_dep_encode_decode(5i16, &[0, 5]);
122        check_dep_encode_decode(5i32, &[0, 0, 0, 5]);
123        check_dep_encode_decode(5isize, &[0, 0, 0, 5]);
124        check_dep_encode_decode(5i64, &[0, 0, 0, 0, 0, 0, 0, 5]);
125        // signed negative
126        check_dep_encode_decode(-5i8, &[251]);
127        check_dep_encode_decode(-5i16, &[255, 251]);
128        check_dep_encode_decode(-5i32, &[255, 255, 255, 251]);
129        check_dep_encode_decode(-5isize, &[255, 255, 255, 251]);
130        check_dep_encode_decode(-5i64, &[255, 255, 255, 255, 255, 255, 255, 251]);
131    }
132}