des_sim/modeling/sampler/instance/
rotate.rs1use crate::modeling::sampler::{DurationSampler, PendingDuration};
10use crate::primitive::time::SimTime;
11use rand::Rng;
12
13#[derive(Debug, Clone)]
19pub struct RotateSampler {
20 next_index: usize,
21 list: Vec<PendingDuration>,
22 item_count: usize,
23}
24
25impl DurationSampler for RotateSampler {
26 fn sample(&mut self, _rng: &mut dyn Rng, _current_tick: SimTime) -> PendingDuration {
27 let result = self.list[self.next_index];
28 self.next_index = (self.next_index + 1) % self.item_count;
29 result
30 }
31}
32
33impl RotateSampler {
34 pub fn new(duration_list: impl IntoIterator<Item = PendingDuration>) -> RotateSampler {
36 let list: Vec<_> = duration_list.into_iter().collect();
37 assert!(
38 !list.is_empty(),
39 "RotateSampler requires at least one duration"
40 );
41
42 let item_count = list.len();
43 RotateSampler {
44 next_index: 0,
45 list,
46 item_count,
47 }
48 }
49
50 pub fn new_with_index(
52 duration_list: impl IntoIterator<Item = PendingDuration>,
53 next_index: usize,
54 ) -> RotateSampler {
55 let list: Vec<_> = duration_list.into_iter().collect();
56 assert!(
57 !list.is_empty(),
58 "RotateSampler requires at least one duration"
59 );
60 assert!(next_index < list.len(), "Initial index is out of bounds");
61
62 let item_count = list.len();
63 RotateSampler {
64 next_index,
65 list,
66 item_count,
67 }
68 }
69
70 pub fn peek_next_index(&self) -> usize {
72 self.next_index
73 }
74
75 pub fn item_count(&self) -> usize {
77 self.item_count
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use crate::primitive::time::Duration;
85 use rand::SeedableRng;
86 use rand::rngs::SmallRng;
87
88 #[test]
89 fn test_rotate_sampler() {
90 let mut rng = SmallRng::seed_from_u64(2);
91 let durations = vec![
92 Duration::ticks(1).into(),
93 Duration::ticks(2).into(),
94 Duration::ticks(3).into(),
95 ];
96 let mut sampler = RotateSampler::new(durations.clone());
97
98 assert_eq!(sampler.peek_next_index(), 0);
99 assert_eq!(sampler.item_count(), 3);
100
101 assert_eq!(
102 sampler.sample(&mut rng, SimTime::from_ticks(0)).raw_value(),
103 1.0
104 );
105 assert_eq!(sampler.peek_next_index(), 1);
106
107 assert_eq!(
108 sampler.sample(&mut rng, SimTime::from_ticks(0)).raw_value(),
109 2.0
110 );
111 assert_eq!(sampler.peek_next_index(), 2);
112
113 assert_eq!(
114 sampler.sample(&mut rng, SimTime::from_ticks(0)).raw_value(),
115 3.0
116 );
117 assert_eq!(sampler.peek_next_index(), 0); assert_eq!(
120 sampler.sample(&mut rng, SimTime::from_ticks(0)).raw_value(),
121 1.0
122 );
123 assert_eq!(sampler.peek_next_index(), 1);
124 }
125
126 #[test]
127 fn test_rotate_sampler_with_initial_index() {
128 let mut rng = SmallRng::seed_from_u64(2);
129 let durations = vec![
130 Duration::ticks(1).into(),
131 Duration::ticks(2).into(),
132 Duration::ticks(3).into(),
133 ];
134 let mut sampler = RotateSampler::new_with_index(durations, 1);
135
136 assert_eq!(sampler.peek_next_index(), 1);
137
138 assert_eq!(
139 sampler.sample(&mut rng, SimTime::from_ticks(0)).raw_value(),
140 2.0
141 );
142 assert_eq!(sampler.peek_next_index(), 2);
143 }
144
145 #[test]
146 #[should_panic(expected = "RotateSampler requires at least one duration")]
147 fn test_rotate_sampler_empty_list1() {
148 let _ = RotateSampler::new(vec![]);
149 }
150
151 #[test]
152 #[should_panic(expected = "RotateSampler requires at least one duration")]
153 fn test_rotate_sampler_empty_list2() {
154 let _ = RotateSampler::new_with_index(vec![], 0);
155 }
156
157 #[test]
158 #[should_panic(expected = "Initial index is out of bounds")]
159 fn test_rotate_sampler_invalid_initial_index() {
160 let durations = vec![Duration::ticks(1).into()];
161 let _ = RotateSampler::new_with_index(durations, 1);
162 }
163}