use std::fmt;
use fxhash::FxHashMap;
use dispatch::Dispatcher;
use dispatch::dispatcher::{SystemId, ThreadLocal};
use dispatch::stage::StagesBuilder;
use system::{RunNow, System};
#[derive(Default)]
pub struct DispatcherBuilder<'a, 'b> {
current_id: usize,
map: FxHashMap<String, SystemId>,
stages_builder: StagesBuilder<'a>,
thread_local: ThreadLocal<'b>,
#[cfg(feature = "parallel")]
thread_pool: Option<::std::sync::Arc<::rayon::ThreadPool>>,
}
impl<'a, 'b> DispatcherBuilder<'a, 'b> {
pub fn new() -> Self {
Default::default()
}
pub fn with<T>(mut self, system: T, name: &str, dep: &[&str]) -> Self
where
T: for<'c> System<'c> + Send + 'a,
{
self.add(system, name, dep);
self
}
pub fn add<T>(&mut self, system: T, name: &str, dep: &[&str])
where
T: for<'c> System<'c> + Send + 'a,
{
use std::collections::hash_map::Entry;
let id = self.next_id();
let dependencies = dep.iter()
.map(|x| {
*self.map
.get(*x)
.expect(&format!("No such system registered (\"{}\")", *x))
})
.collect();
if name != "" {
if let Entry::Vacant(e) = self.map.entry(name.to_owned()) {
e.insert(id);
} else {
panic!(
"Cannot insert multiple systems with the same name (\"{}\")",
name
);
}
}
self.stages_builder.insert(dependencies, id, system);
}
pub fn with_thread_local<T>(mut self, system: T) -> Self
where
T: for<'c> RunNow<'c> + 'b,
{
self.add_thread_local(system);
self
}
pub fn add_thread_local<T>(&mut self, system: T)
where
T: for<'c> RunNow<'c> + 'b,
{
self.thread_local.push(Box::new(system));
}
pub fn with_barrier(mut self) -> Self {
self.add_barrier();
self
}
pub fn add_barrier(&mut self) {
self.stages_builder.add_barrier();
}
#[cfg(feature = "parallel")]
pub fn with_pool(mut self, pool: ::std::sync::Arc<::rayon::ThreadPool>) -> Self {
self.add_pool(pool);
self
}
#[cfg(feature = "parallel")]
pub fn add_pool(&mut self, pool: ::std::sync::Arc<::rayon::ThreadPool>) {
self.thread_pool = Some(pool);
}
pub fn print_par_seq(&self) {
println!("{:#?}", self);
}
pub fn build(self) -> Dispatcher<'a, 'b> {
use dispatch::dispatcher::new_dispatcher;
#[cfg(feature = "parallel")]
let d = new_dispatcher(
self.stages_builder.build(),
self.thread_local,
self.thread_pool.unwrap_or_else(Self::create_thread_pool),
);
#[cfg(not(feature = "parallel"))]
let d = new_dispatcher(self.stages_builder.build(), self.thread_local);
d
}
fn next_id(&mut self) -> SystemId {
let id = self.current_id;
self.current_id += 1;
SystemId(id)
}
#[cfg(feature = "parallel")]
fn create_thread_pool() -> ::std::sync::Arc<::rayon::ThreadPool> {
use rayon::ThreadPoolBuilder;
use std::sync::Arc;
Arc::new(
ThreadPoolBuilder::new()
.build()
.expect("Invalid configuration"),
)
}
}
#[cfg(feature = "parallel")]
impl<'b> DispatcherBuilder<'static, 'b> {
pub fn build_async<R>(self, res: R) -> ::dispatch::async::AsyncDispatcher<'b, R> {
use dispatch::async::new_async;
new_async(
res,
self.stages_builder.build(),
self.thread_local,
self.thread_pool.unwrap_or_else(Self::create_thread_pool),
)
}
}
impl<'a, 'b> fmt::Debug for DispatcherBuilder<'a, 'b> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.stages_builder.write_par_seq(f, &self.map)
}
}