1use std::time::Duration;
2
3fn randomize(backoff_ms: usize) -> usize {
4 let new_value = (fastrand::usize(750..=1250) * backoff_ms) / 1000;
5 if new_value == 0 { backoff_ms } else { new_value }
6}
7
8pub struct Quadratic<Fn> {
10 multiplier: usize,
11 max_multiplier: usize,
12 exponent: usize,
13 transform: Fn,
14}
15
16impl Default for Quadratic<fn(usize) -> usize> {
17 fn default() -> Self {
18 Quadratic {
19 multiplier: 1,
20 max_multiplier: 1000,
21 exponent: 1,
22 transform: std::convert::identity,
23 }
24 }
25}
26
27impl Quadratic<fn(usize) -> usize> {
28 pub fn default_with_random() -> Self {
30 Quadratic {
31 multiplier: 1,
32 max_multiplier: 1000,
33 exponent: 1,
34 transform: randomize,
35 }
36 }
37}
38
39impl<Transform> Quadratic<Transform>
40where
41 Transform: Fn(usize) -> usize,
42{
43 pub fn until_no_remaining(&mut self, time: Duration) -> impl Iterator<Item = Duration> + '_ {
45 let mut elapsed = Duration::default();
46 let mut stop_next_iteration = false;
47 self.take_while(move |d| {
48 if stop_next_iteration {
49 false
50 } else {
51 elapsed += *d;
52 if elapsed > time {
53 stop_next_iteration = true;
54 }
55 true
56 }
57 })
58 }
59}
60
61impl<Transform> Iterator for Quadratic<Transform>
62where
63 Transform: Fn(usize) -> usize,
64{
65 type Item = Duration;
66
67 fn next(&mut self) -> Option<Self::Item> {
68 let wait = Duration::from_millis((self.transform)(self.multiplier) as u64);
69
70 self.multiplier += 2 * self.exponent + 1;
71 if self.multiplier > self.max_multiplier {
72 self.multiplier = self.max_multiplier;
73 } else {
74 self.exponent += 1;
75 }
76 Some(wait)
77 }
78}