]>
Commit | Line | Data |
---|---|---|
1 | use crate::opaque::MemDecoder; | |
2 | use crate::serialize::Decoder; | |
3 | ||
4 | /// Returns the length of the longest LEB128 encoding for `T`, assuming `T` is an integer type | |
5 | pub const fn max_leb128_len<T>() -> usize { | |
6 | // The longest LEB128 encoding for an integer uses 7 bits per byte. | |
7 | (std::mem::size_of::<T>() * 8 + 6) / 7 | |
8 | } | |
9 | ||
10 | /// Returns the length of the longest LEB128 encoding of all supported integer types. | |
11 | pub const fn largest_max_leb128_len() -> usize { | |
12 | max_leb128_len::<u128>() | |
13 | } | |
14 | ||
15 | macro_rules! impl_write_unsigned_leb128 { | |
16 | ($fn_name:ident, $int_ty:ty) => { | |
17 | #[inline] | |
18 | pub fn $fn_name( | |
19 | out: &mut [::std::mem::MaybeUninit<u8>; max_leb128_len::<$int_ty>()], | |
20 | mut value: $int_ty, | |
21 | ) -> &[u8] { | |
22 | let mut i = 0; | |
23 | ||
24 | loop { | |
25 | if value < 0x80 { | |
26 | unsafe { | |
27 | *out.get_unchecked_mut(i).as_mut_ptr() = value as u8; | |
28 | } | |
29 | ||
30 | i += 1; | |
31 | break; | |
32 | } else { | |
33 | unsafe { | |
34 | *out.get_unchecked_mut(i).as_mut_ptr() = ((value & 0x7f) | 0x80) as u8; | |
35 | } | |
36 | ||
37 | value >>= 7; | |
38 | i += 1; | |
39 | } | |
40 | } | |
41 | ||
42 | unsafe { ::std::mem::MaybeUninit::slice_assume_init_ref(&out.get_unchecked(..i)) } | |
43 | } | |
44 | }; | |
45 | } | |
46 | ||
47 | impl_write_unsigned_leb128!(write_u16_leb128, u16); | |
48 | impl_write_unsigned_leb128!(write_u32_leb128, u32); | |
49 | impl_write_unsigned_leb128!(write_u64_leb128, u64); | |
50 | impl_write_unsigned_leb128!(write_u128_leb128, u128); | |
51 | impl_write_unsigned_leb128!(write_usize_leb128, usize); | |
52 | ||
53 | macro_rules! impl_read_unsigned_leb128 { | |
54 | ($fn_name:ident, $int_ty:ty) => { | |
55 | #[inline] | |
56 | pub fn $fn_name(decoder: &mut MemDecoder<'_>) -> $int_ty { | |
57 | // The first iteration of this loop is unpeeled. This is a | |
58 | // performance win because this code is hot and integer values less | |
59 | // than 128 are very common, typically occurring 50-80% or more of | |
60 | // the time, even for u64 and u128. | |
61 | let byte = decoder.read_u8(); | |
62 | if (byte & 0x80) == 0 { | |
63 | return byte as $int_ty; | |
64 | } | |
65 | let mut result = (byte & 0x7F) as $int_ty; | |
66 | let mut shift = 7; | |
67 | loop { | |
68 | let byte = decoder.read_u8(); | |
69 | if (byte & 0x80) == 0 { | |
70 | result |= (byte as $int_ty) << shift; | |
71 | return result; | |
72 | } else { | |
73 | result |= ((byte & 0x7F) as $int_ty) << shift; | |
74 | } | |
75 | shift += 7; | |
76 | } | |
77 | } | |
78 | }; | |
79 | } | |
80 | ||
81 | impl_read_unsigned_leb128!(read_u16_leb128, u16); | |
82 | impl_read_unsigned_leb128!(read_u32_leb128, u32); | |
83 | impl_read_unsigned_leb128!(read_u64_leb128, u64); | |
84 | impl_read_unsigned_leb128!(read_u128_leb128, u128); | |
85 | impl_read_unsigned_leb128!(read_usize_leb128, usize); | |
86 | ||
87 | macro_rules! impl_write_signed_leb128 { | |
88 | ($fn_name:ident, $int_ty:ty) => { | |
89 | #[inline] | |
90 | pub fn $fn_name( | |
91 | out: &mut [::std::mem::MaybeUninit<u8>; max_leb128_len::<$int_ty>()], | |
92 | mut value: $int_ty, | |
93 | ) -> &[u8] { | |
94 | let mut i = 0; | |
95 | ||
96 | loop { | |
97 | let mut byte = (value as u8) & 0x7f; | |
98 | value >>= 7; | |
99 | let more = !(((value == 0) && ((byte & 0x40) == 0)) | |
100 | || ((value == -1) && ((byte & 0x40) != 0))); | |
101 | ||
102 | if more { | |
103 | byte |= 0x80; // Mark this byte to show that more bytes will follow. | |
104 | } | |
105 | ||
106 | unsafe { | |
107 | *out.get_unchecked_mut(i).as_mut_ptr() = byte; | |
108 | } | |
109 | ||
110 | i += 1; | |
111 | ||
112 | if !more { | |
113 | break; | |
114 | } | |
115 | } | |
116 | ||
117 | unsafe { ::std::mem::MaybeUninit::slice_assume_init_ref(&out.get_unchecked(..i)) } | |
118 | } | |
119 | }; | |
120 | } | |
121 | ||
122 | impl_write_signed_leb128!(write_i16_leb128, i16); | |
123 | impl_write_signed_leb128!(write_i32_leb128, i32); | |
124 | impl_write_signed_leb128!(write_i64_leb128, i64); | |
125 | impl_write_signed_leb128!(write_i128_leb128, i128); | |
126 | impl_write_signed_leb128!(write_isize_leb128, isize); | |
127 | ||
128 | macro_rules! impl_read_signed_leb128 { | |
129 | ($fn_name:ident, $int_ty:ty) => { | |
130 | #[inline] | |
131 | pub fn $fn_name(decoder: &mut MemDecoder<'_>) -> $int_ty { | |
132 | let mut result = 0; | |
133 | let mut shift = 0; | |
134 | let mut byte; | |
135 | ||
136 | loop { | |
137 | byte = decoder.read_u8(); | |
138 | result |= <$int_ty>::from(byte & 0x7F) << shift; | |
139 | shift += 7; | |
140 | ||
141 | if (byte & 0x80) == 0 { | |
142 | break; | |
143 | } | |
144 | } | |
145 | ||
146 | if (shift < <$int_ty>::BITS) && ((byte & 0x40) != 0) { | |
147 | // sign extend | |
148 | result |= (!0 << shift); | |
149 | } | |
150 | ||
151 | result | |
152 | } | |
153 | }; | |
154 | } | |
155 | ||
156 | impl_read_signed_leb128!(read_i16_leb128, i16); | |
157 | impl_read_signed_leb128!(read_i32_leb128, i32); | |
158 | impl_read_signed_leb128!(read_i64_leb128, i64); | |
159 | impl_read_signed_leb128!(read_i128_leb128, i128); | |
160 | impl_read_signed_leb128!(read_isize_leb128, isize); |