varing 0.14.0

Protobuf's varint encoding/decoding for LEB128 friendly types with full const context operations supports.
Documentation
use super::*;
use ::ruint_1::aliases::*;

impl_arbitrary_ratio!(@ruint (U64, U128, U192, U256, U384, U448, U512, U768, U1024, U2048, U4096,));

fuzzy!(@varint_into (
  RatioU128(Ratio<u128>),
  RatioI128(Ratio<i128>),
));

macro_rules! ratio_ruint_fuzzy {
  (@varint_into ($($ty:ident($target:ty)), +$(,)?)) => {
    $(
      paste::paste! {
        #[quickcheck_macros::quickcheck]
        fn [< fuzzy_ $ty:snake _varint>](value: $ty) -> bool {
          let value: $target = ::core::convert::Into::into(value);
          let mut buf = [0; <$target>::MAX_ENCODED_LEN.get()];
          let Ok(encoded_len) = value.encode(&mut buf) else { return false; };
          if encoded_len != value.encoded_len() || !(value.encoded_len() <= <$target>::MAX_ENCODED_LEN) {
            return false;
          }

          let Some(consumed) = $crate::consume_varint_checked(&buf) else {
            return false;
          };
          if consumed != encoded_len {
            return false;
          }

          if let Ok((bytes_read, decoded)) = <$target>::decode(&buf) {
            value.numer() == decoded.numer() && value.denom() == decoded.denom() && encoded_len == bytes_read
          } else {
            false
          }
        }
      }
    )*
  };
}

ratio_ruint_fuzzy!(@varint_into (
  RUintRatioU64(Ratio<U64>),
  RUintRatioU128(Ratio<U128>),
  RUintRatioU192(Ratio<U192>),
  RUintRatioU256(Ratio<U256>),
  RUintRatioU384(Ratio<U384>),
  RUintRatioU448(Ratio<U448>),
  RUintRatioU512(Ratio<U512>),
  RUintRatioU768(Ratio<U768>),
  RUintRatioU1024(Ratio<U1024>),
  RUintRatioU2048(Ratio<U2048>),
  RUintRatioU4096(Ratio<U4096>),
));

// F6: the packed `Ratio<ruint>` types must advertise a `MIN_ENCODED_LEN` that lower-
// bounds every value's encoded length. The shortest representable value is a zero
// numerator over `1`; because `pack` stores the numerator low and denominator high,
// `0/1` does not pack to `0`, so `MIN_ENCODED_LEN` must equal `encoded_len(0/1)`
// (2+ bytes) and no representable `Ratio` may encode any shorter.
#[test]
fn min_encoded_len_in_range() {
  use crate::Varint;

  fn check<T: crate::Varint>(v: T) {
    let len = v.encoded_len().get();
    assert!(len >= T::MIN_ENCODED_LEN.get());
    assert!(len <= T::MAX_ENCODED_LEN.get());
    assert!(T::MIN_ENCODED_LEN.get() <= T::MAX_ENCODED_LEN.get());
  }

  // `MIN_ENCODED_LEN` must equal `encoded_len(0/1)` for small and wide widths.
  assert_eq!(
    Ratio::<U64>::MIN_ENCODED_LEN.get(),
    Ratio::new_raw(U64::ZERO, U64::from(1u64))
      .encoded_len()
      .get(),
  );
  assert_eq!(
    Ratio::<U256>::MIN_ENCODED_LEN.get(),
    Ratio::new_raw(U256::ZERO, U256::from(1u64))
      .encoded_len()
      .get(),
  );

  // small (64-bit) and wide (256-bit)
  check(Ratio::new_raw(U64::ZERO, U64::from(1u64)));
  check(Ratio::new_raw(U256::ZERO, U256::from(1u64)));

  // Non-vacuous: sample small representable `Ratio<U64>` values (which are the
  // candidates for the shortest encoding). `0/1` achieves `MIN_ENCODED_LEN` and
  // nothing encodes shorter.
  let min = Ratio::<U64>::MIN_ENCODED_LEN.get();
  assert_eq!(
    min,
    Ratio::new_raw(U64::ZERO, U64::from(1u64))
      .encoded_len()
      .get()
  );
  for numer in 0u64..256 {
    for denom in 1u64..256 {
      let r = Ratio::new_raw(U64::from(numer), U64::from(denom));
      assert!(r.encoded_len().get() >= min);
    }
  }
}