use rand::Rng;
use rand::distr::Distribution;
use rand::distr::uniform::Uniform;
pub fn smallest_number_in_n_byte_varint(byte_length: usize) -> u64 {
assert!((1..=9).contains(&byte_length));
match byte_length {
1 => 0,
_ => largest_number_in_n_byte_varint(byte_length - 1) + 1,
}
}
pub fn largest_number_in_n_byte_varint(byte_length: usize) -> u64 {
assert!((1..=9).contains(&byte_length));
match byte_length {
9 => u64::MAX,
_ => largest_number_in_7_bit_chunk(byte_length - 1),
}
}
fn largest_number_in_7_bit_chunk(chunk_index: usize) -> u64 {
assert!(chunk_index <= 7);
let lower_bits = match chunk_index {
0 => 0,
_ => largest_number_in_7_bit_chunk(chunk_index - 1),
};
let this_chunk = 0x7F_u64 << (chunk_index * 7);
lower_bits | this_chunk
}
pub struct RandomVarintEncodedLengthIter<R: Rng> {
ranges: [Uniform<u64>; 9],
range_for_picking_range: Uniform<usize>,
rng: R,
}
impl<R: Rng> RandomVarintEncodedLengthIter<R> {
pub fn new(rng: R) -> RandomVarintEncodedLengthIter<R> {
RandomVarintEncodedLengthIter {
ranges: std::array::from_fn(|i| {
let byte_length = i + 1;
let smallest = smallest_number_in_n_byte_varint(byte_length);
let largest = largest_number_in_n_byte_varint(byte_length);
Uniform::new_inclusive(smallest, largest).expect("range is non-empty")
}),
range_for_picking_range: Uniform::new(0, 9).expect("range is non-empty"),
rng,
}
}
}
impl<R: Rng> Iterator for RandomVarintEncodedLengthIter<R> {
type Item = u64;
fn next(&mut self) -> Option<Self::Item> {
let value_range = self.ranges[self.range_for_picking_range.sample(&mut self.rng)];
Some(value_range.sample(&mut self.rng))
}
}
#[test]
fn largest_number_in_7_bit_chunk_correct() {
for i in 0..8 {
let largest = largest_number_in_7_bit_chunk(i);
assert_eq!((i as u32 + 1) * 7, largest.count_ones());
assert_eq!(64 - ((i as u32) + 1) * 7, largest.leading_zeros());
assert_eq!(largest.leading_zeros() - 1, (largest + 1).leading_zeros());
}
}