use smallvec::SmallVec;
use crate::{
dispatch::{stage::Stage, SendDispatcher},
system::RunNow,
world::World,
};
#[cfg(feature = "parallel")]
pub type ThreadPoolWrapper = Option<::std::sync::Arc<::rayon::ThreadPool>>;
pub struct Dispatcher<'a, 'b> {
inner: SendDispatcher<'a>,
thread_local: ThreadLocal<'b>,
}
impl<'a, 'b> Dispatcher<'a, 'b> {
pub fn setup(&mut self, world: &mut World) {
self.inner.setup(world);
for sys in &mut self.thread_local {
sys.setup(world);
}
}
pub fn dispose(self, world: &mut World) {
self.inner.dispose(world);
for sys in self.thread_local {
sys.dispose(world);
}
}
pub fn dispatch(&mut self, world: &World) {
self.inner.dispatch(world);
self.dispatch_thread_local(world);
}
#[cfg(feature = "parallel")]
pub fn dispatch_par(&mut self, world: &World) {
self.inner.dispatch_par(world);
}
pub fn dispatch_seq(&mut self, world: &World) {
self.inner.dispatch_seq(world);
}
pub fn dispatch_thread_local(&mut self, world: &World) {
for sys in &mut self.thread_local {
sys.run_now(world);
}
}
pub fn try_into_sendable(self) -> Result<SendDispatcher<'a>, Self> {
let Dispatcher {
inner: _,
thread_local,
} = &self;
if thread_local.is_empty() {
Ok(self.inner)
} else {
Err(self)
}
}
#[cfg(feature = "parallel")]
pub fn max_threads(&self) -> usize {
self.inner.max_threads()
}
}
impl<'a, 'b, 'c> RunNow<'a> for Dispatcher<'b, 'c> {
fn run_now(&mut self, world: &World) {
self.dispatch(world);
}
fn setup(&mut self, world: &mut World) {
self.setup(world);
}
fn dispose(self: Box<Self>, world: &mut World) {
(*self).dispose(world);
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct SystemId(pub usize);
pub type SystemExecSend<'b> = Box<dyn for<'a> RunNow<'a> + Send + 'b>;
pub type ThreadLocal<'a> = SmallVec<[Box<dyn for<'b> RunNow<'b> + 'a>; 4]>;
#[cfg(feature = "parallel")]
pub fn new_dispatcher<'a, 'b>(
stages: Vec<Stage<'a>>,
thread_local: ThreadLocal<'b>,
thread_pool: ::std::sync::Arc<::std::sync::RwLock<ThreadPoolWrapper>>,
) -> Dispatcher<'a, 'b> {
Dispatcher {
inner: SendDispatcher {
stages,
thread_pool,
},
thread_local,
}
}
#[cfg(not(feature = "parallel"))]
pub fn new_dispatcher<'a, 'b>(
stages: Vec<Stage<'a>>,
thread_local: ThreadLocal<'b>,
) -> Dispatcher<'a, 'b> {
Dispatcher {
inner: SendDispatcher { stages },
thread_local,
}
}
#[cfg(test)]
mod tests {
use crate::{dispatch::builder::DispatcherBuilder, system::*, world::*};
#[derive(Default)]
struct Res(i32);
struct Dummy(i32);
impl<'a> System<'a> for Dummy {
type SystemData = Write<'a, Res>;
fn run(&mut self, mut data: Self::SystemData) {
if self.0 == 4 {
assert_eq!(data.0, 6);
} else if self.0 == 5 {
assert_eq!(data.0, 10);
}
data.0 += self.0;
}
}
struct Panic;
impl<'a> System<'a> for Panic {
type SystemData = ();
fn run(&mut self, _: Self::SystemData) {
panic!("Propagated panic");
}
}
fn new_builder() -> DispatcherBuilder<'static, 'static> {
DispatcherBuilder::new()
.with(Dummy(0), "0", &[])
.with(Dummy(1), "1", &[])
.with(Dummy(2), "2", &[])
.with(Dummy(3), "3", &["1"])
.with_barrier()
.with(Dummy(4), "4", &[])
.with(Dummy(5), "5", &["4"])
}
fn new_world() -> World {
let mut world = World::empty();
world.insert(Res(0));
world
}
#[test]
#[should_panic(expected = "Propagated panic")]
fn dispatcher_panics() {
DispatcherBuilder::new()
.with(Panic, "p", &[])
.build()
.dispatch(&new_world())
}
#[test]
fn stages() {
let mut d = new_builder().build();
d.dispatch(&new_world());
}
#[test]
#[cfg(feature = "parallel")]
fn stages_async() {
let mut d = new_builder().build_async(new_world());
d.dispatch();
}
}