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