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