Skip to main content

varing/
primitives.rs

1use core::num::{NonZeroU64, NonZeroUsize};
2
3use super::{
4  ConstDecodeError, ConstEncodeError, DecodeError, EncodeError, Varint,
5  utils::{self, zigzag_encode_i64},
6};
7
8macro_rules! impl_varint {
9  ($($ty:literal), +$(,)?) => {
10    $(
11      paste::paste! {
12        impl Varint for [< u $ty >] {
13          const MIN_ENCODED_LEN: ::core::num::NonZeroUsize = [< encoded_ u $ty _varint_len >](0);
14          const MAX_ENCODED_LEN: ::core::num::NonZeroUsize = [< encoded_ u $ty _varint_len >](<[< u $ty >]>::MAX);
15
16          #[inline]
17          fn encoded_len(&self) -> ::core::num::NonZeroUsize {
18            [< encoded_ u $ty _varint_len >](*self)
19          }
20
21          fn encode(&self, buf: &mut [u8]) -> Result<::core::num::NonZeroUsize, EncodeError> {
22            [< encode_ u $ty _varint_to >](*self, buf).map_err(Into::into)
23          }
24
25          #[inline]
26          fn decode(buf: &[u8]) -> Result<(::core::num::NonZeroUsize, Self), DecodeError> {
27            [< decode_ u $ty _varint >](buf).map_err(Into::into)
28          }
29        }
30
31        impl Varint for [< i $ty >] {
32          const MIN_ENCODED_LEN: ::core::num::NonZeroUsize = [< encoded_ i $ty _varint_len >](0);
33          const MAX_ENCODED_LEN: ::core::num::NonZeroUsize = [< encoded_ i $ty _varint_len >](<[< i $ty >]>::MAX);
34
35          #[inline]
36          fn encoded_len(&self) -> ::core::num::NonZeroUsize {
37            [< encoded_ i $ty _varint_len >](*self)
38          }
39
40          fn encode(&self, buf: &mut [u8]) -> Result<::core::num::NonZeroUsize, EncodeError> {
41            [< encode_ i $ty _varint_to >](*self, buf).map_err(Into::into)
42          }
43
44          #[inline]
45          fn decode(buf: &[u8]) -> Result<(::core::num::NonZeroUsize, Self), DecodeError> {
46            [< decode_ i $ty _varint >](buf).map_err(Into::into)
47          }
48        }
49      }
50    )*
51  };
52}
53
54macro_rules! decode_varint {
55  (|$buf:ident| $ty:ident) => {{
56    const MAX_ENCODED_LEN: usize = <$ty as Varint>::MAX_ENCODED_LEN.get();
57
58    let mut result = 0;
59    let mut shift = 0;
60    let mut index = 0;
61
62    loop {
63      if index == MAX_ENCODED_LEN {
64        return Err(ConstDecodeError::Overflow);
65      }
66
67      if index >= $buf.len() {
68        return Err(ConstDecodeError::insufficient_data($buf.len()));
69      }
70
71      let next = $buf[index] as $ty;
72
73      let v = $ty::BITS as usize / 7 * 7;
74      let has_overflow = if shift < v {
75        false
76      } else if shift == v {
77        next & ((u8::MAX << (::core::mem::size_of::<$ty>() % 7)) as $ty) != 0
78      } else {
79        true
80      };
81
82      if has_overflow {
83        return Err(ConstDecodeError::Overflow);
84      }
85
86      result += (next & 0x7F) << shift;
87      if next & 0x80 == 0 {
88        break;
89      }
90      shift += 7;
91      index += 1;
92    }
93    // Safety: +1 guaranteed to be non-zero
94    Ok((
95      unsafe { ::core::num::NonZeroUsize::new_unchecked(index + 1) },
96      result,
97    ))
98  }};
99}
100
101macro_rules! encode_varint {
102  ($buf:ident[$x:ident]) => {{
103    let mut i = 0;
104
105    while $x >= 0x80 {
106      if i >= $buf.len() {
107        panic!("insufficient buffer capacity");
108      }
109
110      $buf[i] = ($x as u8) | 0x80;
111      $x >>= 7;
112      i += 1;
113    }
114
115    // Check buffer capacity before writing final byte
116    if i >= $buf.len() {
117      panic!("insufficient buffer capacity");
118    }
119
120    $buf[i] = $x as u8;
121    i + 1
122  }};
123  (@to_buf $ty:ident::$buf:ident[$x:ident]) => {{
124    paste::paste! {
125      let mut i = 0;
126      let orig = $x;
127
128      while $x >= 0x80 {
129        if i >= $buf.len() {
130          return Err(ConstEncodeError::insufficient_space([< encoded_ $ty _varint_len >](orig), $buf.len()));
131        }
132
133        $buf[i] = ($x as u8) | 0x80;
134        $x >>= 7;
135        i += 1;
136      }
137
138      // Check buffer capacity before writing final byte
139      if i >= $buf.len() {
140        // Safety: +1 guaranteed to be non-zero
141        return Err(ConstEncodeError::insufficient_space(unsafe { ::core::num::NonZeroUsize::new_unchecked(i + 1) }, $buf.len()));
142      }
143
144      $buf[i] = $x as u8;
145      // Safety: +1 guaranteed to be non-zero
146      Ok(unsafe { ::core::num::NonZeroUsize::new_unchecked(i + 1) })
147    }
148  }};
149}
150
151macro_rules! varint_len {
152  ($($ty:ident),+$(,)?) => {
153    $(
154      paste::paste! {
155        /// Returns the encoded length of the value in LEB128 variable length format.
156        #[doc = "The returned value will be in range of [`" $ty "::ENCODED_LEN_RANGE`]."]
157        #[inline]
158        pub const fn [< encoded_ $ty _varint_len >](value: $ty) -> ::core::num::NonZeroUsize {
159          encoded_u64_varint_len(value as u64)
160        }
161      }
162    )*
163  };
164  (@zigzag $($ty:ident),+$(,)?) => {
165    $(
166      paste::paste! {
167        /// Returns the encoded length of the value in LEB128 variable length format.
168        #[doc = "The returned value will be in range of [`" $ty "::ENCODED_LEN_RANGE`]."]
169        #[inline]
170        pub const fn [< encoded_ $ty _varint_len >](value: $ty) -> ::core::num::NonZeroUsize {
171          encoded_i64_varint_len(value as i64)
172        }
173      }
174    )*
175  };
176}
177
178macro_rules! encode {
179  ($($ty:literal), +$(,)?) => {
180    $(
181      paste::paste! {
182        #[doc = "Encodes an `u" $ty "` value into LEB128 variable length format, and writes it to the buffer."]
183        #[inline]
184        pub const fn [< encode_ u $ty _varint >](mut x: [< u $ty >]) -> $crate::utils::Buffer<{ [<u $ty>]::MAX_ENCODED_LEN.get() + 1 }> {
185          let mut buf = [0; { [<u $ty>]::MAX_ENCODED_LEN.get() + 1 }];
186          let mut_buf = &mut buf;
187          let len = encode_varint!(mut_buf[x]);
188          buf[$crate::utils::Buffer::<{ [<u $ty>]::MAX_ENCODED_LEN.get() + 1 }>::CAPACITY.get()] = len as u8;
189          $crate::utils::Buffer::new(buf)
190        }
191
192        #[doc = "Encodes an `i" $ty "` value into LEB128 variable length format, and writes it to the buffer."]
193        #[inline]
194        pub const fn [< encode_ i $ty _varint >](x: [< i $ty >]) -> $crate::utils::Buffer<{ [<u $ty>]::MAX_ENCODED_LEN.get() + 1 }> {
195          let x = utils::[< zigzag_encode_i $ty>](x);
196          [< encode_ u $ty _varint >](x as [< u $ty >])
197        }
198
199        #[doc = "Encodes an `u" $ty "` value into LEB128 variable length format, and writes it to the buffer."]
200        #[inline]
201        pub const fn [< encode_ u $ty _varint_to >](mut x: [< u $ty >], buf: &mut [u8]) -> Result<::core::num::NonZeroUsize, ConstEncodeError> {
202          encode_varint!(@to_buf [< u $ty >]::buf[x])
203        }
204
205        #[doc = "Returns the encoded length of a sequence of `u" $ty "` values"]
206        #[inline]
207        pub const fn [< encoded_ u $ty _sequence_len >](sequence: &[[< u $ty >]]) -> usize {
208          encode!(@sequence_encoded_len_impl sequence, [< encoded_ u $ty _varint_len >])
209        }
210
211        #[doc = "Encodes a sequence of `u" $ty "` to the buffer."]
212        #[inline]
213        pub const fn [< encode_ u $ty _sequence_to >](sequence: &[[< u $ty >]], buf: &mut [u8]) -> Result<usize, ConstEncodeError> {
214          encode!(@sequence_encode_to_impl buf, sequence, [< encode_ u $ty _varint_to >], [< encoded_ u $ty _sequence_len >])
215        }
216
217        #[doc = "Encodes an `i" $ty "` value into LEB128 variable length format, and writes it to the buffer."]
218        #[inline]
219        pub const fn [< encode_ i $ty _varint_to >](x: [< i $ty >], buf: &mut [u8]) -> Result<::core::num::NonZeroUsize, ConstEncodeError> {
220          let mut x = utils::[< zigzag_encode_i $ty>](x);
221          encode_varint!(@to_buf [<u $ty>]::buf[x])
222        }
223
224        #[doc = "Returns the encoded length of a sequence of `i" $ty "` values"]
225        #[inline]
226        pub const fn [< encoded_i $ty _sequence_len >](sequence: &[[< i $ty >]]) -> usize {
227          encode!(@sequence_encoded_len_impl sequence, [< encoded_ i $ty _varint_len >])
228        }
229
230        #[doc = "Encodes a sequence of `i" $ty "` to the buffer."]
231        #[inline]
232        pub const fn [< encode_i $ty _sequence_to >](sequence: &[[< i $ty >]], buf: &mut [u8]) -> Result<usize, ConstEncodeError> {
233          encode!(@sequence_encode_to_impl buf, sequence, [< encode_ i $ty _varint_to >], [< encoded_ i $ty _sequence_len >])
234        }
235      }
236    )*
237  };
238  (@sequence_encode_to_impl $buf:ident, $sequence:ident, $encode_to:ident, $encoded_sequence_len:ident) => {{
239    let mut total_bytes = 0;
240    let mut idx = 0;
241    let len = $sequence.len();
242    let buf_len = $buf.len();
243
244    while idx < len && total_bytes < buf_len {
245      let (_, buf) = $buf.split_at_mut(total_bytes);
246      let bytes_written = match $encode_to($sequence[idx], buf) {
247        Ok(bytes_written) => bytes_written,
248        Err(e) => return Err({
249          let encoded_len = $encoded_sequence_len($sequence);
250          match ::core::num::NonZeroUsize::new(encoded_len) {
251            None => e,
252            Some(encoded_len) => e.update(encoded_len, buf_len),
253          }
254        }),
255      };
256      total_bytes += bytes_written.get();
257      idx += 1;
258    }
259
260    Ok(total_bytes)
261  }};
262  (@sequence_encoded_len_impl $sequence:ident, $encoded_len:ident) => {{
263    let mut total_bytes = 0;
264    let mut idx = 0;
265    let len = $sequence.len();
266
267    while idx < len {
268      total_bytes += $encoded_len($sequence[idx]).get();
269      idx += 1;
270    }
271
272    total_bytes
273  }};
274}
275
276macro_rules! decode {
277  ($($ty:literal), + $(,)?) => {
278    $(
279      paste::paste! {
280        #[doc = "Decodes a `u" $ty "` in LEB128 encoded format from the buffer."]
281        ///
282        /// Returns the bytes read and the decoded value if successful.
283        pub const fn [< decode_ u $ty _varint >](buf: &[u8]) -> Result<(::core::num::NonZeroUsize, [< u $ty >]), ConstDecodeError> {
284          decode_varint!(|buf| [< u $ty >])
285        }
286
287        #[doc = "Decodes an `i" $ty "` in LEB128 encoded format from the buffer."]
288        ///
289        /// Returns the bytes read and the decoded value if successful.
290        pub const fn [< decode_ i $ty _varint >](buf: &[u8]) -> Result<(::core::num::NonZeroUsize, [< i $ty >]), ConstDecodeError> {
291          match [< decode_ u $ty _varint >](buf) {
292            Ok((bytes_read, value)) => {
293              let value = utils::[<zigzag_decode_i $ty>](value);
294              Ok((bytes_read, value))
295            },
296            Err(e) => Err(e),
297          }
298        }
299      }
300    )*
301  };
302}
303
304impl_varint!(8, 16, 32, 64, 128,);
305varint_len!(u8, u16, u32,);
306varint_len!(@zigzag i8, i16, i32,);
307encode!(128, 64, 32, 16, 8);
308decode!(128, 64, 32, 16, 8);
309
310/// Returns the encoded length of the value in LEB128 variable length format.
311/// The returned value will be in range [`u128::ENCODED_LEN_RANGE`].
312#[inline]
313pub const fn encoded_u128_varint_len(value: u128) -> NonZeroUsize {
314  // Each byte in LEB128 encoding can hold 7 bits of data
315  // We want to find how many groups of 7 bits are needed
316  // Special case for 0 and small numbers
317  if value < 128 {
318    return super::NON_ZERO_USIZE_ONE;
319  }
320
321  // Calculate position of highest set bit
322  let highest_bit = 128 - value.leading_zeros();
323  // Convert to number of LEB128 bytes needed
324  // Each byte holds 7 bits, but we need to round up
325  // Safety: highest_bit is guaranteed to be non-zero here
326  unsafe { NonZeroUsize::new_unchecked(highest_bit.div_ceil(7) as usize) }
327}
328
329/// Returns the encoded length of the value in LEB128 variable length format.
330/// The returned value will be in range [`i128::ENCODED_LEN_RANGE`].
331#[inline]
332pub const fn encoded_i128_varint_len(x: i128) -> NonZeroUsize {
333  let x = utils::zigzag_encode_i128(x);
334  encoded_u128_varint_len(x)
335}
336
337/// Returns the encoded length of the value in LEB128 variable length format.
338/// The returned value will be in range [`i64::ENCODED_LEN_RANGE`].
339#[inline]
340pub const fn encoded_i64_varint_len(x: i64) -> NonZeroUsize {
341  let x = zigzag_encode_i64(x);
342  encoded_u64_varint_len(x)
343}
344
345/// Returns the encoded length of the value in LEB128 variable length format.
346/// The returned value will be in range [`u64::ENCODED_LEN_RANGE`].
347#[inline]
348pub const fn encoded_u64_varint_len(value: u64) -> NonZeroUsize {
349  // Based on [VarintSize64][1].
350  // [1]: https://github.com/protocolbuffers/protobuf/blob/v28.3/src/google/protobuf/io/coded_stream.h#L1744-L1756
351
352  // Safety: The value is guaranteed to be non-zero, so the result will always be a valid NonZeroUsize.
353  unsafe {
354    // Safety: (value | 1) is never zero
355    let log2value = NonZeroU64::new_unchecked(value | 1).ilog2();
356    NonZeroUsize::new_unchecked(((log2value * 9 + (64 + 9)) / 64) as usize)
357  }
358}
359
360impl Varint for bool {
361  const MIN_ENCODED_LEN: NonZeroUsize = crate::NON_ZERO_USIZE_ONE;
362
363  const MAX_ENCODED_LEN: NonZeroUsize = crate::NON_ZERO_USIZE_ONE;
364
365  #[inline]
366  fn encoded_len(&self) -> NonZeroUsize {
367    encoded_u8_varint_len(*self as u8)
368  }
369
370  #[inline]
371  fn encode(&self, buf: &mut [u8]) -> Result<NonZeroUsize, EncodeError> {
372    encode_u8_varint_to(*self as u8, buf).map_err(Into::into)
373  }
374
375  #[inline]
376  fn decode(buf: &[u8]) -> Result<(NonZeroUsize, Self), DecodeError>
377  where
378    Self: Sized,
379  {
380    decode_u8_varint(buf)
381      .map_err(Into::into)
382      .and_then(|(bytes_read, value)| {
383        if value > 1 {
384          return Err(DecodeError::other("invalid boolean value"));
385        }
386        Ok((bytes_read, value != 0))
387      })
388  }
389}
390
391impl Varint for f32 {
392  const MIN_ENCODED_LEN: NonZeroUsize = u32::MIN_ENCODED_LEN;
393
394  const MAX_ENCODED_LEN: NonZeroUsize = u32::MAX_ENCODED_LEN;
395
396  #[inline]
397  fn encoded_len(&self) -> NonZeroUsize {
398    encoded_f32_varint_len(*self)
399  }
400
401  #[inline]
402  fn encode(&self, buf: &mut [u8]) -> Result<NonZeroUsize, EncodeError> {
403    encode_f32_varint_to(*self, buf).map_err(Into::into)
404  }
405
406  #[inline]
407  fn decode(buf: &[u8]) -> Result<(NonZeroUsize, Self), DecodeError>
408  where
409    Self: Sized,
410  {
411    decode_f32_varint(buf).map_err(Into::into)
412  }
413}
414
415impl Varint for f64 {
416  const MIN_ENCODED_LEN: NonZeroUsize = u64::MIN_ENCODED_LEN;
417
418  const MAX_ENCODED_LEN: NonZeroUsize = u64::MAX_ENCODED_LEN;
419
420  #[inline]
421  fn encoded_len(&self) -> NonZeroUsize {
422    encoded_f64_varint_len(*self)
423  }
424
425  #[inline]
426  fn encode(&self, buf: &mut [u8]) -> Result<NonZeroUsize, EncodeError> {
427    encode_f64_varint_to(*self, buf).map_err(Into::into)
428  }
429
430  #[inline]
431  fn decode(buf: &[u8]) -> Result<(NonZeroUsize, Self), DecodeError>
432  where
433    Self: Sized,
434  {
435    decode_f64_varint(buf).map_err(Into::into)
436  }
437}
438
439/// Returns the encoded length of the value in LEB128 variable length format. The returned value will be in range of [`f32::ENCODED_LEN_RANGE`].
440#[inline]
441pub const fn encoded_f32_varint_len(value: f32) -> NonZeroUsize {
442  crate::encoded_u32_varint_len(value.to_bits())
443}
444
445/// Encodes an `f32` value into LEB128 variable length format, and writes it to the buffer.
446#[inline]
447pub const fn encode_f32_varint(
448  value: f32,
449) -> crate::utils::Buffer<{ f32::MAX_ENCODED_LEN.get() + 1 }> {
450  crate::encode_u32_varint(value.to_bits())
451}
452
453/// Encodes an `f32` value into LEB128 variable length format, and writes it to the buffer.
454#[inline]
455pub const fn encode_f32_varint_to(
456  value: f32,
457  buf: &mut [u8],
458) -> Result<NonZeroUsize, crate::ConstEncodeError> {
459  crate::encode_u32_varint_to(value.to_bits(), buf)
460}
461
462/// Decodes an `f32` in LEB128 encoded format from the buffer.
463///
464/// Returns the bytes read and the decoded value if successful.
465#[inline]
466pub const fn decode_f32_varint(buf: &[u8]) -> Result<(NonZeroUsize, f32), crate::ConstDecodeError> {
467  match crate::decode_u32_varint(buf) {
468    Ok((len, bits)) => Ok((len, f32::from_bits(bits))),
469    Err(e) => Err(e),
470  }
471}
472
473/// Returns the encoded length of the value in LEB128 variable length format. The returned value will be in range of [`f64::ENCODED_LEN_RANGE`].
474#[inline]
475pub const fn encoded_f64_varint_len(value: f64) -> NonZeroUsize {
476  crate::encoded_u64_varint_len(value.to_bits())
477}
478
479/// Encodes an `f64` value into LEB128 variable length format, and writes it to the buffer.
480#[inline]
481pub const fn encode_f64_varint(
482  value: f64,
483) -> crate::utils::Buffer<{ f64::MAX_ENCODED_LEN.get() + 1 }> {
484  crate::encode_u64_varint(value.to_bits())
485}
486
487/// Encodes an `f64` value into LEB128 variable length format, and writes it to the buffer.
488#[inline]
489pub const fn encode_f64_varint_to(
490  value: f64,
491  buf: &mut [u8],
492) -> Result<NonZeroUsize, crate::ConstEncodeError> {
493  crate::encode_u64_varint_to(value.to_bits(), buf)
494}
495
496/// Decodes an `f64` in LEB128 encoded format from the buffer.
497///
498/// Returns the bytes read and the decoded value if successful.
499#[inline]
500pub const fn decode_f64_varint(buf: &[u8]) -> Result<(NonZeroUsize, f64), crate::ConstDecodeError> {
501  match crate::decode_u64_varint(buf) {
502    Ok((len, bits)) => Ok((len, f64::from_bits(bits))),
503    Err(e) => Err(e),
504  }
505}
506
507/// Returns the encoded length of a sequence of `f32` values
508#[inline]
509pub const fn encoded_f32_sequence_len(sequence: &[f32]) -> usize {
510  encode!(@sequence_encoded_len_impl sequence, encoded_f32_varint_len)
511}
512
513/// Encodes a sequence of `f32` to the buffer.
514#[inline]
515pub const fn encode_f32_sequence_to(
516  sequence: &[f32],
517  buf: &mut [u8],
518) -> Result<usize, ConstEncodeError> {
519  encode!(@sequence_encode_to_impl buf, sequence, encode_f32_varint_to, encoded_f32_sequence_len)
520}
521
522/// Returns the encoded length of a sequence of `f64` values
523#[inline]
524pub const fn encoded_f64_sequence_len(sequence: &[f64]) -> usize {
525  encode!(@sequence_encoded_len_impl sequence, encoded_f64_varint_len)
526}
527
528/// Encodes a sequence of `f64` to the buffer.
529#[inline]
530pub const fn encode_f64_sequence_to(
531  sequence: &[f64],
532  buf: &mut [u8],
533) -> Result<usize, ConstEncodeError> {
534  encode!(@sequence_encode_to_impl buf, sequence, encode_f64_varint_to, encoded_f64_sequence_len)
535}
536
537/// LEB128 encoding/decoding for [`half`](https://crates.io/crates/half) types.
538#[cfg(feature = "half_2")]
539mod half;
540#[cfg(feature = "half_2")]
541pub use half::*;
542
543/// LEB128 encoding/decoding for [`float8`](https://crates.io/crates/float8) types.
544#[cfg(feature = "float8_0_4")]
545mod float8;
546#[cfg(feature = "float8_0_4")]
547pub use float8::*;