use rand::{Rng, RngCore};
fn calculate_upper(min: u64) -> (u64, u8) {
const fn inner_func(min: u64) -> (u64, u8) {
let mut product = 1;
let mut count: u8 = 0;
loop {
if let Some(p) = u64::checked_mul(product, min + (count as u64)) {
product = p;
count += 1;
} else {
return (product, count);
}
}
}
const RESULT2: (u64, u8) = inner_func(2);
if min == 2 {
return RESULT2;
}
inner_func(min)
}
pub(crate) struct Chooser<R: RngCore> {
pub rng: R,
consumed: usize,
chunk: u64,
chunk_remaining: u8,
}
impl<R: RngCore> Chooser<R> {
pub fn new_zero(rng: R) -> Self {
Self {
rng,
consumed: 0,
chunk: 1,
chunk_remaining: 1,
}
}
pub fn new_one(rng: R) -> Self {
Self {
rng,
consumed: 1,
chunk: 0,
chunk_remaining: 0,
}
}
pub fn set_consumed_to_one(&mut self) {
self.consumed = 1;
if self.chunk_remaining > 0 {
self.chunk_remaining -= 1;
}
}
pub fn get_consumed(&self) -> usize {
self.consumed
}
pub fn set_consumed(&mut self, consumed: usize) {
self.consumed = consumed;
self.chunk_remaining = 0;
}
#[inline]
pub fn next(&mut self) -> bool {
self.consumed = self.consumed.saturating_add(1);
if self.chunk_remaining == 0 {
let (bound, remaining) = calculate_upper(self.consumed as u64);
self.chunk_remaining = remaining;
self.chunk = self.rng.gen_range(0..bound);
}
let result = self.chunk % (self.consumed as u64) == 0;
self.chunk /= self.consumed as u64;
self.chunk_remaining -= 1;
result
}
}