/rust/registry/src/index.crates.io-1949cf8c6b5b557f/leb128fmt-0.1.0/src/lib.rs
Line | Count | Source |
1 | | //! Leb128fmt is a library to decode and encode [LEB128][leb128] formatted numbers. |
2 | | //! LEB128 is a variable length integer compression format. |
3 | | //! |
4 | | //! The library does not allocate memory and can be used in `no_std` and |
5 | | //! `no_std::no_alloc` environments. |
6 | | //! |
7 | | //! Various functions are provided which encode and decode signed and unsigned |
8 | | //! integers with the number of bits in the function name. There are generic |
9 | | //! functions provided to read and write slices of encoded values as well. |
10 | | //! |
11 | | //! There are encoding functions with the word `fixed` in the name which will |
12 | | //! write out a value using the maximum number of bytes for a given bit size. |
13 | | //! For instance, using [`encode_fixed_u32`] will always use 5 bytes to |
14 | | //! write out the value. While always using the maximum number of bytes removes |
15 | | //! the benefit of compression, in some scenarios, it is beneficial to have a |
16 | | //! fixed encoding size. |
17 | | //! |
18 | | //! Finally, there are macros provided which you can use to build your own |
19 | | //! encoding and decoding functions for unusual variants like signed 33 bit |
20 | | //! values. |
21 | | //! |
22 | | //! # Examples |
23 | | //! |
24 | | //! ## Functions using Arrays |
25 | | //! |
26 | | //! ```rust |
27 | | //! // Encode an unsigned 32 bit number: |
28 | | //! let (output, written_len) = leb128fmt::encode_u32(43110).unwrap(); |
29 | | //! // The number of bytes written in the output array |
30 | | //! assert_eq!(written_len, 3); |
31 | | //! assert_eq!(&output[..written_len], &[0xE6, 0xD0, 0x02]); |
32 | | //! // The entire output array. Note you should only use &output[..written_len] to copy |
33 | | //! // into your output buffer |
34 | | //! assert_eq!(output, [0xE6, 0xD0, 0x02, 0x00, 0x00]); |
35 | | //! |
36 | | //! // Decode an unsigned 32 bit number: |
37 | | //! let input = [0xE6, 0xD0, 0x02, 0x00, 0x00]; |
38 | | //! let (result, read_len) = leb128fmt::decode_u32(input).unwrap(); |
39 | | //! assert_eq!(result, 43110); |
40 | | //! assert_eq!(read_len, 3); |
41 | | //! ``` |
42 | | //! |
43 | | //! ### Helper Functions |
44 | | //! |
45 | | //! If you are reading from an input buffer, you can use [`is_last`] and |
46 | | //! [`max_len`] to determine the bytes to copy into the array. |
47 | | //! |
48 | | //! ```rust |
49 | | //! let buffer = vec![0xFE, 0xFE, 0xE6, 0xD0, 0x02, 0xFE, 0xFE, 0xFE]; |
50 | | //! let pos = 2; |
51 | | //! let end = buffer.iter().skip(pos).copied().position(leb128fmt::is_last).map(|p| pos + p); |
52 | | //! if let Some(end) = end { |
53 | | //! if end <= pos + leb128fmt::max_len::<32>() { |
54 | | //! let mut input = [0u8; leb128fmt::max_len::<32>()]; |
55 | | //! input[..=end - pos].copy_from_slice(&buffer[pos..=end]); |
56 | | //! let (result, read_len) = leb128fmt::decode_u32(input).unwrap(); |
57 | | //! assert_eq!(result, 43110); |
58 | | //! assert_eq!(read_len, 3); |
59 | | //! } else { |
60 | | //! // invalid LEB128 encoding |
61 | | //!# panic!(); |
62 | | //! } |
63 | | //! } else { |
64 | | //! if buffer.len() - pos < leb128fmt::max_len::<32>() { |
65 | | //! // Need more bytes in the buffer |
66 | | //!# panic!(); |
67 | | //! } else { |
68 | | //! // invalid LEB128 encoding |
69 | | //!# panic!(); |
70 | | //! } |
71 | | //! } |
72 | | //! |
73 | | //! ``` |
74 | | //! |
75 | | //! ## Functions Using Slices |
76 | | //! |
77 | | //! ```rust |
78 | | //! let mut buffer = vec![0xFE; 10]; |
79 | | //! let mut pos = 1; |
80 | | //! |
81 | | //! // Encode an unsigned 64 bit number with a mutable slice: |
82 | | //! let result = leb128fmt::encode_uint_slice::<u64, 64>(43110u64, &mut buffer, &mut pos); |
83 | | //! // The number of bytes written in the output array |
84 | | //! assert_eq!(result, Some(3)); |
85 | | //! assert_eq!(pos, 4); |
86 | | //! |
87 | | //! assert_eq!(buffer, [0xFE, 0xE6, 0xD0, 0x02, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE]); |
88 | | //! |
89 | | //! // Decode an unsigned 64 bit number with a slice: |
90 | | //! pos = 1; |
91 | | //! let result = leb128fmt::decode_uint_slice::<u64, 64>(&buffer, &mut pos); |
92 | | //! assert_eq!(result, Ok(43110)); |
93 | | //! assert_eq!(pos, 4); |
94 | | //! ``` |
95 | | //! |
96 | | //! ## Functions Using Fixed Sized Encoding |
97 | | //! |
98 | | //! There may be several different ways to encode a value. For instance, `0` can |
99 | | //! be encoded as 32 bits unsigned: |
100 | | //! |
101 | | //! ```rust |
102 | | //! let mut pos = 0; |
103 | | //! assert_eq!(leb128fmt::decode_uint_slice::<u32, 32>(&[0x00], &mut pos), Ok(0)); |
104 | | //! pos = 0; |
105 | | //! assert_eq!(leb128fmt::decode_uint_slice::<u32, 32>(&[0x80, 0x00], &mut pos), Ok(0)); |
106 | | //! pos = 0; |
107 | | //! assert_eq!(leb128fmt::decode_uint_slice::<u32, 32>(&[0x80, 0x80, 0x00], &mut pos), Ok(0)); |
108 | | //! pos = 0; |
109 | | //! assert_eq!(leb128fmt::decode_uint_slice::<u32, 32>(&[0x80, 0x80, 0x80, 0x00], &mut pos), Ok(0)); |
110 | | //! pos = 0; |
111 | | //! assert_eq!(leb128fmt::decode_uint_slice::<u32, 32>(&[0x80, 0x80, 0x80, 0x80, 0x00], &mut pos), Ok(0)); |
112 | | //! ``` |
113 | | //! |
114 | | //! There are functions provided to encode a value using the maximum number of |
115 | | //! bytes possible for a given bit size. Using the maximum number of bytes |
116 | | //! removes the benefit of compression, but it may be useful in a few scenarios. |
117 | | //! |
118 | | //! For instance, if a binary format needs to store the size or offset of some |
119 | | //! data before the size of data is known, it can be beneficial to write a fixed |
120 | | //! sized `0` placeholder value first. Then, once the real value is known, the |
121 | | //! `0` placeholder can be overwritten without moving other bytes. The real |
122 | | //! value is also written out using the fixed maximum number of bytes. |
123 | | //! |
124 | | //! ```rust |
125 | | //! // Encode an unsigned 32 bit number with all 5 bytes: |
126 | | //! let output = leb128fmt::encode_fixed_u32(43110).unwrap(); |
127 | | //! assert_eq!(output, [0xE6, 0xD0, 0x82, 0x80, 0x00]); |
128 | | //! |
129 | | //! // Decode an unsigned 32 bit number: |
130 | | //! let input = output; |
131 | | //! let (result, read_len) = leb128fmt::decode_u32(input).unwrap(); |
132 | | //! assert_eq!(result, 43110); |
133 | | //! |
134 | | //! // Note that all 5 bytes are read |
135 | | //! assert_eq!(read_len, 5); |
136 | | //! ``` |
137 | | //! |
138 | | //! [leb128]: https://en.wikipedia.org/wiki/LEB128 |
139 | | |
140 | | #![cfg_attr(not(feature = "std"), no_std)] |
141 | | #![cfg_attr(docsrs, feature(doc_cfg))] |
142 | | #![warn( |
143 | | missing_copy_implementations, |
144 | | missing_debug_implementations, |
145 | | missing_docs, |
146 | | rust_2018_idioms, |
147 | | unused_lifetimes, |
148 | | unused_qualifications |
149 | | )] |
150 | | |
151 | | use core::fmt; |
152 | | |
153 | | /// Returns the maximum byte length that is used to encode a value for a given |
154 | | /// number of `BITS`. |
155 | | /// |
156 | | /// A value can possibly be encoded with a fewer number of bytes. |
157 | | /// |
158 | | /// # Example |
159 | | /// |
160 | | /// ```rust |
161 | | /// assert_eq!(5, leb128fmt::max_len::<32>()); |
162 | | /// assert_eq!(10, leb128fmt::max_len::<64>()); |
163 | | /// |
164 | | /// assert_eq!(5, leb128fmt::max_len::<33>()); |
165 | | /// ``` |
166 | | #[inline] |
167 | | #[must_use] |
168 | | pub const fn max_len<const BITS: u32>() -> usize { |
169 | | let rem = if BITS % 7 == 0 { 0 } else { 1 }; |
170 | | ((BITS / 7) + rem) as usize |
171 | | } |
172 | | |
173 | | /// Returns true if this is the last byte in an encoded LEB128 value. |
174 | | /// |
175 | | /// # Example |
176 | | /// |
177 | | /// ```rust |
178 | | /// let bytes = &[0x42, 0x8F, 0xFF, 0x7F, 0xFF]; |
179 | | /// let pos = 1; |
180 | | /// let end = bytes.iter().skip(pos).copied().position(leb128fmt::is_last); |
181 | | /// let end = end.unwrap(); |
182 | | /// assert_eq!(pos + end, 3); |
183 | | /// let value = &bytes[pos..=pos + end]; |
184 | | /// ``` |
185 | | #[inline] |
186 | | #[must_use] |
187 | 21.5k | pub const fn is_last(byte: u8) -> bool { |
188 | 21.5k | byte & 0x80 == 0 |
189 | 21.5k | } |
190 | | |
191 | | /// Builds custom unsigned integer encode functions. |
192 | | /// |
193 | | /// The macro's 3 parameters are: |
194 | | /// |
195 | | /// 1. The name of the function. |
196 | | /// 2. The type to return. |
197 | | /// 3. The number of encoded BITS to decode. |
198 | | /// |
199 | | /// ```rust |
200 | | /// leb128fmt::encode_uint_arr!(encode_u33, u64, 33); |
201 | | /// |
202 | | /// let result = encode_u33(0); |
203 | | /// assert_eq!(Some(([0x00, 0x00, 0x00, 0x00, 0x00], 1)), result); |
204 | | /// |
205 | | /// let result = encode_u33(8589934591); |
206 | | /// assert_eq!(Some(([0xFF, 0xFF, 0xFF, 0xFF, 0x1F], 5)), result); |
207 | | /// ``` |
208 | | #[macro_export] |
209 | | macro_rules! encode_uint_arr { |
210 | | ($func:ident, $num_ty:ty, $bits:literal) => { |
211 | | /// Encodes a value as an unsigned LEB128 number. |
212 | | /// |
213 | | /// If the value can be encoded in the given number of bits, then return |
214 | | /// the encoded output and the index after the last byte written. |
215 | | /// |
216 | | /// If the value cannot be encoded with the given number of bits, then return None. |
217 | | #[must_use] |
218 | 16.7M | pub const fn $func( |
219 | 16.7M | mut value: $num_ty, |
220 | 16.7M | ) -> Option<( |
221 | 16.7M | [u8; (($bits / 7) + if $bits % 7 == 0 { 0 } else { 1 }) as usize], |
222 | 16.7M | usize, |
223 | 16.7M | )> { |
224 | | const BITS: u32 = $bits; |
225 | 16.7M | if <$num_ty>::BITS > BITS && 1 < value >> BITS - 1 { |
226 | 0 | return None; |
227 | 16.7M | } |
228 | | |
229 | 16.7M | let mut output = [0; (($bits / 7) + if $bits % 7 == 0 { 0 } else { 1 }) as usize]; |
230 | 16.7M | let mut index = 0; |
231 | | loop { |
232 | 19.6M | let mut b = (value & 0x7f) as u8; |
233 | | |
234 | 19.6M | value >>= 7; |
235 | 19.6M | let done = value == 0; |
236 | | |
237 | 19.6M | if !done { |
238 | 2.90M | b |= 0x80; |
239 | 16.7M | } |
240 | | |
241 | 19.6M | output[index] = b; |
242 | 19.6M | index += 1; |
243 | | |
244 | 19.6M | if done { |
245 | 16.7M | return Some((output, index)); |
246 | 2.90M | } |
247 | | } |
248 | 16.7M | } Line | Count | Source | 218 | 16.2M | pub const fn $func( | 219 | 16.2M | mut value: $num_ty, | 220 | 16.2M | ) -> Option<( | 221 | 16.2M | [u8; (($bits / 7) + if $bits % 7 == 0 { 0 } else { 1 }) as usize], | 222 | 16.2M | usize, | 223 | 16.2M | )> { | 224 | | const BITS: u32 = $bits; | 225 | 16.2M | if <$num_ty>::BITS > BITS && 1 < value >> BITS - 1 { | 226 | 0 | return None; | 227 | 16.2M | } | 228 | | | 229 | 16.2M | let mut output = [0; (($bits / 7) + if $bits % 7 == 0 { 0 } else { 1 }) as usize]; | 230 | 16.2M | let mut index = 0; | 231 | | loop { | 232 | 18.2M | let mut b = (value & 0x7f) as u8; | 233 | | | 234 | 18.2M | value >>= 7; | 235 | 18.2M | let done = value == 0; | 236 | | | 237 | 18.2M | if !done { | 238 | 2.02M | b |= 0x80; | 239 | 16.2M | } | 240 | | | 241 | 18.2M | output[index] = b; | 242 | 18.2M | index += 1; | 243 | | | 244 | 18.2M | if done { | 245 | 16.2M | return Some((output, index)); | 246 | 2.02M | } | 247 | | } | 248 | 16.2M | } |
Line | Count | Source | 218 | 518k | pub const fn $func( | 219 | 518k | mut value: $num_ty, | 220 | 518k | ) -> Option<( | 221 | 518k | [u8; (($bits / 7) + if $bits % 7 == 0 { 0 } else { 1 }) as usize], | 222 | 518k | usize, | 223 | 518k | )> { | 224 | | const BITS: u32 = $bits; | 225 | 518k | if <$num_ty>::BITS > BITS && 1 < value >> BITS - 1 { | 226 | 0 | return None; | 227 | 518k | } | 228 | | | 229 | 518k | let mut output = [0; (($bits / 7) + if $bits % 7 == 0 { 0 } else { 1 }) as usize]; | 230 | 518k | let mut index = 0; | 231 | | loop { | 232 | 1.40M | let mut b = (value & 0x7f) as u8; | 233 | | | 234 | 1.40M | value >>= 7; | 235 | 1.40M | let done = value == 0; | 236 | | | 237 | 1.40M | if !done { | 238 | 884k | b |= 0x80; | 239 | 884k | } | 240 | | | 241 | 1.40M | output[index] = b; | 242 | 1.40M | index += 1; | 243 | | | 244 | 1.40M | if done { | 245 | 518k | return Some((output, index)); | 246 | 884k | } | 247 | | } | 248 | 518k | } |
|
249 | | }; |
250 | | } |
251 | | |
252 | | encode_uint_arr!(encode_u32, u32, 32); |
253 | | encode_uint_arr!(encode_u64, u64, 64); |
254 | | |
255 | | /// Builds custom unsigned integer encode functions with the max byte length of |
256 | | /// byte arrays used. |
257 | | /// |
258 | | /// The macro's 3 parameters are: |
259 | | /// |
260 | | /// 1. The name of the function. |
261 | | /// 2. The type to return. |
262 | | /// 3. The number of encoded BITS to decode. |
263 | | /// |
264 | | /// ```rust |
265 | | /// leb128fmt::encode_fixed_uint_arr!(encode_fixed_u33, u64, 33); |
266 | | /// |
267 | | /// let output = encode_fixed_u33(0); |
268 | | /// assert_eq!(Some([0x80, 0x80, 0x80, 0x80, 0x00]), output); |
269 | | /// |
270 | | /// let output = encode_fixed_u33(8589934591); |
271 | | /// assert_eq!(Some([0xFF, 0xFF, 0xFF, 0xFF, 0x1F]), output); |
272 | | /// ``` |
273 | | #[macro_export] |
274 | | macro_rules! encode_fixed_uint_arr { |
275 | | ($func:ident, $num_ty:ty, $bits:literal) => { |
276 | | /// Encodes an unsigned LEB128 number with using the maximum number of |
277 | | /// bytes for the given bits length. |
278 | | /// |
279 | | /// If the value can be encoded in the given number of bits, then return |
280 | | /// the encoded value. |
281 | | /// |
282 | | /// If the value cannot be encoded with the given number of bits, then return None. |
283 | | #[must_use] |
284 | | pub const fn $func( |
285 | | value: $num_ty, |
286 | | ) -> Option<[u8; (($bits / 7) + if $bits % 7 == 0 { 0 } else { 1 }) as usize]> { |
287 | | const BITS: u32 = $bits; |
288 | | if <$num_ty>::BITS > BITS && 1 < value >> BITS - 1 { |
289 | | return None; |
290 | | } |
291 | | |
292 | | let mut output = [0; (($bits / 7) + if $bits % 7 == 0 { 0 } else { 1 }) as usize]; |
293 | | |
294 | | let mut index = 0; |
295 | | let mut shift: u32 = 0; |
296 | | loop { |
297 | | let v = value >> shift; |
298 | | |
299 | | let mut b = (v & 0x7f) as u8; |
300 | | |
301 | | let done = shift == BITS - (BITS % 7); |
302 | | |
303 | | if !done { |
304 | | b |= 0x80; |
305 | | } |
306 | | |
307 | | output[index] = b; |
308 | | index += 1; |
309 | | shift += 7; |
310 | | |
311 | | if done { |
312 | | return Some(output); |
313 | | } |
314 | | } |
315 | | } |
316 | | }; |
317 | | } |
318 | | |
319 | | encode_fixed_uint_arr!(encode_fixed_u32, u32, 32); |
320 | | encode_fixed_uint_arr!(encode_fixed_u64, u64, 64); |
321 | | |
322 | | /// Builds custom unsigned integer decode functions. |
323 | | /// |
324 | | /// The macro's 3 parameters are: |
325 | | /// |
326 | | /// 1. The name of the function. |
327 | | /// 2. The type to return. |
328 | | /// 3. The number of encoded BITS to decode. |
329 | | /// |
330 | | /// ```rust |
331 | | /// leb128fmt::decode_uint_arr!(decode_u33, u64, 33); |
332 | | /// |
333 | | /// let input = [0xFF, 0xFF, 0xFF, 0xFF, 0x1F]; |
334 | | /// let result = decode_u33(input); |
335 | | /// assert_eq!(Some((8589934591, 5)), result); |
336 | | /// ``` |
337 | | #[macro_export] |
338 | | macro_rules! decode_uint_arr { |
339 | | ($func:ident, $num_ty:ty, $bits:literal) => { |
340 | | /// Decodes an unsigned LEB128 number. |
341 | | /// |
342 | | /// If there is a valid encoded value, returns the decoded value and the |
343 | | /// index after the last byte read. |
344 | | /// |
345 | | /// If the encoding is incorrect, returns `None`. |
346 | | /// |
347 | | /// If the size in bits of the returned type is less than the size of the value in bits, returns `None`. |
348 | | /// For instance, if 33 bits are being decoded, then the returned type must be at least a `u64`. |
349 | | #[must_use] |
350 | | pub const fn $func( |
351 | | input: [u8; (($bits / 7) + if $bits % 7 == 0 { 0 } else { 1 }) as usize], |
352 | | ) -> Option<($num_ty, usize)> { |
353 | | const BITS: u32 = $bits; |
354 | | if <$num_ty>::BITS < BITS { |
355 | | return None; |
356 | | } |
357 | | |
358 | | let n = input[0]; |
359 | | if n & 0x80 == 0 { |
360 | | return Some((n as $num_ty, 1)); |
361 | | } |
362 | | |
363 | | let mut result = (n & 0x7f) as $num_ty; |
364 | | let mut shift = 7; |
365 | | let mut pos = 1; |
366 | | loop { |
367 | | let n = input[pos]; |
368 | | |
369 | | // If unnecessary bits are set (the bits would be dropped when |
370 | | // the value is shifted), then return an error. |
371 | | // |
372 | | // This error may be too strict. |
373 | | // |
374 | | // There should be at least a simple check to quickly |
375 | | // determine that the decoding has failed instead of |
376 | | // misinterpreting further data. |
377 | | // |
378 | | // For a less strict check, the && condition could be: |
379 | | // |
380 | | // (n & 0x80) != 0 |
381 | | // |
382 | | // Another stricter condition is if the last byte has a 0 value. |
383 | | // The encoding is correct but not the minimal number of bytes |
384 | | // was used to express the final value. |
385 | | if shift == BITS - (BITS % 7) && 1 << (BITS % 7) <= n { |
386 | | return None; |
387 | | } |
388 | | |
389 | | if n & 0x80 == 0 { |
390 | | result |= (n as $num_ty) << shift; |
391 | | return Some((result, pos + 1)); |
392 | | } |
393 | | |
394 | | result |= ((n & 0x7f) as $num_ty) << shift; |
395 | | shift += 7; |
396 | | pos += 1; |
397 | | } |
398 | | } |
399 | | }; |
400 | | } |
401 | | |
402 | | decode_uint_arr!(decode_u32, u32, 32); |
403 | | decode_uint_arr!(decode_u64, u64, 64); |
404 | | |
405 | | mod private { |
406 | | pub trait Sealed {} |
407 | | |
408 | | impl Sealed for u8 {} |
409 | | impl Sealed for u16 {} |
410 | | impl Sealed for u32 {} |
411 | | impl Sealed for u64 {} |
412 | | impl Sealed for u128 {} |
413 | | |
414 | | impl Sealed for i8 {} |
415 | | impl Sealed for i16 {} |
416 | | impl Sealed for i32 {} |
417 | | impl Sealed for i64 {} |
418 | | impl Sealed for i128 {} |
419 | | } |
420 | | |
421 | | /// Sealed trait for supported unsigned integer types. |
422 | | pub trait UInt: private::Sealed { |
423 | | /// Size of the type in bits. |
424 | | const BITS: u32; |
425 | | } |
426 | | |
427 | | impl UInt for u8 { |
428 | | const BITS: u32 = u8::BITS; |
429 | | } |
430 | | |
431 | | impl UInt for u16 { |
432 | | const BITS: u32 = u16::BITS; |
433 | | } |
434 | | |
435 | | impl UInt for u32 { |
436 | | const BITS: u32 = u32::BITS; |
437 | | } |
438 | | |
439 | | impl UInt for u64 { |
440 | | const BITS: u32 = u64::BITS; |
441 | | } |
442 | | |
443 | | impl UInt for u128 { |
444 | | const BITS: u32 = u128::BITS; |
445 | | } |
446 | | |
447 | | #[derive(Debug, Clone, PartialEq, Eq)] |
448 | | enum InnerError { |
449 | | NeedMoreBytes, |
450 | | InvalidEncoding, |
451 | | } |
452 | | |
453 | | /// Error when decoding a LEB128 value. |
454 | | #[derive(Debug, Clone, PartialEq, Eq)] |
455 | | pub struct Error(InnerError); |
456 | | |
457 | | impl fmt::Display for Error { |
458 | | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
459 | | match self.0 { |
460 | | InnerError::NeedMoreBytes => f.write_str("need more bytes"), |
461 | | InnerError::InvalidEncoding => f.write_str("invalid encoding"), |
462 | | } |
463 | | } |
464 | | } |
465 | | |
466 | | #[cfg(feature = "std")] |
467 | | impl std::error::Error for Error { |
468 | | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { |
469 | | None |
470 | | } |
471 | | } |
472 | | |
473 | | impl Error { |
474 | | /// If more bytes are needed in the slice to decode the value |
475 | | #[inline] |
476 | | #[must_use] |
477 | | pub const fn is_more_bytes_needed(&self) -> bool { |
478 | | matches!(self.0, InnerError::NeedMoreBytes) |
479 | | } |
480 | | |
481 | | /// If the value has an invalid encoding |
482 | | #[inline] |
483 | | #[must_use] |
484 | | pub const fn is_invalid_encoding(&self) -> bool { |
485 | | matches!(self.0, InnerError::InvalidEncoding) |
486 | | } |
487 | | } |
488 | | |
489 | | /// Encodes a given value into an output slice using the fixed set of bytes. |
490 | | /// |
491 | | /// # Examples |
492 | | /// |
493 | | /// ```rust |
494 | | /// let mut buffer = vec![254; 10]; |
495 | | /// let mut pos = 0; |
496 | | /// let result = leb128fmt::encode_uint_slice::<_, 32>(0u32, &mut buffer, &mut pos); |
497 | | /// assert_eq!(Some(1), result); |
498 | | /// assert_eq!(1, pos); |
499 | | /// assert_eq!(&[0x00], &buffer[..pos]); |
500 | | /// |
501 | | /// assert_eq!(&[0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE], buffer.as_slice()); |
502 | | /// |
503 | | /// let result = leb128fmt::encode_uint_slice::<_, 32>(u32::MAX, &mut buffer, &mut pos); |
504 | | /// assert_eq!(Some(5), result); |
505 | | /// assert_eq!(6, pos); |
506 | | /// assert_eq!(&[0xFF, 0xFF, 0xFF, 0xFF, 0x0F], &buffer[1..pos]); |
507 | | /// |
508 | | /// assert_eq!(&[0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFE, 0xFE, 0xFE, 0xFE], buffer.as_slice()); |
509 | | /// |
510 | | /// // Will try to encode even if the output slice is not as big as the maximum |
511 | | /// // number of bytes required to output every value for the given BITS |
512 | | /// let mut buffer = vec![254; 4]; |
513 | | /// let mut pos = 0; |
514 | | /// let result = leb128fmt::encode_uint_slice::<_, 32>(1028u32, &mut buffer, &mut pos); |
515 | | /// assert_eq!(Some(2), result); |
516 | | /// assert_eq!(&[0x84, 0x08, 0xFE, 0xFE], buffer.as_slice()); |
517 | | /// |
518 | | /// // Will return `None` if the output buffer is not long enough but will have partially written |
519 | | /// // the value |
520 | | /// let mut buffer = vec![254; 4]; |
521 | | /// let mut pos = 0; |
522 | | /// let result = leb128fmt::encode_uint_slice::<_, 32>(u32::MAX, &mut buffer, &mut pos); |
523 | | /// assert_eq!(None, result); |
524 | | /// assert_eq!(&[0xFF, 0xFF, 0xFF, 0xFF], buffer.as_slice()); |
525 | | /// |
526 | | /// // Will return `None` if the given value cannot be encoded with the given number of bits. |
527 | | /// let mut buffer = vec![254; 10]; |
528 | | /// let mut pos = 0; |
529 | | /// let result = leb128fmt::encode_uint_slice::<_, 32>(u64::MAX, &mut buffer, &mut pos); |
530 | | /// assert_eq!(None, result); |
531 | | /// assert_eq!(&[0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE], buffer.as_slice()); |
532 | | /// ``` |
533 | | #[allow(clippy::manual_let_else)] |
534 | | pub fn encode_uint_slice<T, const BITS: u32>( |
535 | | mut value: T, |
536 | | output: &mut [u8], |
537 | | pos: &mut usize, |
538 | | ) -> Option<usize> |
539 | | where |
540 | | T: Copy |
541 | | + PartialEq |
542 | | + core::ops::BitAnd |
543 | | + core::ops::Shr<u32> |
544 | | + core::ops::ShrAssign<u32> |
545 | | + From<u8> |
546 | | + UInt, |
547 | | <T as core::ops::Shr<u32>>::Output: PartialEq<T>, |
548 | | u8: TryFrom<<T as core::ops::BitAnd<T>>::Output>, |
549 | | { |
550 | | if BITS < T::BITS && value >> BITS != T::from(0) { |
551 | | return None; |
552 | | } |
553 | | |
554 | | let mut index = *pos; |
555 | | loop { |
556 | | if output.len() <= index { |
557 | | return None; |
558 | | } |
559 | | |
560 | | let mut b = match u8::try_from(value & T::from(0x7f)) { |
561 | | Ok(b) => b, |
562 | | Err(_) => unreachable!(), |
563 | | }; |
564 | | |
565 | | value >>= 7; |
566 | | |
567 | | let done = value == T::from(0); |
568 | | |
569 | | if !done { |
570 | | b |= 0x80; |
571 | | } |
572 | | |
573 | | output[index] = b; |
574 | | index += 1; |
575 | | |
576 | | if done { |
577 | | let len = index - *pos; |
578 | | *pos = index; |
579 | | return Some(len); |
580 | | } |
581 | | } |
582 | | } |
583 | | |
584 | | /// Encodes a given value into an output slice using a fixed set of bytes. |
585 | | /// |
586 | | /// # Examples |
587 | | /// |
588 | | /// ```rust |
589 | | /// let mut buffer = vec![254; 10]; |
590 | | /// let mut pos = 0; |
591 | | /// let result = leb128fmt::encode_fixed_uint_slice::<_, 32>(0u32, &mut buffer, &mut pos); |
592 | | /// assert_eq!(Some(5), result); |
593 | | /// assert_eq!(5, pos); |
594 | | /// assert_eq!(&[0x80, 0x80, 0x80, 0x80, 0x00], &buffer[..pos]); |
595 | | /// |
596 | | /// assert_eq!(&[0x80, 0x80, 0x80, 0x80, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE], buffer.as_slice()); |
597 | | /// |
598 | | /// let result = leb128fmt::encode_fixed_uint_slice::<_, 32>(u32::MAX, &mut buffer, &mut pos); |
599 | | /// assert_eq!(Some(5), result); |
600 | | /// assert_eq!(10, pos); |
601 | | /// assert_eq!(&[0xFF, 0xFF, 0xFF, 0xFF, 0x0F], &buffer[5..pos]); |
602 | | /// |
603 | | /// assert_eq!(&[0x80, 0x80, 0x80, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F], buffer.as_slice()); |
604 | | /// |
605 | | /// // Will return `None` if the output buffer is not long enough. |
606 | | /// let mut buffer = vec![254; 4]; |
607 | | /// let mut pos = 0; |
608 | | /// let result = leb128fmt::encode_fixed_uint_slice::<_, 32>(u32::MAX, &mut buffer, &mut pos); |
609 | | /// assert_eq!(None, result); |
610 | | /// assert_eq!(&[0xFE, 0xFE, 0xFE, 0xFE], buffer.as_slice()); |
611 | | /// |
612 | | /// // Will return `None` if the given value cannot be encoded with the given number of bits. |
613 | | /// let mut buffer = vec![254; 10]; |
614 | | /// let mut pos = 0; |
615 | | /// let result = leb128fmt::encode_fixed_uint_slice::<_, 32>(u64::MAX, &mut buffer, &mut pos); |
616 | | /// assert_eq!(None, result); |
617 | | /// assert_eq!(&[0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE], buffer.as_slice()); |
618 | | /// ``` |
619 | | #[allow(clippy::manual_let_else)] |
620 | | pub fn encode_fixed_uint_slice<T, const BITS: u32>( |
621 | | mut value: T, |
622 | | output: &mut [u8], |
623 | | pos: &mut usize, |
624 | | ) -> Option<usize> |
625 | | where |
626 | | T: Copy + core::ops::BitAnd + core::ops::Shr<u32> + core::ops::ShrAssign<u32> + From<u8> + UInt, |
627 | | <T as core::ops::Shr<u32>>::Output: PartialEq<T>, |
628 | | u8: TryFrom<<T as core::ops::BitAnd>::Output>, |
629 | | { |
630 | | if BITS < T::BITS && value >> BITS != T::from(0) { |
631 | | return None; |
632 | | } |
633 | | |
634 | | if output[*pos..].len() < max_len::<BITS>() { |
635 | | return None; |
636 | | } |
637 | | |
638 | | let mut index = *pos; |
639 | | for _ in 0..(max_len::<BITS>() - 1) { |
640 | | let mut b = match u8::try_from(value & T::from(0x7f)) { |
641 | | Ok(b) => b, |
642 | | Err(_) => unreachable!(), |
643 | | }; |
644 | | |
645 | | b |= 0x80; |
646 | | |
647 | | value >>= 7; |
648 | | |
649 | | output[index] = b; |
650 | | index += 1; |
651 | | } |
652 | | |
653 | | let b = match u8::try_from(value & T::from(0x7f)) { |
654 | | Ok(b) => b, |
655 | | Err(_) => unreachable!(), |
656 | | }; |
657 | | output[index] = b; |
658 | | index += 1; |
659 | | |
660 | | let len = index - *pos; |
661 | | *pos = index; |
662 | | Some(len) |
663 | | } |
664 | | |
665 | | /// Decodes an unsigned integer from a slice of bytes and starting at a given position. |
666 | | /// |
667 | | /// # Errors |
668 | | /// |
669 | | /// Returns an error if the value is not properly encoded or if more bytes are |
670 | | /// needed to decode the value. |
671 | | /// |
672 | | /// # Panics |
673 | | /// |
674 | | /// Panics if the size in bits of the returned type is less than the size of the value in bits. |
675 | | /// For instance, if 33 bits are being decoded, then the returned type must be at least a `u64`. |
676 | | /// |
677 | | /// ```rust |
678 | | /// let input = [0x42, 0x8F, 0xFF, 0x7F, 0xFF]; |
679 | | /// let mut pos = 1; |
680 | | /// let result = leb128fmt::decode_uint_slice::<u32, 32>(&input, &mut pos); |
681 | | /// assert_eq!(result, Ok(2097039)); |
682 | | /// assert_eq!(pos, 4); |
683 | | /// ``` |
684 | 17.2k | pub fn decode_uint_slice<T, const BITS: u32>(input: &[u8], pos: &mut usize) -> Result<T, Error> |
685 | 17.2k | where |
686 | 17.2k | T: core::ops::Shl<u32, Output = T> + core::ops::BitOrAssign + From<u8> + UInt, |
687 | | { |
688 | 17.2k | assert!(BITS <= T::BITS); |
689 | 17.2k | if input.len() <= *pos { |
690 | 0 | return Err(Error(InnerError::NeedMoreBytes)); |
691 | 17.2k | } |
692 | | |
693 | 17.2k | let n = input[*pos]; |
694 | 17.2k | if is_last(n) { |
695 | 12.9k | *pos += 1; |
696 | 12.9k | return Ok(T::from(n)); |
697 | 4.31k | } |
698 | | |
699 | 4.31k | let mut result = T::from(n & 0x7f); |
700 | 4.31k | let mut shift: u32 = 7; |
701 | | |
702 | 4.31k | let mut idx = *pos + 1; |
703 | | loop { |
704 | 4.31k | if input.len() <= idx { |
705 | 0 | return Err(Error(InnerError::NeedMoreBytes)); |
706 | 4.31k | } |
707 | | |
708 | 4.31k | let n = input[idx]; |
709 | | |
710 | | // If unnecessary bits are set (the bits would be dropped when |
711 | | // the value is shifted), then return an error. |
712 | | // |
713 | | // This error may be too strict. |
714 | | // |
715 | | // There should be at least a simple check to quickly |
716 | | // determine that the decoding has failed instead of |
717 | | // misinterpreting further data. |
718 | | // |
719 | | // For a less strict check, the && condition could be: |
720 | | // |
721 | | // (n & 0x80) != 0 |
722 | | // |
723 | | // Another stricter condition is if the last byte has a 0 value. |
724 | | // The encoding is correct but not the minimal number of bytes |
725 | | // was used to express the final value. |
726 | 4.31k | if shift == BITS - (BITS % 7) && 1 << (BITS % 7) <= n { |
727 | 0 | return Err(Error(InnerError::InvalidEncoding)); |
728 | 4.31k | } |
729 | | |
730 | 4.31k | if is_last(n) { |
731 | 4.31k | result |= T::from(n) << shift; |
732 | 4.31k | *pos = idx + 1; |
733 | 4.31k | return Ok(result); |
734 | 0 | } |
735 | | |
736 | 0 | result |= T::from(n & 0x7f) << shift; |
737 | 0 | shift += 7; |
738 | 0 | idx += 1; |
739 | | } |
740 | 17.2k | } |
741 | | |
742 | | /// Builds custom signed integer encode functions. |
743 | | /// |
744 | | /// The macro's 3 parameters are: |
745 | | /// |
746 | | /// 1. The name of the function. |
747 | | /// 2. The type to return. |
748 | | /// 3. The number of encoded BITS to decode. |
749 | | /// |
750 | | /// ```rust |
751 | | /// leb128fmt::encode_sint_arr!(encode_s33, i64, 33); |
752 | | /// |
753 | | /// let result = encode_s33(0); |
754 | | /// assert_eq!(Some(([0x00, 0x00, 0x00, 0x00, 0x00], 1)), result); |
755 | | /// |
756 | | /// let result = encode_s33(4_294_967_295); |
757 | | /// assert_eq!(Some(([0xFF, 0xFF, 0xFF, 0xFF, 0x0F], 5)), result); |
758 | | /// |
759 | | /// let result = encode_s33(-4_294_967_296); |
760 | | /// assert_eq!(Some(([0x80, 0x80, 0x80, 0x80, 0x70], 5)), result); |
761 | | /// |
762 | | /// let result = encode_s33(-1); |
763 | | /// assert_eq!(Some(([0x7F, 0x00, 0x00, 0x00, 0x00], 1)), result); |
764 | | /// ``` |
765 | | #[macro_export] |
766 | | macro_rules! encode_sint_arr { |
767 | | ($func:ident, $num_ty:ty, $bits:literal) => { |
768 | | /// Encodes a value as a signed LEB128 number. |
769 | | #[must_use] |
770 | 3.68M | pub fn $func( |
771 | 3.68M | mut value: $num_ty, |
772 | 3.68M | ) -> Option<( |
773 | 3.68M | [u8; (($bits / 7) + if $bits % 7 == 0 { 0 } else { 1 }) as usize], |
774 | 3.68M | usize, |
775 | 3.68M | )> { |
776 | | const BITS: u32 = $bits; |
777 | 3.68M | if BITS < <$num_ty>::BITS { |
778 | 0 | let v: $num_ty = value >> BITS - 1; |
779 | 0 | if v != 0 && v != -1 { |
780 | 0 | return None; |
781 | 0 | } |
782 | 3.68M | } |
783 | | |
784 | 3.68M | let mut output = [0; (($bits / 7) + if $bits % 7 == 0 { 0 } else { 1 }) as usize]; |
785 | 3.68M | let mut index = 0; |
786 | | loop { |
787 | 13.2M | let b = (value & 0x7f) as u8; |
788 | | |
789 | 13.2M | value >>= 7; |
790 | | |
791 | 13.2M | if (value == 0 && b & 0x40 == 0) || (value == -1 && (b & 0x40) != 0) { |
792 | 3.68M | output[index] = b; |
793 | 3.68M | return Some((output, index + 1)); |
794 | 9.53M | } |
795 | | |
796 | 9.53M | output[index] = b | 0x80; |
797 | 9.53M | index += 1; |
798 | | } |
799 | 3.68M | } Line | Count | Source | 770 | 1.62M | pub fn $func( | 771 | 1.62M | mut value: $num_ty, | 772 | 1.62M | ) -> Option<( | 773 | 1.62M | [u8; (($bits / 7) + if $bits % 7 == 0 { 0 } else { 1 }) as usize], | 774 | 1.62M | usize, | 775 | 1.62M | )> { | 776 | | const BITS: u32 = $bits; | 777 | 1.62M | if BITS < <$num_ty>::BITS { | 778 | 0 | let v: $num_ty = value >> BITS - 1; | 779 | 0 | if v != 0 && v != -1 { | 780 | 0 | return None; | 781 | 0 | } | 782 | 1.62M | } | 783 | | | 784 | 1.62M | let mut output = [0; (($bits / 7) + if $bits % 7 == 0 { 0 } else { 1 }) as usize]; | 785 | 1.62M | let mut index = 0; | 786 | | loop { | 787 | 3.97M | let b = (value & 0x7f) as u8; | 788 | | | 789 | 3.97M | value >>= 7; | 790 | | | 791 | 3.97M | if (value == 0 && b & 0x40 == 0) || (value == -1 && (b & 0x40) != 0) { | 792 | 1.62M | output[index] = b; | 793 | 1.62M | return Some((output, index + 1)); | 794 | 2.35M | } | 795 | | | 796 | 2.35M | output[index] = b | 0x80; | 797 | 2.35M | index += 1; | 798 | | } | 799 | 1.62M | } |
Line | Count | Source | 770 | 2.05M | pub fn $func( | 771 | 2.05M | mut value: $num_ty, | 772 | 2.05M | ) -> Option<( | 773 | 2.05M | [u8; (($bits / 7) + if $bits % 7 == 0 { 0 } else { 1 }) as usize], | 774 | 2.05M | usize, | 775 | 2.05M | )> { | 776 | | const BITS: u32 = $bits; | 777 | 2.05M | if BITS < <$num_ty>::BITS { | 778 | 0 | let v: $num_ty = value >> BITS - 1; | 779 | 0 | if v != 0 && v != -1 { | 780 | 0 | return None; | 781 | 0 | } | 782 | 2.05M | } | 783 | | | 784 | 2.05M | let mut output = [0; (($bits / 7) + if $bits % 7 == 0 { 0 } else { 1 }) as usize]; | 785 | 2.05M | let mut index = 0; | 786 | | loop { | 787 | 9.23M | let b = (value & 0x7f) as u8; | 788 | | | 789 | 9.23M | value >>= 7; | 790 | | | 791 | 9.23M | if (value == 0 && b & 0x40 == 0) || (value == -1 && (b & 0x40) != 0) { | 792 | 2.05M | output[index] = b; | 793 | 2.05M | return Some((output, index + 1)); | 794 | 7.17M | } | 795 | | | 796 | 7.17M | output[index] = b | 0x80; | 797 | 7.17M | index += 1; | 798 | | } | 799 | 2.05M | } |
|
800 | | }; |
801 | | } |
802 | | |
803 | | encode_sint_arr!(encode_s32, i32, 32); |
804 | | encode_sint_arr!(encode_s64, i64, 64); |
805 | | |
806 | | /// Builds custom signed integer encode functions with the max byte length of |
807 | | /// byte arrays used. |
808 | | /// |
809 | | /// The macro's 3 parameters are: |
810 | | /// |
811 | | /// 1. The name of the function. |
812 | | /// 2. The type to return. |
813 | | /// 3. The number of encoded BITS to decode. |
814 | | /// |
815 | | /// ```rust |
816 | | /// leb128fmt::encode_fixed_sint_arr!(encode_fixed_s33, i64, 33); |
817 | | /// |
818 | | /// let result = encode_fixed_s33(0); |
819 | | /// assert_eq!(Some([0x80, 0x80, 0x80, 0x80, 0x00]), result); |
820 | | /// |
821 | | /// let result = encode_fixed_s33(4_294_967_295); |
822 | | /// assert_eq!(Some([0xFF, 0xFF, 0xFF, 0xFF, 0x0F]), result); |
823 | | /// |
824 | | /// let result = encode_fixed_s33(-4_294_967_296); |
825 | | /// assert_eq!(Some([0x80, 0x80, 0x80, 0x80, 0x70]), result); |
826 | | /// |
827 | | /// let result = encode_fixed_s33(-1); |
828 | | /// assert_eq!(Some([0xFF, 0xFF, 0xFF, 0xFF, 0x7F]), result); |
829 | | /// ``` |
830 | | #[macro_export] |
831 | | macro_rules! encode_fixed_sint_arr { |
832 | | ($func:ident, $num_ty:ty, $bits:literal) => { |
833 | | /// Encodes a value as a signed LEB128 number. |
834 | | #[must_use] |
835 | | pub const fn $func( |
836 | | mut value: $num_ty, |
837 | | ) -> Option<[u8; (($bits / 7) + if $bits % 7 == 0 { 0 } else { 1 }) as usize]> { |
838 | | const BITS: u32 = $bits; |
839 | | if BITS < <$num_ty>::BITS { |
840 | | let v = value >> BITS - 1; |
841 | | if v != 0 && v != -1 { |
842 | | return None; |
843 | | } |
844 | | } |
845 | | |
846 | | let mut output = [0; (($bits / 7) + if $bits % 7 == 0 { 0 } else { 1 }) as usize]; |
847 | | let mut index = 0; |
848 | | let mut extend_negative = false; |
849 | | loop { |
850 | | let b = (value & 0x7f) as u8; |
851 | | |
852 | | value >>= 7; |
853 | | |
854 | | output[index] = b | 0x80; |
855 | | index += 1; |
856 | | |
857 | | if value == 0 && b & 0x40 == 0 { |
858 | | break; |
859 | | } |
860 | | if value == -1 && (b & 0x40) != 0 { |
861 | | extend_negative = true; |
862 | | break; |
863 | | } |
864 | | } |
865 | | |
866 | | loop { |
867 | | if index == output.len() { |
868 | | output[index - 1] &= 0x7F; |
869 | | return Some(output); |
870 | | } |
871 | | |
872 | | if extend_negative { |
873 | | output[index] = 0xFF; |
874 | | } else { |
875 | | output[index] = 0x80; |
876 | | } |
877 | | |
878 | | index += 1; |
879 | | } |
880 | | } |
881 | | }; |
882 | | } |
883 | | |
884 | | encode_fixed_sint_arr!(encode_fixed_s32, i32, 32); |
885 | | encode_fixed_sint_arr!(encode_fixed_s64, i64, 64); |
886 | | |
887 | | /// Builds custom signed integer decode functions. |
888 | | /// |
889 | | /// The macro's 3 parameters are: |
890 | | /// |
891 | | /// 1. The name of the function. |
892 | | /// 2. The type to return. |
893 | | /// 3. The number of encoded BITS to decode. |
894 | | /// |
895 | | /// ```rust |
896 | | /// leb128fmt::decode_sint_arr!(decode_s33, i64, 33); |
897 | | /// |
898 | | /// let input = [0xFF, 0xFF, 0xFF, 0xFF, 0x0F]; |
899 | | /// let result = decode_s33(input); |
900 | | /// assert_eq!(Some((4_294_967_295, 5)), result); |
901 | | /// |
902 | | /// let input = [0x7F, 0x00, 0x00, 0x00, 0x00]; |
903 | | /// let result = decode_s33(input); |
904 | | /// assert_eq!(Some((-1, 1)), result); |
905 | | /// |
906 | | /// let input = [0xFF, 0xFF, 0xFF, 0xFF, 0x7F]; |
907 | | /// let result = decode_s33(input); |
908 | | /// assert_eq!(Some((-1, 5)), result); |
909 | | /// |
910 | | /// let input = [0xFF, 0xFF, 0xFF, 0xFF, 0x1F]; |
911 | | /// let result = decode_s33(input); |
912 | | /// assert_eq!(None, result); |
913 | | /// ``` |
914 | | #[macro_export] |
915 | | macro_rules! decode_sint_arr { |
916 | | ($func:ident, $num_ty:ty, $bits:literal) => { |
917 | | /// Decodes an unsigned LEB128 number. |
918 | | /// |
919 | | /// If there is a valid encoded value, returns the decoded value and the |
920 | | /// index after the last byte read. |
921 | | /// |
922 | | /// If the encoding is incorrect, returns `None`. |
923 | | /// |
924 | | /// If the size in bits of the returned type is less than the size of the value in bits, returns `None`. |
925 | | /// For instance, if 33 bits are being decoded, then the returned type must be at least a `u64`. |
926 | | #[must_use] |
927 | | pub const fn $func( |
928 | | input: [u8; (($bits / 7) + if $bits % 7 == 0 { 0 } else { 1 }) as usize], |
929 | | ) -> Option<($num_ty, usize)> { |
930 | | const BITS: u32 = $bits; |
931 | | if <$num_ty>::BITS < BITS { |
932 | | return None; |
933 | | } |
934 | | |
935 | | let mut result = 0; |
936 | | let mut shift = 0; |
937 | | let mut n; |
938 | | let mut pos = 0; |
939 | | |
940 | | loop { |
941 | | n = input[pos]; |
942 | | let more = n & 0x80 != 0; |
943 | | |
944 | | // For the last valid shift, perform some checks to ensure the |
945 | | // encoding is valid. |
946 | | // |
947 | | // Notably, the one bit that MUST NOT be set is the high order bit |
948 | | // indicating there are more bytes to decode. |
949 | | // |
950 | | // For a signed integer, depending on if the value is positive or negative, |
951 | | // some bits SHOULD or SHOULD NOT be set. |
952 | | // |
953 | | // The expectation is that if this is a negative number, then |
954 | | // there should have been a sign extension so that all the bits |
955 | | // greater than the highest order bit is a 1. |
956 | | // |
957 | | // 32-bit |
958 | | // ------ |
959 | | // |
960 | | // The maximum shift value is 28 meaning a 32-bit number is |
961 | | // encoded in a maximum of 5 bytes. If the shift value is 35 or |
962 | | // greater, then, the byte's value will be shifted out beyond the |
963 | | // 32-bit value. |
964 | | // |
965 | | // With 28 being the highest valid shift value, the highest |
966 | | // order relevant bit in the final byte should be 0x08 or: |
967 | | // |
968 | | // 0000 1000 |
969 | | // |
970 | | // Any higher bit is "lost" during the bitshift. |
971 | | // |
972 | | // Due to the encoding rules and two's complement, if the |
973 | | // highest order relevant bit is set, then the number is |
974 | | // negative and the `1` is extended to the higher bits like: |
975 | | // |
976 | | // 0111 1000 |
977 | | // |
978 | | // Note that the highest order bit (the first bit from left to right) |
979 | | // MUST BE a 0. It is the bit which indicates more bytes should |
980 | | // be processed. For the maximum final byte (byte #5 for a |
981 | | // 32-bit number)), it MUST be 0. There are no additional bytes |
982 | | // to decode. |
983 | | // |
984 | | // If the highest order relevant bit is not set, then the |
985 | | // integer is positive. Any of the lower bits can be set. |
986 | | // |
987 | | // 0000 0111 |
988 | | // |
989 | | // So the conditions to check are: |
990 | | // |
991 | | // 1. The highest order bit is not set (so there are no more |
992 | | // bytes to decode). If it is set, the encoding is invalid. |
993 | | // This is the "more" check. |
994 | | // |
995 | | // 2. Determine if any sign extended negative bit is set. |
996 | | // So is any bit in: |
997 | | // |
998 | | // 0111 1000 |
999 | | // |
1000 | | // set. If none of the bits are set, then the number is |
1001 | | // positive, and the encoding is valid. |
1002 | | // This is the "(n & mask != 0)" check. |
1003 | | // 3. If any sign extended negative bits are set, the number is |
1004 | | // negative, and ALL of the bits MUST be set for a valid negative number. |
1005 | | // This is the "(n < mask)"" check. |
1006 | | // An equivalent check would be that "(n < mask) || (n >= 0x80)" |
1007 | | // But the earlier check for "more" removes the need for the additional check. |
1008 | | // |
1009 | | // The check could also be "(n & mask) != mask". |
1010 | | // |
1011 | | // Another stricter condition is if the last byte has a 0 value. |
1012 | | // The encoding is correct but not the minimal number of bytes |
1013 | | // was used to express the final value. |
1014 | | if shift == BITS - (BITS % 7) { |
1015 | | #[allow(clippy::cast_sign_loss)] |
1016 | | let mask = ((-1i8 << ((BITS % 7).saturating_sub(1))) & 0x7f) as u8; |
1017 | | if more || (n & mask != 0 && n < mask) { |
1018 | | return None; |
1019 | | } |
1020 | | } |
1021 | | |
1022 | | result |= ((n & 0x7f) as $num_ty) << shift; |
1023 | | shift += 7; |
1024 | | pos += 1; |
1025 | | |
1026 | | if !more { |
1027 | | break; |
1028 | | } |
1029 | | } |
1030 | | |
1031 | | if shift < <$num_ty>::BITS && n & 0x40 != 0 { |
1032 | | result |= -1 << shift; |
1033 | | } |
1034 | | |
1035 | | Some((result, pos)) |
1036 | | } |
1037 | | }; |
1038 | | } |
1039 | | |
1040 | | decode_sint_arr!(decode_s32, i32, 32); |
1041 | | decode_sint_arr!(decode_s64, i64, 64); |
1042 | | |
1043 | | /// Sealed trait for supported signed integer types. |
1044 | | pub trait SInt: private::Sealed { |
1045 | | /// Size of the type in bits. |
1046 | | const BITS: u32; |
1047 | | } |
1048 | | |
1049 | | impl SInt for i8 { |
1050 | | const BITS: u32 = i8::BITS; |
1051 | | } |
1052 | | |
1053 | | impl SInt for i16 { |
1054 | | const BITS: u32 = i16::BITS; |
1055 | | } |
1056 | | |
1057 | | impl SInt for i32 { |
1058 | | const BITS: u32 = i32::BITS; |
1059 | | } |
1060 | | |
1061 | | impl SInt for i64 { |
1062 | | const BITS: u32 = i64::BITS; |
1063 | | } |
1064 | | |
1065 | | impl SInt for i128 { |
1066 | | const BITS: u32 = i128::BITS; |
1067 | | } |
1068 | | |
1069 | | /// Encodes a given value into an output slice using the fixed set of bytes. |
1070 | | /// |
1071 | | /// # Examples |
1072 | | /// |
1073 | | /// ```rust |
1074 | | /// let mut buffer = vec![254; 10]; |
1075 | | /// let mut pos = 0; |
1076 | | /// let result = leb128fmt::encode_sint_slice::<_, 32>(0i32, &mut buffer, &mut pos); |
1077 | | /// assert_eq!(Some(1), result); |
1078 | | /// assert_eq!(1, pos); |
1079 | | /// assert_eq!(&[0x00], &buffer[..pos]); |
1080 | | /// |
1081 | | /// assert_eq!(&[0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE], buffer.as_slice()); |
1082 | | /// |
1083 | | /// let result = leb128fmt::encode_sint_slice::<_, 32>(i32::MAX, &mut buffer, &mut pos); |
1084 | | /// assert_eq!(Some(5), result); |
1085 | | /// assert_eq!(6, pos); |
1086 | | /// assert_eq!(&[0xFF, 0xFF, 0xFF, 0xFF, 0x07], &buffer[1..pos]); |
1087 | | /// |
1088 | | /// assert_eq!(&[0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFE, 0xFE, 0xFE, 0xFE], buffer.as_slice()); |
1089 | | /// |
1090 | | /// // Will try to encode even if the output slice is not as big as the maximum |
1091 | | /// // number of bytes required to output every value for the given BITS |
1092 | | /// let mut buffer = vec![254; 4]; |
1093 | | /// let mut pos = 0; |
1094 | | /// let result = leb128fmt::encode_sint_slice::<_, 32>(1028i32, &mut buffer, &mut pos); |
1095 | | /// assert_eq!(Some(2), result); |
1096 | | /// assert_eq!(&[0x84, 0x08, 0xFE, 0xFE], buffer.as_slice()); |
1097 | | /// |
1098 | | /// // Will return `None` if the output buffer is not long enough but will have partially written |
1099 | | /// // the value |
1100 | | /// let mut buffer = vec![254; 4]; |
1101 | | /// let mut pos = 0; |
1102 | | /// let result = leb128fmt::encode_sint_slice::<_, 32>(i32::MAX, &mut buffer, &mut pos); |
1103 | | /// assert_eq!(None, result); |
1104 | | /// assert_eq!(&[0xFF, 0xFF, 0xFF, 0xFF], buffer.as_slice()); |
1105 | | /// |
1106 | | /// // Will return `None` if the given value cannot be encoded with the given number of bits. |
1107 | | /// let mut buffer = vec![254; 10]; |
1108 | | /// let mut pos = 0; |
1109 | | /// let result = leb128fmt::encode_sint_slice::<_, 32>(i64::MAX, &mut buffer, &mut pos); |
1110 | | /// assert_eq!(None, result); |
1111 | | /// assert_eq!(&[0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE], buffer.as_slice()); |
1112 | | /// ``` |
1113 | | #[allow(clippy::manual_let_else)] |
1114 | | pub fn encode_sint_slice<T, const BITS: u32>( |
1115 | | mut value: T, |
1116 | | output: &mut [u8], |
1117 | | pos: &mut usize, |
1118 | | ) -> Option<usize> |
1119 | | where |
1120 | | T: Copy |
1121 | | + PartialEq |
1122 | | + core::ops::BitAnd |
1123 | | + core::ops::Shr<u32> |
1124 | | + core::ops::ShrAssign<u32> |
1125 | | + From<i8> |
1126 | | + SInt, |
1127 | | <T as core::ops::Shr<u32>>::Output: PartialEq<T>, |
1128 | | u8: TryFrom<<T as core::ops::BitAnd<T>>::Output>, |
1129 | | { |
1130 | | if BITS < T::BITS { |
1131 | | let v = value >> BITS; |
1132 | | if v != T::from(0) && v != T::from(-1) { |
1133 | | return None; |
1134 | | } |
1135 | | } |
1136 | | |
1137 | | let mut index = *pos; |
1138 | | loop { |
1139 | | if output.len() <= index { |
1140 | | return None; |
1141 | | } |
1142 | | |
1143 | | let b = match u8::try_from(value & T::from(0x7f)) { |
1144 | | Ok(b) => b, |
1145 | | Err(_) => unreachable!(), |
1146 | | }; |
1147 | | |
1148 | | value >>= 7; |
1149 | | |
1150 | | if (value == T::from(0) && b & 0x40 == 0) || (value == T::from(-1) && (b & 0x40) != 0) { |
1151 | | output[index] = b; |
1152 | | index += 1; |
1153 | | let len = index - *pos; |
1154 | | *pos = index; |
1155 | | return Some(len); |
1156 | | } |
1157 | | |
1158 | | output[index] = b | 0x80; |
1159 | | index += 1; |
1160 | | } |
1161 | | } |
1162 | | |
1163 | | /// Encodes a given value into an output slice using a fixed set of bytes. |
1164 | | /// |
1165 | | /// # Examples |
1166 | | /// |
1167 | | /// ```rust |
1168 | | /// let mut buffer = vec![254; 10]; |
1169 | | /// let mut pos = 0; |
1170 | | /// let result = leb128fmt::encode_fixed_sint_slice::<_, 32>(0i32, &mut buffer, &mut pos); |
1171 | | /// assert_eq!(Some(5), result); |
1172 | | /// assert_eq!(5, pos); |
1173 | | /// assert_eq!(&[0x80, 0x80, 0x80, 0x80, 0x00], &buffer[..pos]); |
1174 | | /// |
1175 | | /// assert_eq!(&[0x80, 0x80, 0x80, 0x80, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE], buffer.as_slice()); |
1176 | | /// |
1177 | | /// let result = leb128fmt::encode_fixed_sint_slice::<_, 32>(i32::MAX, &mut buffer, &mut pos); |
1178 | | /// assert_eq!(Some(5), result); |
1179 | | /// assert_eq!(10, pos); |
1180 | | /// assert_eq!(&[0xFF, 0xFF, 0xFF, 0xFF, 0x07], &buffer[5..pos]); |
1181 | | /// |
1182 | | /// assert_eq!(&[0x80, 0x80, 0x80, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x07], buffer.as_slice()); |
1183 | | /// |
1184 | | /// // Will return `None` if the output buffer is not long enough. |
1185 | | /// let mut buffer = vec![254; 4]; |
1186 | | /// let mut pos = 0; |
1187 | | /// let result = leb128fmt::encode_fixed_sint_slice::<_, 32>(i32::MAX, &mut buffer, &mut pos); |
1188 | | /// assert_eq!(None, result); |
1189 | | /// assert_eq!(&[0xFE, 0xFE, 0xFE, 0xFE], buffer.as_slice()); |
1190 | | /// |
1191 | | /// // Will return `None` if the given value cannot be encoded with the given number of bits. |
1192 | | /// let mut buffer = vec![254; 10]; |
1193 | | /// let mut pos = 0; |
1194 | | /// let result = leb128fmt::encode_fixed_sint_slice::<_, 32>(i64::MAX, &mut buffer, &mut pos); |
1195 | | /// assert_eq!(None, result); |
1196 | | /// assert_eq!(&[0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE], buffer.as_slice()); |
1197 | | /// ``` |
1198 | | #[allow(clippy::manual_let_else)] |
1199 | | pub fn encode_fixed_sint_slice<T, const BITS: u32>( |
1200 | | mut value: T, |
1201 | | output: &mut [u8], |
1202 | | pos: &mut usize, |
1203 | | ) -> Option<usize> |
1204 | | where |
1205 | | T: Copy |
1206 | | + PartialEq |
1207 | | + core::ops::BitAnd |
1208 | | + core::ops::Shr<u32> |
1209 | | + core::ops::ShrAssign<u32> |
1210 | | + From<i8> |
1211 | | + SInt, |
1212 | | <T as core::ops::Shr<u32>>::Output: PartialEq<T>, |
1213 | | u8: TryFrom<<T as core::ops::BitAnd>::Output>, |
1214 | | { |
1215 | | if BITS < T::BITS { |
1216 | | let v = value >> BITS; |
1217 | | if v != T::from(0) && v != T::from(-1) { |
1218 | | return None; |
1219 | | } |
1220 | | } |
1221 | | |
1222 | | if output[*pos..].len() < max_len::<BITS>() { |
1223 | | return None; |
1224 | | } |
1225 | | |
1226 | | let mut index = *pos; |
1227 | | let mut extend_negative = false; |
1228 | | loop { |
1229 | | let b = match u8::try_from(value & T::from(0x7f)) { |
1230 | | Ok(b) => b, |
1231 | | Err(_) => unreachable!(), |
1232 | | }; |
1233 | | |
1234 | | value >>= 7; |
1235 | | |
1236 | | output[index] = b | 0x80; |
1237 | | index += 1; |
1238 | | |
1239 | | if value == T::from(0) && b & 0x40 == 0 { |
1240 | | break; |
1241 | | } |
1242 | | if value == T::from(-1) && (b & 0x40) != 0 { |
1243 | | extend_negative = true; |
1244 | | break; |
1245 | | } |
1246 | | } |
1247 | | |
1248 | | loop { |
1249 | | if index == *pos + max_len::<BITS>() { |
1250 | | output[index - 1] &= 0x7F; |
1251 | | let len = index - *pos; |
1252 | | *pos = index; |
1253 | | return Some(len); |
1254 | | } |
1255 | | |
1256 | | if extend_negative { |
1257 | | output[index] = 0xFF; |
1258 | | } else { |
1259 | | output[index] = 0x80; |
1260 | | } |
1261 | | |
1262 | | index += 1; |
1263 | | } |
1264 | | } |
1265 | | |
1266 | | /// Decodes an unsigned integer from a slice of bytes and starting at a given position. |
1267 | | /// |
1268 | | /// # Errors |
1269 | | /// |
1270 | | /// Returns an error if the value is not properly encoded or if more bytes are |
1271 | | /// needed to decode the value. |
1272 | | /// |
1273 | | /// # Panics |
1274 | | /// |
1275 | | /// Panics if the size in bits of the returned type is less than the size of the value in bits. |
1276 | | /// For instance, if 33 bits are being decoded, then the returned type must be at least a `u64`. |
1277 | | /// |
1278 | | /// ```rust |
1279 | | /// let input = [0x42, 0x8F, 0xFF, 0x7F, 0xFF]; |
1280 | | /// let mut pos = 1; |
1281 | | /// let result = leb128fmt::decode_sint_slice::<i32, 32>(&input, &mut pos); |
1282 | | /// assert_eq!(result, Ok(-113)); |
1283 | | /// assert_eq!(pos, 4); |
1284 | | /// ``` |
1285 | | pub fn decode_sint_slice<T, const BITS: u32>(input: &[u8], pos: &mut usize) -> Result<T, Error> |
1286 | | where |
1287 | | T: core::ops::Shl<u32, Output = T> + core::ops::BitOrAssign + From<i8> + From<u8> + SInt, |
1288 | | { |
1289 | | assert!(BITS <= T::BITS); |
1290 | | |
1291 | | let mut result = T::from(0i8); |
1292 | | let mut shift = 0; |
1293 | | let mut n; |
1294 | | |
1295 | | let mut idx = *pos; |
1296 | | loop { |
1297 | | if input.len() <= idx { |
1298 | | return Err(Error(InnerError::NeedMoreBytes)); |
1299 | | } |
1300 | | |
1301 | | n = input[idx]; |
1302 | | let more = n & 0x80 != 0; |
1303 | | |
1304 | | // For the last valid shift, perform some checks to ensure the |
1305 | | // encoding is valid. |
1306 | | // |
1307 | | // Notably, the one bit that MUST NOT be set is the high order bit |
1308 | | // indicating there are more bytes to decode. |
1309 | | // |
1310 | | // For a signed integer, depending on if the value is positive or negative, |
1311 | | // some bits SHOULD or SHOULD NOT be set. |
1312 | | // |
1313 | | // The expectation is that if this is a negative number, then |
1314 | | // there should have been a sign extension so that all the bits |
1315 | | // greater than the highest order bit is a 1. |
1316 | | // |
1317 | | // 32-bit |
1318 | | // ------ |
1319 | | // |
1320 | | // The maximum shift value is 28 meaning a 32-bit number is |
1321 | | // encoded in a maximum of 5 bytes. If the shift value is 35 or |
1322 | | // greater, then, the byte's value will be shifted out beyond the |
1323 | | // 32-bit value. |
1324 | | // |
1325 | | // With 28 being the highest valid shift value, the highest |
1326 | | // order relevant bit in the final byte should be 0x08 or: |
1327 | | // |
1328 | | // 0000 1000 |
1329 | | // |
1330 | | // Any higher bit is "lost" during the bitshift. |
1331 | | // |
1332 | | // Due to the encoding rules and two's complement, if the |
1333 | | // highest order relevant bit is set, then the number is |
1334 | | // negative and the `1` is extended to the higher bits like: |
1335 | | // |
1336 | | // 0111 1000 |
1337 | | // |
1338 | | // Note that the highest order bit (the first bit from left to right) |
1339 | | // MUST BE a 0. It is the bit which indicates more bytes should |
1340 | | // be processed. For the maximum final byte (byte #5 for a |
1341 | | // 32-bit number)), it MUST be 0. There are no additional bytes |
1342 | | // to decode. |
1343 | | // |
1344 | | // If the highest order relevant bit is not set, then the |
1345 | | // integer is positive. Any of the lower bits can be set. |
1346 | | // |
1347 | | // 0000 0111 |
1348 | | // |
1349 | | // So the conditions to check are: |
1350 | | // |
1351 | | // 1. The highest order bit is not set (so there are no more |
1352 | | // bytes to decode). If it is set, the encoding is invalid. |
1353 | | // This is the "more" check. |
1354 | | // |
1355 | | // 2. Determine if any sign extended negative bit is set. |
1356 | | // So is any bit in: |
1357 | | // |
1358 | | // 0111 1000 |
1359 | | // |
1360 | | // set. If none of the bits are set, then the number is |
1361 | | // positive, and the encoding is valid. |
1362 | | // This is the "(n & mask != 0)" check. |
1363 | | // 3. If any sign extended negative bits are set, the number is |
1364 | | // negative, and ALL of the bits MUST be set for a valid negative number. |
1365 | | // This is the "(n < mask)"" check. |
1366 | | // An equivalent check would be that "(n < mask) || (n >= 0x80)" |
1367 | | // But the earlier check for "more" removes the need for the additional check. |
1368 | | // |
1369 | | // The check could also be "(n & mask) != mask". |
1370 | | // |
1371 | | // Another stricter condition is if the last byte has a 0 value. |
1372 | | // The encoding is correct but not the minimal number of bytes |
1373 | | // was used to express the final value. |
1374 | | if shift == BITS - (BITS % 7) { |
1375 | | #[allow(clippy::cast_sign_loss)] |
1376 | | let mask = ((-1i8 << ((BITS % 7).saturating_sub(1))) & 0x7f) as u8; |
1377 | | if more || (n & mask != 0 && n < mask) { |
1378 | | return Err(Error(InnerError::InvalidEncoding)); |
1379 | | } |
1380 | | } |
1381 | | |
1382 | | result |= T::from(n & 0x7f) << shift; |
1383 | | shift += 7; |
1384 | | idx += 1; |
1385 | | |
1386 | | if !more { |
1387 | | break; |
1388 | | } |
1389 | | } |
1390 | | |
1391 | | if shift < T::BITS && n & 0x40 != 0 { |
1392 | | result |= T::from(-1i8) << shift; |
1393 | | } |
1394 | | |
1395 | | *pos = idx; |
1396 | | Ok(result) |
1397 | | } |
1398 | | |
1399 | | #[cfg(test)] |
1400 | | mod tests { |
1401 | | use super::*; |
1402 | | |
1403 | | #[test] |
1404 | | fn test_encode_u8() { |
1405 | | let mut buffer = [0; 4]; |
1406 | | let mut pos = 1; |
1407 | | let written = encode_fixed_uint_slice::<_, 8>(u8::MAX, &mut buffer, &mut pos); |
1408 | | assert_eq!(3, pos); |
1409 | | assert_eq!([0x00, 0xFF, 0x01, 0x00], buffer); |
1410 | | assert_eq!(Some(2), written); |
1411 | | } |
1412 | | |
1413 | | #[test] |
1414 | | fn test_encode_u32() { |
1415 | | let mut buffer = [0; 6]; |
1416 | | let mut pos = 1; |
1417 | | let written = encode_fixed_uint_slice::<_, 32>(u32::MAX, &mut buffer, &mut pos); |
1418 | | assert_eq!(6, pos); |
1419 | | assert_eq!([0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F], buffer); |
1420 | | assert_eq!(Some(5), written); |
1421 | | } |
1422 | | |
1423 | | #[test] |
1424 | | fn test_encode_u64_as_33_bits_2() { |
1425 | | let mut buffer = [0; 6]; |
1426 | | let mut pos = 1; |
1427 | | let written = encode_fixed_uint_slice::<_, 33>(2u64.pow(33) - 1, &mut buffer, &mut pos); |
1428 | | let mut pos = 1; |
1429 | | let value = decode_uint_slice::<u64, 33>(&buffer, &mut pos).unwrap(); |
1430 | | assert_eq!(8_589_934_592 - 1, value); |
1431 | | assert_eq!(6, pos); |
1432 | | assert_eq!([0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F], buffer); |
1433 | | assert_eq!(Some(5), written); |
1434 | | } |
1435 | | |
1436 | | #[test] |
1437 | | fn test_encode_u64_as_33_bits_with_too_large_value() { |
1438 | | let mut buffer = [0; 6]; |
1439 | | let mut pos = 1; |
1440 | | let written = encode_fixed_uint_slice::<_, 33>(2u64.pow(34) - 1, &mut buffer, &mut pos); |
1441 | | assert_eq!(1, pos); |
1442 | | assert_eq!([0x00, 0x00, 0x00, 0x00, 0x00, 0x00], buffer); |
1443 | | assert_eq!(None, written); |
1444 | | } |
1445 | | |
1446 | | #[test] |
1447 | | fn test_encode_u64() { |
1448 | | let mut buffer = [0; 20]; |
1449 | | let mut pos = 1; |
1450 | | let written = encode_fixed_uint_slice::<_, 64>(u64::MAX, &mut buffer, &mut pos); |
1451 | | assert_eq!(11, pos); |
1452 | | assert_eq!(Some(10), written); |
1453 | | } |
1454 | | |
1455 | | #[test] |
1456 | | fn test_decode_u32() { |
1457 | | let input = [0xff, 0xff, 0xff, 0xff, 0x0f]; |
1458 | | let result = decode_u32(input); |
1459 | | assert_eq!(result, Some((u32::MAX, 5))); |
1460 | | |
1461 | | let input = [0x00, 0x00, 0x00, 0x00, 0x00]; |
1462 | | let result = decode_u32(input); |
1463 | | assert_eq!(result, Some((u32::MIN, 1))); |
1464 | | |
1465 | | // Valid but in-efficient way to encode 0. |
1466 | | let input = [0x80, 0x80, 0x80, 0x80, 0x00]; |
1467 | | let result = decode_u32(input); |
1468 | | assert_eq!(result, Some((u32::MIN, 5))); |
1469 | | } |
1470 | | |
1471 | | #[test] |
1472 | | fn test_decode_u32_errors() { |
1473 | | // Maximum of 5 bytes encoding, the 0x80 bit must not be set. |
1474 | | let input = [0xff, 0xff, 0xff, 0xff, 0x8f]; |
1475 | | let result = decode_u32(input); |
1476 | | assert_eq!(result, None); |
1477 | | |
1478 | | // Parts of 0x1f (0x10) will be shifted out of the final value and lost. |
1479 | | // This may too strict of a check since it could be ok. |
1480 | | let input = [0xff, 0xff, 0xff, 0xff, 0x1f]; |
1481 | | let result = decode_u32(input); |
1482 | | assert_eq!(result, None); |
1483 | | } |
1484 | | |
1485 | | #[test] |
1486 | | fn test_decode_u64() { |
1487 | | let input = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01]; |
1488 | | let result = decode_u64(input); |
1489 | | assert_eq!(result, Some((u64::MAX, 10))); |
1490 | | |
1491 | | let input = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; |
1492 | | let result = decode_u64(input); |
1493 | | assert_eq!(result, Some((u64::MIN, 1))); |
1494 | | |
1495 | | // Valid but in-efficient way to encode 0. |
1496 | | let input = [0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00]; |
1497 | | let result = decode_u64(input); |
1498 | | assert_eq!(result, Some((u64::MIN, 10))); |
1499 | | } |
1500 | | |
1501 | | #[test] |
1502 | | fn test_decode_u64_errors() { |
1503 | | // Maximum of 10 bytes encoding, the 0x80 bit must not be set in the final byte. |
1504 | | let input = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x81]; |
1505 | | let result = decode_u64(input); |
1506 | | assert_eq!(result, None); |
1507 | | |
1508 | | // 0x02 will be shifted out of the final value and lost. |
1509 | | // This may too strict of a check since it could be ok. |
1510 | | let input = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02]; |
1511 | | let result = decode_u64(input); |
1512 | | assert_eq!(result, None); |
1513 | | } |
1514 | | |
1515 | | #[test] |
1516 | | fn test_decode_s32() { |
1517 | | let input = [0xff, 0xff, 0xff, 0xff, 0x07]; |
1518 | | let result = decode_s32(input); |
1519 | | assert_eq!(result, Some((i32::MAX, 5))); |
1520 | | |
1521 | | let input = [0x80, 0x80, 0x80, 0x80, 0x78]; |
1522 | | let result = decode_s32(input); |
1523 | | assert_eq!(result, Some((i32::MIN, 5))); |
1524 | | |
1525 | | let input = [0x00, 0x00, 0x00, 0x00, 0x00]; |
1526 | | let result = decode_s32(input); |
1527 | | assert_eq!(result, Some((0, 1))); |
1528 | | |
1529 | | // Valid but in-efficient way to encode 0. |
1530 | | let input = [0x80, 0x80, 0x80, 0x80, 0x00]; |
1531 | | let result = decode_s32(input); |
1532 | | assert_eq!(result, Some((0, 5))); |
1533 | | |
1534 | | let input = [0x40, 0x00, 0x00, 0x00, 0x00]; |
1535 | | let result = decode_s32(input); |
1536 | | assert_eq!(result, Some((-64, 1))); |
1537 | | |
1538 | | // Valid but in-efficient way to encode -64. |
1539 | | let input = [0xc0, 0x7f, 0x00, 0x00, 0x00]; |
1540 | | let result = decode_s32(input); |
1541 | | assert_eq!(result, Some((-64, 2))); |
1542 | | } |
1543 | | |
1544 | | #[test] |
1545 | | fn test_decode_s32_errors() { |
1546 | | // Maximum of 5 bytes encoding, the 0x80 bit must not be set in the final byte. |
1547 | | let input = [0x80, 0x80, 0x80, 0x80, 0x80]; |
1548 | | let result = decode_s32(input); |
1549 | | assert_eq!(result, None); |
1550 | | |
1551 | | // If the highest valid bit is set, it should be sign extended. (final byte should be 0x78) |
1552 | | let input = [0x80, 0x80, 0x80, 0x80, 0x08]; |
1553 | | let result = decode_s32(input); |
1554 | | assert_eq!(result, None); |
1555 | | |
1556 | | // If the highest valid bit is set, it should be sign extended. (final byte should be 0x78) |
1557 | | let input = [0x80, 0x80, 0x80, 0x80, 0x38]; |
1558 | | let result = decode_s32(input); |
1559 | | assert_eq!(result, None); |
1560 | | } |
1561 | | |
1562 | | #[test] |
1563 | | fn test_decode_s33() { |
1564 | | decode_sint_arr!(decode_s33, i64, 33); |
1565 | | |
1566 | | let input = [0xff, 0xff, 0xff, 0xff, 0x0f]; |
1567 | | let result = decode_s33(input); |
1568 | | assert_eq!(result, Some((i64::from(u32::MAX), 5))); |
1569 | | |
1570 | | let input = [0x80, 0x80, 0x80, 0x80, 0x70]; |
1571 | | let result = decode_s33(input); |
1572 | | assert_eq!(result, Some((i64::from(i32::MIN) * 2, 5))); |
1573 | | |
1574 | | let input = [0x00, 0x00, 0x00, 0x00, 0x00]; |
1575 | | let result = decode_s33(input); |
1576 | | assert_eq!(result, Some((0, 1))); |
1577 | | |
1578 | | // Valid but in-efficient way to encode 0. |
1579 | | let input = [0x80, 0x80, 0x80, 0x80, 0x00]; |
1580 | | let result = decode_s33(input); |
1581 | | assert_eq!(result, Some((0, 5))); |
1582 | | |
1583 | | let input = [0x40, 0x00, 0x00, 0x00, 0x00]; |
1584 | | let result = decode_s33(input); |
1585 | | assert_eq!(result, Some((-64, 1))); |
1586 | | |
1587 | | // Valid but in-efficient way to encode -64. |
1588 | | let input = [0xc0, 0x7f, 0x00, 0x00, 0x00]; |
1589 | | let result = decode_s33(input); |
1590 | | assert_eq!(result, Some((-64, 2))); |
1591 | | } |
1592 | | |
1593 | | #[test] |
1594 | | fn test_decode_s33_errors() { |
1595 | | decode_sint_arr!(decode_s33, i64, 33); |
1596 | | |
1597 | | // Maximum of 5 bytes encoding, the 0x80 bit must not be set in the final byte. |
1598 | | let input = [0x80, 0x80, 0x80, 0x80, 0x80]; |
1599 | | let result = decode_s33(input); |
1600 | | assert_eq!(result, None); |
1601 | | |
1602 | | // If the highest valid bit is set, it should be sign extended. (final byte should be 0x70) |
1603 | | let input = [0x80, 0x80, 0x80, 0x80, 0x10]; |
1604 | | let result = decode_s33(input); |
1605 | | assert_eq!(result, None); |
1606 | | |
1607 | | // If the highest valid bit is set, it should be sign extended. (final byte should be 0x70) |
1608 | | let input = [0x80, 0x80, 0x80, 0x80, 0x30]; |
1609 | | let result = decode_s33(input); |
1610 | | assert_eq!(result, None); |
1611 | | } |
1612 | | |
1613 | | #[test] |
1614 | | fn test_decode_s64() { |
1615 | | let input = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00]; |
1616 | | let result = decode_s64(input); |
1617 | | assert_eq!(result, Some((i64::MAX, 10))); |
1618 | | |
1619 | | let input = [0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f]; |
1620 | | let result = decode_s64(input); |
1621 | | assert_eq!(result, Some((i64::MIN, 10))); |
1622 | | |
1623 | | let input = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; |
1624 | | let result = decode_s64(input); |
1625 | | assert_eq!(result, Some((0, 1))); |
1626 | | |
1627 | | // Valid but in-efficient way to encode 0. |
1628 | | let input = [0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00]; |
1629 | | let result = decode_s64(input); |
1630 | | assert_eq!(result, Some((0, 10))); |
1631 | | } |
1632 | | |
1633 | | #[test] |
1634 | | fn test_decode_s64_errors() { |
1635 | | // Maximum of 10 bytes encoding, the 0x80 bit must not be set in the final byte. |
1636 | | let input = [0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80]; |
1637 | | let result = decode_s64(input); |
1638 | | assert_eq!(result, None); |
1639 | | |
1640 | | // If the highest valid bit is set, it should be sign extended. (final byte should be 0x78) |
1641 | | let input = [0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x08]; |
1642 | | let result = decode_s64(input); |
1643 | | assert_eq!(result, None); |
1644 | | |
1645 | | // If the highest valid bit is set, it should be sign extended. (final byte should be 0x78) |
1646 | | let input = [0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x28]; |
1647 | | let result = decode_s64(input); |
1648 | | assert_eq!(result, None); |
1649 | | } |
1650 | | } |