Skip to main content

des_sim/modeling/sampler/combinator/
map.rs

1//! The `map` module provides the `MapSampler`, a combinator that transforms
2//! the output of a base `DurationSampler` using a user-defined closure.
3//!
4//! This allows for arbitrary mathematical or logical operations to be applied
5//! to the sampled duration, enabling flexible customization of sampling behavior.
6
7use crate::modeling::sampler::{DurationSampler, PendingDuration};
8use crate::primitive::time::SimTime;
9use rand::Rng;
10
11/// A sampler that maps the output of a base sampler to a new value using a closure.
12#[derive(Debug, Clone)]
13pub struct MapSampler<S, F>
14where
15    S: DurationSampler,
16    F: FnMut(&mut dyn Rng, SimTime, f64) -> f64,
17{
18    sampler: S,
19    f: F,
20}
21
22impl<S, F> DurationSampler for MapSampler<S, F>
23where
24    S: DurationSampler,
25    F: FnMut(&mut dyn Rng, SimTime, f64) -> f64,
26{
27    fn sample(&mut self, rng: &mut dyn Rng, current_tick: SimTime) -> PendingDuration {
28        let sampled = self.sampler.sample(rng, current_tick);
29
30        PendingDuration::new((self.f)(rng, current_tick, sampled.raw_value()))
31    }
32}
33
34impl<S, F> MapSampler<S, F>
35where
36    S: DurationSampler,
37    F: FnMut(&mut dyn Rng, SimTime, f64) -> f64,
38{
39    /// Creates a new `MapSampler`.
40    pub fn new(sampler: S, f: F) -> Self {
41        MapSampler { sampler, f }
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48    use crate::modeling::sampler::instance::ConstantSampler;
49    use rand::SeedableRng;
50    use rand::rngs::SmallRng;
51
52    #[test]
53    fn test_map_sampler_double_value() {
54        let mut rng = SmallRng::seed_from_u64(2);
55        let base_sampler = ConstantSampler::new(10.0);
56        let mut sampler = MapSampler::new(base_sampler, |_, _, value| value * 2.0);
57
58        let sample = sampler.sample(&mut rng, SimTime::from_ticks(0));
59        assert_eq!(sample.raw_value(), 20.0);
60    }
61
62    #[test]
63    fn test_map_sampler_add_offset() {
64        let mut rng = SmallRng::seed_from_u64(2);
65        let base_sampler = ConstantSampler::new(10.0);
66        let mut sampler = MapSampler::new(base_sampler, |_, _, value| value + 5.0);
67
68        let sample = sampler.sample(&mut rng, SimTime::from_ticks(0));
69        assert_eq!(sample.raw_value(), 15.0);
70    }
71
72    #[test]
73    fn test_map_sampler_negate_value() {
74        let mut rng = SmallRng::seed_from_u64(2);
75        let base_sampler = ConstantSampler::new(10.0);
76        let mut sampler = MapSampler::new(base_sampler, |_, _, value| -value);
77
78        let sample = sampler.sample(&mut rng, SimTime::from_ticks(0));
79        assert_eq!(sample.raw_value(), -10.0);
80    }
81}