entity_trait_system/
lib.rs

1/*!
2[![Crates.io](https://img.shields.io/crates/v/entity-trait-system.svg)](https://crates.io/crates/entity-trait-system)
3[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
5An alternative to [ECS](https://en.wikipedia.org/wiki/Entity_component_system).
6Here is a [video](https://youtu.be/AezHJdwDfW0) summary.
7
8# Setup
9
10Requires the nightly compiler and
11[specialization](https://std-dev-guide.rust-lang.org/policy/specialization.html)
12feature - it's only used in a sound way.
13
14```bash
15rustup override set nightly # enable nightly compiler
16cargo add entity-trait-system # get lib
17```
18
19```rs
20// explicitly opt in to language feature
21#![allow(incomplete_features)]
22#![feature(specialization)]
23
24// declare world, entities, and traits which the entities could have
25entity_trait_system::world!(
26    MyWorld, Enemy, Player; TestTrait, SecondTestTrait);
27
28let mut world = MyWorld::default();
29// directly access arena member
30let player_id = world.player.insert(Player { id: 1 });
31// compile time type accessor of arena member (similar)
32world.arena_mut::<Enemy>().insert(Enemy { hp: 10 });
33
34// visit all arenas with types that implement trait
35// (likely static dispatch)
36#[cfg(feature = "rayon")]
37world.par_visit_test_trait(|e| e.do_something());
38#[cfg(not(feature = "rayon"))]
39world.visit_test_trait(|e| e.do_something());
40
41// runtime type API - access type-erased (Any) arena
42let arena_id = MyWorld::arena_id::<Player>();
43let player_arena = world.any_arena_mut(arena_id);
44// unwrap: I know that this is a player
45// and that the reference is valid
46let player = player_arena
47    .get_mut(player_id).unwrap()
48    .downcast_mut::<Player>().unwrap();
49player.do_something_else();
50```
51
52# API Overview
53
54## Per-Trait Methods (generated for each trait)
55- `visit_<trait>` - Iter over implementing entities
56- `visit_mut_<trait>` - Mutable iter over implementing entities
57- `visit_key_<trait>` - Iter `(Key, &Value)` tuples
58- `visit_key_mut_<trait>` - Mutable iter `(Key, &mut Value)` tuples
59- `retain_<trait>` - Keep entities matching predicate
60- `diff_<trait>` - Gather diff vector from immutable view, to apply later
61- `diff_mut_<trait>` - Same as previous, but from mutable view
62- `diff_apply_<trait>` - Apply diff vector
63- `clear_<trait>` - Clear all arenas implementing trait
64- `len_<trait>` - Count entities implementing trait
65- `any_arenas_<trait>` - Array of type-erased arenas implementing trait
66- `any_arenas_mut_<trait>` - Mutable version of above
67
68## World Methods
69- `arena<T>()` / `arena_mut<T>()` - Compile-time typed arena access
70- `any_arena()` / `any_arena_mut()` - Runtime type-erased access
71- `arena_id<T>()` - Get stable arena identifier - serializes to type name.
72- `clear()` - Clear all arenas
73- `len()` - Total entity count across all arenas
74
75# Rayon Support
76Parallel operations exposed via `par_*` variants.
77
78# Serde Support
79Both map (serde_json) and seq (bincode) style ser/deserialization.
80
81# Performance Note
82
83## Benchmarks
84
85Here's a [benchmark test suite](https://github.com/jagprog5/ecs_bench_suite)
86comparing ETS to other popular libraries.
87
88### Simple Insert
89
90ETS performed the best. It's the same speed as the underlying dense slot map
91insertion.
92
93### Simple Iter
94
95The results for this benchmark form two distinct groups. The fastest group,
96including hecs and legion, arrange the components of the data as a structure of
97arrays. The second group (including ETS) iterate through an array of structures.
98A structure of arrays performs better since only the relevant data is loaded
99into the cache.
100
101Since ETS doesn't use components, it is inside the second group.
102
103### Fragmented Iter
104
105ETS arrived in second place, just behind shipyard.
106
107### System Scheduling
108
109ETS performed the best. But, disjoint systems (outer parallelism) must be stated
110explicitly.
111
112### Heavy Compute
113
114ETS overlapped with the other libraries - not much of a difference.
115
116### Add/Remove Component
117
118ETS is omitted from this benchmark since it doesn't use components; it's not
119applicable. For sparse components, an auxiliary structure can store entity keys.
120For dense components, a trait in the ETS can implement the desire behaviour.
121
122### Serialize
123
124Only three libraries implemented serialization. ETS arrived in second.
125
126## Optimization
127
128This can be found in the implementation of `visit_*`:
129
130```ignore
131fn v_if_applicable<F>(
132    arena: &DenseSlotMap<DefaultKey, T>,
133    mut handler: F) where F: FnMut(&dyn $trait_name)
134{
135    arena.values_as_slice().iter()
136        .for_each(|entity| {
137            // implicit type erase T -> &dyn $trait_name
138            handler(entity) 
139        }); 
140}
141```
142
143The handler is typically inlined and devirtualized to erase dynamic dispatch,
144since the type is known at compile time and is type erased just before use. This
145means that static dispatch is reliant on compiler optimization; likely but not
146guaranteed.
147*/
148
149// specialization feature is incomplete, but is being used here in a very
150// limited but required capacity. it is only used to check if a type implements
151// a trait - there is no overlapping impl weirdness that is relied on
152#![allow(incomplete_features)]
153#![feature(specialization)]
154
155// macro is expanded at call site - makes it available to the lib user
156//
157// below macro references these via $crate:: prefix
158#[doc(hidden)]
159pub use paste;
160#[cfg(feature = "rayon")]
161#[doc(hidden)]
162pub use rayon;
163#[cfg(feature = "serde")]
164#[doc(hidden)]
165pub use serde;
166#[doc(hidden)]
167pub use slotmap;
168
169#[doc(hidden)]
170pub trait IsType<T> {
171    const VALUE: bool = false;
172}
173
174impl<A, B> IsType<B> for A {
175    default const VALUE: bool = false;
176}
177
178// specialize for equal types
179impl<T> IsType<T> for T {
180    const VALUE: bool = true;
181}
182
183/// type erased view of an arena. exposes single element API from DenseSlotMap
184#[doc(hidden)]
185pub trait ErasedArena {
186    fn get(&self, key: slotmap::DefaultKey) -> Option<&dyn std::any::Any>;
187    fn get_mut(&mut self, key: slotmap::DefaultKey) -> Option<&mut dyn std::any::Any>;
188    unsafe fn get_unchecked(&self, key: slotmap::DefaultKey) -> &dyn std::any::Any;
189    unsafe fn get_unchecked_mut(&mut self, key: slotmap::DefaultKey) -> &mut dyn std::any::Any;
190    fn insert(&mut self, value: Box<dyn std::any::Any>) -> slotmap::DefaultKey;
191    fn insert_with_key(
192        &mut self,
193        f: Box<dyn FnOnce(slotmap::DefaultKey) -> Box<dyn std::any::Any>>,
194    ) -> slotmap::DefaultKey;
195    fn remove(&mut self, key: slotmap::DefaultKey) -> Option<Box<dyn std::any::Any>>;
196}
197
198impl<T: 'static> ErasedArena for slotmap::DenseSlotMap<slotmap::DefaultKey, T> {
199    fn get(&self, key: slotmap::DefaultKey) -> Option<&dyn std::any::Any> {
200        self.get(key).map(|e| e as &dyn std::any::Any)
201    }
202
203    fn get_mut(&mut self, key: slotmap::DefaultKey) -> Option<&mut dyn std::any::Any> {
204        self.get_mut(key).map(|e| e as &mut dyn std::any::Any)
205    }
206
207    unsafe fn get_unchecked(&self, key: slotmap::DefaultKey) -> &dyn std::any::Any {
208        unsafe {
209            <slotmap::DenseSlotMap<slotmap::DefaultKey, T>>::get_unchecked(self, key)
210                as &dyn std::any::Any
211        }
212    }
213
214    unsafe fn get_unchecked_mut(&mut self, key: slotmap::DefaultKey) -> &mut dyn std::any::Any {
215        unsafe {
216            <slotmap::DenseSlotMap<slotmap::DefaultKey, T>>::get_unchecked_mut(self, key)
217                as &mut dyn std::any::Any
218        }
219    }
220
221    fn insert(&mut self, value: Box<dyn std::any::Any>) -> slotmap::DefaultKey {
222        // expect never triggers, gated by caller
223        self.insert(*value.downcast::<T>().expect("Try mismatch in insert"))
224    }
225
226    fn insert_with_key(
227        &mut self,
228        f: Box<dyn FnOnce(slotmap::DefaultKey) -> Box<dyn std::any::Any>>,
229    ) -> slotmap::DefaultKey {
230        // expect never triggers, gated by caller
231        self.insert_with_key(|k| {
232            *f(k)
233                .downcast::<T>()
234                .expect("Type mismatch in insert_with_key")
235        })
236    }
237
238    fn remove(&mut self, key: slotmap::DefaultKey) -> Option<Box<dyn std::any::Any>> {
239        self.remove(key)
240            .map(|v| Box::new(v) as Box<dyn std::any::Any>)
241    }
242}
243
244#[doc(hidden)]
245pub trait ArenaCast<T> {
246    fn cast(&self) -> &slotmap::DenseSlotMap<slotmap::DefaultKey, T>;
247    fn cast_mut(&mut self) -> &mut slotmap::DenseSlotMap<slotmap::DefaultKey, T>;
248}
249
250// default: panic for mismatched types
251impl<A, B> ArenaCast<B> for slotmap::DenseSlotMap<slotmap::DefaultKey, A> {
252    default fn cast(&self) -> &slotmap::DenseSlotMap<slotmap::DefaultKey, B> {
253        panic!(
254            // never, gated at compile time
255            "Arena type mismatch: {} cannot be cast to {}",
256            std::any::type_name::<A>(),
257            std::any::type_name::<B>()
258        );
259    }
260
261    default fn cast_mut(&mut self) -> &mut slotmap::DenseSlotMap<slotmap::DefaultKey, B> {
262        panic!(
263            // never, gated at compile time
264            "Arena type mismatch: {} cannot be cast to {}",
265            std::any::type_name::<A>(),
266            std::any::type_name::<B>()
267        );
268    }
269}
270
271// specialization: types match
272impl<T> ArenaCast<T> for slotmap::DenseSlotMap<slotmap::DefaultKey, T> {
273    fn cast(&self) -> &slotmap::DenseSlotMap<slotmap::DefaultKey, T> {
274        self
275    }
276
277    fn cast_mut(&mut self) -> &mut slotmap::DenseSlotMap<slotmap::DefaultKey, T> {
278        self
279    }
280}
281
282// conditional serde if specific type is also serde
283#[cfg(feature = "serde")]
284#[doc(hidden)] // must be exposed to caller from macro expansion
285pub trait SerdeArena<'de> {
286    // member serialize into a SerializeStruct (called from world Serialize impl)
287    fn serialize_arena<S>(&self, field_name: &'static str, state: &mut S) -> Result<(), S::Error>
288    where
289        S: serde::ser::SerializeStruct;
290
291    // member deserialize from map access (JSON, etc.)
292    fn deserialize_arena<M>(map: &mut M) -> Result<Self, M::Error>
293    where
294        M: serde::de::MapAccess<'de>,
295        Self: Sized;
296
297    // sequence deserialize (e.g. bincode)
298    fn from_seq<V>(seq: &mut V, field_name: &str) -> Result<Self, V::Error>
299    where
300        V: serde::de::SeqAccess<'de>,
301        Self: Sized;
302
303    const ACTIVE: bool; // whether this arena participates in serde
304}
305
306// default: type does NOT implement serde => do nothing
307#[cfg(feature = "serde")]
308impl<'de, T> SerdeArena<'de> for slotmap::DenseSlotMap<slotmap::DefaultKey, T> {
309    default fn serialize_arena<S>(
310        &self,
311        _field_name: &'static str,
312        _state: &mut S,
313    ) -> Result<(), S::Error>
314    where
315        S: serde::ser::SerializeStruct,
316    {
317        Ok(())
318    }
319
320    default fn deserialize_arena<M>(_map: &mut M) -> Result<Self, M::Error>
321    where
322        M: serde::de::MapAccess<'de>,
323    {
324        Ok(slotmap::DenseSlotMap::new())
325    }
326
327    default fn from_seq<V>(_seq: &mut V, _field_name: &str) -> Result<Self, V::Error>
328    where
329        V: serde::de::SeqAccess<'de>,
330    {
331        Ok(slotmap::DenseSlotMap::new())
332    }
333
334    default const ACTIVE: bool = false;
335}
336
337// specialized: type implements serde Serialize + Deserialize
338#[cfg(feature = "serde")]
339impl<'de, T> SerdeArena<'de> for slotmap::DenseSlotMap<slotmap::DefaultKey, T>
340where
341    T: serde::Serialize + serde::Deserialize<'de>,
342{
343    fn serialize_arena<S>(&self, field_name: &'static str, state: &mut S) -> Result<(), S::Error>
344    where
345        S: serde::ser::SerializeStruct,
346    {
347        state.serialize_field(field_name, self)
348    }
349
350    fn deserialize_arena<M>(map: &mut M) -> Result<Self, M::Error>
351    where
352        M: serde::de::MapAccess<'de>,
353    {
354        map.next_value()
355    }
356
357    fn from_seq<V>(seq: &mut V, field_name: &str) -> Result<Self, V::Error>
358    where
359        V: serde::de::SeqAccess<'de>,
360    {
361        seq.next_element()?
362            .ok_or_else(|| serde::de::Error::custom(format!("Missing element for {}", field_name)))
363    }
364
365    const ACTIVE: bool = true;
366}
367
368#[doc(hidden)]
369#[macro_export]
370#[cfg(not(feature = "rayon"))]
371macro_rules! __world_define_rayon_trait_helpers {
372    ($struct_name:ident $( $trait_name:ident ),*) => {};
373}
374
375#[doc(hidden)]
376#[macro_export]
377#[cfg(feature = "rayon")]
378macro_rules! __world_define_rayon_trait_helpers {
379    ($struct_name:ident $( $trait_name:ident ),*) => {
380        $crate::paste::paste! {
381
382$(
383trait [<$struct_name ParVisitIf $trait_name>]<T> {
384    fn pv_if_applicable<F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F)
385    where
386        F: Fn(&dyn $trait_name) + Send + Sync;
387
388    fn pvm_if_applicable<F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F)
389    where
390        F: Fn(&mut dyn $trait_name) + Send + Sync;
391
392    fn pvk_if_applicable<F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F)
393    where
394        F: Fn(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &dyn $trait_name) + Send + Sync;
395
396    fn pvkm_if_applicable<F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F)
397    where
398        F: Fn(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &mut dyn $trait_name) + Send + Sync;
399
400    fn pr_if_applicable<P>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, predicate: &P)
401    where
402        P: Fn(&mut dyn $trait_name) -> bool + Send + Sync;
403
404    fn pd_if_applicable<D, F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F, out: &mut [std::mem::MaybeUninit<D>])
405    where
406        D: Send,
407        F: Fn(&dyn $trait_name) -> D + Send + Sync;
408
409    fn pdm_if_applicable<D, F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F, out: &mut [std::mem::MaybeUninit<D>])
410    where
411        D: Send,
412        F: Fn(&mut dyn $trait_name) -> D + Send + Sync;
413
414    // parallel diff apply
415    fn pda_if_applicable<D, F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F, i: &[D])
416    where
417        D: Sync,
418        F: Fn(&mut dyn $trait_name, &D) + Send + Sync;
419
420    const ACTIVE: bool;
421}
422
423impl<T> [<$struct_name ParVisitIf $trait_name>]<T> for () {
424    default fn pv_if_applicable<F>(_arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: &F)
425    where F: Fn(&dyn $trait_name) + Send + Sync {}
426
427    default fn pvm_if_applicable<F>(_arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: &F)
428    where F: Fn(&mut dyn $trait_name) + Send + Sync {}
429
430    default fn pvk_if_applicable<F>(_arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: &F)
431    where F: Fn(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &dyn $trait_name) + Send + Sync {}
432
433    default fn pvkm_if_applicable<F>(_arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: &F)
434    where F: Fn(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &mut dyn $trait_name) + Send + Sync {}
435
436    default fn pr_if_applicable<P>(_arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _predicate: &P)
437    where P: Fn(&mut dyn $trait_name) -> bool + Send + Sync {}
438
439    default fn pd_if_applicable<D, F>(_arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: &F, _out: &mut [std::mem::MaybeUninit<D>])
440    where
441        D: Send,
442        F: Fn(&dyn $trait_name) -> D + Send + Sync {}
443
444    default fn pdm_if_applicable<D, F>(_arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: &F, _out: &mut [std::mem::MaybeUninit<D>])
445    where
446        D: Send,
447        F: Fn(&mut dyn $trait_name) -> D + Send + Sync {}
448
449    default fn pda_if_applicable<D, F>(_arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: &F, _i: &[D])
450    where
451        D: Sync,
452        F: Fn(&mut dyn $trait_name, &D) + Send + Sync {}
453
454    default const ACTIVE: bool = false;
455}
456
457impl<T> [<$struct_name ParVisitIf $trait_name>]<T> for ()
458where
459    T: $trait_name + Send + Sync,
460{
461    fn pv_if_applicable<F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F)
462    where F: Fn(&dyn $trait_name) + Send + Sync
463    {
464        use $crate::rayon::iter::IntoParallelRefIterator;
465        use $crate::rayon::iter::ParallelIterator;
466        arena
467            .values_as_slice()
468            .par_iter()
469            .for_each(|entity| handler(entity));
470    }
471
472    fn pvm_if_applicable<F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F)
473    where F: Fn(&mut dyn $trait_name) + Send + Sync
474    {
475        use $crate::rayon::iter::IntoParallelRefMutIterator;
476        use $crate::rayon::iter::ParallelIterator;
477        arena
478            .values_as_mut_slice()
479            .par_iter_mut()
480            .for_each(|entity| handler(entity));
481    }
482
483    fn pvk_if_applicable<F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F)
484    where F: Fn(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &dyn $trait_name) + Send + Sync
485    {
486        use $crate::rayon::iter::IntoParallelRefIterator;
487        use $crate::rayon::iter::IndexedParallelIterator;
488        use $crate::rayon::iter::ParallelIterator;
489        let keys = arena.keys_as_slice();
490        let values = arena.values_as_slice();
491        keys.par_iter()
492            .zip(values.par_iter())
493            .for_each(|(k, v)| handler(($struct_name::arena_id::<T>(), *k), v));
494    }
495
496    fn pvkm_if_applicable<F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F)
497    where F: Fn(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &mut dyn $trait_name) + Send + Sync
498    {
499        use $crate::rayon::iter::IntoParallelRefIterator;
500        use $crate::rayon::iter::IntoParallelRefMutIterator;
501        use $crate::rayon::iter::IndexedParallelIterator;
502        use $crate::rayon::iter::ParallelIterator;
503        let (keys, values) = arena.keys_values_as_mut_slices();
504        keys.par_iter()
505            .zip(values.par_iter_mut())
506            .for_each(|(k, v)| handler(($struct_name::arena_id::<T>(), *k), v));
507    }
508
509    fn pr_if_applicable<P>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, predicate: &P)
510    where P: Fn(&mut dyn $trait_name) -> bool + Send + Sync
511    {
512        // current par retain is only parallel between arenas, not per element.
513        //
514        // I don't think it's possible to do this better but I might be wrong.
515        // keeping send + sync for forward compat. either way, not supported by
516        // DenseSlotMap
517        arena.retain(|_, entity| predicate(entity));
518    }
519
520    fn pd_if_applicable<D, F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F, out: &mut [std::mem::MaybeUninit<D>])
521    where
522        D: Send,
523        F: Fn(&dyn $trait_name) -> D + Sync + Send,
524    {
525        use $crate::rayon::iter::IntoParallelRefMutIterator;
526        use $crate::rayon::iter::IndexedParallelIterator;
527        use $crate::rayon::iter::IntoParallelRefIterator;
528        use $crate::rayon::iter::ParallelIterator;
529        arena
530            .values_as_slice()
531            .par_iter()
532            .zip(out.par_iter_mut())
533            .for_each(|(e, out_slot)| {
534                *out_slot = std::mem::MaybeUninit::new(handler(e));
535            });
536    }
537
538    fn pdm_if_applicable<D, F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F, out: &mut [std::mem::MaybeUninit<D>])
539    where
540        D: Send,
541        F: Fn(&mut dyn $trait_name) -> D + Sync + Send,
542    {
543        use $crate::rayon::iter::IntoParallelRefMutIterator;
544        use $crate::rayon::iter::IndexedParallelIterator;
545        use $crate::rayon::iter::ParallelIterator;
546        arena
547            .values_as_mut_slice()
548            .par_iter_mut()
549            .zip(out.par_iter_mut())
550            .for_each(|(e, out_slot)| {
551                *out_slot = std::mem::MaybeUninit::new(handler(e));
552            });
553    }
554
555    fn pda_if_applicable<D, F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F, i: &[D])
556    where
557        D: Sync,
558        F: Fn(&mut dyn $trait_name, &D) + Send + Sync {
559            use $crate::rayon::iter::IntoParallelRefMutIterator;
560            use $crate::rayon::iter::IndexedParallelIterator;
561            use $crate::rayon::iter::IntoParallelRefIterator;
562            use $crate::rayon::iter::ParallelIterator;
563            arena
564                .values_as_mut_slice()
565                .par_iter_mut()
566                .zip(i.par_iter())
567                .for_each(|(e, in_value)| {
568                    handler(e, in_value);
569                });
570        }
571
572    const ACTIVE: bool = true;
573}
574
575)*
576        }
577    };
578}
579
580#[doc(hidden)]
581#[macro_export]
582macro_rules! __world_define_visitors_common {
583    // https://stackoverflow.com/a/37754096/15534181
584    //
585    // generate visit_* functions per trait (non-parallel)
586    (@pass_entity_tuple $struct_name:ident $($trait_name:ident),* @ $entity_tuple:tt) => {
587        $crate::paste::paste! {
588            $(
589                /// visit all entities that implement the trait
590                #[allow(unused)]
591                pub fn [<visit_ $trait_name:snake>]<F>(&self, mut handler: F)
592                where
593                    F: FnMut(&dyn $trait_name)
594                {
595                    $crate::__world_define_visitors_common!(@v_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
596                }
597
598                /// mutably visit all entities that implement the trait
599                #[allow(unused)]
600                pub fn [<visit_mut_ $trait_name:snake>]<F>(&mut self, mut handler: F)
601                where
602                    F: FnMut(&mut dyn $trait_name)
603                {
604                    $crate::__world_define_visitors_common!(@vm_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
605                }
606
607                /// visit all entities that implement the trait, with their keys
608                /// 
609                /// since the slotmap key is type agnostic, it's important to
610                /// keep the arena id together with the slot map key (don't use
611                /// the slot map key on the wrong slot map)
612                #[allow(unused)]
613                pub fn [<visit_key_ $trait_name:snake>]<F>(&self, mut handler: F)
614                where
615                    F: FnMut(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &dyn $trait_name)
616                {
617                    $crate::__world_define_visitors_common!(@vk_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
618                }
619
620                /// mutably visit all entities that implement the trait, with their keys
621                /// 
622                /// since the slotmap key is type agnostic, it's important to
623                /// keep the arena id together with the slot map key (don't use
624                /// the slot map key on the wrong slot map)
625                #[allow(unused)]
626                pub fn [<visit_key_mut_ $trait_name:snake>]<F>(&mut self, mut handler: F)
627                where
628                    F: FnMut(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &mut dyn $trait_name)
629                {
630                    $crate::__world_define_visitors_common!(@vkm_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
631                }
632
633                /// forwards to retain_with_default with DEFAULT=true
634                #[allow(unused)]
635                pub fn [<retain_ $trait_name:snake>]<F>(&mut self, mut predicate: F)
636                where
637                    F: FnMut(&mut dyn $trait_name) -> bool
638                {
639                    self.[<retain_with_default_ $trait_name:snake>]::<true, F>(predicate)
640                }
641
642                /// retain entities matching predicate, removing those that
643                /// don't.
644                ///
645                /// predicate applies only to entities implementing the trait.
646                ///
647                /// others instead use the DEFAULT value - if true entities not
648                /// implementing trait are kept, false they are removed.
649                #[allow(unused)]
650                pub fn [<retain_with_default_ $trait_name:snake>]<const DEFAULT: bool, F>(&mut self, mut predicate: F)
651                where
652                    F: FnMut(&mut dyn $trait_name) -> bool
653                {
654                    $crate::__world_define_visitors_common!(@r_use_entity_tuple $struct_name $trait_name $entity_tuple self predicate DEFAULT);
655                }
656
657                /// produce a diff vector, created from viewing all elements
658                /// that implement trait
659                ///
660                /// entities must not be inserted or removed between diff
661                /// creation and application
662                #[allow(unused)]
663                pub fn [<diff_ $trait_name:snake>]<D, F>(&mut self, mut handler: F) -> Vec<D>
664                where
665                    F: FnMut(&dyn $trait_name) -> D
666                {
667                    $crate::__world_define_visitors_common!(@d_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
668                }
669
670                /// produce a diff vector, created from mutably viewing all
671                /// elements that implement trait
672                ///
673                /// entities must not be inserted or removed between diff
674                /// creation and application
675                #[allow(unused)]
676                pub fn [<diff_mut_ $trait_name:snake>]<D, F>(&mut self, mut handler: F) -> Vec<D>
677                where
678                    F: FnMut(&mut dyn $trait_name) -> D
679                {
680                    $crate::__world_define_visitors_common!(@dm_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
681                }
682
683                /// apply the diff vector.
684                ///
685                /// entities must not be inserted or removed between diff
686                /// creation and application
687                #[allow(unused)]
688                pub fn [<diff_apply_ $trait_name:snake>]<D, F>(&mut self, diff: Vec<D>, mut handler: F)
689                where F: FnMut(&mut dyn $trait_name, &D)
690                {
691                    $crate::__world_define_visitors_common!(@da_use_entity_tuple $struct_name $trait_name $entity_tuple self diff handler);
692                }
693
694                /// clear all arenas whose element type implements this trait.
695                /// No-op for arenas whose element types do not implement the trait.
696                #[allow(unused)]
697                pub fn [<clear_ $trait_name:snake>](&mut self) {
698                    $crate::__world_define_visitors_common!(@clear_use_entity_tuple $struct_name $trait_name $entity_tuple self);
699                }
700
701                /// total number of elements across arenas whose element type implements trait
702                #[allow(unused)]
703                pub fn [<len_ $trait_name:snake>](&self) -> usize {
704                    $crate::__world_define_visitors_common!(@len_use_entity_tuple $struct_name $trait_name $entity_tuple self)
705                }
706
707                /// get type erased arenas whose element type implements this trait
708                #[allow(unused)]
709                pub fn [<any_arenas_ $trait_name:snake>](&self) -> [&dyn $crate::ErasedArena; $crate::__world_define_visitors_common!(@any_arenas_count_use_entity_tuple $struct_name $trait_name $entity_tuple)] {
710                    $crate::__world_define_visitors_common!(@any_arenas_use_entity_tuple $struct_name $trait_name $entity_tuple self)
711                }
712
713                /// get type erased arenas (mutable) whose element type implements this trait
714                #[allow(unused)]
715                pub fn [<any_arenas_mut_ $trait_name:snake>](&mut self) -> [&mut dyn $crate::ErasedArena; $crate::__world_define_visitors_common!(@any_arenas_count_use_entity_tuple $struct_name $trait_name $entity_tuple)] {
716                    $crate::__world_define_visitors_common!(@any_arenas_mut_use_entity_tuple $struct_name $trait_name $entity_tuple self)
717                }
718            )*
719        }
720    };
721
722    (@v_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
723        $crate::paste::paste! {
724            $(
725                <() as [<$struct_name VisitIf $trait_name>]<$entity>>::v_if_applicable(
726                    &$self_ident.[<$entity:snake>],
727                    &mut $handler_ident,
728                );
729            )*
730        }
731    };
732
733    (@vk_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
734        $crate::paste::paste! {
735            $(
736                <() as [<$struct_name VisitIf $trait_name>]<$entity>>::vk_if_applicable(
737                    &$self_ident.[<$entity:snake>],
738                    &mut $handler_ident,
739                );
740            )*
741        }
742    };
743
744    (@vm_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
745        $crate::paste::paste! {
746            $(
747                <() as [<$struct_name VisitIf $trait_name>]<$entity>>::mv_if_applicable(
748                    &mut $self_ident.[<$entity:snake>],
749                    &mut $handler_ident,
750                );
751            )*
752        }
753    };
754
755    (@vkm_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
756        $crate::paste::paste! {
757            $(
758                <() as [<$struct_name VisitIf $trait_name>]<$entity>>::vkm_if_applicable(
759                    &mut $self_ident.[<$entity:snake>],
760                    &mut $handler_ident,
761                );
762            )*
763        }
764    };
765
766    (@r_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $predicate:ident $default:ident) => {
767        $crate::paste::paste! {
768            $(
769                if <() as [<$struct_name VisitIf $trait_name>]<$entity>>::ACTIVE {
770                    <() as [<$struct_name VisitIf $trait_name>]<$entity>>::r_if_applicable::<_>(
771                        &mut $self_ident.[<$entity:snake>],
772                        &mut $predicate,
773                    );
774                } else {
775                    if !$default {
776                        $self_ident.[<$entity:snake>].clear();
777                    }
778                }
779            )*
780        }
781    };
782
783    (@d_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
784        $crate::paste::paste! {
785            let len = $self_ident.[<len_$trait_name:snake>]();
786            // MaybeUninit required in case population of diff vec panics
787            let mut out: Vec<std::mem::MaybeUninit<D>> = Vec::with_capacity(len);
788            unsafe { out.set_len(len); }
789            let mut offset = 0usize;
790            $(
791                let arena_len = <() as [<$struct_name VisitIf $trait_name>]<$entity>>::len_if_applicable(
792                    & $self_ident.[<$entity:snake>],
793                );
794
795                <() as [<$struct_name VisitIf $trait_name>]<$entity>>::d_if_applicable(
796                    & $self_ident.[<$entity:snake>],
797                    &mut $handler_ident,
798                    &mut out[offset..offset + arena_len],
799                );
800
801                offset += arena_len;
802            )*
803
804            return unsafe { // convert MaybeUninit<Vec> to normal Vec
805                let ptr = out.as_mut_ptr() as *mut D;
806                let len = out.len();
807                let cap = out.capacity();
808                ::std::mem::forget(out);
809                ::std::vec::Vec::from_raw_parts(ptr, len, cap)
810            };
811        }
812    };
813
814    (@dm_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
815        $crate::paste::paste! {
816            let len = $self_ident.[<len_$trait_name:snake>]();
817            // MaybeUninit required in case population of diff vec panics
818            let mut out: Vec<std::mem::MaybeUninit<D>> = Vec::with_capacity(len);
819            unsafe { out.set_len(len); }
820            let mut offset = 0usize;
821            $(
822                let arena_len = <() as [<$struct_name VisitIf $trait_name>]<$entity>>::len_if_applicable(
823                    & $self_ident.[<$entity:snake>],
824                );
825
826                <() as [<$struct_name VisitIf $trait_name>]<$entity>>::dm_if_applicable(
827                    &mut $self_ident.[<$entity:snake>],
828                    &mut $handler_ident,
829                    &mut out[offset..offset + arena_len],
830                );
831
832                offset += arena_len;
833            )*
834
835            return unsafe { // convert MaybeUninit<Vec> to normal Vec
836                let ptr = out.as_mut_ptr() as *mut D;
837                let len = out.len();
838                let cap = out.capacity();
839                ::std::mem::forget(out);
840                ::std::vec::Vec::from_raw_parts(ptr, len, cap)
841            };
842        }
843    };
844
845    (@da_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $diff_ident:ident $handler_ident:ident) => {
846        $crate::paste::paste! {
847            let mut offset = 0usize;
848            $(
849                let arena_len = <() as [<$struct_name VisitIf $trait_name>]<$entity>>::len_if_applicable(
850                    & $self_ident.[<$entity:snake>],
851                );
852
853                <() as [<$struct_name VisitIf $trait_name>]<$entity>>::da_if_applicable(
854                    &mut $self_ident.[<$entity:snake>],
855                    &mut $handler_ident,
856                    &$diff_ident[offset..offset + arena_len],
857                );
858
859                offset += arena_len;
860            )*
861        }
862    };
863
864    (@clear_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident) => {
865        $crate::paste::paste! {
866            $(
867                <() as [<$struct_name VisitIf $trait_name>]<$entity>>::clear_if_applicable(
868                    &mut $self_ident.[<$entity:snake>],
869                );
870            )*
871        }
872    };
873
874    (@len_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident) => {
875        $crate::paste::paste! {
876            {
877                let mut total = 0usize;
878                $(
879                    total += <() as [<$struct_name VisitIf $trait_name>]<$entity>>::len_if_applicable(
880                        & $self_ident.[<$entity:snake>],
881                    );
882                )*
883                total
884            }
885        }
886    };
887
888    (@any_arenas_count_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) ) => {
889        $crate::paste::paste! {
890            {
891                0 $(+ if <() as [<$struct_name VisitIf $trait_name>]<$entity>>::ACTIVE {1} else {0})*
892            }
893        }
894    };
895
896    (@any_arenas_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident) => {
897        $crate::paste::paste! {
898            {
899                const NUM_ARENAS: usize = 0 $(+ if <() as [<$struct_name VisitIf $trait_name>]<$entity>>::ACTIVE {1} else {0})*;
900                let mut tmp: [std::mem::MaybeUninit<&dyn $crate::ErasedArena>; NUM_ARENAS] = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
901                let mut idx = 0;
902                $(
903                    if <() as [<$struct_name VisitIf $trait_name>]<$entity>>::ACTIVE {
904                        tmp[idx] = std::mem::MaybeUninit::new(&$self_ident.[<$entity:snake>] as &dyn $crate::ErasedArena);
905                        idx += 1;
906                    }
907                )*
908                unsafe {
909                    std::mem::transmute::<
910                        [std::mem::MaybeUninit<&dyn $crate::ErasedArena>; NUM_ARENAS],
911                        [&dyn $crate::ErasedArena; NUM_ARENAS]
912                    >(tmp)
913                }
914            }
915        }
916    };
917
918    (@any_arenas_mut_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident) => {
919        $crate::paste::paste! {
920            {
921                const NUM_ARENAS: usize = 0 $(+ if <() as [<$struct_name VisitIf $trait_name>]<$entity>>::ACTIVE {1} else {0})*;
922                let mut tmp: [std::mem::MaybeUninit<&mut dyn $crate::ErasedArena>; NUM_ARENAS] = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
923                let mut idx = 0;
924                $(
925                    if <() as [<$struct_name VisitIf $trait_name>]<$entity>>::ACTIVE {
926                        tmp[idx] = std::mem::MaybeUninit::new(&mut $self_ident.[<$entity:snake>] as &mut dyn $crate::ErasedArena);
927                        idx += 1;
928                    }
929                )*
930                unsafe {
931                    std::mem::transmute::<
932                        [std::mem::MaybeUninit<&mut dyn $crate::ErasedArena>; NUM_ARENAS],
933                        [&mut dyn $crate::ErasedArena; NUM_ARENAS]
934                    >(tmp)
935                }
936            }
937        }
938    };
939}
940
941#[doc(hidden)]
942#[macro_export]
943#[cfg(not(feature = "rayon"))]
944macro_rules! __world_define_visitors {
945    // Non-rayon version simply forwards to the common macro
946    (@pass_entity_tuple $struct_name:ident $($trait_name:ident),* @ $entity_tuple:tt) => {
947        $crate::__world_define_visitors_common!(@pass_entity_tuple $struct_name $($trait_name),* @ $entity_tuple);
948    };
949}
950
951#[doc(hidden)]
952#[macro_export]
953#[cfg(feature = "rayon")]
954macro_rules! __world_define_visitors {
955    // https://stackoverflow.com/a/37754096/15534181
956    //
957    // generate visit_* functions per trait
958    (@pass_entity_tuple $struct_name:ident $($trait_name:ident),* @ $entity_tuple:tt) => {
959        // non-parallel visit functions
960        $crate::__world_define_visitors_common!(@pass_entity_tuple $struct_name $($trait_name),* @ $entity_tuple);
961
962        // parallel visit functions (added only when rayon feature enabled)
963        $crate::paste::paste! {
964            $(
965                /// in parallel, visit all entities that implement the trait
966                #[allow(unused)]
967                pub fn [<par_visit_ $trait_name:snake>]<F>(&self, handler: F)
968                where
969                    F: Fn(&dyn $trait_name) + Send + Sync
970                {
971                    $crate::__world_define_visitors!(@pv_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
972                }
973
974                /// in parallel, mutably visit all entities that implement the trait
975                #[allow(unused)]
976                pub fn [<par_visit_mut_ $trait_name:snake>]<F>(&mut self, handler: F)
977                where
978                    F: Fn(&mut dyn $trait_name) + Send + Sync
979                {
980                    $crate::__world_define_visitors!(@pvm_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
981                }
982
983                /// in parallel, visit all entities that implement the trait,
984                /// with their keys
985                /// 
986                /// since the slotmap key is type agnostic, it's important to
987                /// keep the arena id together with the slot map key (don't use
988                /// the slot map key on the wrong slot map)
989                #[allow(unused)]
990                pub fn [<par_visit_key_ $trait_name:snake>]<F>(&self, handler: F)
991                where
992                    F: Fn(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &dyn $trait_name) + Send + Sync
993                {
994                    $crate::__world_define_visitors!(@pvk_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
995                }
996
997                /// in parallel, mutably visit all entities that implement the
998                /// trait, with their keys
999                ///
1000                /// since the slotmap key is type agnostic, it's important to
1001                /// keep the arena id together with the slot map key (don't use
1002                /// the slot map key on the wrong slot map)
1003                #[allow(unused)]
1004                pub fn [<par_visit_key_mut_ $trait_name:snake>]<F>(&mut self, handler: F)
1005                where
1006                    F: Fn(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &mut dyn $trait_name) + Send + Sync
1007                {
1008                    $crate::__world_define_visitors!(@pvkm_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
1009                }
1010
1011                /// forwards to par_retain_with_default with DEFAULT=true
1012                #[allow(unused)]
1013                pub fn [<par_retain_ $trait_name:snake>]<F>(&mut self, mut predicate: F)
1014                where
1015                    F: Fn(&mut dyn $trait_name) -> bool + Send + Sync
1016                {
1017                    self.[<par_retain_with_default_ $trait_name:snake>]::<true, F>(predicate)
1018                }
1019
1020                /// WARN: this is parallel between arenas, not parallel between
1021                /// elements. this may be improved in a future version
1022                ///
1023                /// in parallel, retain entities matching predicate, removing
1024                /// those that don't.
1025                ///
1026                /// predicate applies only to entities implementing the trait.
1027                ///
1028                /// others instead use the DEFAULT value - if true entities not
1029                /// implementing trait are kept, false they are removed.
1030                #[allow(unused)]
1031                pub fn [<par_retain_with_default_ $trait_name:snake>]<const DEFAULT: bool, F>(&mut self, mut predicate: F)
1032                where
1033                    F: Fn(&mut dyn $trait_name) -> bool + Send + Sync
1034                {
1035                    $crate::__world_define_visitors!(@pr_use_entity_tuple $struct_name $trait_name $entity_tuple self predicate DEFAULT);
1036                }
1037
1038                /// in parallel, produce a diff vector
1039                ///
1040                /// entities must not be inserted or removed between diff
1041                /// creation and application
1042                #[allow(unused)]
1043                pub fn [<par_diff_ $trait_name:snake>]<D, F>(&mut self, mut handler: F) -> Vec<D>
1044                where
1045                    D: Send,
1046                    F: Fn(&dyn $trait_name) -> D + Send + Sync
1047                {
1048                    $crate::__world_define_visitors!(@pd_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
1049                }
1050
1051                /// in parallel, produce a diff vector from mutably viewing
1052                /// elements
1053                ///
1054                /// entities must not be inserted or removed between diff
1055                /// creation and application
1056                #[allow(unused)]
1057                pub fn [<par_diff_mut_ $trait_name:snake>]<D, F>(&mut self, mut handler: F) -> Vec<D>
1058                where
1059                    D: Send,
1060                    F: Fn(&mut dyn $trait_name) -> D + Send + Sync
1061                {
1062                    $crate::__world_define_visitors!(@pdm_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
1063                }
1064
1065                /// in parallel, apply the diff vector.
1066                ///
1067                /// entities must not be inserted or removed between diff
1068                /// creation and application
1069                #[allow(unused)]
1070                pub fn [<par_diff_apply_ $trait_name:snake>]<D, F>(&mut self, diff: Vec<D>, handler: F)
1071                where
1072                    D: Sync,
1073                    F: Fn(&mut dyn $trait_name, &D) + Send + Sync
1074                {
1075                    $crate::__world_define_visitors!(@pda_use_entity_tuple $struct_name $trait_name $entity_tuple self diff handler);
1076                }
1077            )*
1078        }
1079    };
1080
1081    (@pv_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
1082        $crate::paste::paste! {
1083        use $crate::rayon::scope;
1084            scope(|s| {
1085                $(
1086                    if <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::ACTIVE {
1087                        let arena_ref = &$self_ident.[<$entity:snake>];
1088                        s.spawn(|_| {
1089                            <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::pv_if_applicable(
1090                                arena_ref,
1091                                &$handler_ident,
1092                            );
1093                        });
1094                    }
1095                )*
1096            });
1097        }
1098    };
1099
1100    (@pvk_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
1101        $crate::paste::paste! {
1102        use $crate::rayon::scope;
1103            scope(|s| {
1104                $(
1105                    if <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::ACTIVE {
1106                        let arena_ref = &$self_ident.[<$entity:snake>];
1107                        s.spawn(|_| {
1108                            <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::pvk_if_applicable(
1109                                arena_ref,
1110                                &$handler_ident,
1111                            );
1112                        });
1113                    }
1114                )*
1115            });
1116        }
1117    };
1118
1119    (@pvm_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
1120        $crate::paste::paste! {
1121            use $crate::rayon::scope;
1122            scope(|s| {
1123                $(
1124                    if <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::ACTIVE {
1125                        s.spawn(|_| {
1126                            <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::pvm_if_applicable(
1127                                &mut $self_ident.[<$entity:snake>],
1128                                &$handler_ident,
1129                            );
1130                        });
1131                    }
1132                )*
1133            });
1134        }
1135    };
1136
1137    (@pvkm_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
1138        $crate::paste::paste! {
1139            use $crate::rayon::scope;
1140            scope(|s| {
1141                $(
1142                    if <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::ACTIVE {
1143                        s.spawn(|_| {
1144                            <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::pvkm_if_applicable(
1145                                &mut $self_ident.[<$entity:snake>],
1146                                &$handler_ident,
1147                            );
1148                        });
1149                    }
1150                )*
1151            });
1152        }
1153    };
1154
1155    (@pr_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $predicate_ident:ident $default:ident) => {
1156        $crate::paste::paste! {
1157            use $crate::rayon::scope;
1158            scope(|s| {
1159                $(
1160                    if <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::ACTIVE {
1161                        s.spawn(|_| {
1162                            <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::pr_if_applicable::<_>(
1163                                &mut $self_ident.[<$entity:snake>],
1164                                &$predicate_ident,
1165                            );
1166                        });
1167                    } else {
1168                        if !$default {
1169                            $self_ident.[<$entity:snake>].clear();
1170                        }
1171                    }
1172                )*
1173            });
1174        }
1175    };
1176
1177    (@pd_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
1178        $crate::paste::paste! {
1179            let len = $self_ident.[<len_$trait_name:snake>]();
1180            // MaybeUninit required in case population of diff vec panics
1181            let mut out: Vec<std::mem::MaybeUninit<D>> = Vec::with_capacity(len);
1182            unsafe { out.set_len(len); }
1183            use $crate::rayon::scope;
1184            scope(|s| {
1185                let mut remaining: &mut [_] = &mut out[..];
1186                $(
1187                    if <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::ACTIVE {
1188                        let arena_len = <() as [<$struct_name VisitIf $trait_name>]<$entity>>::len_if_applicable(
1189                            & $self_ident.[<$entity:snake>],
1190                        );
1191
1192                        let (arena_slice, rest) = remaining.split_at_mut(arena_len);
1193                        remaining = rest;
1194                        let arena_ref = &$self_ident.[<$entity:snake>];
1195                        let handler_ref = &$handler_ident;
1196                        s.spawn(move |_| {
1197                            <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::pd_if_applicable(
1198                                arena_ref,
1199                                handler_ref,
1200                                arena_slice,
1201                            );
1202                        });
1203                    }
1204                )*
1205            });
1206
1207            return unsafe { // convert MaybeUninit<Vec> to normal Vec
1208                let ptr = out.as_mut_ptr() as *mut D;
1209                let len = out.len();
1210                let cap = out.capacity();
1211                ::std::mem::forget(out);
1212                ::std::vec::Vec::from_raw_parts(ptr, len, cap)
1213            };
1214        }
1215    };
1216
1217    (@pdm_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
1218        $crate::paste::paste! {
1219            let len = $self_ident.[<len_$trait_name:snake>]();
1220            // MaybeUninit required in case population of diff vec panics
1221            let mut out: Vec<std::mem::MaybeUninit<D>> = Vec::with_capacity(len);
1222            unsafe { out.set_len(len); }
1223            use $crate::rayon::scope;
1224            scope(|s| {
1225                let mut remaining: &mut [_] = &mut out[..];
1226                $(
1227                    if <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::ACTIVE {
1228                        let arena_len = <() as [<$struct_name VisitIf $trait_name>]<$entity>>::len_if_applicable(
1229                            & $self_ident.[<$entity:snake>],
1230                        );
1231
1232                        let (arena_slice, rest) = remaining.split_at_mut(arena_len);
1233                        remaining = rest;
1234                        let arena_ref = &mut $self_ident.[<$entity:snake>];
1235                        let handler_ref = &$handler_ident;
1236                        s.spawn(move |_| {
1237                            <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::pdm_if_applicable(
1238                                arena_ref,
1239                                handler_ref,
1240                                arena_slice,
1241                            );
1242                        });
1243                    }
1244                )*
1245            });
1246
1247            return unsafe { // convert MaybeUninit<Vec> to normal Vec
1248                let ptr = out.as_mut_ptr() as *mut D;
1249                let len = out.len();
1250                let cap = out.capacity();
1251                ::std::mem::forget(out);
1252                ::std::vec::Vec::from_raw_parts(ptr, len, cap)
1253            };
1254        }
1255    };
1256
1257    (@pda_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $diff_ident:ident $handler_ident:ident) => {
1258    $crate::paste::paste! {
1259        use $crate::rayon::scope;
1260        scope(|s| {
1261            let mut remaining: &[_] = &$diff_ident[..];
1262            $(
1263                if <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::ACTIVE {
1264                    let arena_len = <() as [<$struct_name VisitIf $trait_name>]<$entity>>::len_if_applicable(
1265                        & $self_ident.[<$entity:snake>],
1266                    );
1267
1268                    let (arena_slice, rest) = remaining.split_at(arena_len);
1269                    remaining = rest;
1270                    let arena_ref = &mut $self_ident.[<$entity:snake>];
1271                    let handler_ref = &$handler_ident;
1272
1273                    s.spawn(move |_| {
1274                        <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::pda_if_applicable(
1275                            arena_ref,
1276                            handler_ref,
1277                            arena_slice,
1278                        );
1279                    });
1280                }
1281            )*
1282        });
1283    }
1284};
1285}
1286
1287#[doc(hidden)]
1288#[macro_export]
1289#[cfg(not(feature = "debug"))]
1290macro_rules! __world_define_struct {
1291    ($struct_name:ident, $( $entity:ty ),*) => {
1292        $crate::paste::paste! {
1293            #[derive(Default)]
1294            #[allow(private_interfaces)] // member is pub even if underlying type isn't
1295            pub struct $struct_name {
1296                $(
1297                    pub [<$entity:snake>]: $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, $entity>,
1298                )*
1299            }
1300        }
1301    };
1302}
1303
1304#[doc(hidden)]
1305#[macro_export]
1306#[cfg(feature = "debug")]
1307macro_rules! __world_define_struct {
1308    ($struct_name:ident, $( $entity:ty ),*) => {
1309        $crate::paste::paste! {
1310            #[derive(Default, Debug)]
1311            #[allow(private_interfaces)] // member is pub even if underlying type isn't
1312            pub struct $struct_name {
1313                $(
1314                    pub [<$entity:snake>]: $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, $entity>,
1315                )*
1316            }
1317        }
1318    };
1319}
1320
1321#[doc(hidden)]
1322#[macro_export]
1323#[cfg(not(feature = "serde"))]
1324macro_rules! __world_serde_support {
1325    ($struct_name:ident $( $entity:ty ),*) => {};
1326}
1327
1328#[doc(hidden)]
1329#[macro_export]
1330#[cfg(feature = "serde")]
1331macro_rules! __world_serde_support {
1332    ($struct_name:ident $( $entity:ty ),*) => {
1333        $crate::paste::paste! {
1334
1335impl $crate::serde::Serialize for [<$struct_name ArenaID>] {
1336    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1337    where
1338        S: $crate::serde::Serializer,
1339    {
1340        let s = match self.0 {
1341            $(
1342                i if i == $struct_name::arena_id::<$entity>().0 => stringify!($entity),
1343            )*
1344            // impossible! could be a panic here instead
1345            _ => return Err($crate::serde::ser::Error::custom(format!("Unknown ArenaID {}", self.0))),
1346        };
1347        serializer.serialize_str(s)
1348    }
1349}
1350
1351impl<'de> $crate::serde::Deserialize<'de> for [<$struct_name ArenaID>] {
1352    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1353    where
1354        D: $crate::serde::Deserializer<'de>,
1355    {
1356        let s = String::deserialize(deserializer)?;
1357        let id = match s.as_str() {
1358            $(
1359                stringify!($entity) => $struct_name::arena_id::<$entity>().0,
1360            )*
1361            // possible! suppose a different world loads it in, and there isn't that type.
1362            _ => return Err($crate::serde::de::Error::custom(format!("Unknown ArenaID string {}", s))),
1363        };
1364        Ok([<$struct_name ArenaID>](id))
1365    }
1366}
1367
1368impl $crate::serde::ser::Serialize for $struct_name {
1369    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1370    where
1371        S: $crate::serde::ser::Serializer,
1372    {
1373        use $crate::SerdeArena;
1374        use $crate::serde::ser::SerializeStruct;
1375
1376        let field_count = 0 $( + if <$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, $entity> as $crate::SerdeArena<'static>>::ACTIVE { 1 } else { 0 } )*;
1377        let mut state = serializer.serialize_struct(
1378            stringify!($struct_name),
1379            field_count
1380        )?;
1381        $(
1382            self.[<$entity:snake>].serialize_arena(stringify!($entity), &mut state)?;
1383        )*
1384        state.end()
1385    }
1386}
1387
1388// build list of serde members in world
1389static [<$struct_name:upper _DESERIALIZE_FIELDS>]: &'static [&'static str] = &{
1390    const TMP: [Option<&'static str>; { 0 $(+ { let _ = stringify!($entity); 1 })* }] = [
1391        $(
1392            if <$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, $entity>
1393                as $crate::SerdeArena<'static>>::ACTIVE {
1394                Some(stringify!($entity))
1395            } else {
1396                None
1397            }
1398        ),*
1399    ];
1400
1401    const COUNT: usize = 0 $(+ if (<$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, $entity>
1402        as $crate::SerdeArena<'static>>::ACTIVE) {1} else {0})*;
1403
1404    let mut arr: [&'static str; COUNT] = [""; COUNT];
1405    let mut j = 0;
1406    let mut k = 0;
1407    while j < TMP.len() {
1408        if let Some(s) = TMP[j] {
1409            arr[k] = s;
1410            k += 1;
1411        }
1412        j += 1;
1413    }
1414
1415    arr
1416};
1417
1418impl<'de> $crate::serde::Deserialize<'de> for $struct_name {
1419    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1420    where
1421        D: $crate::serde::Deserializer<'de>,
1422    {
1423        use $crate::serde::de::{MapAccess, SeqAccess, Visitor, Error};
1424        use std::fmt;
1425
1426        #[derive($crate::serde::Deserialize)]
1427        #[serde(field_identifier)]
1428        enum Field { $($entity),* }
1429
1430        struct WorldVisitor;
1431
1432        impl<'de> Visitor<'de> for WorldVisitor {
1433            type Value = $struct_name;
1434
1435            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
1436                write!(f, "struct {}", stringify!($struct_name))
1437            }
1438
1439            fn visit_map<V>(self, mut map: V) -> Result<$struct_name, V::Error>
1440            where
1441                V: MapAccess<'de>,
1442            {
1443                let mut world = $struct_name::default();
1444
1445                while let Some(key) = map.next_key::<Field>()? {
1446                    match key {
1447                        $(
1448                            Field::$entity => {
1449                                world.[<$entity:snake>] =
1450                                    <$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, $entity>
1451                                        as $crate::SerdeArena<'de>>::deserialize_arena(&mut map)?;
1452                            }
1453                        )*
1454                    }
1455                }
1456
1457                Ok(world)
1458            }
1459
1460            fn visit_seq<V>(self, mut seq: V) -> Result<$struct_name, V::Error>
1461            where
1462                V: SeqAccess<'de>,
1463            {
1464                Ok($struct_name {
1465                    $(
1466                        [<$entity:snake>]: <$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, $entity>
1467                            as $crate::SerdeArena<'de>>::from_seq(&mut seq, stringify!($entity))?,
1468                    )*
1469                })
1470            }
1471        }
1472
1473        deserializer.deserialize_struct(
1474            stringify!($struct_name),
1475            &[<$struct_name:upper _DESERIALIZE_FIELDS>],
1476            WorldVisitor,
1477        )
1478    }
1479}
1480
1481        }
1482    };
1483}
1484
1485/// ```ignore
1486/// entity_trait_system::world!(MyWorld, Enemy, Player; TestTrait, SecondTestTrait);
1487/// ```
1488/// 
1489/// This defines two structs:
1490///  - the world called `MyWorld`. It contains an arena for each entity type,
1491///    and generates query functions based on the supplied traits.
1492///  - the id type `MyWorldArenaId`. It's a stable equivalent to `TypeId`, which
1493///    serializes to the name of an entity's type. It can be used as the key
1494///    when accessing arenas in a type erased way.
1495#[macro_export]
1496macro_rules! world {
1497    // main macro form: define struct + traits + impl
1498    (
1499        // the name of the struct being defined
1500        $struct_name:ident, // the types of entities which can exist in the world
1501        $( $entity:ty ),* $(,)? // optional trailing comma
1502        ;// semi colon separator between lists
1503        // the traits which are query-able over all types in the world
1504        $( $trait_name:ident ),* $(,)? // optional trailing comma
1505    ) => {
1506        $crate::paste::paste! {
1507
1508/// the world is composed of arenas. this selects which arena.
1509///
1510/// unlike TypeID, this is stable across rust versions. It serializes to the
1511/// name of the entity's type.
1512#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
1513pub struct [<$struct_name ArenaID>](usize);
1514
1515$crate::__world_define_struct!($struct_name, $($entity),*);
1516
1517$(
1518    trait [<$struct_name VisitIf $trait_name>]<T> {
1519        fn v_if_applicable<F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: F)
1520        where
1521            F: FnMut(&dyn $trait_name);
1522
1523        fn mv_if_applicable<F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: F)
1524        where
1525            F: FnMut(&mut dyn $trait_name);
1526
1527        fn vk_if_applicable<F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: F)
1528        where
1529            F: FnMut(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &dyn $trait_name);
1530
1531        fn vkm_if_applicable<F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: F)
1532        where
1533            F: FnMut(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &mut dyn $trait_name);
1534
1535        fn r_if_applicable<P>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, predicate: P)
1536        where
1537            P: FnMut(&mut dyn $trait_name) -> bool;
1538
1539        fn d_if_applicable<D, F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: F, out: &mut [std::mem::MaybeUninit<D>])
1540        where
1541            F: FnMut(&dyn $trait_name) -> D;
1542
1543        fn dm_if_applicable<D, F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: F, out: &mut [std::mem::MaybeUninit<D>])
1544        where
1545            F: FnMut(&mut dyn $trait_name) -> D;
1546        
1547        fn da_if_applicable<D, F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: F, i: &[D])
1548        where
1549            F: FnMut(&mut dyn $trait_name, &D);
1550
1551        fn clear_if_applicable(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>);
1552
1553        fn len_if_applicable(arena: & $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>) -> usize;
1554
1555        const ACTIVE: bool;
1556    }
1557
1558    // no-op for types not implementing the trait
1559    impl<T> [<$struct_name VisitIf $trait_name>]<T> for () {
1560        default fn v_if_applicable<F>(_arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: F)
1561        where F: FnMut(&dyn $trait_name) {}
1562
1563        default fn mv_if_applicable<F>(_arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: F)
1564        where F: FnMut(&mut dyn $trait_name) {}
1565
1566        default fn vk_if_applicable<F>(_arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: F)
1567        where F: FnMut(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &dyn $trait_name) {}
1568
1569        default fn vkm_if_applicable<F>(_arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: F)
1570        where F: FnMut(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &mut dyn $trait_name) {}
1571
1572        default fn r_if_applicable<P>(_arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _predicate: P)
1573        where P: FnMut(&mut dyn $trait_name) -> bool {}
1574
1575        default fn d_if_applicable<D, F>(_arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: F, _out: &mut [std::mem::MaybeUninit<D>])
1576        where
1577            F: FnMut(&dyn $trait_name) -> D {}
1578
1579        default fn dm_if_applicable<D, F>(_arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: F, _out: &mut [std::mem::MaybeUninit<D>])
1580        where
1581            F: FnMut(&mut dyn $trait_name) -> D {}
1582
1583        default fn da_if_applicable<D, F>(_arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: F, _i: &[D])
1584        where
1585            F: FnMut(&mut dyn $trait_name, &D) {}
1586
1587        default fn clear_if_applicable(_arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>) {}
1588
1589        default fn len_if_applicable(_arena: & $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>) -> usize { 0 }
1590
1591        default const ACTIVE: bool = false;
1592    }
1593
1594    impl<T: $trait_name> [<$struct_name VisitIf $trait_name>]<T> for () {
1595        fn v_if_applicable<F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, mut handler: F)
1596        where F: FnMut(&dyn $trait_name)
1597        {
1598            arena
1599                .values_as_slice()
1600                .iter()
1601                .for_each(|entity| handler(entity));
1602        }
1603
1604        fn mv_if_applicable<F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, mut handler: F)
1605        where F: FnMut(&mut dyn $trait_name)
1606        {
1607            arena
1608                .values_as_mut_slice()
1609                .iter_mut()
1610                .for_each(|entity| handler(entity));
1611        }
1612
1613        fn r_if_applicable<P>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, mut predicate: P)
1614        where P: FnMut(&mut dyn $trait_name) -> bool
1615        {
1616            arena.retain(|_, entity| predicate(entity));
1617        }
1618
1619        fn d_if_applicable<D, F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, mut handler: F, out: &mut [std::mem::MaybeUninit<D>])
1620        where
1621            F: FnMut(&dyn $trait_name) -> D {
1622                for (e, out_slot) in arena.values_as_slice().iter().zip(out.iter_mut()) {
1623                    *out_slot = std::mem::MaybeUninit::new(handler(e));
1624                }
1625            }
1626
1627        fn dm_if_applicable<D, F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, mut handler: F, out: &mut [std::mem::MaybeUninit<D>])
1628        where
1629            F: FnMut(&mut dyn $trait_name) -> D {
1630                for (e, out_slot) in arena.values_as_mut_slice().iter_mut().zip(out.iter_mut()) {
1631                    *out_slot = std::mem::MaybeUninit::new(handler(e));
1632                }
1633            }
1634        
1635        fn da_if_applicable<D, F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, mut handler: F, i: &[D])
1636        where
1637            F: FnMut(&mut dyn $trait_name, &D) {
1638                for (e, in_value) in arena.values_as_mut_slice().iter_mut().zip(i.iter()) {
1639                    handler(e, in_value);
1640                }
1641            }
1642
1643        fn vk_if_applicable<F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, mut handler: F)
1644        where F: FnMut(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &dyn $trait_name)
1645        {
1646            let keys = arena.keys_as_slice();
1647            let values = arena.values_as_slice();
1648            keys.iter()
1649                .zip(values.iter())
1650                .for_each(|(k, v)| handler(($struct_name::arena_id::<T>(), *k), v));
1651        }
1652
1653        fn vkm_if_applicable<F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, mut handler: F)
1654        where F: FnMut(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &mut dyn $trait_name)
1655        {
1656            let (keys, values) = arena.keys_values_as_mut_slices();
1657            keys.iter()
1658                .zip(values.iter_mut())
1659                .for_each(|(k, v)| handler(($struct_name::arena_id::<T>(), *k), v));
1660        }
1661
1662        fn clear_if_applicable(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>) {
1663            arena.clear();
1664        }
1665
1666        fn len_if_applicable(arena: & $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>) -> usize {
1667            arena.len()
1668        }
1669
1670        default const ACTIVE: bool = true;
1671    }
1672
1673)*
1674
1675impl $struct_name {
1676    $crate::__world_define_visitors!(@pass_entity_tuple $struct_name $($trait_name),* @ ($($entity),*));
1677
1678    /// access underlying arena for type T
1679    /// ```
1680    /// world.arena::<Enemy>().len()
1681    /// ```
1682    #[allow(unused)]
1683    pub fn arena<T>(&self) -> &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T> {
1684        use $crate::ArenaCast;
1685        $(
1686            if <T as $crate::IsType<$entity>>::VALUE {
1687                return <$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, $entity> as ArenaCast<T>>::cast(&self.[<$entity:snake>]);
1688            }
1689        )* // checked compiler explorer to be sure - all of this is constant folded with optimizations enabled
1690        panic!("In call to {}::arena::<{}>(), {} not registered", stringify!($struct_name), std::any::type_name::<T>(), std::any::type_name::<T>());
1691    }
1692
1693    /// mutably access underlying arena for type T
1694    /// ```
1695    /// world.arena::<Enemy>().len()
1696    /// ```
1697    #[allow(unused)]
1698    pub fn arena_mut<T>(&mut self) -> &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T> {
1699        use $crate::ArenaCast;
1700        $(
1701            if <T as $crate::IsType<$entity>>::VALUE {
1702                return <$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, $entity> as ArenaCast<T>>::cast_mut(&mut self.[<$entity:snake>]);
1703            }
1704        )*
1705        panic!("In call to {}::arena_mut::<{}>(), {} not registered", stringify!($struct_name), std::any::type_name::<T>(), std::any::type_name::<T>());
1706    }
1707
1708    /// get the ArenaID for type T
1709    ///
1710    /// this is used as part of the type erased api
1711    /// ```
1712    /// let arena_id = MyWorld::arena_id::<Enemy>();
1713    /// let arena = world.any_arena(arena_id);
1714    /// ```
1715    #[allow(unused)]
1716    pub fn arena_id<T>() -> [<$struct_name ArenaID>] {
1717        let mut i = 0usize;
1718        $(
1719            if <T as $crate::IsType<$entity>>::VALUE {
1720                return [<$struct_name ArenaID>](i);
1721            }
1722            i += 1;
1723        )*
1724        panic!("In call to {}::arena_id::<{}>(), {} not registered", stringify!($struct_name), std::any::type_name::<T>(), std::any::type_name::<T>());
1725    }
1726
1727    /// type erased API. get arena by ArenaID, returning trait object
1728    #[allow(unused)]
1729    pub fn any_arena(&self, which: [<$struct_name ArenaID>]) -> &dyn $crate::ErasedArena {
1730        match which.0 {
1731            $(
1732                i if i == Self::arena_id::<$entity>().0 => &self.[<$entity:snake>] as &dyn $crate::ErasedArena,
1733            )*
1734            _ => panic!("No arena for type id {}", which.0),
1735        }
1736    }
1737
1738    /// type erased API. get mutable arena by ArenaID, returning trait object
1739    #[allow(unused)]
1740    pub fn any_arena_mut(&mut self, which: [<$struct_name ArenaID>]) -> &mut dyn $crate::ErasedArena {
1741        match which.0 {
1742            $(
1743                i if i == Self::arena_id::<$entity>().0 => &mut self.[<$entity:snake>] as &mut dyn $crate::ErasedArena,
1744            )*
1745            _ => panic!("No mutable arena for type id {}", which.0),
1746        }
1747    }
1748
1749    #[allow(unused)]
1750    pub fn clear(&mut self) {
1751        $(
1752            self.[<$entity:snake>].clear();
1753        )*
1754    }
1755
1756    #[allow(unused)]
1757    pub fn len(&self) -> usize {
1758        0 $( + self.[<$entity:snake>].len() )*
1759    }
1760}
1761
1762$crate::__world_serde_support!($struct_name $($entity),*);
1763
1764$crate::__world_define_rayon_trait_helpers!($struct_name $($trait_name),*);
1765
1766        }
1767    };
1768}