entity_trait_system/
lib.rs

1// specialization feature is incomplete, but is being used here in a very
2// limited but required capacity. it is only used to check if a type implements
3// a trait - there is no overlapping impl weirdness that is relied on
4#![allow(incomplete_features)]
5#![feature(specialization)]
6
7// macro is expanded at call site - makes it available to the lib user
8//
9// below macro references these via $crate:: prefix
10#[doc(hidden)]
11pub use paste;
12#[cfg(feature = "rayon")]
13#[doc(hidden)]
14pub use rayon;
15#[cfg(feature = "serde")]
16#[doc(hidden)]
17pub use serde;
18#[doc(hidden)]
19pub use slotmap;
20
21#[doc(hidden)]
22pub trait IsType<T> {
23    const VALUE: bool = false;
24}
25
26impl<A, B> IsType<B> for A {
27    default const VALUE: bool = false;
28}
29
30// specialize for equal types
31impl<T> IsType<T> for T {
32    const VALUE: bool = true;
33}
34
35/// type erased view of an arena. exposes single element API from DenseSlotMap
36#[doc(hidden)]
37pub trait ErasedArena {
38    fn get(&self, key: slotmap::DefaultKey) -> Option<&dyn std::any::Any>;
39    fn get_mut(&mut self, key: slotmap::DefaultKey) -> Option<&mut dyn std::any::Any>;
40    unsafe fn get_unchecked(&self, key: slotmap::DefaultKey) -> &dyn std::any::Any;
41    unsafe fn get_unchecked_mut(&mut self, key: slotmap::DefaultKey) -> &mut dyn std::any::Any;
42    fn insert(&mut self, value: Box<dyn std::any::Any>) -> slotmap::DefaultKey;
43    fn insert_with_key(
44        &mut self,
45        f: Box<dyn FnOnce(slotmap::DefaultKey) -> Box<dyn std::any::Any>>,
46    ) -> slotmap::DefaultKey;
47    fn remove(&mut self, key: slotmap::DefaultKey) -> Option<Box<dyn std::any::Any>>;
48}
49
50impl<T: 'static> ErasedArena for slotmap::DenseSlotMap<slotmap::DefaultKey, T> {
51    fn get(&self, key: slotmap::DefaultKey) -> Option<&dyn std::any::Any> {
52        self.get(key).map(|e| e as &dyn std::any::Any)
53    }
54
55    fn get_mut(&mut self, key: slotmap::DefaultKey) -> Option<&mut dyn std::any::Any> {
56        self.get_mut(key).map(|e| e as &mut dyn std::any::Any)
57    }
58
59    unsafe fn get_unchecked(&self, key: slotmap::DefaultKey) -> &dyn std::any::Any {
60        unsafe {
61            <slotmap::DenseSlotMap<slotmap::DefaultKey, T>>::get_unchecked(self, key)
62                as &dyn std::any::Any
63        }
64    }
65
66    unsafe fn get_unchecked_mut(&mut self, key: slotmap::DefaultKey) -> &mut dyn std::any::Any {
67        unsafe {
68            <slotmap::DenseSlotMap<slotmap::DefaultKey, T>>::get_unchecked_mut(self, key)
69                as &mut dyn std::any::Any
70        }
71    }
72
73    fn insert(&mut self, value: Box<dyn std::any::Any>) -> slotmap::DefaultKey {
74        // expect never triggers, gated by caller
75        self.insert(*value.downcast::<T>().expect("Try mismatch in insert"))
76    }
77
78    fn insert_with_key(
79        &mut self,
80        f: Box<dyn FnOnce(slotmap::DefaultKey) -> Box<dyn std::any::Any>>,
81    ) -> slotmap::DefaultKey {
82        // expect never triggers, gated by caller
83        self.insert_with_key(|k| {
84            *f(k)
85                .downcast::<T>()
86                .expect("Type mismatch in insert_with_key")
87        })
88    }
89
90    fn remove(&mut self, key: slotmap::DefaultKey) -> Option<Box<dyn std::any::Any>> {
91        self.remove(key)
92            .map(|v| Box::new(v) as Box<dyn std::any::Any>)
93    }
94}
95
96#[doc(hidden)]
97pub trait ArenaCast<T> {
98    fn cast(&self) -> &slotmap::DenseSlotMap<slotmap::DefaultKey, T>;
99    fn cast_mut(&mut self) -> &mut slotmap::DenseSlotMap<slotmap::DefaultKey, T>;
100}
101
102// default: panic for mismatched types
103impl<A, B> ArenaCast<B> for slotmap::DenseSlotMap<slotmap::DefaultKey, A> {
104    default fn cast(&self) -> &slotmap::DenseSlotMap<slotmap::DefaultKey, B> {
105        panic!(
106            // never, gated at compile time
107            "Arena type mismatch: {} cannot be cast to {}",
108            std::any::type_name::<A>(),
109            std::any::type_name::<B>()
110        );
111    }
112
113    default fn cast_mut(&mut self) -> &mut slotmap::DenseSlotMap<slotmap::DefaultKey, B> {
114        panic!(
115            // never, gated at compile time
116            "Arena type mismatch: {} cannot be cast to {}",
117            std::any::type_name::<A>(),
118            std::any::type_name::<B>()
119        );
120    }
121}
122
123// specialization: types match
124impl<T> ArenaCast<T> for slotmap::DenseSlotMap<slotmap::DefaultKey, T> {
125    fn cast(&self) -> &slotmap::DenseSlotMap<slotmap::DefaultKey, T> {
126        self
127    }
128
129    fn cast_mut(&mut self) -> &mut slotmap::DenseSlotMap<slotmap::DefaultKey, T> {
130        self
131    }
132}
133
134// conditional serde if specific type is also serde
135#[cfg(feature = "serde")]
136#[doc(hidden)] // must be exposed to caller from macro expansion
137pub trait SerdeArena<'de> {
138    // member serialize into a SerializeStruct (called from world Serialize impl)
139    fn serialize_arena<S>(&self, field_name: &'static str, state: &mut S) -> Result<(), S::Error>
140    where
141        S: serde::ser::SerializeStruct;
142
143    // member deserialize from map access (JSON, etc.)
144    fn deserialize_arena<M>(map: &mut M) -> Result<Self, M::Error>
145    where
146        M: serde::de::MapAccess<'de>,
147        Self: Sized;
148
149    // sequence deserialize (e.g. bincode)
150    fn from_seq<V>(seq: &mut V, field_name: &str) -> Result<Self, V::Error>
151    where
152        V: serde::de::SeqAccess<'de>,
153        Self: Sized;
154
155    const ACTIVE: bool; // whether this arena participates in serde
156}
157
158// default: type does NOT implement serde => do nothing
159#[cfg(feature = "serde")]
160impl<'de, T> SerdeArena<'de> for slotmap::DenseSlotMap<slotmap::DefaultKey, T> {
161    default fn serialize_arena<S>(
162        &self,
163        _field_name: &'static str,
164        _state: &mut S,
165    ) -> Result<(), S::Error>
166    where
167        S: serde::ser::SerializeStruct,
168    {
169        Ok(())
170    }
171
172    default fn deserialize_arena<M>(_map: &mut M) -> Result<Self, M::Error>
173    where
174        M: serde::de::MapAccess<'de>,
175    {
176        Ok(slotmap::DenseSlotMap::new())
177    }
178
179    default fn from_seq<V>(_seq: &mut V, _field_name: &str) -> Result<Self, V::Error>
180    where
181        V: serde::de::SeqAccess<'de>,
182    {
183        Ok(slotmap::DenseSlotMap::new())
184    }
185
186    default const ACTIVE: bool = false;
187}
188
189// specialized: type implements serde Serialize + Deserialize
190#[cfg(feature = "serde")]
191impl<'de, T> SerdeArena<'de> for slotmap::DenseSlotMap<slotmap::DefaultKey, T>
192where
193    T: serde::Serialize + serde::Deserialize<'de>,
194{
195    fn serialize_arena<S>(&self, field_name: &'static str, state: &mut S) -> Result<(), S::Error>
196    where
197        S: serde::ser::SerializeStruct,
198    {
199        state.serialize_field(field_name, self)
200    }
201
202    fn deserialize_arena<M>(map: &mut M) -> Result<Self, M::Error>
203    where
204        M: serde::de::MapAccess<'de>,
205    {
206        map.next_value()
207    }
208
209    fn from_seq<V>(seq: &mut V, field_name: &str) -> Result<Self, V::Error>
210    where
211        V: serde::de::SeqAccess<'de>,
212    {
213        seq.next_element()?
214            .ok_or_else(|| serde::de::Error::custom(format!("Missing element for {}", field_name)))
215    }
216
217    const ACTIVE: bool = true;
218}
219
220#[macro_export]
221#[cfg(not(feature = "rayon"))]
222macro_rules! __world_define_rayon_trait_helpers {
223    ($struct_name:ident $( $trait_name:ident ),*) => {};
224}
225
226#[macro_export]
227#[cfg(feature = "rayon")]
228macro_rules! __world_define_rayon_trait_helpers {
229    ($struct_name:ident $( $trait_name:ident ),*) => {
230        $crate::paste::paste! {
231
232$(
233trait [<$struct_name ParVisitIf $trait_name>]<T> {
234    fn pv_if_applicable<F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F)
235    where
236        F: Fn(&dyn $trait_name) + Send + Sync;
237
238    fn pvm_if_applicable<F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F)
239    where
240        F: Fn(&mut dyn $trait_name) + Send + Sync;
241
242    fn pvk_if_applicable<F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F)
243    where
244        F: Fn(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &dyn $trait_name) + Send + Sync;
245
246    fn pvkm_if_applicable<F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F)
247    where
248        F: Fn(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &mut dyn $trait_name) + Send + Sync;
249
250    fn pr_if_applicable<P>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, predicate: &P)
251    where
252        P: Fn(&mut dyn $trait_name) -> bool + Send + Sync;
253
254    fn pd_if_applicable<D, F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F, out: &mut [std::mem::MaybeUninit<D>])
255    where
256        D: Send,
257        F: Fn(&dyn $trait_name) -> D + Send + Sync;
258
259    fn pdm_if_applicable<D, F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F, out: &mut [std::mem::MaybeUninit<D>])
260    where
261        D: Send,
262        F: Fn(&mut dyn $trait_name) -> D + Send + Sync;
263
264    // parallel diff apply
265    fn pda_if_applicable<D, F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F, i: &[D])
266    where
267        D: Sync,
268        F: Fn(&mut dyn $trait_name, &D) + Send + Sync;
269
270    const ACTIVE: bool;
271}
272
273impl<T> [<$struct_name ParVisitIf $trait_name>]<T> for () {
274    default fn pv_if_applicable<F>(_arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: &F)
275    where F: Fn(&dyn $trait_name) + Send + Sync {}
276
277    default fn pvm_if_applicable<F>(_arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: &F)
278    where F: Fn(&mut dyn $trait_name) + Send + Sync {}
279
280    default fn pvk_if_applicable<F>(_arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: &F)
281    where F: Fn(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &dyn $trait_name) + Send + Sync {}
282
283    default fn pvkm_if_applicable<F>(_arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: &F)
284    where F: Fn(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &mut dyn $trait_name) + Send + Sync {}
285
286    default fn pr_if_applicable<P>(_arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _predicate: &P)
287    where P: Fn(&mut dyn $trait_name) -> bool + Send + Sync {}
288
289    default fn pd_if_applicable<D, F>(_arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: &F, _out: &mut [std::mem::MaybeUninit<D>])
290    where
291        D: Send,
292        F: Fn(&dyn $trait_name) -> D + Send + Sync {}
293
294    default fn pdm_if_applicable<D, F>(_arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: &F, _out: &mut [std::mem::MaybeUninit<D>])
295    where
296        D: Send,
297        F: Fn(&mut dyn $trait_name) -> D + Send + Sync {}
298
299    default fn pda_if_applicable<D, F>(_arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: &F, _i: &[D])
300    where
301        D: Sync,
302        F: Fn(&mut dyn $trait_name, &D) + Send + Sync {}
303
304    default const ACTIVE: bool = false;
305}
306
307impl<T> [<$struct_name ParVisitIf $trait_name>]<T> for ()
308where
309    T: $trait_name + Send + Sync,
310{
311    fn pv_if_applicable<F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F)
312    where F: Fn(&dyn $trait_name) + Send + Sync
313    {
314        use $crate::rayon::iter::IntoParallelRefIterator;
315        use $crate::rayon::iter::ParallelIterator;
316        arena
317            .values_as_slice()
318            .par_iter()
319            .for_each(|entity| handler(entity));
320    }
321
322    fn pvm_if_applicable<F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F)
323    where F: Fn(&mut dyn $trait_name) + Send + Sync
324    {
325        use $crate::rayon::iter::IntoParallelRefMutIterator;
326        use $crate::rayon::iter::ParallelIterator;
327        arena
328            .values_as_mut_slice()
329            .par_iter_mut()
330            .for_each(|entity| handler(entity));
331    }
332
333    fn pvk_if_applicable<F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F)
334    where F: Fn(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &dyn $trait_name) + Send + Sync
335    {
336        use $crate::rayon::iter::IntoParallelRefIterator;
337        use $crate::rayon::iter::IndexedParallelIterator;
338        use $crate::rayon::iter::ParallelIterator;
339        let keys = arena.keys_as_slice();
340        let values = arena.values_as_slice();
341        keys.par_iter()
342            .zip(values.par_iter())
343            .for_each(|(k, v)| handler(($struct_name::arena_id::<T>(), *k), v));
344    }
345
346    fn pvkm_if_applicable<F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F)
347    where F: Fn(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &mut dyn $trait_name) + Send + Sync
348    {
349        use $crate::rayon::iter::IntoParallelRefIterator;
350        use $crate::rayon::iter::IntoParallelRefMutIterator;
351        use $crate::rayon::iter::IndexedParallelIterator;
352        use $crate::rayon::iter::ParallelIterator;
353        let (keys, values) = arena.keys_values_as_mut_slices();
354        keys.par_iter()
355            .zip(values.par_iter_mut())
356            .for_each(|(k, v)| handler(($struct_name::arena_id::<T>(), *k), v));
357    }
358
359    fn pr_if_applicable<P>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, predicate: &P)
360    where P: Fn(&mut dyn $trait_name) -> bool + Send + Sync
361    {
362        // current par retain is only parallel between arenas, not per element.
363        //
364        // I don't think it's possible to do this better but I might be wrong.
365        // keeping send + sync for forward compat. either way, not supported by
366        // DenseSlotMap
367        arena.retain(|_, entity| predicate(entity));
368    }
369
370    fn pd_if_applicable<D, F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F, out: &mut [std::mem::MaybeUninit<D>])
371    where
372        D: Send,
373        F: Fn(&dyn $trait_name) -> D + Sync + Send,
374    {
375        use $crate::rayon::iter::IntoParallelRefMutIterator;
376        use $crate::rayon::iter::IndexedParallelIterator;
377        use $crate::rayon::iter::IntoParallelRefIterator;
378        use $crate::rayon::iter::ParallelIterator;
379        arena
380            .values_as_slice()
381            .par_iter()
382            .zip(out.par_iter_mut())
383            .for_each(|(e, out_slot)| {
384                *out_slot = std::mem::MaybeUninit::new(handler(e));
385            });
386    }
387
388    fn pdm_if_applicable<D, F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F, out: &mut [std::mem::MaybeUninit<D>])
389    where
390        D: Send,
391        F: Fn(&mut dyn $trait_name) -> D + Sync + Send,
392    {
393        use $crate::rayon::iter::IntoParallelRefMutIterator;
394        use $crate::rayon::iter::IndexedParallelIterator;
395        use $crate::rayon::iter::ParallelIterator;
396        arena
397            .values_as_mut_slice()
398            .par_iter_mut()
399            .zip(out.par_iter_mut())
400            .for_each(|(e, out_slot)| {
401                *out_slot = std::mem::MaybeUninit::new(handler(e));
402            });
403    }
404
405    fn pda_if_applicable<D, F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: &F, i: &[D])
406    where
407        D: Sync,
408        F: Fn(&mut dyn $trait_name, &D) + Send + Sync {
409            use $crate::rayon::iter::IntoParallelRefMutIterator;
410            use $crate::rayon::iter::IndexedParallelIterator;
411            use $crate::rayon::iter::IntoParallelRefIterator;
412            use $crate::rayon::iter::ParallelIterator;
413            arena
414                .values_as_mut_slice()
415                .par_iter_mut()
416                .zip(i.par_iter())
417                .for_each(|(e, in_value)| {
418                    handler(e, in_value);
419                });
420        }
421
422    const ACTIVE: bool = true;
423}
424
425)*
426        }
427    };
428}
429
430#[macro_export]
431macro_rules! __world_define_visitors_common {
432    // https://stackoverflow.com/a/37754096/15534181
433    //
434    // generate visit_* functions per trait (non-parallel)
435    (@pass_entity_tuple $struct_name:ident $($trait_name:ident),* @ $entity_tuple:tt) => {
436        $crate::paste::paste! {
437            $(
438                /// visit all entities that implement the trait
439                #[allow(unused)]
440                pub fn [<visit_ $trait_name:snake>]<F>(&self, mut handler: F)
441                where
442                    F: FnMut(&dyn $trait_name)
443                {
444                    $crate::__world_define_visitors_common!(@v_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
445                }
446
447                /// mutably visit all entities that implement the trait
448                #[allow(unused)]
449                pub fn [<visit_mut_ $trait_name:snake>]<F>(&mut self, mut handler: F)
450                where
451                    F: FnMut(&mut dyn $trait_name)
452                {
453                    $crate::__world_define_visitors_common!(@vm_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
454                }
455
456                /// visit all entities that implement the trait, with their keys
457                /// 
458                /// since the slotmap key is type agnostic, it's important to
459                /// keep the arena id together with the slot map key (don't use
460                /// the slot map key on the wrong slot map)
461                #[allow(unused)]
462                pub fn [<visit_key_ $trait_name:snake>]<F>(&self, mut handler: F)
463                where
464                    F: FnMut(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &dyn $trait_name)
465                {
466                    $crate::__world_define_visitors_common!(@vk_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
467                }
468
469                /// mutably visit all entities that implement the trait, with their keys
470                /// 
471                /// since the slotmap key is type agnostic, it's important to
472                /// keep the arena id together with the slot map key (don't use
473                /// the slot map key on the wrong slot map)
474                #[allow(unused)]
475                pub fn [<visit_key_mut_ $trait_name:snake>]<F>(&mut self, mut handler: F)
476                where
477                    F: FnMut(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &mut dyn $trait_name)
478                {
479                    $crate::__world_define_visitors_common!(@vkm_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
480                }
481
482                /// forwards to retain_with_default with DEFAULT=true
483                #[allow(unused)]
484                pub fn [<retain_ $trait_name:snake>]<F>(&mut self, mut predicate: F)
485                where
486                    F: FnMut(&mut dyn $trait_name) -> bool
487                {
488                    self.[<retain_with_default_ $trait_name:snake>]::<true, F>(predicate)
489                }
490
491                /// retain entities matching predicate, removing those that
492                /// don't.
493                ///
494                /// predicate applies only to entities implementing the trait.
495                ///
496                /// others instead use the DEFAULT value - if true entities not
497                /// implementing trait are kept, false they are removed.
498                #[allow(unused)]
499                pub fn [<retain_with_default_ $trait_name:snake>]<const DEFAULT: bool, F>(&mut self, mut predicate: F)
500                where
501                    F: FnMut(&mut dyn $trait_name) -> bool
502                {
503                    $crate::__world_define_visitors_common!(@r_use_entity_tuple $struct_name $trait_name $entity_tuple self predicate DEFAULT);
504                }
505
506                /// produce a diff vector, created from viewing all elements
507                /// that implement trait
508                ///
509                /// entities must not be inserted or removed between diff
510                /// creation and application
511                #[allow(unused)]
512                pub fn [<diff_ $trait_name:snake>]<D, F>(&mut self, mut handler: F) -> Vec<D>
513                where
514                    F: FnMut(&dyn $trait_name) -> D
515                {
516                    $crate::__world_define_visitors_common!(@d_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
517                }
518
519                /// produce a diff vector, created from mutably viewing all
520                /// elements that implement trait
521                ///
522                /// entities must not be inserted or removed between diff
523                /// creation and application
524                #[allow(unused)]
525                pub fn [<diff_mut_ $trait_name:snake>]<D, F>(&mut self, mut handler: F) -> Vec<D>
526                where
527                    F: FnMut(&mut dyn $trait_name) -> D
528                {
529                    $crate::__world_define_visitors_common!(@dm_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
530                }
531
532                /// apply the diff vector.
533                ///
534                /// entities must not be inserted or removed between diff
535                /// creation and application
536                #[allow(unused)]
537                pub fn [<diff_apply_ $trait_name:snake>]<D, F>(&mut self, diff: Vec<D>, mut handler: F)
538                where F: FnMut(&mut dyn $trait_name, &D)
539                {
540                    $crate::__world_define_visitors_common!(@da_use_entity_tuple $struct_name $trait_name $entity_tuple self diff handler);
541                }
542
543                /// clear all arenas whose element type implements this trait.
544                /// No-op for arenas whose element types do not implement the trait.
545                #[allow(unused)]
546                pub fn [<clear_ $trait_name:snake>](&mut self) {
547                    $crate::__world_define_visitors_common!(@clear_use_entity_tuple $struct_name $trait_name $entity_tuple self);
548                }
549
550                /// total number of elements across arenas whose element type implements trait
551                #[allow(unused)]
552                pub fn [<len_ $trait_name:snake>](&self) -> usize {
553                    $crate::__world_define_visitors_common!(@len_use_entity_tuple $struct_name $trait_name $entity_tuple self)
554                }
555
556                /// get type erased arenas whose element type implements this trait
557                #[allow(unused)]
558                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)] {
559                    $crate::__world_define_visitors_common!(@any_arenas_use_entity_tuple $struct_name $trait_name $entity_tuple self)
560                }
561
562                /// get type erased arenas (mutable) whose element type implements this trait
563                #[allow(unused)]
564                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)] {
565                    $crate::__world_define_visitors_common!(@any_arenas_mut_use_entity_tuple $struct_name $trait_name $entity_tuple self)
566                }
567            )*
568        }
569    };
570
571    (@v_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
572        $crate::paste::paste! {
573            $(
574                <() as [<$struct_name VisitIf $trait_name>]<$entity>>::v_if_applicable(
575                    &$self_ident.[<$entity:snake>],
576                    &mut $handler_ident,
577                );
578            )*
579        }
580    };
581
582    (@vk_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
583        $crate::paste::paste! {
584            $(
585                <() as [<$struct_name VisitIf $trait_name>]<$entity>>::vk_if_applicable(
586                    &$self_ident.[<$entity:snake>],
587                    &mut $handler_ident,
588                );
589            )*
590        }
591    };
592
593    (@vm_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
594        $crate::paste::paste! {
595            $(
596                <() as [<$struct_name VisitIf $trait_name>]<$entity>>::mv_if_applicable(
597                    &mut $self_ident.[<$entity:snake>],
598                    &mut $handler_ident,
599                );
600            )*
601        }
602    };
603
604    (@vkm_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
605        $crate::paste::paste! {
606            $(
607                <() as [<$struct_name VisitIf $trait_name>]<$entity>>::vkm_if_applicable(
608                    &mut $self_ident.[<$entity:snake>],
609                    &mut $handler_ident,
610                );
611            )*
612        }
613    };
614
615    (@r_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $predicate:ident $default:ident) => {
616        $crate::paste::paste! {
617            $(
618                if <() as [<$struct_name VisitIf $trait_name>]<$entity>>::ACTIVE {
619                    <() as [<$struct_name VisitIf $trait_name>]<$entity>>::r_if_applicable::<_>(
620                        &mut $self_ident.[<$entity:snake>],
621                        &mut $predicate,
622                    );
623                } else {
624                    if !$default {
625                        $self_ident.[<$entity:snake>].clear();
626                    }
627                }
628            )*
629        }
630    };
631
632    (@d_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
633        $crate::paste::paste! {
634            let len = $self_ident.[<len_$trait_name:snake>]();
635            // MaybeUninit required in case population of diff vec panics
636            let mut out: Vec<std::mem::MaybeUninit<D>> = Vec::with_capacity(len);
637            unsafe { out.set_len(len); }
638            let mut offset = 0usize;
639            $(
640                let arena_len = <() as [<$struct_name VisitIf $trait_name>]<$entity>>::len_if_applicable(
641                    & $self_ident.[<$entity:snake>],
642                );
643
644                <() as [<$struct_name VisitIf $trait_name>]<$entity>>::d_if_applicable(
645                    & $self_ident.[<$entity:snake>],
646                    &mut $handler_ident,
647                    &mut out[offset..offset + arena_len],
648                );
649
650                offset += arena_len;
651            )*
652
653            return unsafe { // convert MaybeUninit<Vec> to normal Vec
654                let ptr = out.as_mut_ptr() as *mut D;
655                let len = out.len();
656                let cap = out.capacity();
657                ::std::mem::forget(out);
658                ::std::vec::Vec::from_raw_parts(ptr, len, cap)
659            };
660        }
661    };
662
663    (@dm_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
664        $crate::paste::paste! {
665            let len = $self_ident.[<len_$trait_name:snake>]();
666            // MaybeUninit required in case population of diff vec panics
667            let mut out: Vec<std::mem::MaybeUninit<D>> = Vec::with_capacity(len);
668            unsafe { out.set_len(len); }
669            let mut offset = 0usize;
670            $(
671                let arena_len = <() as [<$struct_name VisitIf $trait_name>]<$entity>>::len_if_applicable(
672                    & $self_ident.[<$entity:snake>],
673                );
674
675                <() as [<$struct_name VisitIf $trait_name>]<$entity>>::dm_if_applicable(
676                    &mut $self_ident.[<$entity:snake>],
677                    &mut $handler_ident,
678                    &mut out[offset..offset + arena_len],
679                );
680
681                offset += arena_len;
682            )*
683
684            return unsafe { // convert MaybeUninit<Vec> to normal Vec
685                let ptr = out.as_mut_ptr() as *mut D;
686                let len = out.len();
687                let cap = out.capacity();
688                ::std::mem::forget(out);
689                ::std::vec::Vec::from_raw_parts(ptr, len, cap)
690            };
691        }
692    };
693
694    (@da_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $diff_ident:ident $handler_ident:ident) => {
695        $crate::paste::paste! {
696            let mut offset = 0usize;
697            $(
698                let arena_len = <() as [<$struct_name VisitIf $trait_name>]<$entity>>::len_if_applicable(
699                    & $self_ident.[<$entity:snake>],
700                );
701
702                <() as [<$struct_name VisitIf $trait_name>]<$entity>>::da_if_applicable(
703                    &mut $self_ident.[<$entity:snake>],
704                    &mut $handler_ident,
705                    &$diff_ident[offset..offset + arena_len],
706                );
707
708                offset += arena_len;
709            )*
710        }
711    };
712
713    (@clear_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident) => {
714        $crate::paste::paste! {
715            $(
716                <() as [<$struct_name VisitIf $trait_name>]<$entity>>::clear_if_applicable(
717                    &mut $self_ident.[<$entity:snake>],
718                );
719            )*
720        }
721    };
722
723    (@len_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident) => {
724        $crate::paste::paste! {
725            {
726                let mut total = 0usize;
727                $(
728                    total += <() as [<$struct_name VisitIf $trait_name>]<$entity>>::len_if_applicable(
729                        & $self_ident.[<$entity:snake>],
730                    );
731                )*
732                total
733            }
734        }
735    };
736
737    (@any_arenas_count_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) ) => {
738        $crate::paste::paste! {
739            {
740                0 $(+ if <() as [<$struct_name VisitIf $trait_name>]<$entity>>::ACTIVE {1} else {0})*
741            }
742        }
743    };
744
745    (@any_arenas_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident) => {
746        $crate::paste::paste! {
747            {
748                const NUM_ARENAS: usize = 0 $(+ if <() as [<$struct_name VisitIf $trait_name>]<$entity>>::ACTIVE {1} else {0})*;
749                let mut tmp: [std::mem::MaybeUninit<&dyn $crate::ErasedArena>; NUM_ARENAS] = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
750                let mut idx = 0;
751                $(
752                    if <() as [<$struct_name VisitIf $trait_name>]<$entity>>::ACTIVE {
753                        tmp[idx] = std::mem::MaybeUninit::new(&$self_ident.[<$entity:snake>] as &dyn $crate::ErasedArena);
754                        idx += 1;
755                    }
756                )*
757                unsafe {
758                    std::mem::transmute::<
759                        [std::mem::MaybeUninit<&dyn $crate::ErasedArena>; NUM_ARENAS],
760                        [&dyn $crate::ErasedArena; NUM_ARENAS]
761                    >(tmp)
762                }
763            }
764        }
765    };
766
767    (@any_arenas_mut_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident) => {
768        $crate::paste::paste! {
769            {
770                const NUM_ARENAS: usize = 0 $(+ if <() as [<$struct_name VisitIf $trait_name>]<$entity>>::ACTIVE {1} else {0})*;
771                let mut tmp: [std::mem::MaybeUninit<&mut dyn $crate::ErasedArena>; NUM_ARENAS] = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
772                let mut idx = 0;
773                $(
774                    if <() as [<$struct_name VisitIf $trait_name>]<$entity>>::ACTIVE {
775                        tmp[idx] = std::mem::MaybeUninit::new(&mut $self_ident.[<$entity:snake>] as &mut dyn $crate::ErasedArena);
776                        idx += 1;
777                    }
778                )*
779                unsafe {
780                    std::mem::transmute::<
781                        [std::mem::MaybeUninit<&mut dyn $crate::ErasedArena>; NUM_ARENAS],
782                        [&mut dyn $crate::ErasedArena; NUM_ARENAS]
783                    >(tmp)
784                }
785            }
786        }
787    };
788}
789
790#[macro_export]
791#[cfg(not(feature = "rayon"))]
792macro_rules! __world_define_visitors {
793    // Non-rayon version simply forwards to the common macro
794    (@pass_entity_tuple $struct_name:ident $($trait_name:ident),* @ $entity_tuple:tt) => {
795        $crate::__world_define_visitors_common!(@pass_entity_tuple $struct_name $($trait_name),* @ $entity_tuple);
796    };
797}
798
799#[macro_export]
800#[cfg(feature = "rayon")]
801macro_rules! __world_define_visitors {
802    // https://stackoverflow.com/a/37754096/15534181
803    //
804    // generate visit_* functions per trait
805    (@pass_entity_tuple $struct_name:ident $($trait_name:ident),* @ $entity_tuple:tt) => {
806        // non-parallel visit functions
807        $crate::__world_define_visitors_common!(@pass_entity_tuple $struct_name $($trait_name),* @ $entity_tuple);
808
809        // parallel visit functions (added only when rayon feature enabled)
810        $crate::paste::paste! {
811            $(
812                /// in parallel, visit all entities that implement the trait
813                #[allow(unused)]
814                pub fn [<par_visit_ $trait_name:snake>]<F>(&self, handler: F)
815                where
816                    F: Fn(&dyn $trait_name) + Send + Sync
817                {
818                    $crate::__world_define_visitors!(@pv_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
819                }
820
821                /// in parallel, mutably visit all entities that implement the trait
822                #[allow(unused)]
823                pub fn [<par_visit_mut_ $trait_name:snake>]<F>(&mut self, handler: F)
824                where
825                    F: Fn(&mut dyn $trait_name) + Send + Sync
826                {
827                    $crate::__world_define_visitors!(@pvm_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
828                }
829
830                /// in parallel, visit all entities that implement the trait,
831                /// with their keys
832                /// 
833                /// since the slotmap key is type agnostic, it's important to
834                /// keep the arena id together with the slot map key (don't use
835                /// the slot map key on the wrong slot map)
836                #[allow(unused)]
837                pub fn [<par_visit_key_ $trait_name:snake>]<F>(&self, handler: F)
838                where
839                    F: Fn(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &dyn $trait_name) + Send + Sync
840                {
841                    $crate::__world_define_visitors!(@pvk_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
842                }
843
844                /// in parallel, mutably visit all entities that implement the
845                /// trait, with their keys
846                ///
847                /// since the slotmap key is type agnostic, it's important to
848                /// keep the arena id together with the slot map key (don't use
849                /// the slot map key on the wrong slot map)
850                #[allow(unused)]
851                pub fn [<par_visit_key_mut_ $trait_name:snake>]<F>(&mut self, handler: F)
852                where
853                    F: Fn(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &mut dyn $trait_name) + Send + Sync
854                {
855                    $crate::__world_define_visitors!(@pvkm_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
856                }
857
858                /// forwards to par_retain_with_default with DEFAULT=true
859                #[allow(unused)]
860                pub fn [<par_retain_ $trait_name:snake>]<F>(&mut self, mut predicate: F)
861                where
862                    F: Fn(&mut dyn $trait_name) -> bool + Send + Sync
863                {
864                    self.[<par_retain_with_default_ $trait_name:snake>]::<true, F>(predicate)
865                }
866
867                /// WARN: this is parallel between arenas, not parallel between
868                /// elements. this may be improved in a future version
869                ///
870                /// in parallel, retain entities matching predicate, removing
871                /// those that don't.
872                ///
873                /// predicate applies only to entities implementing the trait.
874                ///
875                /// others instead use the DEFAULT value - if true entities not
876                /// implementing trait are kept, false they are removed.
877                #[allow(unused)]
878                pub fn [<par_retain_with_default_ $trait_name:snake>]<const DEFAULT: bool, F>(&mut self, mut predicate: F)
879                where
880                    F: Fn(&mut dyn $trait_name) -> bool + Send + Sync
881                {
882                    $crate::__world_define_visitors!(@pr_use_entity_tuple $struct_name $trait_name $entity_tuple self predicate DEFAULT);
883                }
884
885                /// in parallel, produce a diff vector
886                ///
887                /// entities must not be inserted or removed between diff
888                /// creation and application
889                #[allow(unused)]
890                pub fn [<par_diff_ $trait_name:snake>]<D, F>(&mut self, mut handler: F) -> Vec<D>
891                where
892                    D: Send,
893                    F: Fn(&dyn $trait_name) -> D + Send + Sync
894                {
895                    $crate::__world_define_visitors!(@pd_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
896                }
897
898                /// in parallel, produce a diff vector from mutably viewing
899                /// elements
900                ///
901                /// entities must not be inserted or removed between diff
902                /// creation and application
903                #[allow(unused)]
904                pub fn [<par_diff_mut_ $trait_name:snake>]<D, F>(&mut self, mut handler: F) -> Vec<D>
905                where
906                    D: Send,
907                    F: Fn(&mut dyn $trait_name) -> D + Send + Sync
908                {
909                    $crate::__world_define_visitors!(@pdm_use_entity_tuple $struct_name $trait_name $entity_tuple self handler);
910                }
911
912                /// in parallel, apply the diff vector.
913                ///
914                /// entities must not be inserted or removed between diff
915                /// creation and application
916                #[allow(unused)]
917                pub fn [<par_diff_apply_ $trait_name:snake>]<D, F>(&mut self, diff: Vec<D>, handler: F)
918                where
919                    D: Sync,
920                    F: Fn(&mut dyn $trait_name, &D) + Send + Sync
921                {
922                    $crate::__world_define_visitors!(@pda_use_entity_tuple $struct_name $trait_name $entity_tuple self diff handler);
923                }
924            )*
925        }
926    };
927
928    (@pv_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
929        $crate::paste::paste! {
930        use $crate::rayon::scope;
931            scope(|s| {
932                $(
933                    if <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::ACTIVE {
934                        let arena_ref = &$self_ident.[<$entity:snake>];
935                        s.spawn(|_| {
936                            <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::pv_if_applicable(
937                                arena_ref,
938                                &$handler_ident,
939                            );
940                        });
941                    }
942                )*
943            });
944        }
945    };
946
947    (@pvk_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
948        $crate::paste::paste! {
949        use $crate::rayon::scope;
950            scope(|s| {
951                $(
952                    if <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::ACTIVE {
953                        let arena_ref = &$self_ident.[<$entity:snake>];
954                        s.spawn(|_| {
955                            <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::pvk_if_applicable(
956                                arena_ref,
957                                &$handler_ident,
958                            );
959                        });
960                    }
961                )*
962            });
963        }
964    };
965
966    (@pvm_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
967        $crate::paste::paste! {
968            use $crate::rayon::scope;
969            scope(|s| {
970                $(
971                    if <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::ACTIVE {
972                        s.spawn(|_| {
973                            <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::pvm_if_applicable(
974                                &mut $self_ident.[<$entity:snake>],
975                                &$handler_ident,
976                            );
977                        });
978                    }
979                )*
980            });
981        }
982    };
983
984    (@pvkm_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
985        $crate::paste::paste! {
986            use $crate::rayon::scope;
987            scope(|s| {
988                $(
989                    if <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::ACTIVE {
990                        s.spawn(|_| {
991                            <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::pvkm_if_applicable(
992                                &mut $self_ident.[<$entity:snake>],
993                                &$handler_ident,
994                            );
995                        });
996                    }
997                )*
998            });
999        }
1000    };
1001
1002    (@pr_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $predicate_ident:ident $default:ident) => {
1003        $crate::paste::paste! {
1004            use $crate::rayon::scope;
1005            scope(|s| {
1006                $(
1007                    if <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::ACTIVE {
1008                        s.spawn(|_| {
1009                            <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::pr_if_applicable::<_>(
1010                                &mut $self_ident.[<$entity:snake>],
1011                                &$predicate_ident,
1012                            );
1013                        });
1014                    } else {
1015                        if !$default {
1016                            $self_ident.[<$entity:snake>].clear();
1017                        }
1018                    }
1019                )*
1020            });
1021        }
1022    };
1023
1024    (@pd_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
1025        $crate::paste::paste! {
1026            let len = $self_ident.[<len_$trait_name:snake>]();
1027            // MaybeUninit required in case population of diff vec panics
1028            let mut out: Vec<std::mem::MaybeUninit<D>> = Vec::with_capacity(len);
1029            unsafe { out.set_len(len); }
1030            use $crate::rayon::scope;
1031            scope(|s| {
1032                let mut remaining: &mut [_] = &mut out[..];
1033                $(
1034                    if <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::ACTIVE {
1035                        let arena_len = <() as [<$struct_name VisitIf $trait_name>]<$entity>>::len_if_applicable(
1036                            & $self_ident.[<$entity:snake>],
1037                        );
1038
1039                        let (arena_slice, rest) = remaining.split_at_mut(arena_len);
1040                        remaining = rest;
1041                        let arena_ref = &$self_ident.[<$entity:snake>];
1042                        let handler_ref = &$handler_ident;
1043                        s.spawn(move |_| {
1044                            <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::pd_if_applicable(
1045                                arena_ref,
1046                                handler_ref,
1047                                arena_slice,
1048                            );
1049                        });
1050                    }
1051                )*
1052            });
1053
1054            return unsafe { // convert MaybeUninit<Vec> to normal Vec
1055                let ptr = out.as_mut_ptr() as *mut D;
1056                let len = out.len();
1057                let cap = out.capacity();
1058                ::std::mem::forget(out);
1059                ::std::vec::Vec::from_raw_parts(ptr, len, cap)
1060            };
1061        }
1062    };
1063
1064    (@pdm_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $handler_ident:ident) => {
1065        $crate::paste::paste! {
1066            let len = $self_ident.[<len_$trait_name:snake>]();
1067            // MaybeUninit required in case population of diff vec panics
1068            let mut out: Vec<std::mem::MaybeUninit<D>> = Vec::with_capacity(len);
1069            unsafe { out.set_len(len); }
1070            use $crate::rayon::scope;
1071            scope(|s| {
1072                let mut remaining: &mut [_] = &mut out[..];
1073                $(
1074                    if <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::ACTIVE {
1075                        let arena_len = <() as [<$struct_name VisitIf $trait_name>]<$entity>>::len_if_applicable(
1076                            & $self_ident.[<$entity:snake>],
1077                        );
1078
1079                        let (arena_slice, rest) = remaining.split_at_mut(arena_len);
1080                        remaining = rest;
1081                        let arena_ref = &mut $self_ident.[<$entity:snake>];
1082                        let handler_ref = &$handler_ident;
1083                        s.spawn(move |_| {
1084                            <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::pdm_if_applicable(
1085                                arena_ref,
1086                                handler_ref,
1087                                arena_slice,
1088                            );
1089                        });
1090                    }
1091                )*
1092            });
1093
1094            return unsafe { // convert MaybeUninit<Vec> to normal Vec
1095                let ptr = out.as_mut_ptr() as *mut D;
1096                let len = out.len();
1097                let cap = out.capacity();
1098                ::std::mem::forget(out);
1099                ::std::vec::Vec::from_raw_parts(ptr, len, cap)
1100            };
1101        }
1102    };
1103
1104    (@pda_use_entity_tuple $struct_name:ident $trait_name:ident ($( $entity:ty ),*) $self_ident:ident $diff_ident:ident $handler_ident:ident) => {
1105    $crate::paste::paste! {
1106        use $crate::rayon::scope;
1107        scope(|s| {
1108            let mut remaining: &[_] = &$diff_ident[..];
1109            $(
1110                if <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::ACTIVE {
1111                    let arena_len = <() as [<$struct_name VisitIf $trait_name>]<$entity>>::len_if_applicable(
1112                        & $self_ident.[<$entity:snake>],
1113                    );
1114
1115                    let (arena_slice, rest) = remaining.split_at(arena_len);
1116                    remaining = rest;
1117                    let arena_ref = &mut $self_ident.[<$entity:snake>];
1118                    let handler_ref = &$handler_ident;
1119
1120                    s.spawn(move |_| {
1121                        <() as [<$struct_name ParVisitIf $trait_name>]<$entity>>::pda_if_applicable(
1122                            arena_ref,
1123                            handler_ref,
1124                            arena_slice,
1125                        );
1126                    });
1127                }
1128            )*
1129        });
1130    }
1131};
1132}
1133
1134#[macro_export]
1135#[cfg(not(feature = "debug"))]
1136macro_rules! __world_define_struct {
1137    ($struct_name:ident, $( $entity:ty ),*) => {
1138        $crate::paste::paste! {
1139            #[derive(Default)]
1140            #[allow(private_interfaces)] // member is pub even if underlying type isn't
1141            pub struct $struct_name {
1142                $(
1143                    pub [<$entity:snake>]: $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, $entity>,
1144                )*
1145            }
1146        }
1147    };
1148}
1149
1150#[macro_export]
1151#[cfg(feature = "debug")]
1152macro_rules! __world_define_struct {
1153    ($struct_name:ident, $( $entity:ty ),*) => {
1154        $crate::paste::paste! {
1155            #[derive(Default, Debug)]
1156            #[allow(private_interfaces)] // member is pub even if underlying type isn't
1157            pub struct $struct_name {
1158                $(
1159                    pub [<$entity:snake>]: $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, $entity>,
1160                )*
1161            }
1162        }
1163    };
1164}
1165
1166#[macro_export]
1167#[cfg(not(feature = "serde"))]
1168macro_rules! __world_serde_support {
1169    ($struct_name:ident $( $entity:ty ),*) => {};
1170}
1171
1172#[macro_export]
1173#[cfg(feature = "serde")]
1174macro_rules! __world_serde_support {
1175    ($struct_name:ident $( $entity:ty ),*) => {
1176        $crate::paste::paste! {
1177
1178impl $crate::serde::Serialize for [<$struct_name ArenaID>] {
1179    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1180    where
1181        S: $crate::serde::Serializer,
1182    {
1183        let s = match self.0 {
1184            $(
1185                i if i == $struct_name::arena_id::<$entity>().0 => stringify!($entity),
1186            )*
1187            // impossible! could be a panic here instead
1188            _ => return Err($crate::serde::ser::Error::custom(format!("Unknown ArenaID {}", self.0))),
1189        };
1190        serializer.serialize_str(s)
1191    }
1192}
1193
1194impl<'de> $crate::serde::Deserialize<'de> for [<$struct_name ArenaID>] {
1195    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1196    where
1197        D: $crate::serde::Deserializer<'de>,
1198    {
1199        let s = String::deserialize(deserializer)?;
1200        let id = match s.as_str() {
1201            $(
1202                stringify!($entity) => $struct_name::arena_id::<$entity>().0,
1203            )*
1204            // possible! suppose a different world loads it in, and there isn't that type.
1205            _ => return Err($crate::serde::de::Error::custom(format!("Unknown ArenaID string {}", s))),
1206        };
1207        Ok([<$struct_name ArenaID>](id))
1208    }
1209}
1210
1211impl $crate::serde::ser::Serialize for $struct_name {
1212    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1213    where
1214        S: $crate::serde::ser::Serializer,
1215    {
1216        use $crate::SerdeArena;
1217        use $crate::serde::ser::SerializeStruct;
1218
1219        let field_count = 0 $( + if <$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, $entity> as $crate::SerdeArena<'static>>::ACTIVE { 1 } else { 0 } )*;
1220        let mut state = serializer.serialize_struct(
1221            stringify!($struct_name),
1222            field_count
1223        )?;
1224        $(
1225            self.[<$entity:snake>].serialize_arena(stringify!($entity), &mut state)?;
1226        )*
1227        state.end()
1228    }
1229}
1230
1231// build list of serde members in world
1232static [<$struct_name:upper _DESERIALIZE_FIELDS>]: &'static [&'static str] = &{
1233    const TMP: [Option<&'static str>; { 0 $(+ { let _ = stringify!($entity); 1 })* }] = [
1234        $(
1235            if <$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, $entity>
1236                as $crate::SerdeArena<'static>>::ACTIVE {
1237                Some(stringify!($entity))
1238            } else {
1239                None
1240            }
1241        ),*
1242    ];
1243
1244    const COUNT: usize = 0 $(+ if (<$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, $entity>
1245        as $crate::SerdeArena<'static>>::ACTIVE) {1} else {0})*;
1246
1247    let mut arr: [&'static str; COUNT] = [""; COUNT];
1248    let mut j = 0;
1249    let mut k = 0;
1250    while j < TMP.len() {
1251        if let Some(s) = TMP[j] {
1252            arr[k] = s;
1253            k += 1;
1254        }
1255        j += 1;
1256    }
1257
1258    arr
1259};
1260
1261impl<'de> $crate::serde::Deserialize<'de> for $struct_name {
1262    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1263    where
1264        D: $crate::serde::Deserializer<'de>,
1265    {
1266        use $crate::serde::de::{MapAccess, SeqAccess, Visitor, Error};
1267        use std::fmt;
1268
1269        struct WorldVisitor;
1270
1271        impl<'de> Visitor<'de> for WorldVisitor {
1272            type Value = $struct_name;
1273
1274            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
1275                write!(f, "struct {}", stringify!($struct_name))
1276            }
1277
1278            // JSON-style: map fields
1279            fn visit_map<V>(self, mut map: V) -> Result<$struct_name, V::Error>
1280            where
1281                V: MapAccess<'de>,
1282            {
1283                let mut world = $struct_name::default();
1284
1285                while let Some(key) = map.next_key::<String>()? {
1286                    match key.as_str() {
1287                        $(
1288                            stringify!($entity) => {
1289                                world.[<$entity:snake>] =
1290                                    <$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, $entity> as $crate::SerdeArena<'de>>::deserialize_arena(&mut map)?;
1291                            }
1292                        )*
1293                        other => {
1294                            return Err(V::Error::custom(format!(
1295                                "Unknown field '{}' for {}",
1296                                other,
1297                                stringify!($struct_name)
1298                            )));
1299                        }
1300                    }
1301                }
1302
1303                Ok(world)
1304            }
1305
1306            // Bincode-style: sequence fields.
1307            // WARNING! Requires stated entities not changing order
1308            fn visit_seq<V>(self, mut seq: V) -> Result<$struct_name, V::Error>
1309            where
1310                V: SeqAccess<'de>,
1311            {
1312               Ok($struct_name {
1313                    $(
1314                        [<$entity:snake>]: <$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, $entity> as $crate::SerdeArena<'de>>::from_seq(&mut seq, stringify!($entity))?,
1315                    )*
1316                })
1317            }
1318        }
1319
1320        // Choose entry point depending on deserializer type
1321        //
1322        // JSON/CBOR: calls `deserialize_struct` -> `visit_map`
1323        // Bincode: must call `deserialize_struct` directly (sequence)
1324        deserializer.deserialize_struct(
1325            stringify!($struct_name),
1326            &[<$struct_name:upper _DESERIALIZE_FIELDS>],
1327            WorldVisitor,
1328        )
1329    }
1330}
1331        }
1332    };
1333}
1334
1335#[macro_export]
1336macro_rules! world {
1337    // main macro form: define struct + traits + impl
1338    (
1339        // the name of the struct being defined
1340        $struct_name:ident, // the types of entities which can exist in the world
1341        $( $entity:ty ),* $(,)? // optional trailing comma
1342        ;// semi colon separator between lists
1343        // the traits which are query-able over all types in the world
1344        $( $trait_name:ident ),* $(,)? // optional trailing comma
1345    ) => {
1346        $crate::paste::paste! {
1347
1348/// the world is composed of arenas. this selects which arena.
1349///
1350/// unlike TypeID, this is stable across rust versions. It serializes to the
1351/// name of the entity's type.
1352#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
1353pub struct [<$struct_name ArenaID>](usize);
1354
1355$crate::__world_define_struct!($struct_name, $($entity),*);
1356
1357$(
1358    trait [<$struct_name VisitIf $trait_name>]<T> {
1359        fn v_if_applicable<F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: F)
1360        where
1361            F: FnMut(&dyn $trait_name);
1362
1363        fn mv_if_applicable<F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: F)
1364        where
1365            F: FnMut(&mut dyn $trait_name);
1366
1367        fn vk_if_applicable<F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: F)
1368        where
1369            F: FnMut(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &dyn $trait_name);
1370
1371        fn vkm_if_applicable<F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: F)
1372        where
1373            F: FnMut(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &mut dyn $trait_name);
1374
1375        fn r_if_applicable<P>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, predicate: P)
1376        where
1377            P: FnMut(&mut dyn $trait_name) -> bool;
1378
1379        fn d_if_applicable<D, F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: F, out: &mut [std::mem::MaybeUninit<D>])
1380        where
1381            F: FnMut(&dyn $trait_name) -> D;
1382
1383        fn dm_if_applicable<D, F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: F, out: &mut [std::mem::MaybeUninit<D>])
1384        where
1385            F: FnMut(&mut dyn $trait_name) -> D;
1386        
1387        fn da_if_applicable<D, F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, handler: F, i: &[D])
1388        where
1389            F: FnMut(&mut dyn $trait_name, &D);
1390
1391        fn clear_if_applicable(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>);
1392
1393        fn len_if_applicable(arena: & $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>) -> usize;
1394
1395        const ACTIVE: bool;
1396    }
1397
1398    // no-op for types not implementing the trait
1399    impl<T> [<$struct_name VisitIf $trait_name>]<T> for () {
1400        default fn v_if_applicable<F>(_arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: F)
1401        where F: FnMut(&dyn $trait_name) {}
1402
1403        default fn mv_if_applicable<F>(_arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: F)
1404        where F: FnMut(&mut dyn $trait_name) {}
1405
1406        default fn vk_if_applicable<F>(_arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: F)
1407        where F: FnMut(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &dyn $trait_name) {}
1408
1409        default fn vkm_if_applicable<F>(_arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: F)
1410        where F: FnMut(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &mut dyn $trait_name) {}
1411
1412        default fn r_if_applicable<P>(_arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _predicate: P)
1413        where P: FnMut(&mut dyn $trait_name) -> bool {}
1414
1415        default fn d_if_applicable<D, F>(_arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: F, _out: &mut [std::mem::MaybeUninit<D>])
1416        where
1417            F: FnMut(&dyn $trait_name) -> D {}
1418
1419        default fn dm_if_applicable<D, F>(_arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: F, _out: &mut [std::mem::MaybeUninit<D>])
1420        where
1421            F: FnMut(&mut dyn $trait_name) -> D {}
1422
1423        default fn da_if_applicable<D, F>(_arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, _handler: F, _i: &[D])
1424        where
1425            F: FnMut(&mut dyn $trait_name, &D) {}
1426
1427        default fn clear_if_applicable(_arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>) {}
1428
1429        default fn len_if_applicable(_arena: & $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>) -> usize { 0 }
1430
1431        default const ACTIVE: bool = false;
1432    }
1433
1434    impl<T: $trait_name> [<$struct_name VisitIf $trait_name>]<T> for () {
1435        fn v_if_applicable<F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, mut handler: F)
1436        where F: FnMut(&dyn $trait_name)
1437        {
1438            arena
1439                .values_as_slice()
1440                .iter()
1441                .for_each(|entity| handler(entity));
1442        }
1443
1444        fn mv_if_applicable<F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, mut handler: F)
1445        where F: FnMut(&mut dyn $trait_name)
1446        {
1447            arena
1448                .values_as_mut_slice()
1449                .iter_mut()
1450                .for_each(|entity| handler(entity));
1451        }
1452
1453        fn r_if_applicable<P>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, mut predicate: P)
1454        where P: FnMut(&mut dyn $trait_name) -> bool
1455        {
1456            arena.retain(|_, entity| predicate(entity));
1457        }
1458
1459        fn d_if_applicable<D, F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, mut handler: F, out: &mut [std::mem::MaybeUninit<D>])
1460        where
1461            F: FnMut(&dyn $trait_name) -> D {
1462                for (e, out_slot) in arena.values_as_slice().iter().zip(out.iter_mut()) {
1463                    *out_slot = std::mem::MaybeUninit::new(handler(e));
1464                }
1465            }
1466
1467        fn dm_if_applicable<D, F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, mut handler: F, out: &mut [std::mem::MaybeUninit<D>])
1468        where
1469            F: FnMut(&mut dyn $trait_name) -> D {
1470                for (e, out_slot) in arena.values_as_mut_slice().iter_mut().zip(out.iter_mut()) {
1471                    *out_slot = std::mem::MaybeUninit::new(handler(e));
1472                }
1473            }
1474        
1475        fn da_if_applicable<D, F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, mut handler: F, i: &[D])
1476        where
1477            F: FnMut(&mut dyn $trait_name, &D) {
1478                for (e, in_value) in arena.values_as_mut_slice().iter_mut().zip(i.iter()) {
1479                    handler(e, in_value);
1480                }
1481            }
1482
1483        fn vk_if_applicable<F>(arena: &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, mut handler: F)
1484        where F: FnMut(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &dyn $trait_name)
1485        {
1486            let keys = arena.keys_as_slice();
1487            let values = arena.values_as_slice();
1488            keys.iter()
1489                .zip(values.iter())
1490                .for_each(|(k, v)| handler(($struct_name::arena_id::<T>(), *k), v));
1491        }
1492
1493        fn vkm_if_applicable<F>(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>, mut handler: F)
1494        where F: FnMut(([<$struct_name ArenaID>], $crate::slotmap::DefaultKey), &mut dyn $trait_name)
1495        {
1496            let (keys, values) = arena.keys_values_as_mut_slices();
1497            keys.iter()
1498                .zip(values.iter_mut())
1499                .for_each(|(k, v)| handler(($struct_name::arena_id::<T>(), *k), v));
1500        }
1501
1502        fn clear_if_applicable(arena: &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>) {
1503            arena.clear();
1504        }
1505
1506        fn len_if_applicable(arena: & $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T>) -> usize {
1507            arena.len()
1508        }
1509
1510        default const ACTIVE: bool = true;
1511    }
1512
1513)*
1514
1515impl $struct_name {
1516    $crate::__world_define_visitors!(@pass_entity_tuple $struct_name $($trait_name),* @ ($($entity),*));
1517
1518    /// access underlying arena for type T
1519    /// ```
1520    /// world.arena::<Enemy>().len()
1521    /// ```
1522    #[allow(unused)]
1523    pub fn arena<T>(&self) -> &$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T> {
1524        use $crate::ArenaCast;
1525        $(
1526            if <T as $crate::IsType<$entity>>::VALUE {
1527                return <$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, $entity> as ArenaCast<T>>::cast(&self.[<$entity:snake>]);
1528            }
1529        )* // checked compiler explorer to be sure - all of this is constant folded with optimizations enabled
1530        panic!("In call to {}::arena::<{}>(), {} not registered", stringify!($struct_name), std::any::type_name::<T>(), std::any::type_name::<T>());
1531    }
1532
1533    /// mutably access underlying arena for type T
1534    /// ```
1535    /// world.arena::<Enemy>().len()
1536    /// ```
1537    #[allow(unused)]
1538    pub fn arena_mut<T>(&mut self) -> &mut $crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, T> {
1539        use $crate::ArenaCast;
1540        $(
1541            if <T as $crate::IsType<$entity>>::VALUE {
1542                return <$crate::slotmap::DenseSlotMap<$crate::slotmap::DefaultKey, $entity> as ArenaCast<T>>::cast_mut(&mut self.[<$entity:snake>]);
1543            }
1544        )*
1545        panic!("In call to {}::arena_mut::<{}>(), {} not registered", stringify!($struct_name), std::any::type_name::<T>(), std::any::type_name::<T>());
1546    }
1547
1548    /// get the ArenaID for type T
1549    ///
1550    /// this is used as part of the type erased api
1551    /// ```
1552    /// let arena_id = MyWorld::arena_id::<Enemy>();
1553    /// let arena = world.any_arena(arena_id);
1554    /// ```
1555    #[allow(unused)]
1556    pub fn arena_id<T>() -> [<$struct_name ArenaID>] {
1557        let mut i = 0usize;
1558        $(
1559            if <T as $crate::IsType<$entity>>::VALUE {
1560                return [<$struct_name ArenaID>](i);
1561            }
1562            i += 1;
1563        )*
1564        panic!("In call to {}::arena_id::<{}>(), {} not registered", stringify!($struct_name), std::any::type_name::<T>(), std::any::type_name::<T>());
1565    }
1566
1567    /// type erased API. get arena by ArenaID, returning trait object
1568    #[allow(unused)]
1569    pub fn any_arena(&self, which: [<$struct_name ArenaID>]) -> &dyn $crate::ErasedArena {
1570        match which.0 {
1571            $(
1572                i if i == Self::arena_id::<$entity>().0 => &self.[<$entity:snake>] as &dyn $crate::ErasedArena,
1573            )*
1574            _ => panic!("No arena for type id {}", which.0),
1575        }
1576    }
1577
1578    /// type erased API. get mutable arena by ArenaID, returning trait object
1579    #[allow(unused)]
1580    pub fn any_arena_mut(&mut self, which: [<$struct_name ArenaID>]) -> &mut dyn $crate::ErasedArena {
1581        match which.0 {
1582            $(
1583                i if i == Self::arena_id::<$entity>().0 => &mut self.[<$entity:snake>] as &mut dyn $crate::ErasedArena,
1584            )*
1585            _ => panic!("No mutable arena for type id {}", which.0),
1586        }
1587    }
1588
1589    #[allow(unused)]
1590    pub fn clear(&mut self) {
1591        $(
1592            self.[<$entity:snake>].clear();
1593        )*
1594    }
1595
1596    #[allow(unused)]
1597    pub fn len(&self) -> usize {
1598        0 $( + self.[<$entity:snake>].len() )*
1599    }
1600}
1601
1602$crate::__world_serde_support!($struct_name $($entity),*);
1603
1604$crate::__world_define_rayon_trait_helpers!($struct_name $($trait_name),*);
1605
1606        }
1607    };
1608}
1609
1610// ---------------------------------------------------------------
1611// Tests
1612// ---------------------------------------------------------------
1613#[cfg(test)]
1614mod tests {
1615    // Entities used in tests
1616    #[derive(Debug)]
1617    #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1618    struct Player {
1619        id: i32,
1620    }
1621
1622    #[derive(Debug)]
1623    #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1624    struct Enemy {
1625        hp: i32,
1626    }
1627
1628    // A third entity that implements no traits (for retain default path tests)
1629    #[derive(Debug)]
1630    #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1631    struct NonTrait {
1632        #[allow(unused)]
1633        val: i32,
1634    }
1635
1636    pub trait TestTrait {
1637        fn metric(&self) -> i32;
1638        fn add(&mut self, delta: i32);
1639    }
1640    impl TestTrait for Player {
1641        fn metric(&self) -> i32 {
1642            self.id
1643        }
1644        fn add(&mut self, delta: i32) {
1645            self.id += delta;
1646        }
1647    }
1648    impl TestTrait for Enemy {
1649        fn metric(&self) -> i32 {
1650            self.hp
1651        }
1652        fn add(&mut self, delta: i32) {
1653            self.hp += delta;
1654        }
1655    }
1656
1657    // Second trait, implemented only by Player
1658    pub trait SecondTestTrait {
1659        fn touch(&mut self);
1660    }
1661    impl SecondTestTrait for Player {
1662        fn touch(&mut self) {
1663            self.id += 1000;
1664        }
1665    }
1666
1667    // Primary world used in most tests
1668    world!(MyWorld, Enemy, Player; TestTrait, SecondTestTrait);
1669
1670    // Extended world including a non-trait entity to test default retain/clear
1671    world!(AnotherWorld, Enemy, NonTrait, Player; TestTrait, SecondTestTrait);
1672
1673    // doc: these tests are AI generated
1674
1675    #[test]
1676    fn basic_arena_access_and_len() {
1677        let mut world = MyWorld::default();
1678
1679        let p0 = world.player.insert(Player { id: 1 });
1680        let e0 = world.arena_mut::<Enemy>().insert(Enemy { hp: 10 });
1681        let _e1 = world.arena_mut::<Enemy>().insert(Enemy { hp: 9 });
1682
1683        assert_eq!(world.len(), 3);
1684
1685        // typed arena accessors
1686        assert_eq!(world.arena::<Enemy>().len(), 2);
1687        assert_eq!(world.arena::<Player>().len(), 1);
1688
1689        // arena_id order matches declaration order: Enemy then Player
1690        assert_eq!(MyWorld::arena_id::<Enemy>().0, 0);
1691        assert_eq!(MyWorld::arena_id::<Player>().0, 1);
1692
1693        // type-erased access
1694        let player_id = MyWorld::arena_id::<Player>();
1695        let enemy_id = MyWorld::arena_id::<Enemy>();
1696
1697        let p = world
1698            .any_arena(player_id)
1699            .get(p0)
1700            .unwrap()
1701            .downcast_ref::<Player>()
1702            .unwrap();
1703        assert_eq!(p.id, 1);
1704
1705        let e = world
1706            .any_arena(enemy_id)
1707            .get(e0)
1708            .unwrap()
1709            .downcast_ref::<Enemy>()
1710            .unwrap();
1711        assert_eq!(e.hp, 10);
1712
1713        // get_mut
1714        {
1715            let p_mut = world
1716                .any_arena_mut(player_id)
1717                .get_mut(p0)
1718                .unwrap()
1719                .downcast_mut::<Player>()
1720                .unwrap();
1721            p_mut.id += 5;
1722        }
1723        assert_eq!(world.player.get(p0).unwrap().id, 6);
1724
1725        // unsafe unchecked getters
1726        unsafe {
1727            let p_un = world
1728                .any_arena(player_id)
1729                .get_unchecked(p0)
1730                .downcast_ref::<Player>()
1731                .unwrap();
1732            assert_eq!(p_un.id, 6);
1733            let e_unm = world
1734                .any_arena_mut(enemy_id)
1735                .get_unchecked_mut(e0)
1736                .downcast_mut::<Enemy>()
1737                .unwrap();
1738            e_unm.hp += 1;
1739        }
1740        assert_eq!(world.enemy.get(e0).unwrap().hp, 11);
1741
1742        // world clear
1743        world.clear();
1744        assert_eq!(world.len(), 0);
1745    }
1746
1747    #[test]
1748    fn visitors_immutable_mutable_and_lengths() {
1749        let mut world = MyWorld::default();
1750        world.player.insert(Player { id: 1 });
1751        world.player.insert(Player { id: 2 });
1752        world.enemy.insert(Enemy { hp: 10 });
1753        world.enemy.insert(Enemy { hp: 5 });
1754
1755        // total len of entities implementing TestTrait (both arenas)
1756        assert_eq!(world.len_test_trait(), 4);
1757
1758        // immutable visit (collect metrics)
1759        let mut metrics = Vec::new();
1760        world.visit_test_trait(|t| metrics.push(t.metric()));
1761        metrics.sort();
1762        assert_eq!(metrics, vec![1, 2, 5, 10]);
1763
1764        // mutable visit on SecondTestTrait (only Player implements it)
1765        world.visit_mut_second_test_trait(|t| t.touch());
1766        let ids: Vec<i32> = world.player.values().map(|p| p.id).collect();
1767        assert_eq!(ids, vec![1001, 1002]);
1768        // enemies remain unchanged
1769        let hps: Vec<i32> = world.enemy.values().map(|e| e.hp).collect();
1770        assert_eq!(hps, vec![10, 5]);
1771
1772        // clear only entities implementing TestTrait
1773        world.clear_test_trait();
1774        assert_eq!(world.len_test_trait(), 0);
1775        // both arenas implement TestTrait here, so both are cleared
1776        assert_eq!(world.len(), 0);
1777    }
1778
1779    #[test]
1780    fn retain_with_default_and_selective_clear() {
1781        let mut world = AnotherWorld::default();
1782
1783        // Fill all arenas
1784        let _ = world.enemy.insert(Enemy { hp: 10 });
1785        let _ = world.enemy.insert(Enemy { hp: 3 });
1786        let _ = world.non_trait.insert(NonTrait { val: 99 });
1787        let _ = world.player.insert(Player { id: 1 });
1788
1789        // Retain only TestTrait implementers with metric >= 5, DEFAULT=false
1790        // => Enemy{hp<5} removed; Player{id=1<5} removed; NonTrait cleared due to DEFAULT=false
1791        world.retain_with_default_test_trait::<false, _>(|t| t.metric() >= 5);
1792
1793        assert_eq!(world.enemy.len(), 1); // hp=10 survives
1794        assert_eq!(world.player.len(), 0);
1795        assert_eq!(world.non_trait.len(), 0);
1796
1797        // Now fill again and set DEFAULT=true: NonTrait is preserved.
1798        let _ = world.player.insert(Player { id: 7 });
1799        let _ = world.non_trait.insert(NonTrait { val: 42 });
1800        world.retain_with_default_test_trait::<true, _>(|t| t.metric() >= 5);
1801
1802        assert_eq!(world.enemy.len(), 1); // still hp=10
1803        assert_eq!(world.player.len(), 1); // id=7
1804        assert_eq!(world.non_trait.len(), 1); // preserved by DEFAULT=true
1805
1806        // clear only TestTrait implementers (NonTrait remains)
1807        world.clear_test_trait();
1808        assert_eq!(world.enemy.len(), 0);
1809        assert_eq!(world.player.len(), 0);
1810        assert_eq!(world.non_trait.len(), 1);
1811    }
1812
1813    #[test]
1814    fn diff_and_apply_roundtrip() {
1815        let mut world = MyWorld::default();
1816        world.player.insert(Player { id: 1 });
1817        world.enemy.insert(Enemy { hp: 2 });
1818        world.enemy.insert(Enemy { hp: 3 });
1819
1820        // Create a diff vector from metrics doubled
1821        let diff = world.diff_test_trait(|t| t.metric() * 2);
1822
1823        // Apply inverse operation: add(-diff/2) -> should zero all metrics
1824        world.diff_apply_test_trait(diff, |t, d| t.add(-d / 2));
1825
1826        // Verify all metrics are zero
1827        let mut all_zero = true;
1828        world.visit_test_trait(|t| {
1829            all_zero = all_zero && t.metric() == 0;
1830        });
1831        assert!(all_zero);
1832    }
1833
1834    #[cfg(feature = "rayon")]
1835    #[test]
1836    fn parallel_visitors_and_diff_apply() {
1837        use std::sync::atomic::{AtomicI64, Ordering};
1838        use std::sync::{Arc, Mutex};
1839
1840        let mut world = MyWorld::default();
1841        world.player.insert(Player { id: 1 });
1842        world.player.insert(Player { id: 2 });
1843        world.enemy.insert(Enemy { hp: 10 });
1844        world.enemy.insert(Enemy { hp: 5 });
1845
1846        // parallel immutable visit: sum metrics
1847        let sum = AtomicI64::new(0);
1848        world.par_visit_test_trait(|t| {
1849            sum.fetch_add(t.metric() as i64, Ordering::Relaxed);
1850        });
1851        assert_eq!(sum.load(Ordering::Relaxed), 1 + 2 + 10 + 5);
1852
1853        // parallel mutable visit (Players only)
1854        world.par_visit_mut_second_test_trait(|t| t.touch());
1855        let ids: Vec<i32> = world.player.values().map(|p| p.id).collect();
1856        assert_eq!(ids, vec![1001, 1002]);
1857
1858        // parallel diff and apply
1859        let diff = world.par_diff_test_trait(|t| t.metric() * 3);
1860        // Use handler that resets values to zero via add(-metric)
1861        world.par_diff_apply_test_trait(diff, |t, d| t.add(-d / 3));
1862
1863        // Verify all metrics are zero in parallel
1864        let results = Arc::new(Mutex::new(Vec::new()));
1865        world.par_visit_test_trait(|t| results.lock().unwrap().push(t.metric()));
1866        let mut vals = results.lock().unwrap().clone();
1867        vals.sort();
1868        assert_eq!(vals, vec![0, 0, 0, 0]);
1869
1870        // parallel retain across arenas (note: per-element retain isn't parallel due to DenseSlotMap)
1871        world.par_retain_with_default_test_trait::<true, _>(|t| t.metric() == 0);
1872        assert_eq!(world.len_test_trait(), 4);
1873    }
1874
1875    #[cfg(all(feature = "serde"))]
1876    #[test]
1877    fn serde_roundtrips_json_and_bincode() {
1878        // Only types that derive Serialize/Deserialize are included by SerdeArena
1879        let mut world = MyWorld::default();
1880        world.player.insert(Player { id: 7 });
1881        world.enemy.insert(Enemy { hp: 42 });
1882
1883        // JSON round-trip
1884        let serialized = serde_json::to_string(&world).unwrap();
1885        let de_json: MyWorld = serde_json::from_str(&serialized).unwrap();
1886        // spot-check values
1887        assert_eq!(de_json.player.len(), 1);
1888        assert_eq!(de_json.enemy.len(), 1);
1889        assert_eq!(de_json.player.values().next().unwrap().id, 7);
1890        assert_eq!(de_json.enemy.values().next().unwrap().hp, 42);
1891
1892        // Bincode round-trip (using serde module)
1893        let serialized: Vec<u8> =
1894            bincode::serde::encode_to_vec(&world, bincode::config::standard()).unwrap();
1895        let (de_bin, _): (MyWorld, usize) =
1896            bincode::serde::decode_from_slice(&serialized, bincode::config::standard()).unwrap();
1897
1898        assert_eq!(de_bin.player.len(), 1);
1899        assert_eq!(de_bin.enemy.len(), 1);
1900        assert_eq!(de_bin.player.values().next().unwrap().id, 7);
1901        assert_eq!(de_bin.enemy.values().next().unwrap().hp, 42);
1902    }
1903
1904    #[test]
1905    fn empty_world_behavior() {
1906        let mut world = MyWorld::default();
1907
1908        // empty world has zero length
1909        assert_eq!(world.len(), 0);
1910        assert_eq!(world.len_test_trait(), 0);
1911        assert_eq!(world.len_second_test_trait(), 0);
1912
1913        // visitors on empty world do nothing
1914        let mut visited = false;
1915        world.visit_test_trait(|_| visited = true);
1916        assert!(!visited);
1917
1918        // diff on empty world returns empty vec
1919        let diff = world.diff_test_trait(|t| t.metric());
1920        assert_eq!(diff.len(), 0);
1921    }
1922
1923    #[test]
1924    fn retain_removes_all_when_predicate_always_false() {
1925        let mut world = MyWorld::default();
1926        world.player.insert(Player { id: 1 });
1927        world.player.insert(Player { id: 2 });
1928        world.enemy.insert(Enemy { hp: 10 });
1929
1930        // retain nothing (predicate always false)
1931        world.retain_test_trait(|_| false);
1932
1933        assert_eq!(world.len_test_trait(), 0);
1934        assert_eq!(world.len(), 0);
1935    }
1936
1937    #[test]
1938    fn retain_keeps_all_when_predicate_always_true() {
1939        let mut world = MyWorld::default();
1940        world.player.insert(Player { id: 1 });
1941        world.player.insert(Player { id: 2 });
1942        world.enemy.insert(Enemy { hp: 10 });
1943
1944        let initial_len = world.len_test_trait();
1945
1946        // retain all (predicate always true)
1947        world.retain_test_trait(|_| true);
1948
1949        assert_eq!(world.len_test_trait(), initial_len);
1950    }
1951
1952    #[test]
1953    fn diff_apply_maintains_element_order() {
1954        let mut world = MyWorld::default();
1955
1956        // Insert in specific order
1957        let _e1 = world.enemy.insert(Enemy { hp: 10 });
1958        let _e2 = world.enemy.insert(Enemy { hp: 20 });
1959        let _p1 = world.player.insert(Player { id: 5 });
1960
1961        // Create diff that captures original metrics
1962        let original = world.diff_test_trait(|t| t.metric());
1963
1964        // Modify values
1965        world.visit_mut_test_trait(|t| t.add(100));
1966
1967        // Apply diff to restore (add back the negative delta)
1968        let current = world.diff_test_trait(|t| t.metric());
1969        let restore_diff: Vec<i32> = original
1970            .iter()
1971            .zip(current.iter())
1972            .map(|(orig, curr)| orig - curr)
1973            .collect();
1974        world.diff_apply_test_trait(restore_diff, |t, delta| t.add(*delta));
1975
1976        // Verify restoration
1977        let mut final_metrics = Vec::new();
1978        world.visit_test_trait(|t| final_metrics.push(t.metric()));
1979        assert_eq!(final_metrics, vec![10, 20, 5]);
1980    }
1981
1982    #[test]
1983    fn visit_key_provides_correct_keys_and_arena_ids() {
1984        let mut world = MyWorld::default();
1985        
1986        let e1 = world.enemy.insert(Enemy { hp: 10 });
1987        let e2 = world.enemy.insert(Enemy { hp: 20 });
1988        let p1 = world.player.insert(Player { id: 5 });
1989        
1990        let enemy_arena_id = MyWorld::arena_id::<Enemy>();
1991        let player_arena_id = MyWorld::arena_id::<Player>();
1992        
1993        // Collect (ArenaID, Key) pairs via visit_key
1994        let mut collected = Vec::new();
1995        world.visit_key_test_trait(|(arena_id, key), _entity| {
1996            collected.push((arena_id, key));
1997        });
1998        
1999        // Should have all 3 keys with correct arena IDs
2000        assert_eq!(collected.len(), 3);
2001        
2002        // Verify Arena IDs and keys match
2003        assert!(collected.contains(&(enemy_arena_id, e1)));
2004        assert!(collected.contains(&(enemy_arena_id, e2)));
2005        assert!(collected.contains(&(player_arena_id, p1)));
2006    }
2007
2008    #[test]
2009    fn visit_key_entity_association_with_arena_id() {
2010        let mut world = MyWorld::default();
2011        
2012        let e1 = world.enemy.insert(Enemy { hp: 100 });
2013        let e2 = world.enemy.insert(Enemy { hp: 200 });
2014        let p1 = world.player.insert(Player { id: 50 });
2015        
2016        let enemy_arena_id = MyWorld::arena_id::<Enemy>();
2017        let player_arena_id = MyWorld::arena_id::<Player>();
2018        
2019        // Verify ArenaID-key-entity triplets are correct
2020        world.visit_key_test_trait(|(arena_id, key), entity| {
2021            let metric = entity.metric();
2022            
2023            // Verify the ArenaID + key matches the entity's value
2024            if arena_id == enemy_arena_id && key == e1 {
2025                assert_eq!(metric, 100);
2026            } else if arena_id == enemy_arena_id && key == e2 {
2027                assert_eq!(metric, 200);
2028            } else if arena_id == player_arena_id && key == p1 {
2029                assert_eq!(metric, 50);
2030            } else {
2031                panic!("Unexpected ArenaID/key combination");
2032            }
2033        });
2034    }
2035
2036    #[test]
2037    fn visit_key_mut_can_modify_entities_by_arena_id() {
2038        let mut world = MyWorld::default();
2039        
2040        let e1 = world.enemy.insert(Enemy { hp: 10 });
2041        let p1 = world.player.insert(Player { id: 5 });
2042        let p2 = world.player.insert(Player { id: 7 });
2043        
2044        let enemy_arena_id = MyWorld::arena_id::<Enemy>();
2045        let player_arena_id = MyWorld::arena_id::<Player>();
2046        
2047        // Modify entities based on their ArenaID + key
2048        world.visit_key_mut_test_trait(|(arena_id, key), entity| {
2049            if arena_id == enemy_arena_id && key == e1 {
2050                entity.add(90); // hp: 10 -> 100
2051            } else if arena_id == player_arena_id && key == p1 {
2052                entity.add(95); // id: 5 -> 100
2053            } else if arena_id == player_arena_id && key == p2 {
2054                entity.add(93); // id: 7 -> 100
2055            }
2056        });
2057        
2058        // Verify modifications
2059        assert_eq!(world.enemy.get(e1).unwrap().hp, 100);
2060        assert_eq!(world.player.get(p1).unwrap().id, 100);
2061        assert_eq!(world.player.get(p2).unwrap().id, 100);
2062    }
2063
2064    #[test]
2065    fn visit_key_ordering_with_arena_ids() {
2066        let mut world = MyWorld::default();
2067        
2068        // Insert in specific order
2069        let e1 = world.enemy.insert(Enemy { hp: 1 });
2070        let e2 = world.enemy.insert(Enemy { hp: 2 });
2071        let p1 = world.player.insert(Player { id: 3 });
2072        let p2 = world.player.insert(Player { id: 4 });
2073        
2074        let enemy_arena_id = MyWorld::arena_id::<Enemy>();
2075        let player_arena_id = MyWorld::arena_id::<Player>();
2076        
2077        // Collect in visitation order
2078        let mut arena_key_pairs = Vec::new();
2079        world.visit_key_test_trait(|(arena_id, key), _| {
2080            arena_key_pairs.push((arena_id, key));
2081        });
2082        
2083        // Should match: enemies first (in insertion order), then players
2084        assert_eq!(arena_key_pairs, vec![
2085            (enemy_arena_id, e1),
2086            (enemy_arena_id, e2),
2087            (player_arena_id, p1),
2088            (player_arena_id, p2),
2089        ]);
2090    }
2091
2092    #[test]
2093    fn visit_key_with_selective_trait_arena_ids() {
2094        let mut world = MyWorld::default();
2095        
2096        let _e1 = world.enemy.insert(Enemy { hp: 10 });
2097        let p1 = world.player.insert(Player { id: 5 });
2098        let p2 = world.player.insert(Player { id: 7 });
2099        
2100        let player_arena_id = MyWorld::arena_id::<Player>();
2101        
2102        // SecondTestTrait only implemented by Player
2103        let mut player_data = Vec::new();
2104        world.visit_key_second_test_trait(|(arena_id, key), _| {
2105            player_data.push((arena_id, key));
2106        });
2107        
2108        // Should only have player keys with player arena ID
2109        assert_eq!(player_data.len(), 2);
2110        assert!(player_data.contains(&(player_arena_id, p1)));
2111        assert!(player_data.contains(&(player_arena_id, p2)));
2112    }
2113
2114    #[test]
2115    fn visit_key_mut_selective_modification_by_arena_id() {
2116        let mut world = MyWorld::default();
2117        
2118        world.enemy.insert(Enemy { hp: 10 });
2119        world.enemy.insert(Enemy { hp: 20 });
2120        let p1 = world.player.insert(Player { id: 5 });
2121        let p2 = world.player.insert(Player { id: 7 });
2122        
2123        let player_arena_id = MyWorld::arena_id::<Player>();
2124        
2125        // Modify only players via SecondTestTrait, verifying ArenaID
2126        world.visit_key_mut_second_test_trait(|(arena_id, _key), entity| {
2127            assert_eq!(arena_id, player_arena_id);
2128            entity.touch(); // adds 1000 to id
2129        });
2130        
2131        // Verify only players were modified
2132        assert_eq!(world.player.get(p1).unwrap().id, 1005);
2133        assert_eq!(world.player.get(p2).unwrap().id, 1007);
2134        
2135        // Enemies unchanged
2136        let enemy_hps: Vec<i32> = world.enemy.values().map(|e| e.hp).collect();
2137        assert_eq!(enemy_hps, vec![10, 20]);
2138    }
2139
2140    #[test]
2141    fn visit_key_empty_world_no_arena_ids() {
2142        let world = MyWorld::default();
2143        
2144        let mut visited = false;
2145        world.visit_key_test_trait(|(_arena_id, _key), _entity| {
2146            visited = true;
2147        });
2148        
2149        assert!(!visited);
2150    }
2151
2152    #[cfg(feature = "rayon")]
2153    #[test]
2154    fn par_visit_key_mut_concurrent_modification_with_arena_ids() {
2155        use std::sync::atomic::{AtomicI32, Ordering};
2156        
2157        let mut world = MyWorld::default();
2158        
2159        let player_arena_id = MyWorld::arena_id::<Player>();
2160        
2161        // Insert many entities
2162        for i in 0..100 {
2163            world.player.insert(Player { id: i });
2164        }
2165        
2166        let modification_count = AtomicI32::new(0);
2167        
2168        // Modify all in parallel, verifying ArenaID
2169        world.par_visit_key_mut_test_trait(|(arena_id, _key), entity| {
2170            assert_eq!(arena_id, player_arena_id);
2171            entity.add(1000);
2172            modification_count.fetch_add(1, Ordering::Relaxed);
2173        });
2174        
2175        // Verify all were modified
2176        assert_eq!(modification_count.load(Ordering::Relaxed), 100);
2177        
2178        // Verify values
2179        for player in world.player.values() {
2180            assert!(player.id >= 1000 && player.id < 1100);
2181        }
2182    }
2183
2184    #[cfg(feature = "rayon")]
2185    #[test]
2186    fn par_visit_key_ordering_deterministic_with_arena_ids() {
2187        let mut world = MyWorld::default();
2188        
2189        let enemy_arena_id = MyWorld::arena_id::<Enemy>();
2190        let player_arena_id = MyWorld::arena_id::<Player>();
2191        
2192        // Insert many entities
2193        let mut expected_pairs = Vec::new();
2194        for i in 0..50 {
2195            expected_pairs.push((enemy_arena_id, world.enemy.insert(Enemy { hp: i })));
2196            expected_pairs.push((player_arena_id, world.player.insert(Player { id: i })));
2197        }
2198        
2199        // Collect in visitation order
2200        let mut seq_pairs = Vec::new();
2201        world.visit_key_test_trait(|(arena_id, key), _| {
2202            seq_pairs.push((arena_id, key));
2203        });
2204        
2205        // Collect pairs via parallel visit (multiple times to check consistency)
2206        for _ in 0..5 {
2207            let mut par_pairs = Vec::new();
2208            world.visit_key_test_trait(|(arena_id, key), _| {
2209                par_pairs.push((arena_id, key));
2210            });
2211            
2212            // Order should be deterministic and match sequential
2213            assert_eq!(par_pairs, seq_pairs);
2214        }
2215    }
2216
2217    #[test]
2218    fn visit_key_with_removal_during_iteration_arena_ids() {
2219        let mut world = MyWorld::default();
2220        
2221        let e1 = world.enemy.insert(Enemy { hp: 10 });
2222        let e2 = world.enemy.insert(Enemy { hp: 20 });
2223        let p1 = world.player.insert(Player { id: 5 });
2224        
2225        let enemy_arena_id = MyWorld::arena_id::<Enemy>();
2226        let player_arena_id = MyWorld::arena_id::<Player>();
2227        
2228        // Collect (ArenaID, key) pairs to remove
2229        let mut to_remove = Vec::new();
2230        world.visit_key_test_trait(|(arena_id, key), entity| {
2231            if entity.metric() > 10 {
2232                to_remove.push((arena_id, key));
2233            }
2234        });
2235        
2236        // Remove after iteration (not during)
2237        for (arena_id, key) in to_remove {
2238            if arena_id == enemy_arena_id {
2239                world.enemy.remove(key);
2240            } else if arena_id == player_arena_id {
2241                world.player.remove(key);
2242            }
2243        }
2244        
2245        // Verify correct entities remain
2246        assert!(world.enemy.get(e1).is_some()); // hp=10, not removed
2247        assert!(world.enemy.get(e2).is_none()); // hp=20, removed
2248        assert!(world.player.get(p1).is_some()); // id=5 < 10, not removed
2249    }
2250
2251    #[test]
2252    fn visit_key_mut_with_arena_id_dependent_logic() {
2253        let mut world = MyWorld::default();
2254        
2255        let e1 = world.enemy.insert(Enemy { hp: 10 });
2256        let e2 = world.enemy.insert(Enemy { hp: 20 });
2257        let p1 = world.player.insert(Player { id: 5 });
2258        
2259        let enemy_arena_id = MyWorld::arena_id::<Enemy>();
2260        let target_key = e2;
2261        
2262        // Modify only the targeted entity, verifying ArenaID
2263        world.visit_key_mut_test_trait(|(arena_id, key), entity| {
2264            if arena_id == enemy_arena_id && key == target_key {
2265                entity.add(1000);
2266            }
2267        });
2268        
2269        // Verify only e2 was modified
2270        assert_eq!(world.enemy.get(e1).unwrap().hp, 10);
2271        assert_eq!(world.enemy.get(e2).unwrap().hp, 1020);
2272        assert_eq!(world.player.get(p1).unwrap().id, 5);
2273    }
2274
2275    #[test]
2276    fn visit_key_distinguishes_same_key_different_arenas() {
2277        // Create world where we might get same key values in different arenas
2278        let mut world = MyWorld::default();
2279        
2280        // Clear and insert to potentially get same key values
2281        world.clear();
2282        
2283        let e_key = world.enemy.insert(Enemy { hp: 100 });
2284        let p_key = world.player.insert(Player { id: 200 });
2285        
2286        let enemy_arena_id = MyWorld::arena_id::<Enemy>();
2287        let player_arena_id = MyWorld::arena_id::<Player>();
2288        
2289        // Even if keys have same underlying value, ArenaID distinguishes them
2290        let mut visited = Vec::new();
2291        world.visit_key_test_trait(|(arena_id, key), entity| {
2292            visited.push((arena_id, key, entity.metric()));
2293        });
2294        
2295        // Should visit both entities with correct ArenaID
2296        assert!(visited.contains(&(enemy_arena_id, e_key, 100)));
2297        assert!(visited.contains(&(player_arena_id, p_key, 200)));
2298        assert_eq!(visited.len(), 2);
2299    }
2300
2301    #[cfg(feature = "rayon")]
2302    #[test]
2303    fn par_visit_key_correct_arena_ids_per_spawn() {
2304        use std::sync::{Arc, Mutex};
2305        
2306        let mut world = MyWorld::default();
2307        
2308        let enemy_arena_id = MyWorld::arena_id::<Enemy>();
2309        let player_arena_id = MyWorld::arena_id::<Player>();
2310        
2311        // Insert many entities
2312        for i in 0..100 {
2313            world.enemy.insert(Enemy { hp: i });
2314            world.player.insert(Player { id: i + 100 });
2315        }
2316        
2317        let collected = Arc::new(Mutex::new(Vec::new()));
2318        let collected_clone = Arc::clone(&collected);
2319        
2320        // Parallel visit collecting (ArenaID, metric) pairs
2321        world.par_visit_key_test_trait(move |(arena_id, _key), entity| {
2322            collected_clone.lock().unwrap().push((arena_id, entity.metric()));
2323        });
2324        
2325        let results = collected.lock().unwrap();
2326        
2327        // Verify all enemy entities have enemy_arena_id
2328        let enemy_results: Vec<_> = results.iter()
2329            .filter(|(aid, _)| *aid == enemy_arena_id)
2330            .map(|(_, m)| *m)
2331            .collect();
2332        assert_eq!(enemy_results.len(), 100);
2333        assert!(enemy_results.iter().all(|m| *m < 100));
2334        
2335        // Verify all player entities have player_arena_id  
2336        let player_results: Vec<_> = results.iter()
2337            .filter(|(aid, _)| *aid == player_arena_id)
2338            .map(|(_, m)| *m)
2339            .collect();
2340        assert_eq!(player_results.len(), 100);
2341        assert!(player_results.iter().all(|m| *m >= 100));
2342    }
2343}