tower_fault/latency/
distribution.rs

1use rand::Rng;
2use std::{ops, time::Duration};
3
4/// Trait that returns a random latency.
5pub trait Distribution<R> {
6    /// Returns a random latency.
7    fn sample(&self, req: &R) -> Duration;
8}
9
10macro_rules! impl_distribution_fixed {
11    ($t:ty, $ret:tt) => {
12        impl<R> Distribution<R> for $t {
13            fn sample(&self, _req: &R) -> Duration {
14                #[allow(clippy::redundant_closure_call)]
15                $ret(*self)
16            }
17        }
18    };
19}
20impl_distribution_fixed! { f64, (|value| Duration::from_secs_f64(value / 1000.0)) }
21impl_distribution_fixed! { u64, (Duration::from_millis) }
22impl_distribution_fixed! { Duration, (|value| value) }
23
24macro_rules! impl_distribution_range {
25    ($t:ty, $ret:tt) => {
26        impl<R> Distribution<R> for ops::Range<$t> {
27            fn sample(&self, _req: &R) -> Duration {
28                let mut rng = rand::thread_rng();
29                let value = rng.gen_range(self.clone());
30                #[allow(clippy::redundant_closure_call)]
31                $ret(value)
32            }
33        }
34
35        impl<R> Distribution<R> for ops::RangeInclusive<$t> {
36            fn sample(&self, _req: &R) -> Duration {
37                let mut rng = rand::thread_rng();
38                let value = rng.gen_range(self.clone());
39                #[allow(clippy::redundant_closure_call)]
40                $ret(value)
41            }
42        }
43    };
44}
45impl_distribution_range! { f64, (|value| Duration::from_secs_f64(value / 1000.0)) }
46impl_distribution_range! { u64, (Duration::from_millis) }
47impl_distribution_range! { Duration, (|value| value) }
48
49impl<F, R> Distribution<R> for F
50where
51    F: Fn(&R) -> Duration,
52{
53    fn sample(&self, req: &R) -> Duration {
54        self(req)
55    }
56}