1use std::marker::PhantomData;
4
5use crate::{
6 World,
7 query::{Query, Queryable, ToFilter},
8};
9
10use indexmap::IndexMap;
11use nya_core::sparse_set::SparseSet;
12
13pub trait System: 'static {
15 fn run(&self, world: &mut World);
17}
18
19pub struct QuerySystem<F: ToFilter, C: Fn(Query, &mut World) = fn(Query, &mut World)> {
21 callback: C,
22 _marker: PhantomData<F>,
23}
24
25impl<F: ToFilter, C: Fn(Query, &mut World)> QuerySystem<F, C> {
26 pub const fn new(callback: C) -> Self {
28 Self {
29 callback,
30 _marker: PhantomData,
31 }
32 }
33}
34
35impl<F: ToFilter, C: Fn(Query, &mut World)> System for QuerySystem<F, C>
36where
37 Self: 'static,
38{
39 fn run(&self, world: &mut World) {
40 let query = world.query::<F>();
41 (self.callback)(query, world);
42 }
43}
44
45pub struct SystemManager {
47 pub world: World,
49 runlevels: IndexMap<usize, SparseSet<Box<dyn System>>>,
50}
51
52impl SystemManager {
53 pub fn new(world: World) -> Self {
55 SystemManager {
56 world,
57 runlevels: IndexMap::with_capacity(2),
58 }
59 }
60
61 pub fn has_runlevel(&self, level: usize) -> bool {
63 self.runlevels.contains_key(&level)
64 }
65
66 pub fn add_system<S: System>(&mut self, level: usize, system: S) -> usize {
68 self.runlevels
69 .entry(level)
70 .or_default()
71 .insert(Box::new(system))
72 }
73
74 pub fn remove_system<S: System>(&mut self, level: usize, system: usize) {
76 self.runlevels.entry(level).or_default().remove(system);
77 }
78
79 pub fn run_systems(&mut self, level: usize) {
81 if let Some(systems) = self.runlevels.get(&level) {
82 for s in systems {
83 s.value.run(&mut self.world);
84 }
85 }
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use crate::{
92 Exclude, World, component,
93 system::{QuerySystem, SystemManager},
94 };
95
96 #[allow(dead_code)]
97 struct Tag(i32);
98 component!(Tag);
99
100 struct Hello;
101 component!(Hello);
102
103 #[test]
104 fn basic_query() {
105 let mut manager = SystemManager::new(World::new());
106
107 for i in 0..10 {
108 let e = manager.world.spawn();
109 manager.world.add(e, Tag(32));
110
111 if i % 2 == 0 {
112 manager.world.add(e, Hello);
113 }
114 }
115
116 manager.add_system(
117 0,
118 QuerySystem::<(Tag, Exclude<(Hello,)>)>::new(|query, world| {
119 let _ = world;
120 println!("{:?}", query.entities());
121 }),
122 );
123
124 manager.run_systems(0);
125 manager.run_systems(1); }
127}