use std::marker::PhantomData;
use crate::{
World,
query::{Query, Queryable, ToFilter},
};
use indexmap::IndexMap;
use nya_core::sparse_set::SparseSet;
pub trait System: 'static {
fn run(&self, world: &mut World);
}
pub struct QuerySystem<F: ToFilter, C: Fn(Query, &mut World) = fn(Query, &mut World)> {
callback: C,
_marker: PhantomData<F>,
}
impl<F: ToFilter, C: Fn(Query, &mut World)> QuerySystem<F, C> {
pub const fn new(callback: C) -> Self {
Self {
callback,
_marker: PhantomData,
}
}
}
impl<F: ToFilter, C: Fn(Query, &mut World)> System for QuerySystem<F, C>
where
Self: 'static,
{
fn run(&self, world: &mut World) {
let query = world.query::<F>();
(self.callback)(query, world);
}
}
pub struct SystemManager {
pub world: World,
runlevels: IndexMap<usize, SparseSet<Box<dyn System>>>,
}
impl SystemManager {
pub fn new(world: World) -> Self {
SystemManager {
world,
runlevels: IndexMap::with_capacity(2),
}
}
pub fn has_runlevel(&self, level: usize) -> bool {
self.runlevels.contains_key(&level)
}
pub fn add_system<S: System>(&mut self, level: usize, system: S) -> usize {
self.runlevels
.entry(level)
.or_default()
.insert(Box::new(system))
}
pub fn remove_system<S: System>(&mut self, level: usize, system: usize) {
self.runlevels.entry(level).or_default().remove(system);
}
pub fn run_systems(&mut self, level: usize) {
if let Some(systems) = self.runlevels.get(&level) {
for s in systems {
s.value.run(&mut self.world);
}
}
}
}
#[cfg(test)]
mod tests {
use crate::{
Exclude, World, component,
system::{QuerySystem, SystemManager},
};
#[allow(dead_code)]
struct Tag(i32);
component!(Tag);
struct Hello;
component!(Hello);
#[test]
fn basic_query() {
let mut manager = SystemManager::new(World::new());
for i in 0..10 {
let e = manager.world.spawn();
manager.world.add(e, Tag(32));
if i % 2 == 0 {
manager.world.add(e, Hello);
}
}
manager.add_system(
0,
QuerySystem::<(Tag, Exclude<(Hello,)>)>::new(|query, world| {
let _ = world;
println!("{:?}", query.entities());
}),
);
manager.run_systems(0);
manager.run_systems(1); }
}