use alloc::alloc;
use cmd::{Cmd, CmdKind, CmdRes};
use core::alloc::Layout;
use core::ptr;
use core::sync::atomic::AtomicBool;
use drone_core::drv::{Driver, Resource};
use drone_core::ffi::c_void;
#[cfg(feature = "io")]
use drone_core::ffi::CStr;
use drone_core::stack_adapter::{Adapter, Context, Stack};
#[cfg(feature = "io")]
use exec::exec_path;
use exec::{exec_source, UncaughtException};
use futures::prelude::*;
use rt::{gc_init, mp_deinit, mp_init};
static CREATED: AtomicBool = AtomicBool::new(false);
static mut HEAP: *mut u8 = ptr::null_mut();
#[derive(Driver)]
#[driver(forward)]
pub struct MpSessCore<T: MpSessResCore>(T);
pub trait MpSessResCore: Resource<Source = Self> + Driver {
type Stack: Stack<Cmd, CmdRes, Self::Req, Self::ReqRes>;
type Context: Context<Self::Req, Self::ReqRes>;
type Req: Send + 'static;
type ReqRes: Send + 'static;
type Error: From<UncaughtException>;
const STACK_SIZE: usize;
const HEAP_SIZE: usize;
fn stack(&mut self) -> &mut Self::Stack;
fn run_req<'sess>(
&'sess mut self,
req: Self::Req,
) -> Box<Future<Item = Self::ReqRes, Error = Self::Error> + 'sess>;
fn init();
}
impl<T: MpSessResCore> Adapter for MpSessCore<T> {
type Stack = T::Stack;
type Context = T::Context;
type Cmd = Cmd;
type CmdRes = CmdRes;
type Req = T::Req;
type ReqRes = T::ReqRes;
type Error = T::Error;
const STACK_SIZE: usize = T::STACK_SIZE;
fn singleton() -> Option<&'static AtomicBool> {
Some(&CREATED)
}
fn init() {
T::init();
unsafe {
HEAP = alloc::alloc(heap_layout(T::HEAP_SIZE));
gc_init(HEAP as *mut c_void, HEAP.add(T::HEAP_SIZE) as *mut c_void);
mp_init();
}
}
fn deinit() {
unsafe {
mp_deinit();
alloc::dealloc(HEAP, heap_layout(T::HEAP_SIZE));
}
}
fn stack(&mut self) -> &mut Self::Stack {
self.0.stack()
}
fn run_cmd(cmd: Cmd, _context: Self::Context) -> CmdRes {
match cmd {
Cmd(CmdKind::ExecSource { source }) => CmdRes {
exec_source: unsafe { exec_source(&*source) },
},
#[cfg(feature = "io")]
Cmd(CmdKind::ExecPath { path }) => CmdRes {
exec_path: unsafe { exec_path(&*path) },
},
}
}
fn run_req<'sess>(
&'sess mut self,
req: Self::Req,
) -> Box<Future<Item = Self::ReqRes, Error = Self::Error> + 'sess> {
self.0.run_req(req)
}
}
impl<T: MpSessResCore> MpSessCore<T> {
pub fn exec_source<'sess>(
&'sess mut self,
source: &'sess str,
) -> impl Future<Item = (), Error = T::Error> + 'sess {
async(static move || unsafe {
await!(self.cmd(Cmd(CmdKind::ExecSource { source })))?.exec_source?;
Ok(())
})
}
#[cfg(feature = "io")]
pub fn exec_path<'sess>(
&'sess mut self,
path: &'sess CStr,
) -> impl Future<Item = (), Error = T::Error> + 'sess {
async(static move || unsafe {
await!(self.cmd(Cmd(CmdKind::ExecPath { path })))?.exec_path?;
Ok(())
})
}
}
fn heap_layout(size: usize) -> Layout {
unsafe { Layout::from_size_align_unchecked(size, 1) }
}