2018-10-03 03:13:51 +00:00
|
|
|
extern crate hashing;
|
2018-08-14 06:23:38 +00:00
|
|
|
|
|
|
|
mod rng;
|
|
|
|
|
|
|
|
use self::rng::ShuffleRng;
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum ShuffleErr {
|
|
|
|
ExceedsListLength,
|
|
|
|
}
|
|
|
|
|
2018-08-24 06:01:24 +00:00
|
|
|
/// Performs a deterministic, in-place shuffle of a vector of bytes.
|
2018-08-14 06:23:38 +00:00
|
|
|
/// The final order of the shuffle is determined by successive hashes
|
|
|
|
/// of the supplied `seed`.
|
|
|
|
pub fn shuffle(
|
|
|
|
seed: &[u8],
|
2018-08-24 06:01:24 +00:00
|
|
|
mut list: Vec<usize>)
|
2018-08-14 06:23:38 +00:00
|
|
|
-> Result<Vec<usize>, ShuffleErr>
|
|
|
|
{
|
|
|
|
let mut rng = ShuffleRng::new(seed);
|
|
|
|
if list.len() > rng.rand_max as usize {
|
|
|
|
return Err(ShuffleErr::ExceedsListLength);
|
2018-08-24 06:01:24 +00:00
|
|
|
}
|
2018-08-14 06:23:38 +00:00
|
|
|
for i in 0..(list.len() - 1) {
|
|
|
|
let n = list.len() - i;
|
|
|
|
let j = rng.rand_range(n as u32) as usize + i;
|
|
|
|
list.swap(i, j);
|
|
|
|
}
|
|
|
|
Ok(list)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
2018-10-03 03:13:51 +00:00
|
|
|
use super::hashing::canonical_hash;
|
2018-08-14 06:23:38 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_shuffling() {
|
2018-10-03 03:13:51 +00:00
|
|
|
let seed = canonical_hash(b"4kn4driuctg8");
|
2018-08-14 06:23:38 +00:00
|
|
|
let list: Vec<usize> = (0..12).collect();
|
2018-10-03 03:13:51 +00:00
|
|
|
let s = shuffle(&seed, list).unwrap();
|
2018-08-14 06:23:38 +00:00
|
|
|
assert_eq!(
|
|
|
|
s,
|
2018-10-03 03:13:51 +00:00
|
|
|
vec![7, 3, 2, 5, 11, 9, 1, 0, 4, 6, 10, 8],
|
2018-08-14 06:23:38 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|