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