des_sim/modeling/sampler/combinator/
ensure_non_negative.rs1use crate::modeling::sampler::{DurationSampler, PendingDuration};
10use crate::primitive::time::{Duration, SimTime};
11use rand::Rng;
12
13#[derive(Debug, Clone)]
19pub struct EnsureNonNegativeSampler<S, F>
20where
21 S: DurationSampler,
22 F: FnMut(&mut dyn Rng, SimTime) -> Duration,
23{
24 sampler: S,
25 limit_try_count: u8,
26 fallback: F,
27}
28
29impl<S, F> DurationSampler for EnsureNonNegativeSampler<S, F>
30where
31 S: DurationSampler,
32 F: FnMut(&mut dyn Rng, SimTime) -> Duration,
33{
34 fn sample(&mut self, rng: &mut dyn Rng, current_tick: SimTime) -> PendingDuration {
35 for _ in 0..self.limit_try_count {
36 let sampled = self.sampler.sample(rng, current_tick);
37 let raw_value = sampled.raw_value();
38
39 if raw_value >= 0.0 {
40 return PendingDuration::new(raw_value);
41 }
42 }
43
44 PendingDuration::from_duration((self.fallback)(rng, current_tick))
45 }
46}
47
48impl<S, F> EnsureNonNegativeSampler<S, F>
49where
50 S: DurationSampler,
51 F: FnMut(&mut dyn Rng, SimTime) -> Duration,
52{
53 pub fn new(sampler: S, limit_try_count: u8, fallback: F) -> Self {
55 Self {
56 sampler,
57 limit_try_count,
58 fallback,
59 }
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66 use crate::modeling::sampler::instance::ConstantSampler;
67 use crate::primitive::time::Duration;
68 use rand::SeedableRng;
69 use rand::rngs::SmallRng;
70
71 #[test]
72 fn test_ensure_non_negative_sampler_positive_value() {
73 let mut rng = SmallRng::seed_from_u64(2);
74 let base_sampler = ConstantSampler::new(10.0);
75 let mut sampler = EnsureNonNegativeSampler::new(base_sampler, 3, |_, _| Duration::ticks(0));
76
77 let sample = sampler.sample(&mut rng, SimTime::from_ticks(0));
78 assert_eq!(sample.raw_value(), 10.0);
79 }
80
81 #[test]
82 fn test_ensure_non_negative_sampler_negative_then_fallback() {
83 let mut rng = SmallRng::seed_from_u64(2);
84 struct NegativeSampler;
86 impl DurationSampler for NegativeSampler {
87 fn sample(&mut self, _rng: &mut dyn Rng, _current_tick: SimTime) -> PendingDuration {
88 PendingDuration::new(-1.0)
89 }
90 }
91
92 let base_sampler = NegativeSampler;
93 let mut sampler = EnsureNonNegativeSampler::new(base_sampler, 1, |_, _| Duration::ticks(5));
94
95 let sample = sampler.sample(&mut rng, SimTime::from_ticks(0));
96 assert_eq!(sample.raw_value(), 5.0); }
98
99 #[test]
100 fn test_ensure_non_negative_sampler_multiple_tries_then_positive() {
101 let mut rng = SmallRng::seed_from_u64(2);
102 struct MixedSampler {
103 call_count: usize,
104 }
105 impl DurationSampler for MixedSampler {
106 fn sample(&mut self, _rng: &mut dyn Rng, _current_tick: SimTime) -> PendingDuration {
107 self.call_count += 1;
108 if self.call_count < 3 {
109 PendingDuration::new(-1.0)
110 } else {
111 PendingDuration::new(10.0)
112 }
113 }
114 }
115
116 let base_sampler = MixedSampler { call_count: 0 };
117 let mut sampler = EnsureNonNegativeSampler::new(base_sampler, 5, |_, _| Duration::ticks(0));
118
119 let sample = sampler.sample(&mut rng, SimTime::from_ticks(0));
120 assert_eq!(sample.raw_value(), 10.0);
121 assert_eq!(sampler.sampler.call_count, 3); }
123}