1use snarkvm_utilities::{
17 FromBytes,
18 error,
19 io::{Read, Result as IoResult},
20};
21
22pub fn variable_length_integer(value: &u64) -> Vec<u8> {
25 match value {
26 0..=252 => vec![*value as u8],
28 253..=65535 => [vec![0xfd], (*value as u16).to_le_bytes().to_vec()].concat(),
30 65536..=4_294_967_295 => [vec![0xfe], (*value as u32).to_le_bytes().to_vec()].concat(),
32 _ => [vec![0xff], value.to_le_bytes().to_vec()].concat(),
34 }
35}
36
37pub fn read_variable_length_integer<R: Read>(mut reader: R) -> IoResult<u64> {
40 let flag = u8::read_le(&mut reader)?;
41
42 match flag {
43 0..=252 => Ok(flag as u64),
44 0xfd => match u16::read_le(&mut reader)? {
45 s if s < 253 => Err(error("Invalid variable size integer")),
46 s => Ok(s as u64),
47 },
48 0xfe => match u32::read_le(&mut reader)? {
49 s if s < 65536 => Err(error("Invalid variable size integer")),
50 s => Ok(s as u64),
51 },
52 _ => match u64::read_le(&mut reader)? {
53 s if s < 4_294_967_296 => Err(error("Invalid variable size integer")),
54 s => Ok(s),
55 },
56 }
57}
58
59#[cfg(test)]
60mod test {
61 use super::*;
62
63 const LENGTH_VALUES: [(u64, [u8; 9]); 14] = [
64 (20, [0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
65 (32, [0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
66 (200, [0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
67 (252, [0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
68 (253, [0xfd, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
69 (40000, [0xfd, 0x40, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
70 (65535, [0xfd, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
71 (65536, [0xfe, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00]),
72 (2000000000, [0xfe, 0x00, 0x94, 0x35, 0x77, 0x00, 0x00, 0x00, 0x00]),
73 (2000000000, [0xfe, 0x00, 0x94, 0x35, 0x77, 0x00, 0x00, 0x00, 0x00]),
74 (4294967295, [0xfe, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00]),
75 (4294967296, [0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00]),
76 (500000000000000000, [0xff, 0x00, 0x00, 0xb2, 0xd3, 0x59, 0x5b, 0xf0, 0x06]),
77 (18446744073709551615, [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]),
78 ];
79
80 #[test]
81 fn test_variable_length_integer() {
82 LENGTH_VALUES.iter().for_each(|(size, expected_output)| {
83 let variable_length_int = variable_length_integer(size);
84 let pruned_expected_output = &expected_output[..variable_length_int.len()];
85 assert_eq!(pruned_expected_output, &variable_length_int[..]);
86 });
87 }
88
89 #[test]
90 fn test_read_variable_length_integer() {
91 LENGTH_VALUES.iter().for_each(|(expected_size, _expected_output)| {
92 let variable_length_int = variable_length_integer(expected_size);
93 let size = read_variable_length_integer(&variable_length_int[..]).unwrap();
94 assert_eq!(*expected_size, size);
95 });
96 }
97}