#![feature(generator_trait, never_type, stmt_expr_attributes, proc_macro_hygiene)]
use proc_macro_hack::proc_macro_hack;
use std::marker::PhantomData;
use std::pin::Pin;
use std::sync::Arc;
use std::thread;
pub use eff_attr::eff;
#[doc(hidden)]
pub use pin_utils::pin_mut;
#[doc(hidden)]
pub use std::pin as pin_reexport;
pub mod context;
pub mod coproduct;
pub mod either;
pub mod embed;
#[cfg(feature = "futures-compat")]
pub mod futures_compat;
pub mod generator;
pub mod handled;
pub mod lazy;
pub mod next_event;
pub mod poll_fn;
pub use context::{poll_with_task_context, Context, Notify, TypedContext, Waker};
pub use generator::from_generator;
pub use lazy::{lazy, pure};
use either::Either;
use embed::EmbedEffect;
use handled::Handled;
use next_event::NextEvent;
#[macro_export]
macro_rules! Coproduct {
() => {
!
};
(: $tail:ty) => {
$tail
};
($head:ty $(,$tail:ty)* $(,)?) => {
$crate::coproduct::Either<$head, $crate::Coproduct![$($tail),*]>
};
($head:ty $(,$middle:ty)* : $tail:ty) => {
$crate::coproduct::Either<$head, $crate::Coproduct![$($middle),* : $tail]>
};
}
#[macro_export]
macro_rules! perform {
($eff:expr) => {{
let eff = $eff;
let cx = $crate::context::get_task_context();
let (waker, receiver) = $crate::context::channel(cx);
yield $crate::Poll::Event($crate::Event::Effect($crate::coproduct::Inject::inject(
eff, waker,
)));
loop {
if let Ok(v) = receiver.try_recv() {
break v;
} else {
yield $crate::Poll::Pending;
}
}
}};
}
#[macro_export]
macro_rules! reperform_rest {
($eff:expr) => {{
yield $crate::Poll::Event($crate::Event::Effect(
$crate::coproduct::EmbedRest::embed_rest($eff),
));
}};
}
#[macro_export]
macro_rules! perform_from {
($eff:expr) => {{
let eff = $eff;
$crate::pin_mut!(eff);
loop {
let eff = $crate::pin_reexport::Pin::as_mut(&mut eff);
match $crate::poll_with_task_context(eff) {
$crate::Poll::Event($crate::Event::Complete(x)) => break x,
$crate::Poll::Event($crate::Event::Effect(e)) => {
#[allow(unreachable_code)]
yield $crate::Poll::Event($crate::Event::Effect(
$crate::coproduct::Embed::embed(e),
));
}
$crate::Poll::Pending => {
yield $crate::Poll::Pending;
}
}
}
}};
}
#[proc_macro_hack]
pub use eff_attr::poll;
#[doc(hidden)]
#[macro_export]
macro_rules! handler_impl {
($e:expr , ) => {{
let e: ! = $e;
e
}};
($e:expr , $effect:pat, $k:pat => $handler:expr; $($effects:pat, $ks:pat => $handlers:expr;)*) => {{
match $e {
$crate::coproduct::Either::A($effect, $k) => $handler,
$crate::coproduct::Either::B(effect) => $crate::handler_impl!(effect , $($effects, $ks => $handlers;)*),
}
}};
}
#[macro_export]
macro_rules! handler {
($value:pat => $value_handler:expr $(, $effect:pat, $k:pat => $handler:expr)* $(,)?) => {{
#[allow(unreachable_code)]
|arg| $crate::from_generator(static move || {
if false {
yield unreachable!();
}
match arg {
$crate::Event::Complete(x) => match x {
$value => $value_handler,
},
$crate::Event::Effect(e) => $crate::handler_impl!(e , $($effect, $k => $handler;)*),
}
})
}};
}
#[macro_export]
macro_rules! effectful {
($($tts:tt)*) => {{
$crate::from_generator(static move || {
$($tts)*
})
}};
}
pub trait Effect {
type Output;
}
#[derive(Debug)]
pub struct Continue<R>(PhantomData<R>);
impl<R> Effect for Continue<R> {
type Output = R;
}
impl<R> Continue<R> {
fn new() -> Self {
Continue(PhantomData)
}
}
#[derive(Debug)]
pub enum Event<T, Effect> {
Complete(T),
Effect(Effect),
}
#[derive(Debug)]
pub enum Poll<T, Effect> {
Event(Event<T, Effect>),
Pending,
}
impl<T, Effect> Poll<T, Effect> {
pub fn complete(v: T) -> Poll<T, Effect> {
Poll::Event(Event::Complete(v))
}
pub fn effect(e: Effect) -> Poll<T, Effect> {
Poll::Event(Event::Effect(e))
}
}
pub trait Effectful {
type Output;
type Effect;
#[inline]
fn handle<H, HC, Effect, I>(self, handler: H) -> Handled<Self, H, HC, Effect, I>
where
Self: Sized,
HC: Effectful,
H: FnMut(Event<Self::Output, Effect>) -> HC,
Self::Effect: coproduct::Subset<Effect, I>,
{
Handled::new(self, handler)
}
#[inline]
fn embed<Target, Indices>(self) -> EmbedEffect<Self, Target, Indices>
where
Self: Sized,
{
EmbedEffect::new(self)
}
#[inline]
fn left<R>(self) -> Either<Self, R>
where
Self: Sized,
{
Either::A(self)
}
#[inline]
fn right<L>(self) -> Either<L, Self>
where
Self: Sized,
{
Either::B(self)
}
#[inline]
fn boxed<'a>(self) -> Pin<Box<dyn Effectful<Output = Self::Output, Effect = Self::Effect> + 'a>>
where
Self: Sized + 'a,
{
Box::pin(self)
}
#[inline]
fn output<T>(self) -> Self
where
Self: Effectful<Output = T> + Sized,
{
self
}
#[inline]
fn effect<E>(self) -> Self
where
Self: Effectful<Effect = E> + Sized,
{
self
}
#[cfg(feature = "futures-compat")]
#[inline]
fn into_future(self) -> futures_compat::future::IntoFuture<Self>
where
Self: Effectful<Effect = !> + Sized,
{
futures_compat::future::IntoFuture(self)
}
#[inline]
fn block_on(self) -> Self::Output
where
Self: Sized + Effectful<Effect = !>,
{
struct CurrentThreadNotify {
thread: thread::Thread,
}
impl Notify for CurrentThreadNotify {
fn wake(&self) {
self.thread.unpark();
}
}
let this = self;
pin_mut!(this);
let cx = Context::from_notify(Arc::new(CurrentThreadNotify {
thread: thread::current(),
}));
loop {
match this.as_mut().poll(&cx) {
Poll::Event(Event::Complete(v)) => return v,
Poll::Event(Event::Effect(e)) => e,
Poll::Pending => thread::park(),
}
}
}
#[inline]
fn next_event(self) -> NextEvent<Self>
where
Self: Sized,
{
next_event::NextEvent::Computation(self)
}
fn poll(self: Pin<&mut Self>, cx: &Context) -> Poll<Self::Output, Self::Effect>;
}
impl<C> Effectful for &'_ mut C
where
C: Effectful + Unpin + ?Sized,
{
type Output = C::Output;
type Effect = C::Effect;
#[inline]
fn poll(mut self: Pin<&mut Self>, cx: &Context) -> Poll<Self::Output, Self::Effect> {
C::poll(Pin::new(&mut **self), cx)
}
}
impl<C> Effectful for Pin<&'_ mut C>
where
C: Effectful + ?Sized,
{
type Output = C::Output;
type Effect = C::Effect;
#[inline]
fn poll(mut self: Pin<&mut Self>, cx: &Context) -> Poll<Self::Output, Self::Effect> {
C::poll((*self).as_mut(), cx)
}
}
impl<C> Effectful for Box<C>
where
C: Effectful + Unpin + ?Sized,
{
type Output = C::Output;
type Effect = C::Effect;
#[inline]
fn poll(mut self: Pin<&mut Self>, cx: &Context) -> Poll<Self::Output, Self::Effect> {
C::poll(Pin::new(&mut **self), cx)
}
}
impl<C> Effectful for Pin<Box<C>>
where
C: Effectful + ?Sized,
{
type Output = C::Output;
type Effect = C::Effect;
#[inline]
fn poll(mut self: Pin<&mut Self>, cx: &Context) -> Poll<Self::Output, Self::Effect> {
C::poll((*self).as_mut(), cx)
}
}