1 | use std::hash::{DefaultHasher, Hasher}; |
2 | use std::time::{SystemTime, UNIX_EPOCH}; |
3 | |
4 | use crate::cli::TestOpts; |
5 | use crate::types::{TestDescAndFn, TestId, TestName}; |
6 | |
7 | pub(crate) fn get_shuffle_seed(opts: &TestOpts) -> Option<u64> { |
8 | opts.shuffle_seed.or_else(|| { |
9 | if opts.shuffle { |
10 | Some( |
11 | SystemTimeDuration::now() |
12 | .duration_since(UNIX_EPOCH) |
13 | .expect(msg:"Failed to get system time" ) |
14 | .as_nanos() as u64, |
15 | ) |
16 | } else { |
17 | None |
18 | } |
19 | }) |
20 | } |
21 | |
22 | pub(crate) fn shuffle_tests(shuffle_seed: u64, tests: &mut [(TestId, TestDescAndFn)]) { |
23 | let test_names: Vec<&TestName> = tests.iter().map(|test: &(TestId, TestDescAndFn)| &test.1.desc.name).collect(); |
24 | let test_names_hash: u64 = calculate_hash(&test_names); |
25 | let mut rng: Rng = Rng::new(shuffle_seed, extra:test_names_hash); |
26 | shuffle(&mut rng, slice:tests); |
27 | } |
28 | |
29 | // `shuffle` is from `rust-analyzer/src/cli/analysis_stats.rs`. |
30 | fn shuffle<T>(rng: &mut Rng, slice: &mut [T]) { |
31 | for i: usize in 0..slice.len() { |
32 | randomize_first(rng, &mut slice[i..]); |
33 | } |
34 | |
35 | fn randomize_first<T>(rng: &mut Rng, slice: &mut [T]) { |
36 | assert!(!slice.is_empty()); |
37 | let idx: usize = rng.rand_range(0..slice.len() as u64) as usize; |
38 | slice.swap(a:0, b:idx); |
39 | } |
40 | } |
41 | |
42 | struct Rng { |
43 | state: u64, |
44 | extra: u64, |
45 | } |
46 | |
47 | impl Rng { |
48 | fn new(seed: u64, extra: u64) -> Self { |
49 | Self { state: seed, extra } |
50 | } |
51 | |
52 | fn rand_range(&mut self, range: core::ops::Range<u64>) -> u64 { |
53 | self.rand_u64() % (range.end - range.start) + range.start |
54 | } |
55 | |
56 | fn rand_u64(&mut self) -> u64 { |
57 | self.state = calculate_hash(&(self.state, self.extra)); |
58 | self.state |
59 | } |
60 | } |
61 | |
62 | // `calculate_hash` is from `core/src/hash/mod.rs`. |
63 | fn calculate_hash<T: core::hash::Hash>(t: &T) -> u64 { |
64 | let mut s: DefaultHasher = DefaultHasher::new(); |
65 | t.hash(&mut s); |
66 | s.finish() |
67 | } |
68 | |