rust_chain/
varint.rs

1use crate::serializer::{
2    Packer,
3    Encoder,
4};
5
6use crate::print::{
7    Printable,
8    printi,
9};
10
11use crate::vmapi::eosio::{
12    check,
13};
14
15/// A variable-length unsigned integer structure.
16#[cfg_attr(feature = "std", derive(crate::eosio_scale_info::TypeInfo))]
17#[derive(Copy, Clone, Eq, PartialEq, Default, Debug)]
18pub struct VarUint32 {
19    /// The unsigned integer value.
20    pub n: u32,
21}
22
23impl VarUint32 {
24    /// Create a new VarUint32 instance with the given value.
25    pub fn new(n: u32) -> Self {
26        Self { n: n }
27    }
28
29    /// Get the value of the VarUint32 instance.
30    pub fn value(&self) -> u32 {
31        return self.n;
32    }
33}
34
35impl Packer for VarUint32 {
36    /// Calculate the size of the serialized VarUint32.
37    fn size(&self) -> usize {
38        let mut size: usize = 0;
39        let mut val = self.n;
40        if val == 0 {
41            return 1;
42        }
43
44        while val > 0 {
45            val >>= 7;
46            size += 1;
47        }
48        return size;
49    }
50
51    /// Serialize the VarUint32 value.
52    fn pack(&self, enc: &mut Encoder) -> usize {
53        let mut val = self.n;
54        if val == 0 {
55            return 0u8.pack(enc);
56        }
57
58        let mut size = 0usize;
59
60        while val > 0 {
61            let mut b: u32 = val & 0x7f;
62            val >>= 7;
63            if val > 0 {
64                b |= 1 << 7;
65            }
66            let data = enc.alloc(1);
67            data[0] = b as u8;
68            size += 1;
69        }
70        size
71    }
72
73    /// Deserialize the VarUint32 value from the given byte slice.
74    fn unpack(&mut self, data: &[u8]) -> usize {
75        let mut by: u32 = 0;
76        let mut value: u32 = 0;
77        let mut length: usize = 0;
78        for b in data {
79            value |= (*b as u32 & 0x7f) << by;
80            by += 7;
81            length += 1;
82            if (*b & 0x80) == 0 {
83                break;
84            }
85            check(by < 32, "malformed varuint32 data");
86        }
87        self.n = value;
88        return length;
89    }
90}
91
92impl Printable for VarUint32 {
93    /// Print the VarUint32 value.
94    fn print(&self) {
95        printi(self.n as i64);
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102
103    #[test]
104    fn test_varuint32_pack_unpack() {
105        let values = vec![
106            0,
107            1,
108            127,
109            128,
110            255,
111            256,
112            16383,
113            16384,
114            2097151,
115            2097152,
116            268435455,
117            268435456,
118            u32::MAX,
119        ];
120
121        for value in values {
122            let varuint32 = VarUint32::new(value);
123            let mut encoder = Encoder::new(varuint32.size());
124            varuint32.pack(&mut encoder);
125
126            let mut unpacked_varuint32 = VarUint32::default();
127            let _ = unpacked_varuint32.unpack(encoder.get_bytes());
128
129            assert_eq!(varuint32, unpacked_varuint32);
130        }
131    }
132}