use crate::{JoinHandle, LocalWaker, Waker, Event};
use core::any::Any;
use core::future::Future;
use core::marker::PhantomData;
use core::pin::Pin;
use core::task::{Context, Poll};
struct WakerFuture;
impl Future for WakerFuture {
type Output = Waker;
fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
let waker = LocalWaker::waker(ctx);
Poll::Ready(waker.clone())
}
}
async fn local_waker() -> Waker {
WakerFuture.await
}
pub async fn spawn<T>(future: T) -> JoinHandle<T::Output>
where
T: Future + 'static,
T::Output: 'static,
{
local_waker().await.task_new(future)
}
struct Yield(bool);
impl Future for Yield {
type Output = ();
fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
if self.0 {
return Poll::Ready(());
}
let waker = LocalWaker::waker(ctx);
waker.wake_by_ref();
self.0 = true;
Poll::Pending
}
}
pub async fn sched_yield() {
Yield(false).await
}
struct Suspend(bool);
impl Future for Suspend {
type Output = ();
fn poll(mut self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll<Self::Output> {
if self.0 {
return Poll::Ready(());
}
self.0 = true;
Poll::Pending
}
}
struct Abort(u64);
impl Future for Abort {
type Output = ();
fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
let waker = LocalWaker::waker(ctx);
waker.task_abort(self.0);
Poll::Ready(())
}
}
pub async fn task_suspend() {
Suspend(false).await
}
pub async fn task_force_abort(task_id: u64) {
Abort(task_id).await
}
pub async fn new_event_id() -> u64 {
local_waker().await.new_event_id()
}
pub async fn current_task_id() -> u64 {
local_waker().await.task_id()
}
pub async fn task_self() -> u64 {
local_waker().await.task_id()
}
struct WaitEvent<'a, T: Any> {
event_id: u64,
waker: Option<Waker>,
mark: PhantomData<&'a T>,
}
impl<'a, T: Any> Future for WaitEvent<'a, T> {
type Output = Option<&'a T>;
fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
let waker = LocalWaker::waker(ctx);
if let Some(data) = waker.event_remove(self.event_id) {
self.waker = None;
return Poll::Ready(data.downcast_ref::<T>());
}
waker.event_register(self.event_id);
if self.waker.is_none() {
self.waker = Some(waker.clone());
}
Poll::Pending
}
}
impl<T: Any> Drop for WaitEvent<'_, T> {
fn drop(&mut self) {
if let Some(waker) = &self.waker {
waker.event_unregister(self.event_id);
}
}
}
pub async fn wait_event<'a, T: Any>(event_id: u64) -> Option<&'a T> {
WaitEvent::<T> {
event_id,
waker: None,
mark: PhantomData,
}.await
}
pub async fn notify_events(events: &[Event<'static>]) {
local_waker().await.notify_events(events);
}
pub async fn task_resume(task_id: u64) {
local_waker().await.task_resume(task_id);
}
enum FutureOrOutput<T: Future> {
Future(T),
Output(Option<T::Output>),
}
pub struct And<T1: Future, T2: Future> {
f1: FutureOrOutput<T1>,
f2: FutureOrOutput<T2>,
}
impl<T1: Future, T2: Future> Unpin for And<T1, T2> {}
impl<T1: Future, T2: Future> Future for And<T1, T2> {
type Output = (T1::Output, T2::Output);
fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
if let FutureOrOutput::Future(ref mut f) = &mut self.f1 {
let pin: Pin<&mut T1> = unsafe { Pin::new_unchecked(f) };
if let Poll::Ready(r) = pin.poll(ctx) {
self.f1 = FutureOrOutput::Output(Some(r));
}
}
if let FutureOrOutput::Future(ref mut f) = &mut self.f2 {
let pin: Pin<&mut T2> = unsafe { Pin::new_unchecked(f) };
if let Poll::Ready(r) = pin.poll(ctx) {
self.f2 = FutureOrOutput::Output(Some(r));
}
}
let this: &mut Self = &mut self;
if let (FutureOrOutput::Output(r1), FutureOrOutput::Output(r2)) =
(&mut this.f1, &mut this.f2)
{
return Poll::Ready((r1.take().unwrap(), r2.take().unwrap()));
}
Poll::Pending
}
}
pub fn and<T1: Future, T2: Future>(
f1: T1,
f2: T2,
) -> And<T1, T2> {
And {
f1: FutureOrOutput::Future(f1),
f2: FutureOrOutput::Future(f2),
}
}
pub struct Or<T1: Future, T2: Future> {
f1: T1,
f2: T2,
}
impl<T1: Future, T2: Future> Unpin for Or<T1, T2> {}
impl<T1: Future, T2: Future> Future for Or<T1, T2> {
type Output = (Option<T1::Output>, Option<T2::Output>);
fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
let pin = unsafe { Pin::new_unchecked(&mut self.f1) };
if let Poll::Ready(r) = pin.poll(ctx) {
return Poll::Ready((Some(r), None));
}
let pin = unsafe { Pin::new_unchecked(&mut self.f2) };
if let Poll::Ready(r) = pin.poll(ctx) {
return Poll::Ready((None, Some(r)));
}
Poll::Pending
}
}
pub fn or<T1: Future, T2: Future>(
f1: T1,
f2: T2,
) -> Or<T1, T2> {
Or { f1, f2 }
}
pub struct PartialOr<T1: Future, T2: Future> {
is_first: bool,
f1: FutureOrOutput<T1>,
f2: FutureOrOutput<T2>,
}
impl<T1: Future, T2: Future> Unpin for PartialOr<T1, T2> {}
impl<T1: Future, T2: Future> Future for PartialOr<T1, T2> {
type Output = (T1::Output, Option<T2::Output>);
fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
if let FutureOrOutput::Future(ref mut f) = &mut self.f1 {
let pin: Pin<&mut T1> = unsafe { Pin::new_unchecked(f) };
if let Poll::Ready(r) = pin.poll(ctx) {
if self.is_first {
return Poll::Ready((r, None));
}
self.f1 = FutureOrOutput::Output(Some(r));
}
}
if self.is_first {
self.is_first = false;
}
if let FutureOrOutput::Future(ref mut f) = &mut self.f2 {
let pin: Pin<&mut T2> = unsafe { Pin::new_unchecked(f) };
if let Poll::Ready(r) = pin.poll(ctx) {
self.f2 = FutureOrOutput::Output(Some(r));
}
}
let this: &mut Self = &mut self;
if let (FutureOrOutput::Output(r1), FutureOrOutput::Output(r2)) =
(&mut this.f1, &mut this.f2)
{
return Poll::Ready((r1.take().unwrap(), r2.take()));
}
Poll::Pending
}
}
pub fn partial_or<T1: Future, T2: Future>(
f1: T1,
f2: T2,
) -> PartialOr<T1, T2> {
PartialOr {
is_first: true,
f1: FutureOrOutput::Future(f1),
f2: FutureOrOutput::Future(f2),
}
}
pub trait Extension {
fn and<T>(self, other: T) -> And<Self, T>
where
Self: Future + Sized,
T: Future + Sized,
{
and(self, other)
}
fn or<T>(self, other: T) -> Or<Self, T>
where
Self: Future + Sized,
T: Future + Sized,
{
or(self, other)
}
fn partial_or<T>(self, other: T) -> PartialOr<Self, T>
where
Self: Future + Sized,
T: Future + Sized,
{
partial_or(self, other)
}
}
impl<T: Future + Sized> Extension for T {}