1use std::time::Duration;
4
5
6#[derive(Clone)]
7pub struct Retries<Iters: IterTime = DefaultIterTime> {
8 pub iters: Iters,
10 pub total: Duration,
12}
13
14impl<Iters: IterTime> Retries<Iters> {
15 pub fn new(iters: Iters, total: Duration) -> Self { Self { iters, total } }
16}
17
18impl<T> Default for Retries<T> where T: Default + IterTime {
19 fn default() -> Self {
20 Self { iters: Default::default(),
21 total: Duration::from_secs(10) }
22 }
23}
24
25impl<T> std::fmt::Display for Retries<T> where T: std::fmt::Display + IterTime {
26 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27 write!(f, "({} => {:?})", self.iters, self.total)
28 }
29}
30impl<T> std::fmt::Debug for Retries<T> where T: std::fmt::Debug + IterTime {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 write!(f, "({:?} => {:?})", self.iters, self.total)
33 }
34}
35
36
37pub trait IterTime {
38 fn preferred_iter_time(&self) -> Duration;
39
40 #[inline(always)]
41 fn interval(&self, total_wait: &Duration) -> Duration
42 where for<'t> &'t Self: IterTime {
43 calc_interval(total_wait, self)
44 }
45}
46
47
48impl<T: IterTime> IterTime for &'_ T {
49 #[inline(always)]
50 fn preferred_iter_time(&self) -> Duration { T::preferred_iter_time(*self) }
51
52 #[inline(always)]
53 fn interval(&self, total_wait: &Duration) -> Duration
54 where for<'t> &'t Self: IterTime {
55 T::interval(*self, total_wait)
56 }
57}
58
59pub fn calc_interval<T: IterTime>(wait: &Duration, cfg: T) -> Duration {
60 let iters = wait.as_millis() / cfg.preferred_iter_time().as_millis();
61 Duration::from_millis((wait.as_millis() / iters) as _)
62}
63
64
65#[derive(Clone, Default)]
66pub struct DefaultIterTime;
67const MIN_ITER_TIME: u64 = 100;
68
69impl IterTime for DefaultIterTime {
70 fn preferred_iter_time(&self) -> Duration { Duration::from_millis(MIN_ITER_TIME) }
71}
72
73impl std::fmt::Display for DefaultIterTime {
74 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}ms", MIN_ITER_TIME) }
75}
76impl std::fmt::Debug for DefaultIterTime {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 Duration::from_millis(MIN_ITER_TIME).fmt(f)
79 }
80}
81
82
83impl IterTime for Duration {
84 fn preferred_iter_time(&self) -> Duration { *self }
85
86 fn interval(&self, total_wait: &Duration) -> Duration
87 where for<'t> &'t Self: IterTime {
88 calc_interval(total_wait, self)
89 }
90}
91
92
93pub fn retry_blocking<F, R, E>(retry: Retries<impl IterTime>, f: F) -> Result<R, crate::error::Error>
94 where F: Fn() -> Result<R, E>,
95 E: Into<crate::error::Error> {
96 let total = &retry.total;
97 let iteration = retry.iters.interval(total);
98 let retries_num = total.as_millis() / iteration.as_millis();
99 trace!("start retries: {retries_num} * {iteration:?} ≈ {total:?}.");
100
101 let mut counter = retries_num;
102 loop {
103 trace!("try: {}/{retries_num}", retries_num - counter);
104 match f() {
105 Ok(r) => return Ok(r),
106 Err(e) => {
107 counter -= 1;
108 if counter == 0 {
109 return Err(e.into());
110 }
111 std::thread::sleep(iteration);
112 },
113 }
114 }
115}