use core::cell::Cell;
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll};
use completion_core::CompletionFuture;
use pin_project_lite::pin_project;
#[cfg(test)]
mod tests;
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "macro", feature = "std"))))]
pub use completion_macro::completion;
#[doc(hidden)]
pub use completion_macro::completion_async_inner as __completion_async_inner;
#[doc(hidden)]
pub use completion_macro::completion_async_move_inner as __completion_async_move_inner;
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "macro", feature = "std"))))]
#[macro_export]
macro_rules! completion_async {
($($tt:tt)*) => {
$crate::__completion_async_inner!(($crate) $($tt)*)
}
}
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "macro", feature = "std"))))]
#[macro_export]
macro_rules! completion_async_move {
($($tt:tt)*) => {
$crate::__completion_async_move_inner!(($crate) $($tt)*)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum State {
None,
Polling,
Cancelling,
CompletionPollPending,
CancelReady,
CancelPending,
}
thread_local! {
static STATE: Cell<State> = Cell::new(State::None);
}
#[doc(hidden)]
pub fn __completion_async<F: Future>(fut: F) -> impl CompletionFuture<Output = F::Output> {
pin_project! {
struct Wrapper<F> {
#[pin]
fut: F,
awaiting_on_completion: bool,
}
}
impl<F: Future> CompletionFuture for Wrapper<F> {
type Output = F::Output;
unsafe fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
STATE.with(|state| state.set(State::Polling));
let poll = this.fut.poll(cx);
if poll.is_pending() {
*this.awaiting_on_completion = match STATE.with(Cell::get) {
State::Polling => false,
State::CompletionPollPending => true,
state => panic!("invalid state {:?}", state),
};
}
poll
}
unsafe fn poll_cancel(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
let this = self.project();
if *this.awaiting_on_completion {
STATE.with(|state| state.set(State::Cancelling));
let poll = this.fut.poll(cx);
debug_assert!(poll.is_pending());
match STATE.with(Cell::get) {
State::CancelReady => Poll::Ready(()),
State::CancelPending => Poll::Pending,
state => panic!("invalid state {:?}", state),
}
} else {
Poll::Ready(())
}
}
}
Wrapper {
fut,
awaiting_on_completion: false,
}
}
mod r#await {
use pin_project_lite::pin_project;
pin_project! {
#[derive(Debug)]
pub struct Await<F> {
#[pin]
pub(super) fut: F,
}
}
}
use r#await::Await;
impl<F: CompletionFuture> Future for Await<F> {
type Output = F::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
match STATE.with(Cell::get) {
State::Polling => {
let poll = unsafe { this.fut.poll(cx) };
if poll.is_pending() {
STATE.with(|state| state.set(State::CompletionPollPending));
}
poll
}
State::Cancelling => {
let poll = unsafe { this.fut.poll_cancel(cx) };
STATE.with(|state| {
state.set(match poll {
Poll::Ready(()) => State::CancelReady,
Poll::Pending => State::CancelPending,
})
});
Poll::Pending
}
state => panic!("invalid state {:?}", state),
}
}
}
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct __FutureOrCompletionFuture<F>(pub F);
impl<F: Future> __FutureOrCompletionFuture<F> {
pub fn __into_awaitable(self) -> F {
self.0
}
}
#[doc(hidden)]
pub trait __CompletionFutureIntoAwaitable {
type Future;
fn __into_awaitable(self) -> Self::Future;
}
impl<F> __CompletionFutureIntoAwaitable for __FutureOrCompletionFuture<F> {
type Future = Await<F>;
fn __into_awaitable(self) -> Self::Future {
Await { fut: self.0 }
}
}
#[doc(hidden)]
pub mod __special_macros {
pub use core::{
assert, assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, format_args,
matches, panic, todo, unimplemented, unreachable, write, writeln,
};
pub use alloc::{format, vec};
pub use std::{dbg, eprint, eprintln, print, println};
}