use arbitrary_int_2::prelude::*;
use core::num::NonZeroUsize;
use crate::{utils::Buffer, *};
macro_rules! generate {
($($storage:ident($start:literal..=$end:literal)), +$(,)?) => {
$(
seq_macro::seq!(N in $start..=$end {
generate!($storage(
#(
u~N,
)*
));
});
)*
};
($($underlying:ident($($inner:ident), +$(,)?)),+$(,)?) => {
$(
$(
paste::paste! {
#[doc = "The returned value will be in range of [`" $inner "::ENCODED_LEN_RANGE`]."]
#[inline]
pub const fn [< encoded_ $inner _varint_len >](value: $inner) -> NonZeroUsize {
[<encoded_ $underlying _varint_len>](value.value())
}
#[doc = "Encodes an `" $inner "` value into LEB128 variable length format, and writes it to the buffer."]
#[inline]
pub const fn [< encode_ $inner _varint >](x: $inner) -> $crate::utils::Buffer<{ $inner::MAX_ENCODED_LEN.get() + 1 }> {
let mut buf = [0; { $inner::MAX_ENCODED_LEN.get() + 1 }];
let len = match [< encode_ $inner _varint_to >](x, &mut buf) {
Ok(len) => len,
Err(_) => panic!("buffer should be large enough"),
};
buf[$crate::utils::Buffer::<{ $inner::MAX_ENCODED_LEN.get() + 1 }>::CAPACITY.get()] = len.get() as u8;
$crate::utils::Buffer::new(buf)
}
#[doc = "Encodes an `" $inner "` value into LEB128 variable length format, and writes it to the buffer."]
#[inline]
pub const fn [< encode_ $inner _varint_to >](value: $inner, buf: &mut [u8]) -> Result<NonZeroUsize, ConstEncodeError> {
[<encode_ $underlying _varint_to>](value.value(), buf)
}
#[doc = "Decodes an `" $inner "` in LEB128 encoded format from the buffer."]
#[inline]
pub const fn [< decode_ $inner _varint >](buf: &[u8]) -> Result<(NonZeroUsize, $inner), ConstDecodeError> {
match [<decode_ $underlying _varint>](buf) {
Ok((readed, val)) => {
match $inner::try_new(val) {
Ok(val) => Ok((readed, val)),
Err(_) => Err(ConstDecodeError::Overflow),
}
},
Err(err) => Err(err),
}
}
#[cfg(test)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct [< Fuzzy $inner:camel >]($inner);
#[cfg(test)]
const _: () = {
use quickcheck::{Arbitrary, Gen};
impl Arbitrary for [< Fuzzy $inner:camel >] {
fn arbitrary(g: &mut Gen) -> Self {
let val = loop {
let val = $underlying::arbitrary(g);
if val >= $inner::MIN.[<as_ $underlying>]() && val <= $inner::MAX.[<as_ $underlying>]() {
break val;
}
};
Self($inner::try_new(val).unwrap())
}
}
};
#[cfg(test)]
quickcheck::quickcheck! {
fn [< fuzzy_ $inner _varint >](x: [< Fuzzy $inner:camel >]) -> bool {
let x = x.0;
let mut buf = [0; $inner::MAX_ENCODED_LEN.get()];
let len = [< encode_ $inner _varint_to >](x, &mut buf).unwrap();
let buffer = [< encode_ $inner _varint >](x);
assert_eq!(buffer.len(), len.get());
assert_eq!(buffer.as_slice(), &buf[..len.get()]);
let (readed, val) = [< decode_ $inner _varint >](&buf).unwrap();
assert_eq!(readed, len);
assert_eq!(val, x);
true
}
}
#[test]
fn [< test_ $inner _min_max_varint >]() {
let min = $inner::MIN;
let max = $inner::MAX;
let min_encoded_len = [< encoded_ $inner _varint_len >](min);
let max_encoded_len = [< encoded_ $inner _varint_len >](max);
assert_eq!(min_encoded_len, $inner::MIN_ENCODED_LEN);
assert_eq!(max_encoded_len, $inner::MAX_ENCODED_LEN);
let mut buf = [0; $inner::MAX_ENCODED_LEN.get()];
let len = [< encode_ $inner _varint_to >](min, &mut buf).unwrap();
assert_eq!(len, min_encoded_len);
let buffer = [< encode_ $inner _varint >](min);
assert_eq!(buffer.len(), min_encoded_len.get());
assert_eq!(buffer.as_slice(), &buf[..min_encoded_len.get()]);
let (readed, val) = [< decode_ $inner _varint >](&buf).unwrap();
assert_eq!(readed, len);
assert_eq!(val, min);
let len = [< encode_ $inner _varint_to >](max, &mut buf).unwrap();
assert_eq!(len, max_encoded_len);
let buffer = [< encode_ $inner _varint >](max);
assert_eq!(buffer.len(), max_encoded_len.get());
assert_eq!(buffer.as_slice(), &buf[..max_encoded_len.get()]);
let (readed, val) = [< decode_ $inner _varint >](&buf).unwrap();
assert_eq!(readed, len);
assert_eq!(val, max);
}
}
)*
)*
};
($($storage:literal), +$(,)?) => {
paste::paste! {
$(
#[doc = "Returns the encoded length of the value in LEB128 variable length format."]
pub const fn [< encoded_uint_d $storage _len >]<const BITS: usize>(value: UInt<[< u $storage>], BITS>) -> NonZeroUsize {
[< encoded_u $storage _varint_len >](value.value())
}
#[doc = "Encodes an `Uint<u" $storage ", BITS>` value into LEB128 variable length format, and writes it to the buffer."]
pub const fn [< encode_uint_d $storage _to >]<const BITS: usize>(value: UInt<[< u $storage>], BITS>, buf: &mut [u8]) -> Result<NonZeroUsize, ConstEncodeError> {
[< encode_u $storage _varint_to >](value.value(), buf)
}
#[doc = "Encodes an `Uint<u" $storage ", BITS>` value into LEB128 variable length format, and writes it to the buffer."]
pub const fn [< encode_uint_d $storage>]<const BITS: usize>(value: UInt<[< u $storage>], BITS>) -> Buffer<{ [< u $storage>]::MAX_ENCODED_LEN.get() + 1 }> {
[< encode_u $storage _varint >](value.value())
}
#[doc = "Decodes an `Uint<u" $storage ", BITS>` in LEB128 encoded format from the buffer."]
pub const fn [< decode_uint_d $storage>]<const BITS: usize>(buf: &[u8]) -> Result<(NonZeroUsize, UInt<[< u $storage>], BITS>), ConstDecodeError> {
match [< decode_u $storage _varint >](buf) {
Ok((readed, val)) => {
match UInt::<[< u $storage>], BITS>::try_new(val) {
Ok(val) => Ok((readed, val)),
Err(_) => Err(ConstDecodeError::Overflow),
}
}
Err(err) => Err(err),
}
}
impl<const BITS: usize> Varint for UInt<[< u $storage>], BITS> {
const MIN_ENCODED_LEN: NonZeroUsize = [< encoded_uint_d $storage _len >](UInt::<[< u $storage>], BITS>::MIN);
const MAX_ENCODED_LEN: NonZeroUsize = [< encoded_uint_d $storage _len >](UInt::<[< u $storage>], BITS>::MAX);
fn encoded_len(&self) -> NonZeroUsize {
[< encoded_uint_d $storage _len >](*self)
}
fn encode(&self, buf: &mut [u8]) -> Result<NonZeroUsize, crate::EncodeError> {
[< encode_uint_d $storage _to >](*self, buf).map_err(Into::into)
}
fn decode(buf: &[u8]) -> Result<(NonZeroUsize, Self), crate::DecodeError>
where
Self: Sized,
{
[< decode_uint_d $storage >](buf).map_err(Into::into)
}
}
)*
}
};
}
generate!(
u8(1..=7),
u16(9..=15),
u32(17..=31),
u64(33..=63),
u128(65..=127),
);
generate!(8, 16, 32, 64, 128,);
macro_rules! generate_signed {
($($storage:ident($start:literal..=$end:literal)), +$(,)?) => {
$(
seq_macro::seq!(N in $start..=$end {
generate_signed!($storage(
#(
i~N,
)*
));
});
)*
};
($($underlying:ident($($inner:ident), +$(,)?)),+$(,)?) => {
$(
$(
paste::paste! {
#[doc = "The returned value will be in range of [`" $inner "::ENCODED_LEN_RANGE`]."]
#[inline]
pub const fn [< encoded_ $inner _varint_len >](value: $inner) -> NonZeroUsize {
[<encoded_ $underlying _varint_len>](value.value())
}
#[doc = "Encodes an `" $inner "` value into LEB128 variable length format, and writes it to the buffer."]
#[inline]
pub const fn [< encode_ $inner _varint >](x: $inner) -> $crate::utils::Buffer<{ <$inner as Varint>::MAX_ENCODED_LEN.get() + 1 }> {
let mut buf = [0; { <$inner as Varint>::MAX_ENCODED_LEN.get() + 1 }];
let len = match [< encode_ $inner _varint_to >](x, &mut buf) {
Ok(len) => len,
Err(_) => panic!("buffer should be large enough"),
};
buf[$crate::utils::Buffer::<{ <$inner as Varint>::MAX_ENCODED_LEN.get() + 1 }>::CAPACITY.get()] = len.get() as u8;
$crate::utils::Buffer::new(buf)
}
#[doc = "Encodes an `" $inner "` value into LEB128 variable length format, and writes it to the buffer."]
#[inline]
pub const fn [< encode_ $inner _varint_to >](value: $inner, buf: &mut [u8]) -> Result<NonZeroUsize, ConstEncodeError> {
[<encode_ $underlying _varint_to>](value.value(), buf)
}
#[doc = "Decodes an `" $inner "` in LEB128 encoded format from the buffer."]
#[inline]
pub const fn [< decode_ $inner _varint >](buf: &[u8]) -> Result<(NonZeroUsize, $inner), ConstDecodeError> {
match [<decode_ $underlying _varint>](buf) {
Ok((readed, val)) => {
match $inner::try_new(val) {
Ok(val) => Ok((readed, val)),
Err(_) => Err(ConstDecodeError::Overflow),
}
},
Err(err) => Err(err),
}
}
#[cfg(test)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct [< FuzzySigned $inner:camel >]($inner);
#[cfg(test)]
const _: () = {
use quickcheck::{Arbitrary, Gen};
impl Arbitrary for [< FuzzySigned $inner:camel >] {
fn arbitrary(g: &mut Gen) -> Self {
let val = loop {
let val = $underlying::arbitrary(g);
if val >= $inner::MIN.value() && val <= $inner::MAX.value() {
break val;
}
};
Self($inner::try_new(val).unwrap())
}
}
};
#[cfg(test)]
quickcheck::quickcheck! {
fn [< fuzzy_ $inner _varint >](x: [< FuzzySigned $inner:camel >]) -> bool {
let x = x.0;
let mut buf = [0; <$inner as Varint>::MAX_ENCODED_LEN.get()];
let len = [< encode_ $inner _varint_to >](x, &mut buf).unwrap();
let buffer = [< encode_ $inner _varint >](x);
assert_eq!(buffer.len(), len.get());
assert_eq!(buffer.as_slice(), &buf[..len.get()]);
let (readed, val) = [< decode_ $inner _varint >](&buf).unwrap();
assert_eq!(readed, len);
assert_eq!(val, x);
true
}
}
#[test]
fn [< test_ $inner _min_max_varint >]() {
let min = $inner::MIN;
let max = $inner::MAX;
let min_encoded_len = [< encoded_ $inner _varint_len >](min);
let max_encoded_len = [< encoded_ $inner _varint_len >](max);
assert_eq!(min_encoded_len, <$inner as Varint>::MIN_ENCODED_LEN);
assert_eq!(max_encoded_len, <$inner as Varint>::MAX_ENCODED_LEN);
let mut buf = [0; <$inner as Varint>::MAX_ENCODED_LEN.get()];
let len = [< encode_ $inner _varint_to >](min, &mut buf).unwrap();
assert_eq!(len, min_encoded_len);
let buffer = [< encode_ $inner _varint >](min);
assert_eq!(buffer.len(), min_encoded_len.get());
assert_eq!(buffer.as_slice(), &buf[..min_encoded_len.get()]);
let (readed, val) = [< decode_ $inner _varint >](&buf).unwrap();
assert_eq!(readed, len);
assert_eq!(val, min);
let len = [< encode_ $inner _varint_to >](max, &mut buf).unwrap();
assert_eq!(len, max_encoded_len);
let buffer = [< encode_ $inner _varint >](max);
assert_eq!(buffer.len(), max_encoded_len.get());
assert_eq!(buffer.as_slice(), &buf[..max_encoded_len.get()]);
let (readed, val) = [< decode_ $inner _varint >](&buf).unwrap();
assert_eq!(readed, len);
assert_eq!(val, max);
}
}
)*
)*
};
(@generic $($storage:literal), +$(,)?) => {
paste::paste! {
$(
#[doc = "Returns the encoded length of the value in LEB128 variable length format."]
pub const fn [< encoded_int_d $storage _len >]<const BITS: usize>(value: Int<[< i $storage>], BITS>) -> NonZeroUsize {
[< encoded_i $storage _varint_len >](value.value())
}
#[doc = "Encodes an `Int<i" $storage ", BITS>` value into LEB128 variable length format, and writes it to the buffer."]
pub const fn [< encode_int_d $storage _to >]<const BITS: usize>(value: Int<[< i $storage>], BITS>, buf: &mut [u8]) -> Result<NonZeroUsize, ConstEncodeError> {
[< encode_i $storage _varint_to >](value.value(), buf)
}
#[doc = "Encodes an `Int<i" $storage ", BITS>` value into LEB128 variable length format, and writes it to the buffer."]
pub const fn [< encode_int_d $storage>]<const BITS: usize>(value: Int<[< i $storage>], BITS>) -> Buffer<{ [< i $storage>]::MAX_ENCODED_LEN.get() + 1 }> {
[< encode_i $storage _varint >](value.value())
}
#[doc = "Decodes an `Int<i" $storage ", BITS>` in LEB128 encoded format from the buffer."]
pub const fn [< decode_int_d $storage>]<const BITS: usize>(buf: &[u8]) -> Result<(NonZeroUsize, Int<[< i $storage>], BITS>), ConstDecodeError> {
match [< decode_i $storage _varint >](buf) {
Ok((readed, val)) => {
match Int::<[< i $storage>], BITS>::try_new(val) {
Ok(val) => Ok((readed, val)),
Err(_) => Err(ConstDecodeError::Overflow),
}
}
Err(err) => Err(err),
}
}
impl<const BITS: usize> Varint for Int<[< i $storage>], BITS> {
const MIN_ENCODED_LEN: NonZeroUsize = [< encoded_int_d $storage _len >](Int::<[< i $storage>], BITS>::MIN);
const MAX_ENCODED_LEN: NonZeroUsize = {
let min_len = [< encoded_int_d $storage _len >](Int::<[< i $storage>], BITS>::MIN);
let max_len = [< encoded_int_d $storage _len >](Int::<[< i $storage>], BITS>::MAX);
if min_len.get() > max_len.get() {
min_len
} else {
max_len
}
};
fn encoded_len(&self) -> NonZeroUsize {
[< encoded_int_d $storage _len >](*self)
}
fn encode(&self, buf: &mut [u8]) -> Result<NonZeroUsize, crate::EncodeError> {
[< encode_int_d $storage _to >](*self, buf).map_err(Into::into)
}
fn decode(buf: &[u8]) -> Result<(NonZeroUsize, Self), crate::DecodeError>
where
Self: Sized,
{
[< decode_int_d $storage >](buf).map_err(Into::into)
}
}
)*
}
};
}
generate_signed!(
i8(1..=7),
i16(9..=15),
i32(17..=31),
i64(33..=63),
i128(65..=127),
);
generate_signed!(@generic 8, 16, 32, 64, 128,);