rand_op/
lib.rs

1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
5 */
6
7use rand::distributions::Distribution;
8use rand::Rng;
9
10// rand-op
11pub struct OpCnt<R: Rng, E> {
12    // Return successful or not. If false, then this execution does not count.
13    op: fn(&mut R, &mut E) -> bool,
14    cnt: u64,
15}
16impl<R: Rng, E> OpCnt<R, E> {
17    pub fn new(op: fn(&mut R, &mut E) -> bool, cnt: u64) -> Self {
18        Self { op, cnt }
19    }
20}
21pub fn rand_op<'a, R: Rng, E>(
22    rng: &mut R,
23    env: &mut E,
24    mut op_cnts: Vec<OpCnt<R, E>>,
25) {
26    let mut tot = 0;
27    for op_cnt in op_cnts.iter() {
28        tot += op_cnt.cnt;
29    }
30    while tot > 0 {
31        let mut id = rand::distributions::Uniform::new(0, tot).sample(rng);
32        for op_cnt in &mut op_cnts {
33            if id < op_cnt.cnt {
34                if (op_cnt.op)(rng, env) {
35                    tot -= 1;
36                    op_cnt.cnt -= 1;
37                }
38                break;
39            }
40            id -= op_cnt.cnt;
41        }
42    }
43    for op_cnt in &op_cnts {
44        assert_eq!(op_cnt.cnt, 0);
45    }
46}