use std::any::Any;
use gen_impl::Generator;
use rt::{Context, ContextStack, Error};
use reg_context::RegContext;
#[macro_export]
macro_rules! done { () => ({ return $crate::done() }) }
#[inline]
pub fn done<T>() -> T {
ContextStack::current().top()._ref = 0xf;
unsafe { ::std::mem::uninitialized() }
}
#[inline]
pub fn yield_now() {
let env = ContextStack::current();
let cur = env.top();
raw_yield_now(&env, cur);
}
#[inline]
pub fn raw_yield_now(env: &ContextStack, cur: &mut Context) {
let parent = env.pop_context(cur as *mut _);
RegContext::swap(&mut cur.regs, &parent.regs);
}
#[inline]
fn raw_yield<T: Any>(env: &ContextStack, context: &mut Context, v: T) {
if !context.is_generator() {
panic!("yield from none generator context");
}
context.set_ret(v);
context._ref -= 1;
raw_yield_now(env, context);
if context._ref != 1 {
panic!(Error::Cancel);
}
}
#[inline]
pub fn yield_with<T: Any>(v: T) {
let env = ContextStack::current();
let context = env.top();
raw_yield(&env, context, v);
}
#[inline]
pub fn get_yield<A: Any>() -> Option<A> {
let context = ContextStack::current().top();
raw_get_yield(context)
}
#[inline]
fn raw_get_yield<A: Any>(context: &mut Context) -> Option<A> {
if !context.is_generator() {
error!("get yield from none generator context");
panic!(Error::ContextErr);
}
context.get_para()
}
#[inline]
pub fn yield_<A: Any, T: Any>(v: T) -> Option<A> {
let env = ContextStack::current();
let context = env.top();
raw_yield(&env, context, v);
raw_get_yield(context)
}
pub fn yield_from<A: Any, T: Any>(mut g: Generator<A, T>) -> Option<A> {
let env = ContextStack::current();
let context = env.top();
let mut p = context.get_para();
while !g.is_done() {
match g.raw_send(p) {
None => return None,
Some(r) => raw_yield(&env, context, r),
}
p = context.get_para();
}
p
}
pub fn co_yield_with<T: Any>(v: T) {
let env = ContextStack::current();
let context = env.co_ctx().unwrap();
if context._ref != 1 {
panic!(Error::Cancel);
}
context.set_ret(v);
context._ref -= 1;
let parent = env.pop_context(context);
let top = unsafe { &mut *context.parent };
RegContext::swap(&mut top.regs, &parent.regs);
}
pub fn co_get_yield<A: Any>() -> Option<A> {
match ContextStack::current().co_ctx() {
Some(ctx) => ctx.get_para(),
None => None,
}
}