mod error;
mod runtime;
mod platform;
mod join_handle;
pub mod time;
pub use join_handle::JoinHandle;
use std::ptr;
use std::pin::pin;
use std::future::Future;
use std::cell::{Cell, RefCell};
use std::task::{Poll, Context, Waker, RawWaker, RawWakerVTable};
use error::InitError;
use runtime::{Runtime, WokenTask};
thread_local! {
pub(crate) static RUNTIME: RefCell<Runtime> = panic!("takyon::init() has not been called on this thread!");
pub(crate) static RUNNING: Cell<bool> = const { Cell::new(false) };
}
static WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(|_| panic!(), |_| (), |_| (), |_| ());
pub fn init() -> Result<(), InitError> {
RUNTIME.set(Runtime::new()?);
Ok(())
}
pub fn run<F: Future>(root_task: F) -> F::Output {
RUNNING.set(true);
let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &WAKER_VTABLE)) };
let mut cx = Context::from_waker(&waker);
let mut root_task = pin!(root_task);
loop {
loop {
let task = RUNTIME.with_borrow_mut(|rt| rt.get_woken_task());
match task {
Some(WokenTask::RootTask) => {
let poll = root_task.as_mut().poll(&mut cx);
if let Poll::Ready(res) = poll {
RUNTIME.with_borrow_mut(|rt| rt.reset());
RUNNING.set(false);
return res;
}
},
Some(WokenTask::ChildTask(mut task)) => {
let poll = task.as_mut().poll(&mut cx);
match poll {
Poll::Pending => RUNTIME.with_borrow_mut(|rt| rt.return_task(task)),
Poll::Ready(res) => RUNTIME.with_borrow_mut(|rt| rt.task_finished(res))
}
},
None => break
}
}
RUNTIME.with_borrow_mut(|rt| rt.wait_for_io());
}
}
pub fn spawn<F: Future + 'static>(task: F) -> JoinHandle<F::Output> {
if !RUNNING.get() {
panic!("takyon::spawn() called outside of a takyon::run() call!")
}
RUNTIME.with_borrow_mut(|rt| rt.spawn(task))
}