multiversx_sc_codec/impl_for_types/
impl_num_unsigned.rs

1use crate::{
2    dep_encode_num_mimic, DecodeError, DecodeErrorHandler, EncodeErrorHandler, NestedDecode,
3    NestedDecodeInput, NestedEncode, NestedEncodeOutput, TopDecode, TopDecodeInput, TopEncode,
4    TopEncodeOutput,
5};
6
7// No reversing needed for u8, because it is a single byte.
8impl NestedEncode for u8 {
9    #[inline]
10    fn dep_encode_or_handle_err<O, H>(&self, dest: &mut O, _h: H) -> Result<(), H::HandledErr>
11    where
12        O: NestedEncodeOutput,
13        H: EncodeErrorHandler,
14    {
15        dest.push_byte(*self);
16        Ok(())
17    }
18
19    fn if_u8<Output, If, Else, R>(input: Output, if_branch: If, _else_branch: Else) -> R
20    where
21        If: FnOnce(Output) -> R,
22        Else: FnOnce(Output) -> R,
23    {
24        if_branch(input)
25    }
26}
27
28dep_encode_num_mimic! {usize, u32}
29
30// The main unsigned types need to be reversed before serializing.
31macro_rules! dep_encode_num_unsigned {
32    ($num_type:ty, $size_in_bits:expr) => {
33        impl NestedEncode for $num_type {
34            #[inline]
35            fn dep_encode_or_handle_err<O, H>(
36                &self,
37                dest: &mut O,
38                _h: H,
39            ) -> Result<(), H::HandledErr>
40            where
41                O: NestedEncodeOutput,
42                H: EncodeErrorHandler,
43            {
44                dest.write(&self.to_be_bytes()[..]);
45                Ok(())
46            }
47        }
48    };
49}
50
51dep_encode_num_unsigned! {u128, 128}
52dep_encode_num_unsigned! {u64, 64}
53dep_encode_num_unsigned! {u32, 32}
54dep_encode_num_unsigned! {u16, 16}
55
56macro_rules! top_encode_num_unsigned {
57    ($num_type:ty, $size_in_bits:expr) => {
58        impl TopEncode for $num_type {
59            #[inline]
60            fn top_encode_or_handle_err<O, H>(&self, output: O, _h: H) -> Result<(), H::HandledErr>
61            where
62                O: TopEncodeOutput,
63                H: EncodeErrorHandler,
64            {
65                output.set_u64(*self as u64);
66                Ok(())
67            }
68        }
69    };
70}
71
72top_encode_num_unsigned! {u128, 128}
73top_encode_num_unsigned! {u64, 64}
74top_encode_num_unsigned! {u32, 32}
75top_encode_num_unsigned! {usize, 32}
76top_encode_num_unsigned! {u16, 16}
77top_encode_num_unsigned! {u8, 8}
78
79impl NestedDecode for u8 {
80    fn dep_decode_or_handle_err<I, H>(input: &mut I, h: H) -> Result<Self, H::HandledErr>
81    where
82        I: NestedDecodeInput,
83        H: DecodeErrorHandler,
84    {
85        input.read_byte(h)
86    }
87
88    fn if_u8<Input, If, Else, R>(input: Input, if_branch: If, _else_branch: Else) -> R
89    where
90        If: FnOnce(Input) -> R,
91        Else: FnOnce(Input) -> R,
92    {
93        if_branch(input)
94    }
95}
96
97macro_rules! dep_decode_num_unsigned {
98    ($ty:ty, $num_bytes:expr) => {
99        impl NestedDecode for $ty {
100            fn dep_decode_or_handle_err<I, H>(input: &mut I, h: H) -> Result<Self, H::HandledErr>
101            where
102                I: NestedDecodeInput,
103                H: DecodeErrorHandler,
104            {
105                let mut bytes = [0u8; $num_bytes];
106                input.read_into(&mut bytes[..], h)?;
107                let num = <$ty>::from_be_bytes(bytes);
108                Ok(num)
109            }
110        }
111    };
112}
113
114dep_decode_num_unsigned!(u16, 2);
115dep_decode_num_unsigned!(u32, 4);
116dep_decode_num_unsigned!(u64, 8);
117dep_decode_num_unsigned!(u128, 16);
118
119impl NestedDecode for usize {
120    fn dep_decode_or_handle_err<I, H>(input: &mut I, h: H) -> Result<Self, H::HandledErr>
121    where
122        I: NestedDecodeInput,
123        H: DecodeErrorHandler,
124    {
125        u32::dep_decode_or_handle_err(input, h).map(|num| num as usize)
126    }
127}
128
129macro_rules! top_decode_num_unsigned {
130    ($ty:ty, $bounds_ty:ty) => {
131        impl TopDecode for $ty {
132            fn top_decode_or_handle_err<I, H>(input: I, h: H) -> Result<Self, H::HandledErr>
133            where
134                I: TopDecodeInput,
135                H: DecodeErrorHandler,
136            {
137                let arg_u64 = input.into_u64(h)?;
138                let max = <$bounds_ty>::MAX as u64;
139                if arg_u64 > max {
140                    Err(h.handle_error(DecodeError::INPUT_TOO_LONG))
141                } else {
142                    Ok(arg_u64 as $ty)
143                }
144            }
145        }
146    };
147}
148
149top_decode_num_unsigned!(u8, u8);
150top_decode_num_unsigned!(u16, u16);
151top_decode_num_unsigned!(u32, u32);
152top_decode_num_unsigned!(usize, u32); // even if usize can be 64 bits on some platforms, we always deserialize as max 32 bits
153top_decode_num_unsigned!(u64, u64);
154top_decode_num_unsigned!(u128, u128);
155
156#[cfg(test)]
157pub mod tests {
158    use crate::test_util::{check_dep_encode_decode, check_top_encode_decode};
159
160    #[test]
161    fn test_top() {
162        // unsigned zero
163        check_top_encode_decode(0u8, &[]);
164        check_top_encode_decode(0u16, &[]);
165        check_top_encode_decode(0u32, &[]);
166        check_top_encode_decode(0u64, &[]);
167        check_top_encode_decode(0usize, &[]);
168        check_top_encode_decode(0u128, &[]);
169        // unsigned positive
170        check_top_encode_decode(5u8, &[5]);
171        check_top_encode_decode(5u16, &[5]);
172        check_top_encode_decode(5u32, &[5]);
173        check_top_encode_decode(5u64, &[5]);
174        check_top_encode_decode(5usize, &[5]);
175        check_top_encode_decode(5u128, &[5]);
176    }
177
178    #[test]
179    fn test_dep() {
180        // unsigned zero
181        check_dep_encode_decode(0u8, &[0]);
182        check_dep_encode_decode(0u16, &[0, 0]);
183        check_dep_encode_decode(0u32, &[0, 0, 0, 0]);
184        check_dep_encode_decode(0usize, &[0, 0, 0, 0]);
185        check_dep_encode_decode(0u64, &[0, 0, 0, 0, 0, 0, 0, 0]);
186        check_dep_encode_decode(0u128, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
187        // unsigned positive
188        check_dep_encode_decode(5u8, &[5]);
189        check_dep_encode_decode(5u16, &[0, 5]);
190        check_dep_encode_decode(5u32, &[0, 0, 0, 5]);
191        check_dep_encode_decode(5usize, &[0, 0, 0, 5]);
192        check_dep_encode_decode(5u64, &[0, 0, 0, 0, 0, 0, 0, 5]);
193        check_dep_encode_decode(5u128, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5]);
194    }
195}