varing 0.14.0

Protobuf's varint encoding/decoding for LEB128 friendly types with full const context operations supports.
Documentation
use num_rational_0_4::Ratio;

use crate::{ConstDecodeError, ConstEncodeError, DecodeError, EncodeError, Varint};

use core::num::NonZeroUsize;

macro_rules! impl_varint_for_ratio {
  (@inner $($sign:ident::$bits:literal($merged_ty:ident) => $min_encoded_len:expr),+$(,)?) => {
    paste::paste! {
      $(
        impl Varint for Ratio<[< $sign $bits >]> {
          // The shortest representable `Ratio` is `0/1` (numerator `0` over the
          // smallest nonzero denominator). Because `pack` stores the numerator in
          // the low half and the denominator in the high half, that value does not
          // pack to `0`, so `MIN_ENCODED_LEN` is the encoded length of `pack(0, 1)`
          // rather than the merged integer's own (one-byte) minimum.
          const MIN_ENCODED_LEN: NonZeroUsize = $min_encoded_len;

          const MAX_ENCODED_LEN: NonZeroUsize = $merged_ty::MAX_ENCODED_LEN;

          fn encoded_len(&self) -> NonZeroUsize {
            $crate::utils::[< pack_ $sign $bits >](*self.numer(), *self.denom()).encoded_len()
          }

          fn encode(&self, buf: &mut [u8]) -> Result<NonZeroUsize, EncodeError> {
            $crate::utils::[< pack_ $sign $bits >](*self.numer(), *self.denom()).encode(buf)
              .map_err(Into::into)
          }

          fn decode(buf: &[u8]) -> Result<(NonZeroUsize, Self), DecodeError>
          where
            Self: Sized,
          {
            let (bytes_read, merged) = $merged_ty::decode(buf)?;
            let (numer, denom) = $crate::utils::[< unpack_ $sign $bits >](merged);
            if denom == 0 {
              return Err(DecodeError::other("denominator cannot be zero"));
            }
            Ok((bytes_read, Ratio::new_raw(numer, denom)))
          }
        }
      )*
    }
  };
  ($($bits:literal($merged_ty:ident)),+$(,)?) => {
    paste::paste! {
      // `MIN_ENCODED_LEN` is the encoded length of `pack(0, 1)`, computed with the
      // same const encoded-length function the impl uses on the packed value.
      impl_varint_for_ratio!(@inner $(
        u::$bits($merged_ty) => $crate::[< encoded_ $merged_ty:snake _varint_len >]($crate::utils::[< pack_ u $bits >](0, 1))
      ),+);
      impl_varint_for_ratio!(@inner $(
        i::$bits($merged_ty) => $crate::[< encoded_ $merged_ty:snake _varint_len >]($crate::utils::[< pack_ i $bits >](0, 1))
      ),+);
    }
  };
  (@const_inner $($sign:ident::$bits:literal($merged_ty:ident) {
    encoded_len_fn:$encoded_len_fn:path,
    encode_fn:$encode_fn:path,
    encode_to_fn:$encode_to_fn:path,
    decode_fn:$decode_fn:path,
  }),+$(,)?) => {
    paste::paste! {
      $(
        #[doc = "Returns the encoded length of the `Ratio<" $sign $bits ">` value."]
        #[inline]
        pub const fn [< encoded_ratio_ $sign $bits _len>](val: Ratio<[< $sign $bits >]>) -> NonZeroUsize {
          $encoded_len_fn($crate::utils::[< pack_ $sign $bits >](*val.numer(), *val.denom()))
        }

        #[doc = "Encodes the `Ratio<" $sign $bits ">` value."]
        #[inline]
        pub const fn [< encode_ratio_ $sign $bits >](val: Ratio<[< $sign $bits >]>) -> $crate::utils::Buffer<{ $merged_ty::MAX_ENCODED_LEN.get() + 1 }> {
          $encode_fn ($crate::utils::[< pack_ $sign $bits >](*val.numer(), *val.denom()))
        }

        #[doc = "Encodes the `Ratio<" $sign $bits ">` value into the provided buffer."]
        #[inline]
        pub const fn [< encode_ratio_ $sign $bits _to >](val: Ratio<[< $sign $bits >]>, buf: &mut [u8]) -> Result<NonZeroUsize, ConstEncodeError> {
          $encode_to_fn ($crate::utils::[< pack_ $sign $bits >](*val.numer(), *val.denom()), buf)
        }

        #[doc = "Decodes the `Ratio<" $sign $bits ">` value from the provided buffer."]
        #[inline]
        pub const fn [< decode_ratio_ $sign $bits >](buf: &[u8]) -> Result<(NonZeroUsize, Ratio<[< $sign $bits >]>), ConstDecodeError> {
          match $decode_fn(buf) {
            Ok((bytes_read, merged)) => {
              let (numer, denom) = $crate::utils::[< unpack_ $sign $bits >](merged);
              if denom == 0 {
                Err(ConstDecodeError::other("denominator cannot be zero"))
              } else {
                Ok((bytes_read, Ratio::new_raw(numer, denom)))
              }
            }
            Err(e) => Err(e),
          }
        }
      )*
    }
  };
  (@const $($bits:literal($merged_ty:ident)),+$(,)?) => {
    paste::paste! {
      impl_varint_for_ratio!(@const_inner $(u::$bits($merged_ty) {
        encoded_len_fn: $crate::[< encoded_ $merged_ty:snake _varint_len >],
        encode_fn: $crate::[< encode_ $merged_ty:snake _varint >],
        encode_to_fn: $crate::[< encode_ $merged_ty:snake _varint_to>],
        decode_fn: $crate::[< decode_ $merged_ty:snake _varint >],
      }),+);
      impl_varint_for_ratio!(@const_inner $(i::$bits($merged_ty) {
        encoded_len_fn: $crate::[< encoded_ $merged_ty:snake _varint_len >],
        encode_fn: $crate::[< encode_ $merged_ty:snake _varint >],
        encode_to_fn: $crate::[< encode_ $merged_ty:snake _varint_to>],
        decode_fn: $crate::[< decode_ $merged_ty:snake _varint >],
      }),+);
    }
  };
}

impl_varint_for_ratio!(8(u16), 16(u32), 32(u64), 64(u128));
impl_varint_for_ratio!(@const 8(u16), 16(u32), 32(u64), 64(u128));

#[cfg(feature = "ruint_1")]
mod ruint_1;

#[cfg(feature = "bnum_0_13")]
mod bnum_0_13;

#[cfg(feature = "bnum_0_13")]
#[cfg_attr(docsrs, doc(cfg(feature = "bnum_0_13")))]
pub use bnum_0_13::*;

#[cfg(test)]
mod tests;