#![no_std]
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
pub mod prelude;
#[doc(no_inline)]
pub use core::future::Future;
#[doc(no_inline)]
pub use core::pin::Pin;
#[doc(no_inline)]
pub use core::task::{Context, Poll, Waker};
use core::fmt;
use pin_project_lite::pin_project;
#[inline(always)]
pub fn poll_fn<F, T>(inner: F) -> PollFn<F>
where
F: FnMut(&mut Context<'_>) -> Poll<T>,
{
PollFn { inner }
}
pin_project! {
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct PollFn<F> {
inner: F,
}
}
impl<F> fmt::Debug for PollFn<F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PollFn").finish()
}
}
impl<F, T> Future for PollFn<F>
where
F: FnMut(&mut Context<'_>) -> Poll<T>,
{
type Output = T;
fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<T> {
let this = self.project();
(this.inner)(ctx)
}
}
pin_project! {
#[derive(Debug)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Or<F1, F2> {
#[pin]
future1: F1,
#[pin]
future2: F2,
}
}
impl<F1, F2> Or<F1, F2>
where
F1: Future,
F2: Future,
{
pub fn new(future1: F1, future2: F2) -> Self {
Or { future1, future2 }
}
}
impl<T, F1, F2> Future for Or<F1, F2>
where
F1: Future<Output = T>,
F2: Future<Output = T>,
{
type Output = T;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
if let Poll::Ready(t) = this.future1.poll(cx) {
Poll::Ready(t)
} else if let Poll::Ready(t) = this.future2.poll(cx) {
Poll::Ready(t)
} else {
Poll::Pending
}
}
}
pin_project! {
#[derive(Debug)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Zip<F1, F2>
where
F1: Future,
F2: Future,
{
#[pin]
future1: F1,
output1: Option<F1::Output>,
#[pin]
future2: F2,
output2: Option<F2::Output>,
}
}
impl<F1, F2> Zip<F1, F2>
where
F1: Future,
F2: Future,
{
pub fn new(future1: F1, future2: F2) -> Self {
Zip {
future1,
future2,
output1: None,
output2: None,
}
}
}
impl<F1, F2> Future for Zip<F1, F2>
where
F1: Future,
F2: Future,
{
type Output = (F1::Output, F2::Output);
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
if this.output1.is_none() {
if let Poll::Ready(out) = this.future1.poll(cx) {
*this.output1 = Some(out);
}
}
if this.output2.is_none() {
if let Poll::Ready(out) = this.future2.poll(cx) {
*this.output2 = Some(out);
}
}
if this.output1.is_some() && this.output2.is_some() {
Poll::Ready((this.output1.take().unwrap(), this.output2.take().unwrap()))
} else {
Poll::Pending
}
}
}
pub fn waker() -> impl Future<Output = Waker> {
poll_fn(|ctx| Poll::Ready(ctx.waker().clone()))
}
pub fn sleep() -> impl Future<Output = ()> {
let mut done = false;
poll_fn(move |_| {
if done {
Poll::Ready(())
} else {
done = true;
Poll::Pending
}
})
}
pub fn yield_once() -> impl Future<Output = ()> {
let mut done = false;
poll_fn(move |ctx| {
if done {
Poll::Ready(())
} else {
done = true;
ctx.waker().wake_by_ref();
Poll::Pending }
})
}
#[doc(hidden)]
#[macro_export]
macro_rules! __internal_fold_with {
($func:path, $e:expr) => { $e };
($func:path, $e:expr, $($es:expr),+) => {
$func($e, $crate::__internal_fold_with!($func, $($es),+))
};
}
#[macro_export]
macro_rules! or {
($($es:expr),+$(,)?) => { $crate::__internal_fold_with!($crate::Or::new, $($es),+) };
}
#[macro_export]
macro_rules! pin {
($($x:ident),* $(,)?) => {
$(
let mut $x = $x;
#[allow(unused_mut)]
let mut $x = unsafe {
core::pin::Pin::new_unchecked(&mut $x)
};
)*
}
}
#[macro_export]
macro_rules! ready {
($e:expr $(,)?) => {
match $e {
core::task::Poll::Ready(t) => t,
t @ core::task::Poll::Pending => return t,
}
};
}
#[macro_export]
macro_rules! zip {
($($es:expr),+ $(,)?) => {{
let mut zips = $crate::__internal_fold_with!($crate::Zip::new, $($es),+);
$crate::poll_fn(move |ctx| {
use ::core::pin::Pin;
use ::core::task::Poll;
let zips = unsafe { Pin::new_unchecked(&mut zips) };
if let Poll::Ready(val) = ::core::future::Future::poll(zips, ctx) {
Poll::Ready($crate::zip!(@flatten; ; val; $($es),+))
} else {
Poll::Pending
}
})
}};
(@flatten; $($prev:expr,)*; $tuple:expr; $e:expr) => {
($($prev,)* $tuple)
};
(@flatten; $($prev:expr,)*; $tuple:expr; $e:expr, $($es:expr),+) => {
$crate::zip!(@flatten; $($prev,)* $tuple.0,; $tuple.1; $($es),+)
};
}