]>
Commit | Line | Data |
---|---|---|
49aad941 FG |
1 | use crate::opaque::MemDecoder; |
2 | use crate::serialize::Decoder; | |
3 | ||
487cf647 FG |
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 | |
5869c6ff XL |
8 | } |
9 | ||
487cf647 FG |
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>() | |
5869c6ff XL |
13 | } |
14 | ||
2c00a5a8 | 15 | macro_rules! impl_write_unsigned_leb128 { |
5869c6ff | 16 | ($fn_name:ident, $int_ty:ty) => { |
2c00a5a8 | 17 | #[inline] |
5869c6ff | 18 | pub fn $fn_name( |
487cf647 | 19 | out: &mut [::std::mem::MaybeUninit<u8>; max_leb128_len::<$int_ty>()], |
5869c6ff XL |
20 | mut value: $int_ty, |
21 | ) -> &[u8] { | |
22 | let mut i = 0; | |
23 | ||
74b04a01 XL |
24 | loop { |
25 | if value < 0x80 { | |
5869c6ff XL |
26 | unsafe { |
27 | *out.get_unchecked_mut(i).as_mut_ptr() = value as u8; | |
28 | } | |
29 | ||
30 | i += 1; | |
2c00a5a8 | 31 | break; |
74b04a01 | 32 | } else { |
5869c6ff XL |
33 | unsafe { |
34 | *out.get_unchecked_mut(i).as_mut_ptr() = ((value & 0x7f) | 0x80) as u8; | |
35 | } | |
36 | ||
74b04a01 | 37 | value >>= 7; |
5869c6ff | 38 | i += 1; |
2c00a5a8 XL |
39 | } |
40 | } | |
5869c6ff XL |
41 | |
42 | unsafe { ::std::mem::MaybeUninit::slice_assume_init_ref(&out.get_unchecked(..i)) } | |
9cc50fc6 | 43 | } |
dfeec247 | 44 | }; |
476ff2be SL |
45 | } |
46 | ||
2c00a5a8 XL |
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 | ||
2c00a5a8 | 53 | macro_rules! impl_read_unsigned_leb128 { |
5869c6ff | 54 | ($fn_name:ident, $int_ty:ty) => { |
2c00a5a8 | 55 | #[inline] |
49aad941 | 56 | pub fn $fn_name(decoder: &mut MemDecoder<'_>) -> $int_ty { |
5099ac24 FG |
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. | |
49aad941 | 61 | let byte = decoder.read_u8(); |
5099ac24 FG |
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; | |
74b04a01 | 67 | loop { |
49aad941 | 68 | let byte = decoder.read_u8(); |
2c00a5a8 | 69 | if (byte & 0x80) == 0 { |
74b04a01 | 70 | result |= (byte as $int_ty) << shift; |
5099ac24 | 71 | return result; |
74b04a01 XL |
72 | } else { |
73 | result |= ((byte & 0x7F) as $int_ty) << shift; | |
2c00a5a8 XL |
74 | } |
75 | shift += 7; | |
76 | } | |
2c00a5a8 | 77 | } |
dfeec247 | 78 | }; |
9cc50fc6 SL |
79 | } |
80 | ||
2c00a5a8 XL |
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 | ||
5869c6ff XL |
87 | macro_rules! impl_write_signed_leb128 { |
88 | ($fn_name:ident, $int_ty:ty) => { | |
89 | #[inline] | |
90 | pub fn $fn_name( | |
487cf647 | 91 | out: &mut [::std::mem::MaybeUninit<u8>; max_leb128_len::<$int_ty>()], |
5869c6ff XL |
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))); | |
9cc50fc6 | 101 | |
5869c6ff XL |
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 | } | |
9cc50fc6 | 116 | |
5869c6ff | 117 | unsafe { ::std::mem::MaybeUninit::slice_assume_init_ref(&out.get_unchecked(..i)) } |
9cc50fc6 | 118 | } |
5869c6ff | 119 | }; |
476ff2be SL |
120 | } |
121 | ||
5869c6ff XL |
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); | |
9cc50fc6 | 127 | |
5869c6ff XL |
128 | macro_rules! impl_read_signed_leb128 { |
129 | ($fn_name:ident, $int_ty:ty) => { | |
130 | #[inline] | |
49aad941 | 131 | pub fn $fn_name(decoder: &mut MemDecoder<'_>) -> $int_ty { |
5869c6ff XL |
132 | let mut result = 0; |
133 | let mut shift = 0; | |
5869c6ff | 134 | let mut byte; |
9cc50fc6 | 135 | |
5869c6ff | 136 | loop { |
49aad941 | 137 | byte = decoder.read_u8(); |
5869c6ff XL |
138 | result |= <$int_ty>::from(byte & 0x7F) << shift; |
139 | shift += 7; | |
9cc50fc6 | 140 | |
5869c6ff XL |
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 | ||
5099ac24 | 151 | result |
5869c6ff XL |
152 | } |
153 | }; | |
9cc50fc6 | 154 | } |
5869c6ff XL |
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); |