use std::ops::Generator;
use std::ops::GeneratorState;
#[macro_export]
macro_rules! return_from_yield {
($g:expr) => {
unsafe {
match $g.resume() {
GeneratorState::Yielded(_) => return Some(State::Yield(())),
GeneratorState::Complete(ret) => ret
}
}
}
}
#[macro_export]
macro_rules! return_yielded {
($g:expr) => {
unsafe {
match $g.resume() {
GeneratorState::Yielded(y) => return Some(State::Yield(y)),
GeneratorState::Complete(ret) => ret
}
}
}
}
#[derive(Debug)]
pub enum State<Y, R> {
Yield(Y),
Return(R)
}
impl <Y, R: Into<Y>> Into<Option<Y>> for State<Y, R> {
#[inline]
fn into(self) -> Option<Y> {
match self {
State::Yield(value) => Some(value),
State::Return(value) => Some(value.into())
}
}
}
pub type Futor<R> = Option<State<(), R>>;
pub trait Futerator {
type Return;
fn resume(&mut self) -> Futor<Self::Return>;
}
pub type Senor<Y, R> = Option<State<Y, R>>;
pub trait Senerator: Futerator {
type Yield;
fn resume_with_yield(&mut self) -> Senor<Self::Yield, Self::Return>;
}
pub struct Callable<G>(Option<G>);
impl<G> Callable<G> {
#[inline]
pub fn new(g: G) -> Self {
Callable(Some(g))
}
pub fn chain<O>(self, g: impl FnOnce(G::Return) -> O) -> Option<Callable<impl Generator<Yield = G::Yield, Return = G::Return>>>
where
G: Generator,
O: Generator<Yield = G::Yield, Return = G::Return>,
{
let mut generator = self.into_inner()?;
Some(Callable::new(move || {
let ret = yield_from!(generator);
let mut provided_gen = g(ret);
return yield_from!(provided_gen)
}))
}
#[inline]
pub fn move_into<O>(self, func: impl FnOnce(G) -> O) -> Option<Callable<impl Generator<Yield = O::Yield, Return = O::Return>>>
where
G: Generator,
O: Generator,
{
let generator = self.into_inner()?;
Some(Callable::new(func(generator)))
}
#[inline]
pub fn make_new<O>(self, func: impl FnOnce(Self) -> O) -> Option<Callable<impl Generator<Yield = O::Yield, Return = O::Return>>>
where
G: Generator,
O: Generator
{
if self.0.is_some() {
return Some(Callable::new(func(self)))
}
None
}
#[inline]
pub fn borrow_mut<'a, 's: 'a, O>(&'s mut self, func: impl FnOnce(&'a mut Self) -> O) -> Option<Callable<impl Generator<Yield = O::Yield, Return = O::Return>>>
where
G: Generator,
O: Generator
{
if self.0.is_some() {
return Some(Callable::new(func(self)))
}
None
}
#[inline]
pub fn into_inner(self) -> Option<G> {
self.0
}
#[inline]
pub fn take(&mut self) -> Option<G> {
self.0.take()
}
#[inline]
pub fn as_mut(&mut self) -> Option<&mut G> {
self.0.as_mut()
}
}
impl <G> Futerator for Callable<G>
where
G: Generator
{
type Return = G::Return;
#[inline]
fn resume(&mut self) -> Futor<Self::Return> {
let r = return_from_yield!(self.as_mut()?);
self.take();
return Some(State::Return(r));
}
}
impl <'a, G> Futerator for &'a mut G
where
G: Futerator
{
type Return = G::Return;
#[inline]
fn resume(&mut self) -> Futor<Self::Return> {
(*self).resume()
}
}
impl <G> Senerator for Callable<G>
where
G: Generator
{
type Yield = G::Yield;
#[inline]
fn resume_with_yield(&mut self) -> Senor<Self::Yield, Self::Return> {
let r = return_yielded!(self.as_mut()?);
self.take();
return Some(State::Return(r));
}
}
impl <'a, G> Senerator for &'a mut G
where
G: Senerator
{
type Yield = G::Yield;
#[inline]
fn resume_with_yield(&mut self) -> Senor<Self::Yield, Self::Return> {
(*self).resume_with_yield()
}
}
#[cfg(feature = "extfutures")]
pub mod ext_futures {
extern crate futures;
use self::futures::{Future, Stream};
use self::futures::task::Context;
use self::futures::{Async, Poll};
use super::{Callable, Futerator, Senerator, State};
use std::ops::Generator;
impl <G: Generator> Future for Callable<G> {
type Item = G::Return;
type Error = ();
fn poll(&mut self, _cx: &mut Context) -> Poll<Self::Item, Self::Error> {
match self.resume() {
Some(State::Yield(_)) => Ok(Async::Pending),
Some(State::Return(r)) => Ok(Async::Ready(r)),
None => Err(())
}
}
}
impl <G: Generator>Stream for Callable<G> {
type Item = G::Yield;
type Error = ();
fn poll_next(&mut self, _cx: &mut Context) -> Poll<Option<Self::Item>, Self::Error> {
match self.resume_with_yield() {
Some(State::Yield(y)) => Ok(Async::Ready(Some(y))),
Some(State::Return(_)) => Ok(Async::Ready(None)),
None => Ok(Async::Ready(None)),
}
}
}
}