use rand::Rng;
#[inline]
pub(crate) fn gen_index<R: Rng + ?Sized>(rng: &mut R, n: usize) -> usize {
rng.gen_range(0..n as u64) as usize
}
#[cfg(test)]
mod tests {
use super::*;
use rand::rngs::StdRng;
use rand::{RngCore, SeedableRng};
fn counts() -> Vec<usize> {
let mut ns: Vec<usize> = vec![1, 2, 3, 4, 5, 6, 7, 10, 17, 100, 255, 256, 257, 1000, 4096];
ns.extend([
65_535,
65_536,
1_000_003,
(1 << 31) - 1,
1 << 31,
(1 << 31) + 1,
]);
ns.push(u32::MAX as usize);
#[cfg(target_pointer_width = "64")]
ns.extend([
1usize << 32,
(1usize << 32) + 1,
(1usize << 32) * 3 + 7,
1usize << 40,
usize::MAX / 3,
(1usize << 63) - 1,
1usize << 63,
(1usize << 63) + 1,
usize::MAX - 1,
usize::MAX,
]);
ns
}
#[test]
#[cfg(target_pointer_width = "64")]
fn matches_the_old_usize_draw_on_64_bit() {
for seed in 0..64u64 {
let mut old = StdRng::seed_from_u64(seed);
let mut new = StdRng::seed_from_u64(seed);
for &n in &counts() {
for _ in 0..8 {
let a: usize = old.gen_range(0..n);
let b = gen_index(&mut new, n);
assert_eq!(a, b, "seed {seed}, n {n}");
assert_eq!(
old.next_u64(),
new.next_u64(),
"seed {seed}, n {n}: words consumed differ"
);
}
}
}
}
#[test]
fn works_through_a_trait_object() {
let mut rng = StdRng::seed_from_u64(7);
let dyn_rng: &mut dyn RngCore = &mut rng;
for n in 1..50 {
assert!(gen_index(dyn_rng, n) < n);
}
}
#[test]
fn pinned_sequence() {
let mut rng = StdRng::seed_from_u64(42);
let got: Vec<usize> = [2, 3, 7, 10, 100, 1000, 65_536, u32::MAX as usize]
.iter()
.map(|&n| gen_index(&mut rng, n))
.collect();
assert_eq!(got, vec![1, 1, 4, 4, 3, 414, 8603, 13_967_647]);
assert_eq!(rng.next_u64(), 17_195_042_692_806_716_983);
}
#[test]
#[should_panic]
fn empty_range_panics() {
let mut rng = StdRng::seed_from_u64(0);
gen_index(&mut rng, 0);
}
}