use tokio::select;
use tokio::sync::watch;
use tokio::time::{Duration, Instant, sleep_until};
#[allow(unused)]
pub trait WatchDebounceExt<T> {
async fn recv_debounced<'a>(&'a mut self, duration: Duration) -> Result<watch::Ref<'a, T>, watch::error::RecvError>
where
T: 'a;
async fn recv_debounced_distinct<'a, F>(
&'a mut self,
duration: Duration,
accept: F,
) -> Result<watch::Ref<'a, T>, watch::error::RecvError>
where
T: 'a,
F: FnMut(&watch::Ref<'a, T>) -> bool;
}
impl<T: Clone> WatchDebounceExt<T> for watch::Receiver<T> {
async fn recv_debounced<'a>(&'a mut self, duration: Duration) -> Result<watch::Ref<'a, T>, watch::error::RecvError>
where
T: 'a,
{
self.changed().await?;
let mut deadline = Instant::now() + duration;
loop {
select! {
_ = async { self.changed().await.ok() } => {
deadline = Instant::now() + duration;
}
_ = sleep_until(deadline) => {
return Ok(self.borrow());
}
}
}
}
async fn recv_debounced_distinct<'a, F>(
&'a mut self,
duration: Duration,
mut accept: F,
) -> Result<watch::Ref<'a, T>, watch::error::RecvError>
where
T: 'a,
F: FnMut(&watch::Ref<'a, T>) -> bool,
{
let last = self.recv_debounced(duration).await?;
loop {
if accept(&last) {
return Ok(last);
}
}
}
}