1use std::time::Duration;
4
5mod random;
6
7pub use random::{jitter, jitter_rng, Range};
8
9#[derive(Debug)]
11pub struct Bounded<T> {
12 inner: T,
13 acc: Duration,
14 max: Duration,
15}
16
17impl<T> Bounded<T>
18where
19 T: Iterator<Item = Duration>,
20{
21 pub fn new<U>(inner: U, max: Duration) -> Self
22 where
23 U: IntoIterator<Item = Duration, IntoIter = T>,
24 {
25 Self {
26 inner: inner.into_iter(),
27 max,
28 acc: Default::default(),
29 }
30 }
31}
32
33impl<T> Iterator for Bounded<T>
34where
35 T: Iterator<Item = Duration>,
36{
37 type Item = Duration;
38
39 fn next(&mut self) -> Option<Duration> {
40 self.inner.next().filter(|next| {
41 if let Some(acc) = self.acc.checked_add(*next) {
42 self.acc = acc;
43 self.acc <= self.max
44 } else {
45 false
46 }
47 })
48 }
49}
50
51#[derive(Debug, Clone)]
53pub struct Exponential {
54 current: Duration,
55 factor: f64,
56}
57
58impl Exponential {
59 pub fn new(duration: Duration) -> Self {
62 Self::with_factor(duration, duration.as_millis() as f64)
63 }
64
65 pub fn with_factor(base: Duration, factor: f64) -> Self {
68 Self {
69 current: jitter(base),
70 factor,
71 }
72 }
73
74 pub fn exact(duration: Duration) -> Self {
77 Self::exact_with_factor(duration, duration.as_millis() as f64)
78 }
79
80 pub fn exact_with_factor(base: Duration, factor: f64) -> Self {
83 Self {
84 current: base,
85 factor,
86 }
87 }
88
89 pub fn bounded(self, max: Duration) -> Bounded<Self> {
91 Bounded::new(self, max)
92 }
93}
94
95impl Iterator for Exponential {
96 type Item = Duration;
97
98 fn next(&mut self) -> Option<Duration> {
99 fn try_from_secs_f64(secs: f64) -> Option<Duration> {
100 const NANOS_PER_SEC: u32 = 1_000_000_000;
101 const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f64;
102 let nanos = secs * (NANOS_PER_SEC as f64);
103 if !nanos.is_finite() || nanos >= MAX_NANOS_F64 || nanos < 0.0 {
104 None
105 } else {
106 Some(Duration::from_secs_f64(secs))
107 }
108 }
109
110 let duration = self.current;
111
112 let next_secs = self.current.as_secs_f64() * self.factor;
113 self.current = try_from_secs_f64(next_secs).unwrap_or(self.current);
114
115 Some(duration)
116 }
117}
118
119impl From<Duration> for Exponential {
120 fn from(duration: Duration) -> Self {
121 Self::new(duration)
122 }
123}
124
125#[test]
126fn exponential_with_factor() {
127 let mut iter = Exponential::exact_with_factor(Duration::from_secs(1), 2.0);
128 assert_eq!(iter.next(), Some(Duration::from_secs(1)));
129 assert_eq!(iter.next(), Some(Duration::from_secs(2)));
130 assert_eq!(iter.next(), Some(Duration::from_secs(4)));
131 assert_eq!(iter.next(), Some(Duration::from_secs(8)));
132 assert_eq!(iter.next(), Some(Duration::from_secs(16)));
133 assert_eq!(iter.next(), Some(Duration::from_secs(32)));
134}
135
136#[test]
137fn exponential_overflow() {
138 let mut iter = Exponential::exact(Duration::MAX);
139 assert_eq!(iter.next(), Some(Duration::MAX));
140 assert_eq!(iter.next(), Some(Duration::MAX));
141}
142
143#[test]
144fn exponential_with_upper_bound() {
145 let mut iter =
146 Exponential::exact_with_factor(Duration::from_secs(1), 2.0).bounded(Duration::from_secs(4));
147 assert_eq!(iter.next(), Some(Duration::from_secs(1)));
148 assert_eq!(iter.next(), Some(Duration::from_secs(2)));
149 assert_eq!(iter.next(), None);
151}
152
153#[derive(Debug, Clone)]
162pub struct Fibonacci {
163 curr: Duration,
164 next: Duration,
165}
166
167impl Fibonacci {
168 pub fn new(duration: Duration) -> Fibonacci {
170 let duration = jitter(duration);
171 Fibonacci {
172 curr: duration,
173 next: duration,
174 }
175 }
176 pub fn exact(duration: Duration) -> Fibonacci {
178 Fibonacci {
179 curr: duration,
180 next: duration,
181 }
182 }
183}
184
185impl Iterator for Fibonacci {
186 type Item = Duration;
187
188 fn next(&mut self) -> Option<Duration> {
189 let duration = self.curr;
190
191 let next = self.curr.saturating_add(self.next);
192 self.curr = self.next;
193 self.next = next;
194
195 Some(duration)
196 }
197}
198
199impl From<Duration> for Fibonacci {
200 fn from(duration: Duration) -> Self {
201 Self::new(duration)
202 }
203}
204
205#[test]
206fn fibonacci() {
207 let mut iter = Fibonacci::exact(Duration::from_millis(10));
208 assert_eq!(iter.next(), Some(Duration::from_millis(10)));
209 assert_eq!(iter.next(), Some(Duration::from_millis(10)));
210 assert_eq!(iter.next(), Some(Duration::from_millis(20)));
211 assert_eq!(iter.next(), Some(Duration::from_millis(30)));
212 assert_eq!(iter.next(), Some(Duration::from_millis(50)));
213 assert_eq!(iter.next(), Some(Duration::from_millis(80)));
214}
215
216#[test]
217fn fibonacci_saturated() {
218 let mut iter = Fibonacci::exact(Duration::MAX);
219 assert_eq!(iter.next(), Some(Duration::MAX));
220 assert_eq!(iter.next(), Some(Duration::MAX));
221}
222
223#[derive(Debug, Clone)]
225pub struct Fixed {
226 duration: Duration,
227}
228
229impl Fixed {
230 pub fn new(duration: Duration) -> Self {
232 Fixed {
233 duration: jitter(duration),
234 }
235 }
236
237 pub fn exact(duration: Duration) -> Self {
239 Fixed { duration }
240 }
241}
242
243impl Iterator for Fixed {
244 type Item = Duration;
245
246 fn next(&mut self) -> Option<Duration> {
247 Some(self.duration)
248 }
249}
250
251impl From<Duration> for Fixed {
252 fn from(duration: Duration) -> Self {
253 Self { duration }
254 }
255}
256
257#[derive(Debug, Clone)]
259pub struct NoDelay;
260
261impl Iterator for NoDelay {
262 type Item = Duration;
263
264 fn next(&mut self) -> Option<Duration> {
265 Some(Duration::default())
266 }
267}
268
269#[cfg(test)]
270mod test {
271 use crate::delay::Exponential;
272 use std::time::Duration;
273
274 #[test]
275 fn test_bounded_overflow() {
276 let mut delays = Exponential::exact_with_factor(Duration::MAX, 1.0).bounded(Duration::MAX);
277
278 assert_eq!(delays.next(), Some(Duration::MAX));
279
280 assert_eq!(delays.next(), None);
281 }
282}