use std::sync::Arc;
use std::task::Context;
use std::task::Poll;
use std::task::Waker;
use std::time::Duration;
use super::internal::ThreadWaker;
use crate::MonotonicInstant;
use crate::TimeError;
use crate::Timer;
use crate::TimerFuture;
#[derive(Clone)]
pub struct BlockingSleeper {
timer: Arc<dyn Timer>,
}
impl BlockingSleeper {
#[must_use]
pub const fn new(timer: Arc<dyn Timer>) -> Self {
Self { timer }
}
#[must_use]
pub fn timer(&self) -> &dyn Timer {
self.timer.as_ref()
}
pub fn sleep_until(&self, deadline: MonotonicInstant) -> Result<(), TimeError> {
let future = self.timer.at(deadline)?;
Self::block_on(future)
}
pub fn sleep_for(&self, duration: Duration) -> Result<(), TimeError> {
let future = self.timer.after(duration)?;
Self::block_on(future)
}
fn block_on(mut future: TimerFuture) -> Result<(), TimeError> {
let thread_waker = Arc::new(ThreadWaker::new(std::thread::current()));
let waker = Waker::from(Arc::clone(&thread_waker));
let mut context = Context::from_waker(&waker);
loop {
thread_waker.clear_notification();
if let Poll::Ready(result) = future.as_mut().poll(&mut context) {
return result;
}
while !thread_waker.take_notification() {
std::thread::park();
}
}
}
}
impl std::fmt::Debug for BlockingSleeper {
#[inline]
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter.debug_struct("BlockingSleeper").finish_non_exhaustive()
}
}