governor/
jitter.rs
1use std::prelude::v1::*;
2
3use crate::nanos::Nanos;
4#[cfg(feature = "jitter")]
5use rand::distributions::uniform::{SampleBorrow, SampleUniform, UniformInt, UniformSampler};
6#[cfg(feature = "jitter")]
7use rand::distributions::{Distribution, Uniform};
8#[cfg(feature = "jitter")]
9use rand::{thread_rng, Rng};
10use std::ops::Add;
11use std::time::Duration;
12
13#[cfg(feature = "std")]
14use std::time::Instant;
15
16#[derive(Debug, PartialEq, Eq, Default, Clone, Copy)]
61#[cfg_attr(feature = "docs", doc(cfg(jitter)))]
62pub struct Jitter {
63 min: Nanos,
64 max: Nanos,
65}
66
67impl Jitter {
68 #[cfg(feature = "std")]
69 pub(crate) const NONE: Jitter = Jitter {
71 min: Nanos::new(0),
72 max: Nanos::new(0),
73 };
74
75 #[cfg(any(all(feature = "jitter", not(feature = "no_std")), feature = "std"))]
90 pub fn up_to(max: Duration) -> Jitter {
91 Jitter {
92 min: Nanos::from(0),
93 max: max.into(),
94 }
95 }
96
97 #[cfg(any(all(feature = "jitter", not(feature = "no_std")), feature = "std"))]
99 pub fn new(min: Duration, interval: Duration) -> Jitter {
100 let min: Nanos = min.into();
101 let max: Nanos = min + Nanos::from(interval);
102 Jitter { min, max }
103 }
104
105 #[cfg(feature = "jitter")]
107 pub(crate) fn get(&self) -> Nanos {
108 if self.min == self.max {
109 return self.min;
110 }
111 let uniform = Uniform::new(self.min, self.max);
112 uniform.sample(&mut thread_rng())
113 }
114
115 #[cfg(not(feature = "jitter"))]
117 pub(crate) fn get(&self) -> Nanos {
118 self.min
119 }
120}
121
122#[cfg(feature = "jitter")]
124#[derive(Clone, Copy, Debug)]
125pub struct UniformJitter(UniformInt<u64>);
126
127#[cfg(feature = "jitter")]
128impl UniformSampler for UniformJitter {
129 type X = Nanos;
130
131 fn new<B1, B2>(low: B1, high: B2) -> Self
132 where
133 B1: SampleBorrow<Self::X> + Sized,
134 B2: SampleBorrow<Self::X> + Sized,
135 {
136 UniformJitter(UniformInt::new(
137 low.borrow().as_u64(),
138 high.borrow().as_u64(),
139 ))
140 }
141
142 fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self
143 where
144 B1: SampleBorrow<Self::X> + Sized,
145 B2: SampleBorrow<Self::X> + Sized,
146 {
147 UniformJitter(UniformInt::new_inclusive(
148 low.borrow().as_u64(),
149 high.borrow().as_u64(),
150 ))
151 }
152
153 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
154 Nanos::from(self.0.sample(rng))
155 }
156}
157
158#[cfg(feature = "jitter")]
159impl SampleUniform for Nanos {
160 type Sampler = UniformJitter;
161}
162
163impl Add<Duration> for Jitter {
164 type Output = Duration;
165
166 fn add(self, rhs: Duration) -> Duration {
167 let amount: Duration = self.get().into();
168 rhs + amount
169 }
170}
171
172impl Add<Nanos> for Jitter {
173 type Output = Nanos;
174
175 fn add(self, rhs: Nanos) -> Nanos {
176 rhs + self.get()
177 }
178}
179
180#[cfg(feature = "std")]
181impl Add<Instant> for Jitter {
182 type Output = Instant;
183
184 fn add(self, rhs: Instant) -> Instant {
185 let amount: Duration = self.get().into();
186 rhs + amount
187 }
188}
189
190#[cfg(all(feature = "jitter", not(feature = "no_std"), test))]
191mod test {
192 use super::*;
193
194 #[test]
195 fn jitter_impl_coverage() {
196 let basic = Jitter::up_to(Duration::from_secs(20));
197 let verbose = Jitter::new(Duration::from_secs(0), Duration::from_secs(20));
198 assert_eq!(basic, verbose);
199 }
200
201 #[test]
202 fn uniform_sampler_coverage() {
203 let low = Duration::from_secs(0);
204 let high = Duration::from_secs(20);
205 let sampler = UniformJitter::new_inclusive(Nanos::from(low), Nanos::from(high));
206 assert!(format!("{:?}", sampler).len() > 0);
207 assert!(format!("{:?}", sampler.clone()).len() > 0);
208 }
209}