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