qubit_codec_binary/codec/leb128_codec.rs
1// =============================================================================
2// Copyright (c) 2026 Haixing Hu.
3//
4// SPDX-License-Identifier: Apache-2.0
5//
6// Licensed under the Apache License, Version 2.0.
7// =============================================================================
8
9use core::{
10 convert::Infallible,
11 marker::PhantomData,
12 num::NonZeroUsize,
13};
14
15use qubit_codec::Codec;
16
17use crate::{
18 Leb128DecodeError,
19 Leb128DecodePolicy,
20 NonStrict,
21};
22
23/// Type-level unchecked LEB128 codec.
24///
25/// Encoding is always canonical; `P` only affects decoding.
26///
27/// # Type Parameters
28///
29/// - `T`: Integer value type to decode from LEB128 bytes and encode into
30/// canonical LEB128 bytes.
31/// - `P`: Type-level decoding policy implementing [`Leb128DecodePolicy`]. Use
32/// [`crate::Strict`] to reject non-canonical inputs, or [`NonStrict`] to
33/// accept non-canonical inputs.
34///
35/// # Examples
36///
37/// ```
38/// use qubit_codec_binary::{
39/// Leb128Codec,
40/// NonStrict,
41/// };
42///
43/// let mut output = [0_u8; Leb128Codec::<u64, NonStrict>::MAX_UNITS_PER_VALUE];
44/// let written = unsafe {
45/// Leb128Codec::<u64, NonStrict>::encode_unchecked(300, &mut output, 0)
46/// };
47/// assert_eq!(2, written);
48///
49/// let (decoded, consumed) = unsafe {
50/// Leb128Codec::<u64, NonStrict>::decode_unchecked(&output[..written], 0)
51/// }.expect("canonical LEB128 value should decode");
52/// assert_eq!(300, decoded);
53/// assert_eq!(2, consumed.get());
54/// ```
55#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
56pub struct Leb128Codec<T, P = NonStrict> {
57 marker: PhantomData<fn() -> (T, P)>,
58}
59
60macro_rules! impl_unsigned_leb128_codec {
61 ($ty:ty) => {
62 impl<P> Leb128Codec<$ty, P>
63 where
64 P: Leb128DecodePolicy,
65 {
66 /// Minimum number of bytes that can represent a complete value.
67 pub const MIN_UNITS_PER_VALUE: usize = 1;
68
69 /// Maximum number of bytes required to encode or decode this type.
70 pub const MAX_UNITS_PER_VALUE: usize =
71 (<$ty>::BITS as usize).div_ceil(7);
72
73 /// Decodes a value from `input` starting at `index` without bounds
74 /// checks.
75 ///
76 /// # Parameters
77 ///
78 /// - `input`: Source byte buffer.
79 /// - `index`: Start index in `input`.
80 ///
81 /// # Returns
82 ///
83 /// Returns the decoded value and the non-zero number of consumed
84 /// bytes.
85 ///
86 /// # Errors
87 ///
88 /// Returns [`Leb128DecodeError`] if the bytes are incomplete,
89 /// malformed, or strict decoding rejects a non-canonical
90 /// representation.
91 ///
92 /// # Safety
93 ///
94 /// The caller must guarantee that `index` is a valid boundary and
95 /// at least [`Self::MIN_UNITS_PER_VALUE`] byte is readable from
96 /// `index`.
97 #[inline(always)]
98 pub unsafe fn decode_unchecked(
99 input: &[u8],
100 index: usize,
101 ) -> Result<($ty, core::num::NonZeroUsize), Leb128DecodeError> {
102 debug_assert!(
103 input.len().saturating_sub(index)
104 >= Self::MIN_UNITS_PER_VALUE
105 );
106
107 // SAFETY: The caller guarantees enough readable bytes for this
108 // type.
109 let (value, consumed) = unsafe {
110 read_uleb_unchecked::<P>(
111 input,
112 index,
113 <$ty>::BITS,
114 Self::MAX_UNITS_PER_VALUE,
115 )?
116 };
117 Ok((value as $ty, consumed))
118 }
119
120 /// Encodes `value` into `output` starting at `index` without bounds
121 /// checks.
122 ///
123 /// # Parameters
124 ///
125 /// - `value`: Value to encode.
126 /// - `output`: Destination byte buffer.
127 /// - `index`: Start index in `output`.
128 ///
129 /// # Returns
130 ///
131 /// Returns the number of written bytes.
132 ///
133 /// # Safety
134 ///
135 /// The caller must guarantee that `output.as_mut_ptr().add(index)`
136 /// is valid to write [`Self::MAX_UNITS_PER_VALUE`] bytes.
137 #[inline(always)]
138 pub unsafe fn encode_unchecked(
139 value: $ty,
140 output: &mut [u8],
141 index: usize,
142 ) -> usize {
143 // SAFETY: The caller guarantees enough writable bytes for this
144 // type.
145 unsafe { write_uleb_unchecked(output, index, value as u128) }
146 }
147 }
148
149 unsafe impl<P> Codec for Leb128Codec<$ty, P>
150 where
151 P: Leb128DecodePolicy,
152 {
153 type Value = $ty;
154 type Unit = u8;
155 type DecodeError = Leb128DecodeError;
156 type EncodeError = Infallible;
157
158 #[inline(always)]
159 fn min_units_per_value(&self) -> core::num::NonZeroUsize {
160 core::num::NonZeroUsize::MIN
161 }
162
163 #[inline(always)]
164 fn max_units_per_value(&self) -> core::num::NonZeroUsize {
165 // SAFETY: LEB128 has a non-zero maximum encoded width.
166 unsafe {
167 core::num::NonZeroUsize::new_unchecked(
168 Self::MAX_UNITS_PER_VALUE,
169 )
170 }
171 }
172
173 #[inline(always)]
174 unsafe fn decode_unchecked(
175 &self,
176 input: &[u8],
177 index: usize,
178 ) -> Result<($ty, core::num::NonZeroUsize), Self::DecodeError> {
179 debug_assert!(
180 input.len().saturating_sub(index)
181 >= Self::MIN_UNITS_PER_VALUE
182 );
183
184 // SAFETY: The caller upholds the `Codec::decode_unchecked`
185 // contract.
186 unsafe { Self::decode_unchecked(input, index) }
187 }
188
189 #[inline(always)]
190 unsafe fn encode_unchecked(
191 &self,
192 value: &$ty,
193 output: &mut [u8],
194 index: usize,
195 ) -> Result<usize, Self::EncodeError> {
196 debug_assert!(
197 output.len().saturating_sub(index)
198 >= Self::MAX_UNITS_PER_VALUE
199 );
200
201 // SAFETY: The caller upholds the `Codec::encode_unchecked`
202 // contract.
203 Ok(unsafe { Self::encode_unchecked(*value, output, index) })
204 }
205 }
206 };
207}
208
209macro_rules! impl_signed_leb128_codec {
210 ($ty:ty) => {
211 impl<P> Leb128Codec<$ty, P>
212 where
213 P: Leb128DecodePolicy,
214 {
215 /// Minimum number of bytes that can represent a complete value.
216 pub const MIN_UNITS_PER_VALUE: usize = 1;
217
218 /// Maximum number of bytes required to encode or decode this type.
219 pub const MAX_UNITS_PER_VALUE: usize =
220 (<$ty>::BITS as usize).div_ceil(7);
221
222 /// Decodes a value from `input` starting at `index` without bounds
223 /// checks.
224 ///
225 /// # Parameters
226 ///
227 /// - `input`: Source byte buffer.
228 /// - `index`: Start index in `input`.
229 ///
230 /// # Returns
231 ///
232 /// Returns the decoded value and the non-zero number of consumed
233 /// bytes.
234 ///
235 /// # Errors
236 ///
237 /// Returns [`Leb128DecodeError`] if the bytes are incomplete,
238 /// malformed, or strict decoding rejects a non-canonical
239 /// representation.
240 ///
241 /// # Safety
242 ///
243 /// The caller must guarantee that `index` is a valid boundary and
244 /// at least [`Self::MIN_UNITS_PER_VALUE`] byte is readable from
245 /// `index`.
246 #[inline(always)]
247 pub unsafe fn decode_unchecked(
248 input: &[u8],
249 index: usize,
250 ) -> Result<($ty, core::num::NonZeroUsize), Leb128DecodeError> {
251 debug_assert!(
252 input.len().saturating_sub(index)
253 >= Self::MIN_UNITS_PER_VALUE
254 );
255
256 // SAFETY: The caller guarantees enough readable bytes for this
257 // type.
258 let (value, consumed) = unsafe {
259 read_sleb_unchecked::<P>(
260 input,
261 index,
262 <$ty>::BITS,
263 Self::MAX_UNITS_PER_VALUE,
264 )?
265 };
266 Ok((value as $ty, consumed))
267 }
268
269 /// Encodes `value` into `output` starting at `index` without bounds
270 /// checks.
271 ///
272 /// # Parameters
273 ///
274 /// - `value`: Value to encode.
275 /// - `output`: Destination byte buffer.
276 /// - `index`: Start index in `output`.
277 ///
278 /// # Returns
279 ///
280 /// Returns the number of written bytes.
281 ///
282 /// # Safety
283 ///
284 /// The caller must guarantee that `output.as_mut_ptr().add(index)`
285 /// is valid to write [`Self::MAX_UNITS_PER_VALUE`] bytes.
286 #[inline(always)]
287 pub unsafe fn encode_unchecked(
288 value: $ty,
289 output: &mut [u8],
290 index: usize,
291 ) -> usize {
292 // SAFETY: The caller guarantees enough writable bytes for this
293 // type.
294 unsafe { write_sleb_unchecked(output, index, value as i128) }
295 }
296 }
297
298 unsafe impl<P> Codec for Leb128Codec<$ty, P>
299 where
300 P: Leb128DecodePolicy,
301 {
302 type Value = $ty;
303 type Unit = u8;
304 type DecodeError = Leb128DecodeError;
305 type EncodeError = Infallible;
306
307 #[inline(always)]
308 fn min_units_per_value(&self) -> core::num::NonZeroUsize {
309 core::num::NonZeroUsize::MIN
310 }
311
312 #[inline(always)]
313 fn max_units_per_value(&self) -> core::num::NonZeroUsize {
314 // SAFETY: LEB128 has a non-zero maximum encoded width.
315 unsafe {
316 core::num::NonZeroUsize::new_unchecked(
317 Self::MAX_UNITS_PER_VALUE,
318 )
319 }
320 }
321
322 #[inline(always)]
323 unsafe fn decode_unchecked(
324 &self,
325 input: &[u8],
326 index: usize,
327 ) -> Result<($ty, core::num::NonZeroUsize), Self::DecodeError> {
328 debug_assert!(
329 input.len().saturating_sub(index)
330 >= Self::MIN_UNITS_PER_VALUE
331 );
332
333 // SAFETY: The caller upholds the `Codec::decode_unchecked`
334 // contract.
335 unsafe { Self::decode_unchecked(input, index) }
336 }
337
338 #[inline(always)]
339 unsafe fn encode_unchecked(
340 &self,
341 value: &$ty,
342 output: &mut [u8],
343 index: usize,
344 ) -> Result<usize, Self::EncodeError> {
345 debug_assert!(
346 output.len().saturating_sub(index)
347 >= Self::MAX_UNITS_PER_VALUE
348 );
349
350 // SAFETY: The caller upholds the `Codec::encode_unchecked`
351 // contract.
352 Ok(unsafe { Self::encode_unchecked(*value, output, index) })
353 }
354 }
355 };
356}
357
358impl_unsigned_leb128_codec!(u8);
359impl_unsigned_leb128_codec!(u16);
360impl_unsigned_leb128_codec!(u32);
361impl_unsigned_leb128_codec!(u64);
362impl_unsigned_leb128_codec!(u128);
363impl_unsigned_leb128_codec!(usize);
364
365impl_signed_leb128_codec!(i8);
366impl_signed_leb128_codec!(i16);
367impl_signed_leb128_codec!(i32);
368impl_signed_leb128_codec!(i64);
369impl_signed_leb128_codec!(i128);
370impl_signed_leb128_codec!(isize);
371
372/// Decodes an unsigned LEB128 value without bounds checks.
373///
374/// # Type Parameters
375///
376/// - `P`: Type-level decoding policy used to decide whether non-canonical
377/// encodings are accepted.
378///
379/// # Parameters
380///
381/// - `input`: Source byte buffer.
382/// - `index`: Start index in `input`.
383/// - `bits`: Bit width of the target integer type.
384/// - `max_bytes`: Maximum number of bytes allowed for that target width.
385///
386/// # Returns
387///
388/// Returns the decoded value and the non-zero number of consumed bytes.
389///
390/// # Errors
391///
392/// Returns [`Leb128DecodeError`] when the byte sequence is incomplete,
393/// malformed, or when `P` rejects a non-canonical encoding.
394///
395/// # Safety
396///
397/// The caller must guarantee that at least one byte is readable from `index`.
398#[inline]
399unsafe fn read_uleb_unchecked<P>(
400 input: &[u8],
401 index: usize,
402 bits: u32,
403 max_bytes: usize,
404) -> Result<(u128, core::num::NonZeroUsize), Leb128DecodeError>
405where
406 P: Leb128DecodePolicy,
407{
408 debug_assert!(input.len().saturating_sub(index) >= 1);
409
410 let available = input.len().saturating_sub(index).min(max_bytes);
411 // SAFETY: The caller guarantees that the currently available bytes are
412 // readable from `index`.
413 match unsafe {
414 read_uleb_prefix_unchecked::<P>(
415 input, index, bits, max_bytes, available,
416 )
417 } {
418 Ok(Some((value, consumed))) => {
419 debug_assert!(consumed > 0);
420 // SAFETY: Prefix readers only return `Some` after consuming at
421 // least one terminating byte.
422 let consumed =
423 unsafe { core::num::NonZeroUsize::new_unchecked(consumed) };
424 Ok((value, consumed))
425 }
426 Ok(None) => {
427 debug_assert!(
428 available < usize::MAX,
429 "available byte count overflowed"
430 );
431 // SAFETY: Adding one to the available byte count produces a
432 // non-zero retry lower bound.
433 let required =
434 unsafe { NonZeroUsize::new_unchecked(available + 1) };
435 Err(Leb128DecodeError::incomplete(index, required, available))
436 }
437 Err(error) => Err(error),
438 }
439}
440
441/// Tries to decode an unsigned LEB128 value from currently available bytes.
442///
443/// # Type Parameters
444///
445/// - `P`: Type-level decoding policy used to decide whether non-canonical
446/// encodings are accepted.
447///
448/// # Parameters
449///
450/// - `input`: Source byte buffer.
451/// - `index`: Start index in `input`.
452/// - `bits`: Bit width of the target integer type.
453/// - `max_bytes`: Maximum number of bytes allowed for that target width.
454/// - `available`: Number of bytes currently readable from `index`.
455///
456/// # Returns
457///
458/// Returns `Ok(Some((value, consumed)))` when a complete value is decoded,
459/// `Ok(None)` when more bytes are needed, or `Err(error)` when the payload is
460/// invalid. Invalid errors carry the consumable byte count.
461///
462/// # Safety
463///
464/// The caller must guarantee that `input.as_ptr().add(index)` is valid to read
465/// `available` bytes and that `available <= max_bytes`.
466#[inline]
467unsafe fn read_uleb_prefix_unchecked<P>(
468 input: &[u8],
469 index: usize,
470 bits: u32,
471 max_bytes: usize,
472 available: usize,
473) -> Result<Option<(u128, usize)>, Leb128DecodeError>
474where
475 P: Leb128DecodePolicy,
476{
477 debug_assert!(
478 available <= max_bytes,
479 "available bytes exceed LEB128 maximum width"
480 );
481 let mut value = 0u128;
482 let mut shift = 0u32;
483 // SAFETY: The caller guarantees that `available` bytes are readable from
484 // `index`, so this base pointer can be advanced by every loop offset.
485 let base = unsafe { input.as_ptr().add(index) };
486 for offset in 0..available {
487 // SAFETY: The caller guarantees enough readable bytes for this loop.
488 let byte = unsafe { *base.add(offset) };
489 let payload = u128::from(byte & 0x7F);
490 value |= payload << shift;
491 if byte & 0x80 == 0 {
492 if offset == max_bytes - 1
493 && !unsigned_final_payload_fits(byte, bits, offset)
494 {
495 return Err(malformed_decode_error(
496 index,
497 index + offset,
498 offset + 1,
499 ));
500 }
501 let consumed = offset + 1;
502 if P::STRICT && !has_canonical_uleb_len(value, consumed) {
503 return Err(noncanonical_decode_error(index, consumed));
504 }
505 return Ok(Some((value, consumed)));
506 }
507 shift += 7;
508 }
509 if available < max_bytes {
510 return Ok(None);
511 }
512 Err(malformed_decode_error(
513 index,
514 index + max_bytes - 1,
515 max_bytes,
516 ))
517}
518
519/// Decodes a signed LEB128 value without bounds checks.
520///
521/// # Type Parameters
522///
523/// - `P`: Type-level decoding policy used to decide whether non-canonical
524/// encodings are accepted.
525///
526/// # Parameters
527///
528/// - `input`: Source byte buffer.
529/// - `index`: Start index in `input`.
530/// - `bits`: Bit width of the target integer type.
531/// - `max_bytes`: Maximum number of bytes allowed for that target width.
532///
533/// # Returns
534///
535/// Returns the decoded value and the non-zero number of consumed bytes.
536///
537/// # Errors
538///
539/// Returns [`Leb128DecodeError`] when the byte sequence is incomplete,
540/// malformed, or when `P` rejects a non-canonical encoding.
541///
542/// # Safety
543///
544/// The caller must guarantee that at least one byte is readable from `index`.
545#[inline]
546unsafe fn read_sleb_unchecked<P>(
547 input: &[u8],
548 index: usize,
549 bits: u32,
550 max_bytes: usize,
551) -> Result<(i128, core::num::NonZeroUsize), Leb128DecodeError>
552where
553 P: Leb128DecodePolicy,
554{
555 debug_assert!(input.len().saturating_sub(index) >= 1);
556
557 let available = input.len().saturating_sub(index).min(max_bytes);
558 // SAFETY: The caller guarantees that the currently available bytes are
559 // readable from `index`.
560 match unsafe {
561 read_sleb_prefix_unchecked::<P>(
562 input, index, bits, max_bytes, available,
563 )
564 } {
565 Ok(Some((value, consumed))) => {
566 debug_assert!(consumed > 0);
567 // SAFETY: Prefix readers only return `Some` after consuming at
568 // least one terminating byte.
569 let consumed =
570 unsafe { core::num::NonZeroUsize::new_unchecked(consumed) };
571 Ok((value, consumed))
572 }
573 Ok(None) => {
574 debug_assert!(
575 available < usize::MAX,
576 "available byte count overflowed"
577 );
578 // SAFETY: Adding one to the available byte count produces a
579 // non-zero retry lower bound.
580 let required =
581 unsafe { NonZeroUsize::new_unchecked(available + 1) };
582 Err(Leb128DecodeError::incomplete(index, required, available))
583 }
584 Err(error) => Err(error),
585 }
586}
587
588/// Tries to decode a signed LEB128 value from currently available bytes.
589///
590/// # Type Parameters
591///
592/// - `P`: Type-level decoding policy used to decide whether non-canonical
593/// encodings are accepted.
594///
595/// # Parameters
596///
597/// - `input`: Source byte buffer.
598/// - `index`: Start index in `input`.
599/// - `bits`: Bit width of the target integer type.
600/// - `max_bytes`: Maximum number of bytes allowed for that target width.
601/// - `available`: Number of bytes currently readable from `index`.
602///
603/// # Returns
604///
605/// Returns `Ok(Some((value, consumed)))` when a complete value is decoded,
606/// `Ok(None)` when more bytes are needed, or `Err(error)` when the payload is
607/// invalid. Invalid errors carry the consumable byte count.
608///
609/// # Safety
610///
611/// The caller must guarantee that `input.as_ptr().add(index)` is valid to read
612/// `available` bytes and that `available <= max_bytes`.
613#[inline]
614unsafe fn read_sleb_prefix_unchecked<P>(
615 input: &[u8],
616 index: usize,
617 bits: u32,
618 max_bytes: usize,
619 available: usize,
620) -> Result<Option<(i128, usize)>, Leb128DecodeError>
621where
622 P: Leb128DecodePolicy,
623{
624 debug_assert!(
625 available <= max_bytes,
626 "available bytes exceed LEB128 maximum width"
627 );
628 let mut value = 0i128;
629 let mut shift = 0u32;
630 // SAFETY: The caller guarantees that `available` bytes are readable from
631 // `index`, so this base pointer can be advanced by every loop offset.
632 let base = unsafe { input.as_ptr().add(index) };
633 for offset in 0..available {
634 // SAFETY: The caller guarantees enough readable bytes for this loop.
635 let byte = unsafe { *base.add(offset) };
636 let payload = i128::from(byte & 0x7F);
637 value |= payload << shift;
638 if byte & 0x80 == 0 {
639 if offset == max_bytes - 1
640 && !signed_final_payload_fits(byte, bits, offset)
641 {
642 return Err(malformed_decode_error(
643 index,
644 index + offset,
645 offset + 1,
646 ));
647 }
648 if byte & 0x40 != 0 && shift + 7 < i128::BITS {
649 value |= (!0i128) << (shift + 7);
650 }
651 let consumed = offset + 1;
652 if P::STRICT && !has_canonical_sleb_len(value, consumed) {
653 return Err(noncanonical_decode_error(index, consumed));
654 }
655 return Ok(Some((value, consumed)));
656 }
657 shift += 7;
658 }
659 if available < max_bytes {
660 return Ok(None);
661 }
662 Err(malformed_decode_error(
663 index,
664 index + max_bytes - 1,
665 max_bytes,
666 ))
667}
668
669/// Builds a malformed LEB128 error on the cold error path.
670///
671/// # Parameters
672///
673/// - `start_index`: Absolute byte index where the malformed payload starts.
674/// - `error_index`: Absolute byte index associated with the malformed payload.
675/// - `consumed`: Number of bytes that should be consumed before reporting the
676/// error.
677///
678/// # Returns
679///
680/// Returns the error carrying the byte count to consume.
681#[cold]
682fn malformed_decode_error(
683 start_index: usize,
684 error_index: usize,
685 consumed: usize,
686) -> Leb128DecodeError {
687 debug_assert!(consumed > 0, "malformed LEB128 errors must consume bytes");
688 // SAFETY: All malformed call sites pass either `offset + 1` or `max_bytes`,
689 // both of which are non-zero for supported LEB128 codecs.
690 let consumed = unsafe { NonZeroUsize::new_unchecked(consumed) };
691 Leb128DecodeError::malformed(start_index, error_index, consumed)
692}
693
694/// Builds a non-canonical LEB128 error on the cold error path.
695///
696/// # Parameters
697///
698/// - `index`: Absolute byte index at which the non-canonical payload starts.
699/// - `consumed`: Number of bytes that should be consumed before reporting the
700/// error.
701///
702/// # Returns
703///
704/// Returns the error carrying the byte count to consume.
705#[cold]
706fn noncanonical_decode_error(
707 index: usize,
708 consumed: usize,
709) -> Leb128DecodeError {
710 debug_assert!(
711 consumed > 0,
712 "non-canonical LEB128 errors must consume bytes"
713 );
714 // SAFETY: Non-canonical errors are detected only after reading at least one
715 // terminating byte.
716 let consumed = unsafe { NonZeroUsize::new_unchecked(consumed) };
717 Leb128DecodeError::noncanonical(index, consumed)
718}
719
720/// Checks whether the final unsigned LEB128 payload byte fits the target width.
721///
722/// # Parameters
723///
724/// - `byte`: Final LEB128 byte to validate.
725/// - `bits`: Bit width of the target unsigned integer type.
726/// - `offset`: Zero-based byte offset of `byte` within the encoded value.
727///
728/// # Returns
729///
730/// Returns `true` if the unused payload bits are all zero.
731#[must_use]
732#[inline(always)]
733fn unsigned_final_payload_fits(byte: u8, bits: u32, offset: usize) -> bool {
734 let used_bits = bits - offset as u32 * 7;
735 byte >> used_bits == 0
736}
737
738/// Checks whether the final signed LEB128 payload byte fits the target width.
739///
740/// # Parameters
741///
742/// - `byte`: Final LEB128 byte to validate.
743/// - `bits`: Bit width of the target signed integer type.
744/// - `offset`: Zero-based byte offset of `byte` within the encoded value.
745///
746/// # Returns
747///
748/// Returns `true` if the unused payload bits are a valid sign extension.
749#[must_use]
750#[inline(always)]
751fn signed_final_payload_fits(byte: u8, bits: u32, offset: usize) -> bool {
752 let used_bits = bits - offset as u32 * 7;
753 let payload = byte & 0x7F;
754 let used_mask = ((1u16 << used_bits) - 1) as u8;
755 let unused_mask = 0x7F & !used_mask;
756 let sign_bit = 1u8 << (used_bits - 1);
757 if payload & sign_bit == 0 {
758 payload & unused_mask == 0
759 } else {
760 payload & unused_mask == unused_mask
761 }
762}
763
764/// Checks whether an unsigned LEB128 value used its canonical encoded length.
765///
766/// # Parameters
767///
768/// - `value`: Decoded unsigned value.
769/// - `actual_len`: Number of bytes consumed from the input.
770///
771/// # Returns
772///
773/// Returns `true` if `actual_len` is the canonical encoded length of `value`.
774#[must_use]
775#[inline(always)]
776fn has_canonical_uleb_len(value: u128, actual_len: usize) -> bool {
777 canonical_uleb_len(value) == actual_len
778}
779
780/// Checks whether a signed LEB128 value used its canonical encoded length.
781///
782/// # Parameters
783///
784/// - `value`: Decoded signed value.
785/// - `actual_len`: Number of bytes consumed from the input.
786///
787/// # Returns
788///
789/// Returns `true` if `actual_len` is the canonical encoded length of `value`.
790#[must_use]
791#[inline(always)]
792fn has_canonical_sleb_len(value: i128, actual_len: usize) -> bool {
793 canonical_sleb_len(value) == actual_len
794}
795
796/// Computes the canonical unsigned LEB128 encoded length.
797///
798/// # Parameters
799///
800/// - `value`: Unsigned value to measure.
801///
802/// # Returns
803///
804/// Returns the number of bytes used by the canonical unsigned LEB128 encoding.
805#[must_use]
806#[inline]
807fn canonical_uleb_len(mut value: u128) -> usize {
808 let mut len = 1;
809 while value >= 0x80 {
810 value >>= 7;
811 len += 1;
812 }
813 len
814}
815
816/// Computes the canonical signed LEB128 encoded length.
817///
818/// # Parameters
819///
820/// - `value`: Signed value to measure.
821///
822/// # Returns
823///
824/// Returns the number of bytes used by the canonical signed LEB128 encoding.
825#[must_use]
826#[inline]
827fn canonical_sleb_len(mut value: i128) -> usize {
828 let mut len = 0;
829 loop {
830 let byte = (value & 0x7F) as u8;
831 let sign_bit_set = byte & 0x40 != 0;
832 value >>= 7;
833 len += 1;
834 if (value == 0 && !sign_bit_set) || (value == -1 && sign_bit_set) {
835 return len;
836 }
837 }
838}
839
840/// Encodes an unsigned integer as canonical LEB128 without bounds checks.
841///
842/// # Parameters
843///
844/// - `output`: Destination byte buffer.
845/// - `index`: Start index in `output`.
846/// - `value`: Unsigned value to encode.
847///
848/// # Returns
849///
850/// Returns the number of written bytes.
851///
852/// # Safety
853///
854/// The caller must guarantee that `output.as_mut_ptr().add(index)` is valid to
855/// write the full canonical LEB128 representation of `value`.
856unsafe fn write_uleb_unchecked(
857 output: &mut [u8],
858 index: usize,
859 mut value: u128,
860) -> usize {
861 let mut offset = 0;
862 loop {
863 let mut byte = (value & 0x7F) as u8;
864 value >>= 7;
865 if value != 0 {
866 byte |= 0x80;
867 }
868 // SAFETY: The caller guarantees enough writable bytes for the encoded
869 // value.
870 unsafe {
871 *output.as_mut_ptr().add(index + offset) = byte;
872 }
873 offset += 1;
874 if value == 0 {
875 return offset;
876 }
877 }
878}
879
880/// Encodes a signed integer as canonical LEB128 without bounds checks.
881///
882/// # Parameters
883///
884/// - `output`: Destination byte buffer.
885/// - `index`: Start index in `output`.
886/// - `value`: Signed value to encode.
887///
888/// # Returns
889///
890/// Returns the number of written bytes.
891///
892/// # Safety
893///
894/// The caller must guarantee that `output.as_mut_ptr().add(index)` is valid to
895/// write the full canonical LEB128 representation of `value`.
896unsafe fn write_sleb_unchecked(
897 output: &mut [u8],
898 index: usize,
899 mut value: i128,
900) -> usize {
901 let mut offset = 0;
902 loop {
903 let mut byte = (value & 0x7F) as u8;
904 let sign_bit_set = byte & 0x40 != 0;
905 value >>= 7;
906 let done =
907 (value == 0 && !sign_bit_set) || (value == -1 && sign_bit_set);
908 if !done {
909 byte |= 0x80;
910 }
911 // SAFETY: The caller guarantees enough writable bytes for the encoded
912 // value.
913 unsafe {
914 *output.as_mut_ptr().add(index + offset) = byte;
915 }
916 offset += 1;
917 if done {
918 return offset;
919 }
920 }
921}