1use std::{collections::BTreeMap, time::Duration};
5use tokio::sync::watch;
6
7pub(crate) const IDLE_INTERVAL: Duration = Duration::from_secs(30);
9
10pub struct SyncOften(watch::Sender<BTreeMap<Duration, usize>>);
12
13impl SyncOften {
14 pub fn new() -> Self {
16 Self(watch::channel(BTreeMap::new()).0)
17 }
18 pub fn hold(&self, interval: Duration) -> SyncOftenGuard {
20 self.0.send_modify(|held| *held.entry(interval).or_default() += 1);
21 SyncOftenGuard { held: self.0.clone(), interval }
22 }
23 pub fn subscribe(&self) -> HeldIntervals {
25 HeldIntervals(self.0.subscribe())
26 }
27}
28
29#[derive(Clone)]
31pub struct HeldIntervals(watch::Receiver<BTreeMap<Duration, usize>>);
32
33impl HeldIntervals {
34 pub fn shortest(&self) -> Option<Duration> {
36 self.0.borrow().keys().next().copied()
37 }
38 pub(crate) fn idle_wait(&self) -> Duration {
41 self.shortest().map_or(IDLE_INTERVAL, |shortest| shortest.min(IDLE_INTERVAL))
42 }
43 pub async fn changed(&mut self) {
47 if self.0.changed().await.is_err() {
48 std::future::pending::<()>().await;
49 }
50 }
51}
52
53#[derive(Debug)]
56#[must_use = "dropping the guard ends the request at once"]
57pub struct SyncOftenGuard {
58 held: watch::Sender<BTreeMap<Duration, usize>>,
59 interval: Duration,
60}
61
62impl Drop for SyncOftenGuard {
63 fn drop(&mut self) {
64 self.held.send_modify(|held| {
65 let count = held
66 .get_mut(&self.interval)
67 .expect("a guard's interval stays held until the guard drops");
68 *count -= 1;
69 if *count == 0 {
70 held.remove(&self.interval);
71 }
72 });
73 }
74}