1use pal_async::driver::Driver;
7use pal_async::timer::PolledTimer;
8use std::future::Future;
9use std::pin::Pin;
10use std::task::Context;
11use std::task::Poll;
12use std::time::Duration;
13
14const YIELD_ATTEMPTS: u64 = 250;
15const SHORT_SLEEP_ATTEMPTS: u64 = 250;
16const SHORT_SLEEP_DURATION: Duration = Duration::from_millis(1);
17const LONG_SLEEP_DURATION: Duration = Duration::from_millis(15);
18
19pub struct Backoff<'a> {
25 n: u64,
26 timer: Option<PolledTimer>,
27 driver: &'a dyn Driver,
28}
29
30impl<'a> Backoff<'a> {
31 pub fn new(driver: &'a dyn Driver) -> Self {
33 Self {
34 n: 0,
35 timer: None,
36 driver,
37 }
38 }
39
40 pub async fn back_off(&mut self) {
45 if self.n < 250 {
46 yield_once().await;
47 } else {
48 let delay = if self.n - YIELD_ATTEMPTS < SHORT_SLEEP_ATTEMPTS {
49 SHORT_SLEEP_DURATION
50 } else {
51 LONG_SLEEP_DURATION
52 };
53 self.timer
54 .get_or_insert_with(|| PolledTimer::new(self.driver))
55 .sleep(delay)
56 .await;
57 }
58 self.n += 1;
59 }
60}
61
62fn yield_once() -> YieldOnce {
63 YieldOnce { yielded: false }
64}
65
66struct YieldOnce {
67 yielded: bool,
68}
69
70impl Future for YieldOnce {
71 type Output = ();
72
73 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
74 if !self.yielded {
75 self.yielded = true;
76 cx.waker().wake_by_ref();
77 return Poll::Pending;
78 }
79 ().into()
80 }
81}