use std::cell::Cell;
use std::cell::UnsafeCell;
use std::mem::MaybeUninit;
use std::ops::Deref;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
use std::task::Waker;
use std::time::Duration;
use cooked_waker::IntoWaker;
use cooked_waker::ViaRawPointer;
use cooked_waker::Wake;
use cooked_waker::WakeRef;
use crate::reactor::Reactor;
use crate::reactor::ReactorInstant;
use crate::reactor::ReactorTimer;
#[repr(transparent)]
struct OwnedPtr<T> {
ptr: *mut T,
}
impl<T> OwnedPtr<T> {
fn from_box(b: Box<T>) -> Self {
Self {
ptr: Box::into_raw(b),
}
}
}
impl<T> Deref for OwnedPtr<T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.ptr }
}
}
impl<T> std::ops::DerefMut for OwnedPtr<T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.ptr }
}
}
impl<T> Drop for OwnedPtr<T> {
fn drop(&mut self) {
unsafe {
let _ = Box::from_raw(self.ptr);
}
}
}
struct MutableSleep<Tmr: ReactorTimer> {
sleep: UnsafeCell<Option<Tmr>>,
ready: Cell<bool>,
external_waker: UnsafeCell<Option<Waker>>,
internal_waker: Waker,
}
impl<Tmr: ReactorTimer + 'static> MutableSleep<Tmr> {
fn new() -> OwnedPtr<Self> {
unsafe {
let mut ptr = OwnedPtr::from_box(Box::new(MaybeUninit::<Self>::uninit()));
let raw = ptr.as_ptr();
ptr.write(MutableSleep {
sleep: Default::default(),
ready: Default::default(),
external_waker: Default::default(),
internal_waker: MutableSleepWaker::<Tmr> { inner: raw }.into_waker(),
});
std::mem::transmute(ptr)
}
}
fn poll_ready(&self, cx: &mut Context) -> Poll<()> {
if self.ready.take() {
Poll::Ready(())
} else {
let external =
unsafe { self.external_waker.get().as_mut().unwrap_unchecked() };
if let Some(external) = external {
let waker = cx.waker();
if !external.will_wake(waker) {
external.clone_from(waker);
}
#[cfg(not(miri))]
{
let sleep = unsafe { self.sleep.get().as_mut().unwrap_unchecked() };
if let Some(sleep) = sleep
&& Tmr::Instant::now() >= sleep.deadline()
{
return Poll::Ready(());
}
}
Poll::Pending
} else {
*external = Some(cx.waker().clone());
Poll::Pending
}
}
}
fn clear(&self) {
unsafe {
*self.sleep.get() = None;
}
self.ready.set(false);
}
fn change(&self, timer: Tmr) {
let pin = unsafe {
*self.sleep.get() = Some(timer);
Pin::new_unchecked(
self
.sleep
.get()
.as_mut()
.unwrap_unchecked()
.as_mut()
.unwrap_unchecked(),
)
};
let waker = &self.internal_waker;
if pin.poll(&mut Context::from_waker(waker)).is_ready() {
self.ready.set(true);
self.internal_waker.wake_by_ref();
}
}
}
#[repr(transparent)]
struct MutableSleepWaker<Tmr: ReactorTimer> {
inner: *const MutableSleep<Tmr>,
}
impl<Tmr: ReactorTimer> Clone for MutableSleepWaker<Tmr> {
fn clone(&self) -> Self {
MutableSleepWaker { inner: self.inner }
}
}
unsafe impl<Tmr: ReactorTimer> Send for MutableSleepWaker<Tmr> {}
unsafe impl<Tmr: ReactorTimer> Sync for MutableSleepWaker<Tmr> {}
impl<Tmr: ReactorTimer> WakeRef for MutableSleepWaker<Tmr> {
fn wake_by_ref(&self) {
unsafe {
let this = self.inner.as_ref().unwrap_unchecked();
this.ready.set(true);
let waker = this.external_waker.get().as_mut().unwrap_unchecked();
if let Some(waker) = waker.as_ref() {
waker.wake_by_ref();
}
}
}
}
impl<Tmr: ReactorTimer> Wake for MutableSleepWaker<Tmr> {
fn wake(self) {
self.wake_by_ref()
}
}
impl<Tmr: ReactorTimer> Drop for MutableSleepWaker<Tmr> {
fn drop(&mut self) {}
}
unsafe impl<Tmr: ReactorTimer> ViaRawPointer for MutableSleepWaker<Tmr> {
type Target = ();
fn into_raw(self) -> *mut () {
self.inner as _
}
unsafe fn from_raw(ptr: *mut ()) -> Self {
MutableSleepWaker { inner: ptr as _ }
}
}
pub(crate) struct UserTimer<R: Reactor> {
reactor: R,
sleep: OwnedPtr<MutableSleep<R::Timer>>,
base_instant: R::Instant,
refed: Cell<bool>,
}
impl<R: Reactor + Default> Default for UserTimer<R> {
fn default() -> Self {
Self::new(R::default())
}
}
impl<R: Reactor> UserTimer<R> {
pub fn new(reactor: R) -> Self {
Self {
base_instant: reactor.now(),
sleep: MutableSleep::new(),
reactor,
refed: Cell::new(false),
}
}
pub fn schedule(&self, delay: Duration) {
let deadline = self.reactor.now().checked_add(delay).unwrap();
self.sleep.change(self.reactor.timer(deadline));
}
pub fn clear(&self) {
self.sleep.clear();
}
pub fn poll_ready(&self, cx: &mut Context) -> Poll<()> {
self.sleep.poll_ready(cx)
}
pub fn now(&self) -> f64 {
self.base_instant.elapsed().as_secs_f64() * 1000.0
}
pub fn ref_timer(&self) {
self.refed.set(true);
}
pub fn unref_timer(&self) {
self.refed.set(false);
}
pub fn is_refed(&self) -> bool {
self.refed.get()
}
}