1pub(crate) mod component;
2
3use crate::entity::ArchetypeId;
4use crate::system::component::{
5 CompMutability, GenericComponentGlobalAccess, GlobalComponentAccess, GlobalComponentAccessMut,
6};
7use crate::{Component, EntityStorage, HashMap};
8use std::any::TypeId;
9use std::cell::{RefCell, UnsafeCell};
10use std::collections::hash_map;
11use std::pin::Pin;
12use std::vec;
13
14pub trait SystemHandler: Send + Sync {
15 fn run(&mut self, data: SystemAccess);
16}
17
18impl<F: FnMut(SystemAccess) + Send + Sync> SystemHandler for F {
19 fn run(&mut self, data: SystemAccess) {
20 self(data);
21 }
22}
23
24pub struct System<'a> {
26 handler: Box<&'a mut dyn SystemHandler>,
27 components: HashMap<TypeId, CompMutability>,
28}
29
30impl<'a> System<'a> {
31 pub fn new(handler: &'a mut impl SystemHandler) -> Self {
33 Self {
34 handler: Box::new(handler),
35 components: Default::default(),
36 }
37 }
38
39 pub fn with<C: Component>(mut self) -> Self {
41 self.components.insert(TypeId::of::<C>(), false);
42 self
43 }
44
45 pub fn with_mut<C: Component>(mut self) -> Self {
47 self.components.insert(TypeId::of::<C>(), true);
48 self
49 }
50}
51
52pub struct SystemAccess<'a> {
54 storage: &'a EntityStorage,
55 new_components_allowed: bool,
58 global_components:
60 UnsafeCell<HashMap<TypeId, Pin<Box<RefCell<GenericComponentGlobalAccess<'a>>>>>>,
61}
62
63impl<'a> SystemAccess<'a> {
64 fn get_component(&self, ty: TypeId) -> Option<&RefCell<GenericComponentGlobalAccess<'a>>> {
65 let global_components = unsafe { &mut *self.global_components.get() };
66
67 match global_components.entry(ty) {
68 hash_map::Entry::Occupied(e) => Some(e.into_mut()),
69 hash_map::Entry::Vacant(e) => {
70 if !self.new_components_allowed {
71 return None;
72 }
73
74 let new = RefCell::new(GenericComponentGlobalAccess {
76 filtered_archetype_ids: self
77 .storage
78 .component_to_archetypes_map
79 .get(&ty)
80 .unwrap_or(&vec![])
81 .clone(),
82 all_archetypes: &self.storage.archetypes,
83 mutable: true,
86 });
87
88 Some(e.insert(Box::pin(new)))
89 }
90 }
91 }
92
93 pub fn type_id_to_archetype_id(&self, type_id: &TypeId) -> Option<ArchetypeId> {
95 self.storage.type_id_to_archetype_id(type_id)
96 }
97
98 pub fn component<C: Component>(&self) -> GlobalComponentAccess<'_, C> {
101 let ty = TypeId::of::<C>();
102
103 let generic = self.get_component(ty).expect("Component must be available");
105
106 GlobalComponentAccess {
107 generic: generic
108 .try_borrow()
109 .expect("Component must not be mutably borrowed"),
110 _ty: Default::default(),
111 }
112 }
113
114 pub fn component_mut<'b, C: Component>(&'b self) -> GlobalComponentAccessMut<'a, 'b, C> {
117 let generic = self
118 .get_component(TypeId::of::<C>())
119 .expect("Component must be available");
120
121 let guard = generic
122 .try_borrow_mut()
123 .expect("Component must not be borrowed");
124
125 if !guard.mutable {
126 panic!("Component is not allowed to be mutated");
127 }
128
129 GlobalComponentAccessMut {
130 generic: guard,
131 _ty: Default::default(),
132 }
133 }
134}
135
136#[cfg(feature = "rayon")]
137mod parallel {
138 use crate::system::component::CompMutability;
139 use crate::{HashMap, System};
140 use std::any::TypeId;
141 use std::collections::hash_map;
142 use std::mem;
143
144 #[derive(Debug)]
145 pub struct ParallelSystems {
146 pub systems: Vec<usize>,
147 pub all_components: HashMap<TypeId, CompMutability>,
148 }
149
150 impl ParallelSystems {
151 fn take(&mut self) -> Self {
152 Self {
153 systems: mem::replace(&mut self.systems, vec![]),
154 all_components: mem::replace(&mut self.all_components, Default::default()),
155 }
156 }
157
158 fn append(&mut self, other: Self) {
159 self.systems.extend(other.systems);
160
161 self.all_components.reserve(other.all_components.len());
162
163 for (ty, b_mutable) in &other.all_components {
164 match self.all_components.entry(*ty) {
165 hash_map::Entry::Occupied(mut e) => {
166 let a_mutable = e.get_mut();
167 if !*a_mutable {
168 e.insert(*b_mutable);
169 }
170 }
171 hash_map::Entry::Vacant(e) => {
172 e.insert(*b_mutable);
173 }
174 }
175 }
176 }
177 }
178
179 pub fn systems_do_conflict(
180 a_components: &HashMap<TypeId, CompMutability>,
181 b_components: &HashMap<TypeId, CompMutability>,
182 ) -> bool {
183 a_components.iter().any(|(ty, mutable_a)| {
184 b_components
185 .get(ty)
186 .map_or(false, |mutable_b| *mutable_a || *mutable_b)
187 })
188 }
189
190 pub fn partition_parallel_systems(systems: &[System]) -> Vec<ParallelSystems> {
192 fn extract_potential_moves(systems: &[ParallelSystems], moves: &mut [Vec<usize>]) {
237 for ((i, sys), moves) in systems.iter().enumerate().zip(moves) {
238 if sys.systems.is_empty() {
239 continue;
240 }
241
242 for (j, sys2) in systems.iter().enumerate() {
243 if j == i || sys2.systems.is_empty() {
244 continue;
245 }
246
247 let conflicting =
248 systems_do_conflict(&sys.all_components, &sys2.all_components);
249
250 if !conflicting {
251 moves.push(j);
252 }
253 }
254 }
255 }
256
257 let mut parallel_runs: Vec<_> = systems
258 .iter()
259 .enumerate()
260 .map(|(i, sys)| ParallelSystems {
261 systems: vec![i],
262 all_components: sys.components.clone(),
263 })
264 .collect();
265
266 let mut potential_moves = vec![Vec::<usize>::with_capacity(systems.len()); systems.len()];
267
268 loop {
269 for v in &mut potential_moves {
270 v.clear();
271 }
272 extract_potential_moves(¶llel_runs, &mut potential_moves);
273
274 if potential_moves.iter().all(|v| v.is_empty()) {
275 break;
276 }
277
278 let (min_i, min_moves) = potential_moves
279 .iter_mut()
280 .enumerate()
281 .filter(|(_, v)| !v.is_empty())
282 .min_by_key(|(_, v)| v.len())
283 .unwrap();
284
285 let mv_from = min_i;
286 let mv_to = min_moves.pop().unwrap();
287
288 let mv_systems = parallel_runs[mv_from].take();
289 parallel_runs[mv_to].append(mv_systems);
290 }
291
292 parallel_runs.retain(|v| !v.systems.is_empty());
293
294 parallel_runs
295 }
296}
297
298impl EntityStorage {
299 pub(crate) unsafe fn global_component_by_id(
301 &self,
302 ty: TypeId,
303 mutable: bool,
304 ) -> GenericComponentGlobalAccess<'_> {
305 let filtered_archetype_ids: Vec<usize> = self
306 .component_to_archetypes_map
307 .get(&ty)
308 .map_or(vec![], |v| v.clone());
309
310 GenericComponentGlobalAccess {
311 filtered_archetype_ids,
312 all_archetypes: &self.archetypes,
313 mutable,
314 }
315 }
316
317 unsafe fn get_system_data(
319 &self,
320 components: &HashMap<TypeId, CompMutability>,
321 ) -> SystemAccess<'_> {
322 unsafe {
323 let global_components = components
324 .iter()
325 .map(|(&ty, mutable)| {
326 (
327 ty,
328 Box::pin(RefCell::new(self.global_component_by_id(ty, *mutable))),
329 )
330 })
331 .collect();
332
333 SystemAccess {
334 storage: self,
335 new_components_allowed: false,
337 global_components: UnsafeCell::new(global_components),
338 }
339 }
340 }
341
342 pub fn access(&mut self) -> SystemAccess<'_> {
344 SystemAccess {
345 storage: self,
346 new_components_allowed: true,
348 global_components: UnsafeCell::new(HashMap::with_capacity(
349 self.component_to_archetypes_map.len(),
350 )),
351 }
352 }
353
354 pub fn dispatch<'a>(&self, mut systems: impl AsMut<[System<'a>]>) {
397 for sys in systems.as_mut() {
398 let data = unsafe { self.get_system_data(&sys.components) };
399 sys.handler.run(data);
400 }
401 }
402
403 #[cfg(feature = "rayon")]
406 pub fn dispatch_par<'a>(&self, mut systems: impl AsMut<[System<'a>]>) {
407 let systems = systems.as_mut();
408
409 if systems.is_empty() {
410 return;
411 }
412
413 let parallel_runs = parallel::partition_parallel_systems(systems);
414
415 rayon::scope(|s| {
416 for mut run in parallel_runs {
417 for sys_i in &mut run.systems {
418 let system = &systems[*sys_i];
419
420 let system_mut: &mut System = unsafe { &mut *(system as *const _ as *mut _) };
422
423 s.spawn(|_| {
424 let data = unsafe { self.get_system_data(&system.components) };
425 system_mut.handler.run(data);
426 });
427 }
428 }
429 });
430 }
431}
432
433#[cfg(feature = "rayon")]
434#[test]
435fn test_optimization() {
436 #[derive(Copy, Clone)]
437 struct TestSystem {}
438
439 impl SystemHandler for TestSystem {
440 fn run(&mut self, _: SystemAccess) {}
441 }
442
443 let mut test_sys0 = TestSystem {};
458 let mut test_sys1 = TestSystem {};
459 let mut test_sys2 = TestSystem {};
460 let mut test_sys3 = TestSystem {};
461 let mut test_sys4 = TestSystem {};
462
463 let sys0 = System::new(&mut test_sys0).with_mut::<i16>();
464 let sys1 = System::new(&mut test_sys1)
465 .with_mut::<i32>()
466 .with_mut::<i64>();
467 let sys2 = System::new(&mut test_sys2)
468 .with_mut::<i16>()
469 .with_mut::<u64>();
470 let sys3 = System::new(&mut test_sys3)
471 .with_mut::<i8>()
472 .with_mut::<i64>();
473 let sys4 = System::new(&mut test_sys4)
474 .with_mut::<i8>()
475 .with_mut::<i16>()
476 .with_mut::<u64>();
477
478 let mut systems = [sys0, sys1, sys2, sys3, sys4];
479 let parallel_runs = parallel::partition_parallel_systems(&mut systems);
480
481 assert_eq!(systems.len(), 5);
482 assert_eq!(parallel_runs.len(), 3);
483
484 assert_eq!(
485 ¶llel_runs[0].systems.iter().cloned().collect::<Vec<_>>(),
486 &[1, 4]
487 );
488 assert_eq!(
489 ¶llel_runs[1].systems.iter().cloned().collect::<Vec<_>>(),
490 &[2]
491 );
492 assert_eq!(
493 ¶llel_runs[2].systems.iter().cloned().collect::<Vec<_>>(),
494 &[3, 0]
495 );
496
497 for run in ¶llel_runs {
498 let conflicting = run.systems.iter().enumerate().any(|(i, sys0_id)| {
499 run.systems.iter().enumerate().any(|(j, sys1_id)| {
500 if i == j {
501 return false;
502 }
503 parallel::systems_do_conflict(
504 &systems[*sys0_id].components,
505 &systems[*sys1_id].components,
506 )
507 })
508 });
509
510 assert_eq!(conflicting, false);
511 }
512}
513
514#[test]
515fn test_system_data_access() {
516 use crate::EntityId;
517
518 #[derive(Clone, crate::Archetype)]
519 struct Arch {
520 comp: i16,
521 }
522
523 #[derive(Copy, Clone)]
524 struct TestSystem {
525 entity: EntityId,
526 }
527
528 impl SystemHandler for TestSystem {
529 fn run(&mut self, data: SystemAccess) {
530 let mut comp = data.component_mut::<i16>();
531
532 let e_comp = comp.get_mut(&self.entity).unwrap();
533 assert_eq!(*e_comp, 123);
534 *e_comp = 321;
535 }
536 }
537
538 let mut storage = EntityStorage::new();
539 let entity = storage.add(Arch { comp: 123 });
540
541 let mut test_sys = TestSystem { entity };
542 let sys0 = System::new(&mut test_sys).with_mut::<i16>();
543
544 storage.dispatch(&mut [sys0]);
545
546 assert_eq!(*storage.get::<i16>(&entity).unwrap(), 321);
547}