use std::cell::UnsafeCell;
use std::any::Any;
use std::mem;
use context::stack::{StackPool, Stack};
use coroutine::Coroutine;
use {State, Handle};
thread_local!(static COROUTINE_ENVIRONMENT: UnsafeCell<Box<Environment>> = UnsafeCell::new(Environment::new()));
#[allow(raw_pointer_derive)]
pub struct Environment {
stack_pool: StackPool,
coroutine_stack: Vec<*mut Handle>,
_main_coroutine: Handle,
running_state: Option<Box<Any + Send>>,
#[cfg(feature = "enable-clonable-handle")]
switch_state: State,
}
impl Environment {
#[cfg(feature = "enable-clonable-handle")]
fn new() -> Box<Environment> {
let coro = unsafe {
let coro = Coroutine::empty(Some("<Environment Root Coroutine>".to_string()),
State::Running);
coro
};
let mut env = Box::new(Environment {
stack_pool: StackPool::new(),
coroutine_stack: Vec::new(),
_main_coroutine: coro,
running_state: None,
switch_state: State::Suspended,
});
let coro: *mut Handle = &mut env._main_coroutine;
env.coroutine_stack.push(coro);
env
}
#[cfg(not(feature = "enable-clonable-handle"))]
fn new() -> Box<Environment> {
let coro = unsafe {
let coro = Coroutine::empty(Some("<Environment Root Coroutine>".to_string()),
State::Running);
coro
};
let mut env = Box::new(Environment {
stack_pool: StackPool::new(),
coroutine_stack: Vec::new(),
_main_coroutine: coro,
running_state: None,
});
let coro: *mut Handle = &mut env._main_coroutine;
env.coroutine_stack.push(coro);
env
}
#[inline]
pub fn current() -> &'static mut Environment {
COROUTINE_ENVIRONMENT.with(|env| unsafe { &mut *env.get() })
}
#[inline]
pub fn running_count(&self) -> usize {
self.coroutine_stack.len() - 1
}
#[inline]
pub fn running<'a>(&'a self) -> &'static Handle {
self.coroutine_stack
.last()
.map(|hdl| unsafe { (&**hdl) })
.expect("Impossible happened! No current coroutine!")
}
#[inline]
pub fn push(&mut self, hdl: &Handle) {
self.coroutine_stack.push(unsafe { mem::transmute(hdl) });
}
#[inline]
pub fn pop(&mut self) -> Option<&'static Handle> {
if self.running_count() == 0 {
None
} else {
self.coroutine_stack.pop().map(|hdl| unsafe { (&*hdl) })
}
}
#[inline]
pub fn set_resume_result(&mut self, result: Option<Box<Any + Send>>) {
self.running_state = result;
}
#[inline]
#[cfg(feature = "enable-clonable-handle")]
pub fn set_switch_state(&mut self, state: State) {
self.switch_state = state;
}
#[inline]
pub fn take_last_resume_result(&mut self) -> Option<Box<Any + Send>> {
self.running_state.take()
}
#[inline]
#[cfg(feature = "enable-clonable-handle")]
pub fn last_switch_state(&mut self) -> State {
self.switch_state
}
#[inline]
pub fn take_stack(&mut self, size: usize) -> Stack {
self.stack_pool.take_stack(size)
}
#[inline]
pub fn give_stack(&mut self, stack: Stack) {
self.stack_pool.give_stack(stack)
}
}