use crate::RandomNumberGenerator;
use sp_runtime::traits::Hash;
#[cfg(not(feature = "std"))]
use sp_std::vec::Vec;
pub trait RandomPermutation {
type Item;
fn random_permutation<Hashing: Hash>(
self,
random: &mut RandomNumberGenerator<Hashing>,
) -> Option<Vec<Self::Item>>;
}
impl<T> RandomPermutation for Vec<T> {
type Item = T;
fn random_permutation<Hashing: Hash>(
self,
random: &mut RandomNumberGenerator<Hashing>,
) -> Option<Vec<T>> {
let mut input = self;
if input.is_empty() {
None
} else {
let size = input.len();
let mut r = Vec::with_capacity(size);
for i in 1..=size {
r.push(input.swap_remove(random.pick_usize(size - i)));
}
Some(r)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use sp_runtime::traits::BlakeTwo256;
#[test]
fn random_permutation_works() {
let mut random_source =
RandomNumberGenerator::<BlakeTwo256>::new(BlakeTwo256::hash(b"my_seed"));
let mut random_source_2 =
RandomNumberGenerator::<BlakeTwo256>::new(BlakeTwo256::hash(b"my_seed2"));
let input = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq!(
input.clone().random_permutation(&mut random_source),
Some(vec![5, 9, 7, 4, 6, 8, 2, 3, 1, 10])
);
assert_eq!(
input.clone().random_permutation(&mut random_source),
Some(vec![9, 8, 3, 5, 6, 2, 10, 4, 7, 1])
);
assert_eq!(
input.random_permutation(&mut random_source_2),
Some(vec![1, 7, 8, 9, 2, 3, 10, 5, 4, 6])
);
assert_eq!(Vec::<u8>::new().random_permutation(&mut random_source_2), None)
}
}