clvm_traits/
int_encoding.rs1pub fn encode_number(slice: &[u8], negative: bool) -> Vec<u8> {
2 let mut start = 0;
3 let pad_byte = if negative { 0xFF } else { 0x00 };
4
5 while start < slice.len() && slice[start] == pad_byte {
7 start += 1;
8 }
9
10 let needs_padding = if negative {
11 start == slice.len() || (slice[start] & 0x80) == 0
12 } else {
13 start < slice.len() && (slice[start] & 0x80) != 0
14 };
15
16 let mut result = Vec::with_capacity(if needs_padding {
17 slice.len() - start + 1
18 } else {
19 slice.len() - start
20 });
21
22 if needs_padding {
23 result.push(pad_byte);
24 }
25
26 result.extend_from_slice(&slice[start..]);
27 result
28}
29
30pub fn decode_number<const LEN: usize>(mut slice: &[u8], signed: bool) -> Option<[u8; LEN]> {
31 let negative = signed && !slice.is_empty() && slice[0] & 0x80 != 0;
32 let padding_byte = if negative { 0xFF } else { 0x00 };
33
34 if slice.len() > LEN && slice[0] == padding_byte {
35 slice = &slice[slice.len() - LEN..];
36 }
37
38 if slice.len() > LEN {
39 return None;
40 }
41
42 assert!(slice.len() <= LEN);
43
44 let mut result = [padding_byte; LEN];
45 let start = LEN - slice.len();
46
47 result[start..].copy_from_slice(slice);
48
49 Some(result)
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55
56 use clvmr::Allocator;
57
58 macro_rules! test_roundtrip {
59 ( $num:expr, $signed:expr ) => {
60 let mut allocator = Allocator::new();
61 let ptr = allocator.new_number($num.into()).unwrap();
62 let atom = allocator.atom(ptr);
63 let expected = atom.as_ref();
64
65 #[allow(unused_comparisons)]
66 let encoded = encode_number(&$num.to_be_bytes(), $num < 0);
67 assert_eq!(expected, encoded);
68
69 let expected = $num.to_be_bytes();
70 let decoded = decode_number(&encoded, $signed).unwrap();
71 assert_eq!(expected, decoded);
72 };
73 }
74
75 #[test]
76 fn test_signed_encoding() {
77 test_roundtrip!(0i32, true);
78 test_roundtrip!(1i32, true);
79 test_roundtrip!(2i32, true);
80 test_roundtrip!(3i32, true);
81 test_roundtrip!(255i32, true);
82 test_roundtrip!(4716i32, true);
83 test_roundtrip!(-255i32, true);
84 test_roundtrip!(-10i32, true);
85 test_roundtrip!(i32::MIN, true);
86 test_roundtrip!(i32::MAX, true);
87 }
88
89 #[test]
90 fn test_unsigned_encoding() {
91 test_roundtrip!(0u32, false);
92 test_roundtrip!(1u32, false);
93 test_roundtrip!(2u32, false);
94 test_roundtrip!(3u32, false);
95 test_roundtrip!(255u32, false);
96 test_roundtrip!(u32::MAX, false);
97 }
98}