use rand::SeedableRng;
use rand::rngs::SmallRng;
use rand::seq::SliceRandom;
#[derive(Debug)]
pub struct SimulatedScheduler {
rng: SmallRng,
}
impl SimulatedScheduler {
pub fn new(seed: u64) -> Self {
Self {
rng: SmallRng::seed_from_u64(seed),
}
}
pub fn run_tasks<T>(&mut self, tasks: Vec<Box<dyn FnOnce() -> T>>) -> Vec<T> {
if tasks.is_empty() {
return Vec::new();
}
let mut indexed: Vec<(usize, Box<dyn FnOnce() -> T>)> =
tasks.into_iter().enumerate().collect();
indexed.shuffle(&mut self.rng);
indexed.into_iter().map(|(_, task)| task()).collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn all_tasks_execute() {
let mut s = SimulatedScheduler::new(0);
let mut results = s.run_tasks(vec![
Box::new(|| 1_u32),
Box::new(|| 2_u32),
Box::new(|| 3_u32),
]);
results.sort_unstable();
assert_eq!(results, vec![1, 2, 3]);
}
#[test]
fn empty_task_list() {
let mut s = SimulatedScheduler::new(0);
let r: Vec<i32> = s.run_tasks(vec![]);
assert!(r.is_empty());
}
#[test]
fn same_seed_same_order() {
let make_tasks = || -> Vec<Box<dyn FnOnce() -> usize>> {
vec![Box::new(|| 10), Box::new(|| 20), Box::new(|| 30)]
};
let mut a = SimulatedScheduler::new(7);
let mut b = SimulatedScheduler::new(7);
assert_eq!(a.run_tasks(make_tasks()), b.run_tasks(make_tasks()));
}
}