1 use std::mem::MaybeUninit;
2
3 use crate::varint::MAX_VARINT_ENCODED_LEN;
4
5 /// Encode u64 as varint.
6 /// Panics if buffer length is less than 10.
7 #[inline]
encode_varint64(mut value: u64, buf: &mut [MaybeUninit<u8>]) -> usize8 pub(crate) fn encode_varint64(mut value: u64, buf: &mut [MaybeUninit<u8>]) -> usize {
9 assert!(buf.len() >= MAX_VARINT_ENCODED_LEN);
10
11 fn iter(value: &mut u64, byte: &mut MaybeUninit<u8>) -> bool {
12 if (*value & !0x7F) > 0 {
13 byte.write(((*value & 0x7F) | 0x80) as u8);
14 *value >>= 7;
15 true
16 } else {
17 byte.write(*value as u8);
18 false
19 }
20 }
21
22 // Explicitly unroll loop to avoid either
23 // unsafe code or bound checking when writing to `buf`
24
25 if !iter(&mut value, &mut buf[0]) {
26 return 1;
27 };
28 if !iter(&mut value, &mut buf[1]) {
29 return 2;
30 };
31 if !iter(&mut value, &mut buf[2]) {
32 return 3;
33 };
34 if !iter(&mut value, &mut buf[3]) {
35 return 4;
36 };
37 if !iter(&mut value, &mut buf[4]) {
38 return 5;
39 };
40 if !iter(&mut value, &mut buf[5]) {
41 return 6;
42 };
43 if !iter(&mut value, &mut buf[6]) {
44 return 7;
45 };
46 if !iter(&mut value, &mut buf[7]) {
47 return 8;
48 };
49 if !iter(&mut value, &mut buf[8]) {
50 return 9;
51 };
52 buf[9].write(value as u8);
53 10
54 }
55
56 /// Encode u32 value as varint.
57 /// Panics if buffer length is less than 5.
58 #[inline]
encode_varint32(mut value: u32, buf: &mut [MaybeUninit<u8>]) -> usize59 pub(crate) fn encode_varint32(mut value: u32, buf: &mut [MaybeUninit<u8>]) -> usize {
60 assert!(buf.len() >= 5);
61
62 fn iter(value: &mut u32, byte: &mut MaybeUninit<u8>) -> bool {
63 if (*value & !0x7F) > 0 {
64 byte.write(((*value & 0x7F) | 0x80) as u8);
65 *value >>= 7;
66 true
67 } else {
68 byte.write(*value as u8);
69 false
70 }
71 }
72
73 // Explicitly unroll loop to avoid either
74 // unsafe code or bound checking when writing to `buf`
75
76 if !iter(&mut value, &mut buf[0]) {
77 return 1;
78 };
79 if !iter(&mut value, &mut buf[1]) {
80 return 2;
81 };
82 if !iter(&mut value, &mut buf[2]) {
83 return 3;
84 };
85 if !iter(&mut value, &mut buf[3]) {
86 return 4;
87 };
88 buf[4].write(value as u8);
89 5
90 }
91
92 /// Encoded size of u64 value.
93 #[inline]
encoded_varint64_len(value: u64) -> usize94 pub(crate) fn encoded_varint64_len(value: u64) -> usize {
95 if value == 0 {
96 1
97 } else {
98 let significant_bits = 64 - value.leading_zeros();
99 (significant_bits + 6) as usize / 7
100 }
101 }
102
103 #[cfg(test)]
104 mod test {
105 use std::mem::MaybeUninit;
106
107 use crate::varint::encode::encode_varint64;
108 use crate::varint::encode::encoded_varint64_len;
109
110 #[test]
test_encoded_varint64_len()111 fn test_encoded_varint64_len() {
112 fn test(n: u64) {
113 let mut buf = [MaybeUninit::uninit(); 10];
114 let expected = encode_varint64(n, &mut buf);
115 assert_eq!(expected, encoded_varint64_len(n), "n={}", n);
116 }
117
118 for n in 0..1000 {
119 test(n);
120 }
121
122 for p in 0.. {
123 match 2u64.checked_pow(p) {
124 Some(n) => test(n),
125 None => break,
126 }
127 }
128
129 for p in 0.. {
130 match 3u64.checked_pow(p) {
131 Some(n) => test(n),
132 None => break,
133 }
134 }
135
136 test(u64::MAX);
137 test(u64::MAX - 1);
138 test((i64::MAX as u64) + 1);
139 test(i64::MAX as u64);
140 test((i64::MAX as u64) - 1);
141 test((u32::MAX as u64) + 1);
142 test(u32::MAX as u64);
143 test((u32::MAX as u64) - 1);
144 test((i32::MAX as u64) + 1);
145 test(i32::MAX as u64);
146 test((i32::MAX as u64) - 1);
147 }
148 }
149