use crate::*;
use core::cell::Cell;
use core::future::Future;
#[cfg(feature="alloc")]
use core::mem::ManuallyDrop;
use core::pin::Pin;
use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
#[macro_export]
macro_rules! local {
($name:ident) => {
let mut $name = unsafe { $crate::Local::new($name) };
#[allow(unused_mut)]
let mut $name = unsafe { core::pin::Pin::new_unchecked(&mut $name) };
};
($name:ident : $future:expr) => {
let mut $name = unsafe { $crate::Local::new($future) };
#[allow(unused_mut)]
let mut $name = unsafe { core::pin::Pin::new_unchecked(&mut $name) };
}
}
pub struct Local<F> {
wakey: Wakey,
future: F,
}
impl<F: Future> Local<F> {
#[inline(always)]
pub fn new(future: F) -> Local<F> {
let wakey = Wakey::default();
Local { wakey, future }
}
#[inline(always)]
pub fn woken(self: &mut Pin<&mut Self>) -> u16 {
self.as_mut().project().wakey.woken.get()
}
#[inline(always)]
pub fn cloned(self: &mut Pin<&mut Self>) -> u16 {
self.as_mut().project().wakey.cloned.get()
}
#[inline(always)]
pub fn dropped(self: &mut Pin<&mut Self>) -> u16 {
self.as_mut().project().wakey.dropped.get()
}
#[inline(always)]
pub fn stats(self: &mut Pin<&mut Self>) -> Stats {
let wakey = &self.as_mut().project().wakey;
Stats {
cloned: wakey.cloned.get(),
dropped: wakey.dropped.get(),
woken: wakey.woken.get(),
}
}
#[inline(always)]
pub fn live(self: &mut Pin<&mut Self>) -> u16 {
let wakey = &self.as_mut().project().wakey;
wakey.cloned.get() - wakey.dropped.get()
}
#[inline(always)]
pub unsafe fn poll(
self: &mut Pin<&mut Self>
) -> Poll<<F as Future>::Output> {
let this = self.as_mut().project();
let waker = ManuallyDrop::new(this.waker());
let future = Pin::new_unchecked(&mut this.future);
let mut ctx = Context::from_waker(&waker);
Future::poll(future, &mut ctx)
}
#[inline(always)]
pub unsafe fn poll_while_woken(
self: &mut Pin<&mut Self>
) -> Poll<<F as Future>::Output> {
let mut woken = self.woken();
loop {
if let Poll::Ready(r) = self.poll() { return Poll::Ready(r); }
let w = self.woken();
if w == woken { return Poll::Pending; }
woken = w;
}
}
#[inline(always)]
fn waker(&self) -> Waker {
let raw = raw_waker(&self.wakey as *const Wakey);
unsafe { Waker::from_raw(raw) }
}
#[inline(always)]
fn project(self: Pin<&mut Self>) -> &mut Self {
unsafe { Pin::into_inner_unchecked(self) }
}
}
#[derive(Default)]
struct Wakey {
cloned: Cell<u16>,
dropped: Cell<u16>,
woken: Cell<u16>,
}
impl Wakey {
fn bump_cloned(&self) { self.cloned.set(self.cloned.get() + 1) }
fn bump_woken(&self) { self.woken.set(self.woken.get() + 1) }
fn bump_dropped(&self) { self.dropped.set(self.dropped.get() + 1) }
}
fn raw_waker(wakey: *const Wakey) -> RawWaker {
fn do_clone(data: *const ()) -> RawWaker {
unsafe { &*data.cast::<Wakey>() }.bump_cloned();
raw_waker(data.cast())
}
fn do_wake(data: *const ()) {
do_wake_by_ref(data);
do_drop(data);
}
fn do_wake_by_ref(data: *const ()) {
unsafe { &*data.cast::<Wakey>() }.bump_woken()
}
fn do_drop(data: *const ()) {
unsafe { &*data.cast::<Wakey>() }.bump_dropped()
}
RawWaker::new(
wakey.cast(),
&RawWakerVTable::new(do_clone, do_wake, do_wake_by_ref, do_drop)
)
}