Skip to main content

goud_engine/ecs/query/
fetch.rs

1//! Query fetch traits for the ECS.
2//!
3//! This module defines the foundational traits for the query system. Queries
4//! allow systems to access component data in a type-safe manner. The fetch
5//! traits define what can be queried and how data is retrieved.
6//!
7//! # Architecture
8//!
9//! The query system is built around two key traits:
10//!
11//! - [`WorldQuery`]: Defines what data a query fetches and how to access it
12//! - [`ReadOnlyWorldQuery`]: Marker trait for queries that don't mutate data
13//!
14//! # Query Item Lifetime
15//!
16//! The [`WorldQuery`] trait uses Generic Associated Types (GATs) for the `Item`
17//! type. This allows the fetched item to have a lifetime tied to the world
18//! borrow, enabling references to component data.
19//!
20//! # Example
21//!
22//! ```
23//! use goud_engine::ecs::{Component, Entity, World};
24//! use goud_engine::ecs::query::{WorldQuery, QueryState};
25//!
26//! #[derive(Debug, Clone, Copy)]
27//! struct Position { x: f32, y: f32 }
28//! impl Component for Position {}
29//!
30//! // WorldQuery is implemented for &T to fetch component references
31//! // (Implementation shown in fetch.rs Step 2.5.2)
32//! ```
33//!
34//! # Design Rationale
35//!
36//! This design is inspired by Bevy's query system, adapted for GoudEngine's
37//! needs:
38//!
39//! 1. **Type Safety**: The trait bounds ensure only valid queries compile
40//! 2. **Performance**: State caching avoids repeated archetype lookups
41//! 3. **Flexibility**: The generic design supports arbitrary query types
42//! 4. **Parallel Safety**: ReadOnlyWorldQuery enables safe concurrent reads
43
44use std::collections::BTreeSet;
45use std::fmt;
46
47use crate::ecs::archetype::Archetype;
48use crate::ecs::component::ComponentId;
49use crate::ecs::entity::Entity;
50use crate::ecs::resource::{NonSendResourceId, ResourceId};
51use crate::ecs::World;
52
53// =============================================================================
54// WorldQuery Trait
55// =============================================================================
56
57/// Trait for types that can be queried from a [`World`].
58///
59/// `WorldQuery` is the foundational trait of the ECS query system. It defines:
60///
61/// 1. What type of data the query produces (`Item`)
62/// 2. What state the query caches (`State`)
63/// 3. How to match archetypes (`matches_archetype`)
64/// 4. How to fetch data from the world (`fetch`)
65///
66/// # Generic Associated Type
67///
68/// The `Item<'w>` associated type uses a Generic Associated Type (GAT) to
69/// express that the fetched item has a lifetime tied to the world borrow.
70/// This enables returning references to component data.
71///
72/// # State Caching
73///
74/// The `State` type caches information needed for efficient queries, typically:
75/// - Component IDs (avoids repeated TypeId lookups)
76/// - Cached archetype matches (avoids repeated set operations)
77///
78/// # Safety
79///
80/// Implementors must ensure:
81/// 1. `matches_archetype` accurately reflects what entities can be fetched
82/// 2. `fetch` returns `None` for entities that don't match
83/// 3. Mutable queries conflict with other queries on the same component
84///
85/// # Built-in Implementations
86///
87/// The following types implement `WorldQuery`:
88///
89/// - `&T` where `T: Component` - Fetches immutable component reference
90/// - `&mut T` where `T: Component` - Fetches mutable component reference
91/// - `Entity` - Fetches the entity ID itself
92/// - Tuples `(A, B, ...)` - Combines multiple queries
93/// - `Option<Q>` - Optional query, always matches
94/// - `With<T>` - Filter for entities that have T (no data)
95/// - `Without<T>` - Filter for entities that don't have T (no data)
96///
97/// # Example
98///
99/// ```
100/// use goud_engine::ecs::{Component, Entity, World};
101/// use goud_engine::ecs::query::WorldQuery;
102///
103/// #[derive(Debug)]
104/// struct Health(f32);
105/// impl Component for Health {}
106///
107/// // The trait bounds ensure type safety:
108/// fn query_requires_world_query<Q: WorldQuery>() {}
109///
110/// // Entity always implements WorldQuery
111/// query_requires_world_query::<Entity>();
112/// ```
113pub trait WorldQuery {
114    /// The type of data this query fetches.
115    ///
116    /// This is a Generic Associated Type (GAT) that takes a lifetime parameter
117    /// `'w` representing the world borrow lifetime. This allows the item to
118    /// contain references to data stored in the world.
119    ///
120    /// Examples:
121    /// - For `&T`: `Item<'w> = &'w T`
122    /// - For `&mut T`: `Item<'w> = &'w mut T`
123    /// - For `Entity`: `Item<'w> = Entity` (no reference needed)
124    type Item<'w>;
125
126    /// The cached state for this query.
127    ///
128    /// State is initialized once via `init_state` and reused for subsequent
129    /// queries. This avoids repeated lookups of component IDs and other
130    /// metadata.
131    ///
132    /// Examples:
133    /// - For `&T`: `State = ComponentId`
134    /// - For tuples: `State = (A::State, B::State, ...)`
135    type State: QueryState;
136
137    /// Initializes the query state from the world.
138    ///
139    /// This is called once when a query is first created. The returned state
140    /// is cached and reused for all subsequent operations.
141    ///
142    /// # Arguments
143    ///
144    /// * `world` - Reference to the world (may be used for resource lookups)
145    ///
146    /// # Returns
147    ///
148    /// The initialized state for this query.
149    fn init_state(world: &World) -> Self::State;
150
151    /// Returns the set of component IDs this query reads.
152    ///
153    /// Used for access conflict detection. Two queries conflict if one writes
154    /// a component that the other reads or writes.
155    ///
156    /// # Arguments
157    ///
158    /// * `state` - The query state
159    ///
160    /// # Returns
161    ///
162    /// Set of component IDs accessed for reading (includes mutable access).
163    fn component_access(state: &Self::State) -> BTreeSet<ComponentId>;
164
165    /// Checks whether this query matches the given archetype.
166    ///
167    /// Returns `true` if entities in the archetype can produce a valid `Item`.
168    /// This is used to filter archetypes during query iteration.
169    ///
170    /// # Arguments
171    ///
172    /// * `state` - The cached query state
173    /// * `archetype` - The archetype to check
174    ///
175    /// # Returns
176    ///
177    /// `true` if entities in this archetype match the query.
178    fn matches_archetype(state: &Self::State, archetype: &Archetype) -> bool;
179
180    /// Fetches data for a specific entity from the world.
181    ///
182    /// Returns `Some(Item)` if the entity has all required components,
183    /// `None` otherwise.
184    ///
185    /// # Arguments
186    ///
187    /// * `state` - The cached query state
188    /// * `world` - Reference to the world containing component data
189    /// * `entity` - The entity to fetch data for
190    ///
191    /// # Returns
192    ///
193    /// `Some(Item)` if the entity matches the query, `None` otherwise.
194    ///
195    /// # Safety Note
196    ///
197    /// This method takes an immutable world reference but may return mutable
198    /// component references. The caller must ensure aliasing rules are
199    /// maintained (typically enforced by the query iterator).
200    fn fetch<'w>(state: &Self::State, world: &'w World, entity: Entity) -> Option<Self::Item<'w>>;
201
202    /// Fetches data for a specific entity from a mutable world reference.
203    ///
204    /// This variant is used when mutable component access is needed.
205    /// The default implementation calls `fetch` with an immutable borrow,
206    /// but mutable query implementations override this.
207    ///
208    /// # Arguments
209    ///
210    /// * `state` - The cached query state
211    /// * `world` - Mutable reference to the world
212    /// * `entity` - The entity to fetch data for
213    ///
214    /// # Returns
215    ///
216    /// `Some(Item)` if the entity matches the query, `None` otherwise.
217    fn fetch_mut<'w>(
218        state: &Self::State,
219        world: &'w mut World,
220        entity: Entity,
221    ) -> Option<Self::Item<'w>> {
222        // Default implementation for read-only queries
223        Self::fetch(state, world, entity)
224    }
225}
226
227// =============================================================================
228// ReadOnlyWorldQuery Trait
229// =============================================================================
230
231/// Marker trait for queries that only read data.
232///
233/// `ReadOnlyWorldQuery` is a marker trait that indicates a query does not
234/// mutate any component data. This enables:
235///
236/// 1. **Parallel Execution**: Multiple read-only queries can run concurrently
237/// 2. **Shared Borrows**: Can coexist with other readers of the same component
238/// 3. **Query Combination**: Read-only queries can be combined more freely
239///
240/// # Safety
241///
242/// Implementors must ensure that the query never mutates component data,
243/// even when given a mutable world reference.
244///
245/// # Built-in Implementations
246///
247/// - `&T` where `T: Component`
248/// - `Entity`
249/// - `Option<Q>` where `Q: ReadOnlyWorldQuery`
250/// - Tuples of read-only queries
251/// - `With<T>` and `Without<T>` filters
252///
253/// # Example
254///
255/// ```
256/// use goud_engine::ecs::Entity;
257/// use goud_engine::ecs::query::ReadOnlyWorldQuery;
258///
259/// // Entity is always read-only
260/// fn requires_read_only<Q: ReadOnlyWorldQuery>() {}
261/// requires_read_only::<Entity>();
262/// ```
263pub trait ReadOnlyWorldQuery: WorldQuery {}
264
265// =============================================================================
266// QueryState Trait
267// =============================================================================
268
269/// Trait for query state types.
270///
271/// Query state caches information needed for efficient query execution.
272/// The state is initialized once and reused for all query operations.
273///
274/// # Requirements
275///
276/// State types must be:
277/// - `Send + Sync`: For parallel query execution
278/// - `Clone`: To allow query state to be copied if needed
279///
280/// # Example
281///
282/// ```
283/// use goud_engine::ecs::component::ComponentId;
284/// use goud_engine::ecs::query::QueryState;
285///
286/// // ComponentId implements QueryState
287/// fn requires_query_state<S: QueryState>() {}
288/// requires_query_state::<ComponentId>();
289/// ```
290pub trait QueryState: Send + Sync + Clone + 'static {}
291
292// Blanket implementation for all qualifying types
293impl<T: Send + Sync + Clone + 'static> QueryState for T {}
294
295// =============================================================================
296// Entity Implementation
297// =============================================================================
298
299/// `Entity` can be queried to get the entity ID itself.
300///
301/// This is useful when you need the entity ID along with component data,
302/// or when iterating over all entities in an archetype.
303impl WorldQuery for Entity {
304    type Item<'w> = Entity;
305    type State = ();
306
307    #[inline]
308    fn init_state(_world: &World) -> Self::State {
309        // Entity query has no state
310    }
311
312    #[inline]
313    fn component_access(_state: &Self::State) -> BTreeSet<ComponentId> {
314        // Entity query accesses no components
315        BTreeSet::new()
316    }
317
318    #[inline]
319    fn matches_archetype(_state: &Self::State, _archetype: &Archetype) -> bool {
320        // Entity query matches all archetypes
321        true
322    }
323
324    #[inline]
325    fn fetch<'w>(_state: &Self::State, world: &'w World, entity: Entity) -> Option<Self::Item<'w>> {
326        // Return the entity if it's alive
327        if world.is_alive(entity) {
328            Some(entity)
329        } else {
330            None
331        }
332    }
333}
334
335impl ReadOnlyWorldQuery for Entity {}
336
337// =============================================================================
338// Unit Type Implementation
339// =============================================================================
340
341/// Unit type `()` represents an empty query.
342///
343/// This is useful as a base case for tuple queries and for queries that
344/// only use filters without fetching any data.
345impl WorldQuery for () {
346    type Item<'w> = ();
347    type State = ();
348
349    #[inline]
350    fn init_state(_world: &World) -> Self::State {}
351
352    #[inline]
353    fn component_access(_state: &Self::State) -> BTreeSet<ComponentId> {
354        BTreeSet::new()
355    }
356
357    #[inline]
358    fn matches_archetype(_state: &Self::State, _archetype: &Archetype) -> bool {
359        true
360    }
361
362    #[inline]
363    fn fetch<'w>(
364        _state: &Self::State,
365        _world: &'w World,
366        _entity: Entity,
367    ) -> Option<Self::Item<'w>> {
368        Some(())
369    }
370}
371
372impl ReadOnlyWorldQuery for () {}
373
374// =============================================================================
375// Tuple WorldQuery Implementations
376// =============================================================================
377
378// Macro to implement WorldQuery for tuples of different sizes
379macro_rules! impl_tuple_world_query {
380    ($($T:ident),*) => {
381        #[allow(non_snake_case)]
382        impl<$($T: WorldQuery),*> WorldQuery for ($($T,)*) {
383            type Item<'w> = ($($T::Item<'w>,)*);
384            type State = ($($T::State,)*);
385
386            #[inline]
387            fn init_state(world: &World) -> Self::State {
388                ($($T::init_state(world),)*)
389            }
390
391            #[inline]
392            fn component_access(state: &Self::State) -> BTreeSet<ComponentId> {
393                let ($($T,)*) = state;
394                let mut access = BTreeSet::new();
395                $(
396                    access.extend($T::component_access($T));
397                )*
398                access
399            }
400
401            #[inline]
402            fn matches_archetype(state: &Self::State, archetype: &Archetype) -> bool {
403                let ($($T,)*) = state;
404                true $(&& $T::matches_archetype($T, archetype))*
405            }
406
407            #[inline]
408            fn fetch<'w>(state: &Self::State, world: &'w World, entity: Entity) -> Option<Self::Item<'w>> {
409                let ($($T,)*) = state;
410                Some((
411                    $($T::fetch($T, world, entity)?,)*
412                ))
413            }
414        }
415
416        // A tuple is ReadOnlyWorldQuery if all its elements are ReadOnlyWorldQuery
417        impl<$($T: ReadOnlyWorldQuery),*> ReadOnlyWorldQuery for ($($T,)*) {}
418    };
419}
420
421// Implement for tuples of size 1-8
422impl_tuple_world_query!(A);
423impl_tuple_world_query!(A, B);
424impl_tuple_world_query!(A, B, C);
425impl_tuple_world_query!(A, B, C, D);
426impl_tuple_world_query!(A, B, C, D, E);
427impl_tuple_world_query!(A, B, C, D, E, F);
428impl_tuple_world_query!(A, B, C, D, E, F, G);
429impl_tuple_world_query!(A, B, C, D, E, F, G, H);
430
431// =============================================================================
432// Filter Types
433// =============================================================================
434
435/// Query filter that matches entities that have a component.
436///
437/// `With<T>` is a filter, not a data fetch. It filters entities to only those
438/// that have component `T`, but doesn't actually retrieve the component data.
439///
440/// Use `With<T>` when you need to ensure an entity has a component but don't
441/// need to access its data.
442///
443/// # Example
444///
445/// ```
446/// use goud_engine::ecs::{Component, World};
447/// use goud_engine::ecs::query::With;
448///
449/// struct Player;
450/// impl Component for Player {}
451///
452/// struct Health(f32);
453/// impl Component for Health {}
454///
455/// // Query for Health, but only for entities that also have Player
456/// // (Health, With<Player>) - fetches Health data, filters by Player
457/// ```
458#[derive(Debug, Clone, Copy, Default)]
459pub struct With<T>(std::marker::PhantomData<T>);
460
461impl<T> With<T> {
462    /// Creates a new `With` filter.
463    #[inline]
464    pub fn new() -> Self {
465        Self(std::marker::PhantomData)
466    }
467}
468
469impl<T: crate::ecs::Component> WorldQuery for With<T> {
470    type Item<'w> = ();
471    type State = ComponentId;
472
473    #[inline]
474    fn init_state(_world: &World) -> Self::State {
475        ComponentId::of::<T>()
476    }
477
478    #[inline]
479    fn component_access(_state: &Self::State) -> BTreeSet<ComponentId> {
480        // Filters don't access component data, just check existence
481        BTreeSet::new()
482    }
483
484    #[inline]
485    fn matches_archetype(state: &Self::State, archetype: &Archetype) -> bool {
486        archetype.has_component(*state)
487    }
488
489    #[inline]
490    fn fetch<'w>(state: &Self::State, world: &'w World, entity: Entity) -> Option<Self::Item<'w>> {
491        // Filter only checks if entity has the component
492        if world.has::<T>(entity) {
493            Some(())
494        } else {
495            // Also handle state usage to avoid unused warning
496            let _ = state;
497            None
498        }
499    }
500}
501
502impl<T: crate::ecs::Component> ReadOnlyWorldQuery for With<T> {}
503
504/// Query filter that matches entities that don't have a component.
505///
506/// `Without<T>` is a filter that excludes entities with component `T`.
507///
508/// # Example
509///
510/// ```
511/// use goud_engine::ecs::{Component, World};
512/// use goud_engine::ecs::query::Without;
513///
514/// struct Dead;
515/// impl Component for Dead {}
516///
517/// struct Health(f32);
518/// impl Component for Health {}
519///
520/// // Query for Health, but only for entities that don't have Dead
521/// // (Health, Without<Dead>) - fetches Health data, excludes Dead entities
522/// ```
523#[derive(Debug, Clone, Copy, Default)]
524pub struct Without<T>(std::marker::PhantomData<T>);
525
526impl<T> Without<T> {
527    /// Creates a new `Without` filter.
528    #[inline]
529    pub fn new() -> Self {
530        Self(std::marker::PhantomData)
531    }
532}
533
534impl<T: crate::ecs::Component> WorldQuery for Without<T> {
535    type Item<'w> = ();
536    type State = ComponentId;
537
538    #[inline]
539    fn init_state(_world: &World) -> Self::State {
540        ComponentId::of::<T>()
541    }
542
543    #[inline]
544    fn component_access(_state: &Self::State) -> BTreeSet<ComponentId> {
545        BTreeSet::new()
546    }
547
548    #[inline]
549    fn matches_archetype(state: &Self::State, archetype: &Archetype) -> bool {
550        !archetype.has_component(*state)
551    }
552
553    #[inline]
554    fn fetch<'w>(state: &Self::State, world: &'w World, entity: Entity) -> Option<Self::Item<'w>> {
555        // Filter only checks if entity doesn't have the component
556        if !world.has::<T>(entity) {
557            Some(())
558        } else {
559            let _ = state;
560            None
561        }
562    }
563}
564
565impl<T: crate::ecs::Component> ReadOnlyWorldQuery for Without<T> {}
566
567// =============================================================================
568// Component Reference Implementation (&T)
569// =============================================================================
570
571/// Query for an immutable component reference.
572///
573/// `&T` queries fetch a reference to component `T` for each matching entity.
574/// This is one of the most common query types.
575///
576/// # Archetype Matching
577///
578/// An archetype matches `&T` if it contains component `T`. The query returns
579/// `None` for entities that don't have the component.
580///
581/// # Parallel Safety
582///
583/// `&T` is a read-only query and implements [`ReadOnlyWorldQuery`]. Multiple
584/// `&T` queries for the same component can run in parallel, and `&T` can run
585/// alongside `&U` for different components.
586///
587/// # Example
588///
589/// ```
590/// use goud_engine::ecs::{World, Component, Entity};
591/// use goud_engine::ecs::query::WorldQuery;
592///
593/// #[derive(Debug, Clone, Copy, PartialEq)]
594/// struct Position { x: f32, y: f32 }
595/// impl Component for Position {}
596///
597/// let mut world = World::new();
598/// let entity = world.spawn_empty();
599/// world.insert(entity, Position { x: 1.0, y: 2.0 });
600///
601/// // Initialize query state
602/// let state = <&Position>::init_state(&world);
603///
604/// // Fetch component reference
605/// let pos = <&Position>::fetch(&state, &world, entity);
606/// assert!(pos.is_some());
607/// assert_eq!(pos.unwrap(), &Position { x: 1.0, y: 2.0 });
608/// ```
609///
610/// # Access Conflicts
611///
612/// - `&T` conflicts with `&mut T` (read-write conflict)
613/// - `&T` does NOT conflict with `&T` (multiple readers allowed)
614/// - `&T` does NOT conflict with `&U` where U ≠ T
615impl<T: crate::ecs::Component> WorldQuery for &T {
616    type Item<'w> = &'w T;
617    type State = ComponentId;
618
619    #[inline]
620    fn init_state(_world: &World) -> Self::State {
621        ComponentId::of::<T>()
622    }
623
624    #[inline]
625    fn component_access(state: &Self::State) -> BTreeSet<ComponentId> {
626        let mut set = BTreeSet::new();
627        set.insert(*state);
628        set
629    }
630
631    #[inline]
632    fn matches_archetype(state: &Self::State, archetype: &Archetype) -> bool {
633        archetype.has_component(*state)
634    }
635
636    #[inline]
637    fn fetch<'w>(state: &Self::State, world: &'w World, entity: Entity) -> Option<Self::Item<'w>> {
638        // Avoid unused variable warning while maintaining intent
639        let _ = state;
640
641        // Use World::get which already checks entity liveness
642        world.get::<T>(entity)
643    }
644}
645
646impl<T: crate::ecs::Component> ReadOnlyWorldQuery for &T {}
647
648// =============================================================================
649// Mutable Component Reference Implementation (&mut T)
650// =============================================================================
651
652/// Marker type for tracking write access to a component.
653///
654/// Used to distinguish between read and write access in conflict detection.
655/// This allows the query system to detect when two queries would violate
656/// Rust's aliasing rules (one mutable + any other access to same component).
657#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
658pub struct WriteAccess(pub ComponentId);
659
660/// Query state for mutable component access.
661///
662/// Contains both the component ID and a marker indicating this is a write access.
663/// Used for accurate access conflict detection.
664#[derive(Debug, Clone, Copy, PartialEq, Eq)]
665pub struct MutState {
666    /// The component ID being accessed.
667    pub component_id: ComponentId,
668}
669
670impl MutState {
671    /// Creates a new mutable access state for the given component type.
672    #[inline]
673    pub fn of<T: crate::ecs::Component>() -> Self {
674        Self {
675            component_id: ComponentId::of::<T>(),
676        }
677    }
678}
679
680/// Query for a mutable component reference.
681///
682/// `&mut T` queries fetch a mutable reference to component `T` for each matching
683/// entity. This allows modifying component data in place.
684///
685/// # Archetype Matching
686///
687/// An archetype matches `&mut T` if it contains component `T`. The query returns
688/// `None` for entities that don't have the component.
689///
690/// # Access Conflicts
691///
692/// Mutable queries have strict access requirements:
693///
694/// - `&mut T` **conflicts** with `&T` (write-read conflict)
695/// - `&mut T` **conflicts** with `&mut T` (write-write conflict)
696/// - `&mut T` does **NOT** conflict with `&U` or `&mut U` where U ≠ T
697///
698/// The scheduler uses this information to prevent parallel execution of
699/// conflicting systems.
700///
701/// # Thread Safety
702///
703/// `&mut T` does **NOT** implement [`ReadOnlyWorldQuery`]. This means:
704///
705/// 1. Systems using `&mut T` cannot run in parallel with other systems accessing `T`
706/// 2. The query iterator enforces exclusive access at runtime
707///
708/// # Example
709///
710/// ```
711/// use goud_engine::ecs::{World, Component, Entity};
712/// use goud_engine::ecs::query::WorldQuery;
713///
714/// #[derive(Debug, Clone, Copy, PartialEq)]
715/// struct Health(f32);
716/// impl Component for Health {}
717///
718/// let mut world = World::new();
719/// let entity = world.spawn_empty();
720/// world.insert(entity, Health(100.0));
721///
722/// // Initialize query state
723/// let state = <&mut Health>::init_state(&world);
724///
725/// // Fetch mutable component reference
726/// if let Some(health) = <&mut Health>::fetch_mut(&state, &mut world, entity) {
727///     health.0 -= 10.0; // Modify in place
728/// }
729///
730/// // Verify modification
731/// assert_eq!(world.get::<Health>(entity), Some(&Health(90.0)));
732/// ```
733///
734/// # Important Notes
735///
736/// - The `fetch` method returns `None` because mutable access requires a mutable
737///   world reference. Use `fetch_mut` for mutable queries.
738/// - The query system enforces that only one mutable access to a component exists
739///   at any time, preventing aliasing issues.
740impl<T: crate::ecs::Component> WorldQuery for &mut T {
741    type Item<'w> = &'w mut T;
742    type State = MutState;
743
744    #[inline]
745    fn init_state(_world: &World) -> Self::State {
746        MutState::of::<T>()
747    }
748
749    #[inline]
750    fn component_access(state: &Self::State) -> BTreeSet<ComponentId> {
751        let mut set = BTreeSet::new();
752        set.insert(state.component_id);
753        set
754    }
755
756    #[inline]
757    fn matches_archetype(state: &Self::State, archetype: &Archetype) -> bool {
758        archetype.has_component(state.component_id)
759    }
760
761    /// Returns `None` because mutable access requires `fetch_mut`.
762    ///
763    /// This is intentional - the immutable world reference cannot provide
764    /// mutable component access without violating Rust's aliasing rules.
765    #[inline]
766    fn fetch<'w>(
767        _state: &Self::State,
768        _world: &'w World,
769        _entity: Entity,
770    ) -> Option<Self::Item<'w>> {
771        // Cannot provide mutable access from immutable world reference
772        // Callers must use fetch_mut for mutable queries
773        None
774    }
775
776    #[inline]
777    fn fetch_mut<'w>(
778        state: &Self::State,
779        world: &'w mut World,
780        entity: Entity,
781    ) -> Option<Self::Item<'w>> {
782        // Avoid unused variable warning while maintaining intent
783        let _ = state;
784
785        // Use World::get_mut which already checks entity liveness
786        world.get_mut::<T>(entity)
787    }
788}
789
790// NOTE: &mut T does NOT implement ReadOnlyWorldQuery
791// This is intentional - mutable queries conflict with all other access to the same component
792
793// =============================================================================
794// Access Conflict Detection
795// =============================================================================
796
797/// Represents the type of access a query has to a component.
798///
799/// Used for detecting conflicts between queries. Two queries conflict if:
800/// - One has `Write` access and the other has `Read` or `Write` to the same component
801#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
802pub enum AccessType {
803    /// Read-only access (`&T`)
804    Read,
805    /// Mutable access (`&mut T`)
806    Write,
807}
808
809/// Describes the component access pattern for a query.
810///
811/// Used by the scheduler to determine which systems can run in parallel.
812#[derive(Debug, Clone, Default)]
813pub struct Access {
814    /// Components accessed for reading only
815    reads: BTreeSet<ComponentId>,
816    /// Components accessed for writing (also counts as read)
817    writes: BTreeSet<ComponentId>,
818    /// Resources accessed for reading only
819    resource_reads: BTreeSet<ResourceId>,
820    /// Resources accessed for writing (also counts as read)
821    resource_writes: BTreeSet<ResourceId>,
822    /// Non-send resources accessed for reading only
823    non_send_reads: BTreeSet<NonSendResourceId>,
824    /// Non-send resources accessed for writing (also counts as read)
825    non_send_writes: BTreeSet<NonSendResourceId>,
826}
827
828impl Access {
829    /// Creates a new empty access descriptor.
830    #[inline]
831    pub fn new() -> Self {
832        Self::default()
833    }
834
835    /// Adds a read access for the given component.
836    #[inline]
837    pub fn add_read(&mut self, id: ComponentId) {
838        self.reads.insert(id);
839    }
840
841    /// Adds a write access for the given component.
842    ///
843    /// Write access implies read access.
844    #[inline]
845    pub fn add_write(&mut self, id: ComponentId) {
846        self.writes.insert(id);
847    }
848
849    /// Returns all components that are read (including those also written).
850    #[inline]
851    pub fn reads(&self) -> impl Iterator<Item = &ComponentId> {
852        self.reads.iter().chain(self.writes.iter())
853    }
854
855    /// Returns all components that are written.
856    #[inline]
857    pub fn writes(&self) -> &BTreeSet<ComponentId> {
858        &self.writes
859    }
860
861    /// Returns the set of read-only components (read but not written).
862    #[inline]
863    pub fn reads_only(&self) -> impl Iterator<Item = &ComponentId> {
864        self.reads.iter().filter(|id| !self.writes.contains(id))
865    }
866
867    /// Checks if this access conflicts with another.
868    ///
869    /// Two accesses conflict if:
870    /// - One writes to a component that the other reads or writes
871    /// - One writes to a resource that the other reads or writes
872    #[inline]
873    pub fn conflicts_with(&self, other: &Access) -> bool {
874        // Check component conflicts
875
876        // Check if our writes conflict with their reads or writes
877        for write in &self.writes {
878            if other.reads.contains(write) || other.writes.contains(write) {
879                return true;
880            }
881        }
882
883        // Check if their writes conflict with our reads
884        for write in &other.writes {
885            if self.reads.contains(write) {
886                return true;
887            }
888        }
889
890        // Check resource conflicts
891        if self.resource_conflicts_with(other) {
892            return true;
893        }
894
895        // Check non-send resource conflicts
896        self.non_send_conflicts_with(other)
897    }
898
899    /// Returns true if this access pattern is read-only.
900    ///
901    /// This checks component, resource, and non-send resource access.
902    #[inline]
903    pub fn is_read_only(&self) -> bool {
904        self.writes.is_empty() && self.resource_writes.is_empty() && self.non_send_writes.is_empty()
905    }
906
907    /// Merges another access into this one.
908    #[inline]
909    pub fn extend(&mut self, other: &Access) {
910        self.reads.extend(other.reads.iter().copied());
911        self.writes.extend(other.writes.iter().copied());
912        self.resource_reads
913            .extend(other.resource_reads.iter().copied());
914        self.resource_writes
915            .extend(other.resource_writes.iter().copied());
916        self.non_send_reads
917            .extend(other.non_send_reads.iter().copied());
918        self.non_send_writes
919            .extend(other.non_send_writes.iter().copied());
920    }
921
922    // =========================================================================
923    // Resource Access
924    // =========================================================================
925
926    /// Adds a read access for the given resource.
927    #[inline]
928    pub fn add_resource_read(&mut self, id: ResourceId) {
929        self.resource_reads.insert(id);
930    }
931
932    /// Adds a write access for the given resource.
933    ///
934    /// Write access implies read access.
935    #[inline]
936    pub fn add_resource_write(&mut self, id: ResourceId) {
937        self.resource_writes.insert(id);
938    }
939
940    /// Returns all resources that are read (including those also written).
941    #[inline]
942    pub fn resource_reads(&self) -> impl Iterator<Item = &ResourceId> {
943        self.resource_reads
944            .iter()
945            .chain(self.resource_writes.iter())
946    }
947
948    /// Returns all resources that are written.
949    #[inline]
950    pub fn resource_writes(&self) -> &BTreeSet<ResourceId> {
951        &self.resource_writes
952    }
953
954    /// Returns the set of read-only resources (read but not written).
955    #[inline]
956    pub fn resource_reads_only(&self) -> impl Iterator<Item = &ResourceId> {
957        self.resource_reads
958            .iter()
959            .filter(|id| !self.resource_writes.contains(id))
960    }
961
962    /// Checks if resource access conflicts with another.
963    ///
964    /// Two accesses conflict if one writes to a resource that the other
965    /// reads or writes.
966    #[inline]
967    pub fn resource_conflicts_with(&self, other: &Access) -> bool {
968        // Check if our resource writes conflict with their reads or writes
969        for write in &self.resource_writes {
970            if other.resource_reads.contains(write) || other.resource_writes.contains(write) {
971                return true;
972            }
973        }
974
975        // Check if their resource writes conflict with our reads
976        for write in &other.resource_writes {
977            if self.resource_reads.contains(write) {
978                return true;
979            }
980        }
981
982        false
983    }
984
985    /// Checks if this access has any resource access.
986    #[inline]
987    pub fn has_resource_access(&self) -> bool {
988        !self.resource_reads.is_empty() || !self.resource_writes.is_empty()
989    }
990
991    /// Checks if this access has any component access.
992    #[inline]
993    pub fn has_component_access(&self) -> bool {
994        !self.reads.is_empty() || !self.writes.is_empty()
995    }
996
997    // =========================================================================
998    // Non-Send Resource Access
999    // =========================================================================
1000
1001    /// Adds a read access for the given non-send resource.
1002    #[inline]
1003    pub fn add_non_send_read(&mut self, id: NonSendResourceId) {
1004        self.non_send_reads.insert(id);
1005    }
1006
1007    /// Adds a write access for the given non-send resource.
1008    ///
1009    /// Write access implies read access.
1010    #[inline]
1011    pub fn add_non_send_write(&mut self, id: NonSendResourceId) {
1012        self.non_send_writes.insert(id);
1013    }
1014
1015    /// Returns all non-send resources that are read (including those also written).
1016    #[inline]
1017    pub fn non_send_reads(&self) -> impl Iterator<Item = &NonSendResourceId> {
1018        self.non_send_reads
1019            .iter()
1020            .chain(self.non_send_writes.iter())
1021    }
1022
1023    /// Returns all non-send resources that are written.
1024    #[inline]
1025    pub fn non_send_writes(&self) -> &BTreeSet<NonSendResourceId> {
1026        &self.non_send_writes
1027    }
1028
1029    /// Returns the set of read-only non-send resources (read but not written).
1030    #[inline]
1031    pub fn non_send_reads_only(&self) -> impl Iterator<Item = &NonSendResourceId> {
1032        self.non_send_reads
1033            .iter()
1034            .filter(|id| !self.non_send_writes.contains(id))
1035    }
1036
1037    /// Checks if non-send resource access conflicts with another.
1038    ///
1039    /// Two accesses conflict if one writes to a non-send resource that the other
1040    /// reads or writes.
1041    #[inline]
1042    pub fn non_send_conflicts_with(&self, other: &Access) -> bool {
1043        // Check if our non-send writes conflict with their reads or writes
1044        for write in &self.non_send_writes {
1045            if other.non_send_reads.contains(write) || other.non_send_writes.contains(write) {
1046                return true;
1047            }
1048        }
1049
1050        // Check if their non-send writes conflict with our reads
1051        for write in &other.non_send_writes {
1052            if self.non_send_reads.contains(write) {
1053                return true;
1054            }
1055        }
1056
1057        false
1058    }
1059
1060    /// Checks if this access has any non-send resource access.
1061    #[inline]
1062    pub fn has_non_send_access(&self) -> bool {
1063        !self.non_send_reads.is_empty() || !self.non_send_writes.is_empty()
1064    }
1065
1066    /// Returns true if this access requires execution on the main thread.
1067    ///
1068    /// This returns true if there is any non-send resource access.
1069    #[inline]
1070    pub fn requires_main_thread(&self) -> bool {
1071        self.has_non_send_access()
1072    }
1073
1074    /// Returns detailed information about conflicts between this access and another.
1075    ///
1076    /// If there are no conflicts, returns `None`. Otherwise, returns an `AccessConflict`
1077    /// describing all the conflicting components and resources.
1078    ///
1079    /// # Arguments
1080    ///
1081    /// * `other` - The other access pattern to check against
1082    ///
1083    /// # Returns
1084    ///
1085    /// `Some(AccessConflict)` if there are conflicts, `None` otherwise.
1086    ///
1087    /// # Example
1088    ///
1089    /// ```
1090    /// use goud_engine::ecs::query::Access;
1091    /// use goud_engine::ecs::component::ComponentId;
1092    /// use goud_engine::ecs::Component;
1093    ///
1094    /// #[derive(Clone, Copy)]
1095    /// struct Position { x: f32, y: f32 }
1096    /// impl Component for Position {}
1097    ///
1098    /// let mut access1 = Access::new();
1099    /// access1.add_write(ComponentId::of::<Position>());
1100    ///
1101    /// let mut access2 = Access::new();
1102    /// access2.add_read(ComponentId::of::<Position>());
1103    ///
1104    /// let conflict = access1.get_conflicts(&access2);
1105    /// assert!(conflict.is_some());
1106    /// let conflict = conflict.unwrap();
1107    /// assert_eq!(conflict.component_conflicts().len(), 1);
1108    /// ```
1109    pub fn get_conflicts(&self, other: &Access) -> Option<AccessConflict> {
1110        let mut component_conflicts = Vec::new();
1111        let mut resource_conflicts = Vec::new();
1112        let mut non_send_conflicts = Vec::new();
1113
1114        // Check component conflicts: our writes vs their reads/writes
1115        for &write in &self.writes {
1116            if other.reads.contains(&write) {
1117                component_conflicts.push(ConflictInfo::new(
1118                    write,
1119                    AccessType::Write,
1120                    AccessType::Read,
1121                ));
1122            } else if other.writes.contains(&write) {
1123                component_conflicts.push(ConflictInfo::new(
1124                    write,
1125                    AccessType::Write,
1126                    AccessType::Write,
1127                ));
1128            }
1129        }
1130
1131        // Check component conflicts: their writes vs our reads
1132        for &write in &other.writes {
1133            if self.reads.contains(&write) && !self.writes.contains(&write) {
1134                // Only add if we haven't already added this conflict from the other direction
1135                component_conflicts.push(ConflictInfo::new(
1136                    write,
1137                    AccessType::Read,
1138                    AccessType::Write,
1139                ));
1140            }
1141        }
1142
1143        // Check resource conflicts: our writes vs their reads/writes
1144        for &write in &self.resource_writes {
1145            if other.resource_reads.contains(&write) {
1146                resource_conflicts.push(ResourceConflictInfo::new(
1147                    write,
1148                    AccessType::Write,
1149                    AccessType::Read,
1150                ));
1151            } else if other.resource_writes.contains(&write) {
1152                resource_conflicts.push(ResourceConflictInfo::new(
1153                    write,
1154                    AccessType::Write,
1155                    AccessType::Write,
1156                ));
1157            }
1158        }
1159
1160        // Check resource conflicts: their writes vs our reads
1161        for &write in &other.resource_writes {
1162            if self.resource_reads.contains(&write) && !self.resource_writes.contains(&write) {
1163                resource_conflicts.push(ResourceConflictInfo::new(
1164                    write,
1165                    AccessType::Read,
1166                    AccessType::Write,
1167                ));
1168            }
1169        }
1170
1171        // Check non-send resource conflicts: our writes vs their reads/writes
1172        for &write in &self.non_send_writes {
1173            if other.non_send_reads.contains(&write) {
1174                non_send_conflicts.push(NonSendConflictInfo::new(
1175                    write,
1176                    AccessType::Write,
1177                    AccessType::Read,
1178                ));
1179            } else if other.non_send_writes.contains(&write) {
1180                non_send_conflicts.push(NonSendConflictInfo::new(
1181                    write,
1182                    AccessType::Write,
1183                    AccessType::Write,
1184                ));
1185            }
1186        }
1187
1188        // Check non-send resource conflicts: their writes vs our reads
1189        for &write in &other.non_send_writes {
1190            if self.non_send_reads.contains(&write) && !self.non_send_writes.contains(&write) {
1191                non_send_conflicts.push(NonSendConflictInfo::new(
1192                    write,
1193                    AccessType::Read,
1194                    AccessType::Write,
1195                ));
1196            }
1197        }
1198
1199        if component_conflicts.is_empty()
1200            && resource_conflicts.is_empty()
1201            && non_send_conflicts.is_empty()
1202        {
1203            None
1204        } else {
1205            Some(AccessConflict {
1206                component_conflicts,
1207                resource_conflicts,
1208                non_send_conflicts,
1209            })
1210        }
1211    }
1212
1213    /// Returns true if this access is empty (no reads or writes).
1214    #[inline]
1215    pub fn is_empty(&self) -> bool {
1216        self.reads.is_empty()
1217            && self.writes.is_empty()
1218            && self.resource_reads.is_empty()
1219            && self.resource_writes.is_empty()
1220            && self.non_send_reads.is_empty()
1221            && self.non_send_writes.is_empty()
1222    }
1223
1224    /// Clears all access information.
1225    #[inline]
1226    pub fn clear(&mut self) {
1227        self.reads.clear();
1228        self.writes.clear();
1229        self.resource_reads.clear();
1230        self.resource_writes.clear();
1231        self.non_send_reads.clear();
1232        self.non_send_writes.clear();
1233    }
1234}
1235
1236// =============================================================================
1237// Access Conflict Reporting
1238// =============================================================================
1239
1240/// Information about a single component access conflict.
1241///
1242/// Describes which component conflicts and what type of access each side has.
1243#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1244pub struct ConflictInfo {
1245    /// The conflicting component ID.
1246    pub component_id: ComponentId,
1247    /// How the first access pattern accesses this component.
1248    pub first_access: AccessType,
1249    /// How the second access pattern accesses this component.
1250    pub second_access: AccessType,
1251}
1252
1253impl ConflictInfo {
1254    /// Creates a new conflict info.
1255    #[inline]
1256    pub fn new(
1257        component_id: ComponentId,
1258        first_access: AccessType,
1259        second_access: AccessType,
1260    ) -> Self {
1261        Self {
1262            component_id,
1263            first_access,
1264            second_access,
1265        }
1266    }
1267
1268    /// Returns true if this is a write-write conflict.
1269    #[inline]
1270    pub fn is_write_write(&self) -> bool {
1271        self.first_access == AccessType::Write && self.second_access == AccessType::Write
1272    }
1273
1274    /// Returns true if this is a read-write conflict.
1275    #[inline]
1276    pub fn is_read_write(&self) -> bool {
1277        (self.first_access == AccessType::Read && self.second_access == AccessType::Write)
1278            || (self.first_access == AccessType::Write && self.second_access == AccessType::Read)
1279    }
1280}
1281
1282impl fmt::Display for ConflictInfo {
1283    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1284        write!(
1285            f,
1286            "Component {:?}: {:?} vs {:?}",
1287            self.component_id, self.first_access, self.second_access
1288        )
1289    }
1290}
1291
1292/// Information about a single resource access conflict.
1293#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1294pub struct ResourceConflictInfo {
1295    /// The conflicting resource ID.
1296    pub resource_id: ResourceId,
1297    /// How the first access pattern accesses this resource.
1298    pub first_access: AccessType,
1299    /// How the second access pattern accesses this resource.
1300    pub second_access: AccessType,
1301}
1302
1303impl ResourceConflictInfo {
1304    /// Creates a new resource conflict info.
1305    #[inline]
1306    pub fn new(
1307        resource_id: ResourceId,
1308        first_access: AccessType,
1309        second_access: AccessType,
1310    ) -> Self {
1311        Self {
1312            resource_id,
1313            first_access,
1314            second_access,
1315        }
1316    }
1317
1318    /// Returns true if this is a write-write conflict.
1319    #[inline]
1320    pub fn is_write_write(&self) -> bool {
1321        self.first_access == AccessType::Write && self.second_access == AccessType::Write
1322    }
1323}
1324
1325impl fmt::Display for ResourceConflictInfo {
1326    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1327        write!(
1328            f,
1329            "Resource {:?}: {:?} vs {:?}",
1330            self.resource_id, self.first_access, self.second_access
1331        )
1332    }
1333}
1334
1335/// Information about a single non-send resource access conflict.
1336#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1337pub struct NonSendConflictInfo {
1338    /// The conflicting non-send resource ID.
1339    pub resource_id: NonSendResourceId,
1340    /// How the first access pattern accesses this resource.
1341    pub first_access: AccessType,
1342    /// How the second access pattern accesses this resource.
1343    pub second_access: AccessType,
1344}
1345
1346impl NonSendConflictInfo {
1347    /// Creates a new non-send resource conflict info.
1348    #[inline]
1349    pub fn new(
1350        resource_id: NonSendResourceId,
1351        first_access: AccessType,
1352        second_access: AccessType,
1353    ) -> Self {
1354        Self {
1355            resource_id,
1356            first_access,
1357            second_access,
1358        }
1359    }
1360
1361    /// Returns true if this is a write-write conflict.
1362    #[inline]
1363    pub fn is_write_write(&self) -> bool {
1364        self.first_access == AccessType::Write && self.second_access == AccessType::Write
1365    }
1366}
1367
1368impl fmt::Display for NonSendConflictInfo {
1369    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1370        write!(
1371            f,
1372            "NonSendResource {:?}: {:?} vs {:?}",
1373            self.resource_id, self.first_access, self.second_access
1374        )
1375    }
1376}
1377
1378/// Detailed information about all conflicts between two access patterns.
1379///
1380/// This struct is returned by [`Access::get_conflicts()`] when there are
1381/// conflicting accesses. It contains separate lists of component, resource,
1382/// and non-send resource conflicts.
1383///
1384/// # Usage
1385///
1386/// ```
1387/// use goud_engine::ecs::query::{Access, AccessConflict};
1388/// use goud_engine::ecs::component::ComponentId;
1389/// use goud_engine::ecs::Component;
1390///
1391/// #[derive(Clone, Copy)]
1392/// struct Health(f32);
1393/// impl Component for Health {}
1394///
1395/// let mut system_a = Access::new();
1396/// system_a.add_write(ComponentId::of::<Health>());
1397///
1398/// let mut system_b = Access::new();
1399/// system_b.add_read(ComponentId::of::<Health>());
1400///
1401/// if let Some(conflict) = system_a.get_conflicts(&system_b) {
1402///     println!("Systems conflict on {} components", conflict.component_count());
1403///     for info in conflict.component_conflicts() {
1404///         println!("  - {}", info);
1405///     }
1406/// }
1407/// ```
1408#[derive(Debug, Clone, PartialEq, Eq)]
1409pub struct AccessConflict {
1410    /// Component access conflicts.
1411    component_conflicts: Vec<ConflictInfo>,
1412    /// Resource access conflicts.
1413    resource_conflicts: Vec<ResourceConflictInfo>,
1414    /// Non-send resource access conflicts.
1415    non_send_conflicts: Vec<NonSendConflictInfo>,
1416}
1417
1418impl AccessConflict {
1419    /// Creates a new empty access conflict.
1420    #[inline]
1421    pub fn new() -> Self {
1422        Self {
1423            component_conflicts: Vec::new(),
1424            resource_conflicts: Vec::new(),
1425            non_send_conflicts: Vec::new(),
1426        }
1427    }
1428
1429    /// Returns the component conflicts.
1430    #[inline]
1431    pub fn component_conflicts(&self) -> &[ConflictInfo] {
1432        &self.component_conflicts
1433    }
1434
1435    /// Returns the resource conflicts.
1436    #[inline]
1437    pub fn resource_conflicts(&self) -> &[ResourceConflictInfo] {
1438        &self.resource_conflicts
1439    }
1440
1441    /// Returns the non-send resource conflicts.
1442    #[inline]
1443    pub fn non_send_conflicts(&self) -> &[NonSendConflictInfo] {
1444        &self.non_send_conflicts
1445    }
1446
1447    /// Returns the total number of component conflicts.
1448    #[inline]
1449    pub fn component_count(&self) -> usize {
1450        self.component_conflicts.len()
1451    }
1452
1453    /// Returns the total number of resource conflicts.
1454    #[inline]
1455    pub fn resource_count(&self) -> usize {
1456        self.resource_conflicts.len()
1457    }
1458
1459    /// Returns the total number of non-send resource conflicts.
1460    #[inline]
1461    pub fn non_send_count(&self) -> usize {
1462        self.non_send_conflicts.len()
1463    }
1464
1465    /// Returns the total number of conflicts across all categories.
1466    #[inline]
1467    pub fn total_count(&self) -> usize {
1468        self.component_conflicts.len()
1469            + self.resource_conflicts.len()
1470            + self.non_send_conflicts.len()
1471    }
1472
1473    /// Returns true if there are no conflicts.
1474    #[inline]
1475    pub fn is_empty(&self) -> bool {
1476        self.component_conflicts.is_empty()
1477            && self.resource_conflicts.is_empty()
1478            && self.non_send_conflicts.is_empty()
1479    }
1480
1481    /// Returns true if any conflict is a write-write conflict.
1482    #[inline]
1483    pub fn has_write_write(&self) -> bool {
1484        self.component_conflicts.iter().any(|c| c.is_write_write())
1485            || self.resource_conflicts.iter().any(|c| c.is_write_write())
1486            || self.non_send_conflicts.iter().any(|c| c.is_write_write())
1487    }
1488
1489    /// Returns an iterator over all conflicting component IDs.
1490    #[inline]
1491    pub fn conflicting_components(&self) -> impl Iterator<Item = ComponentId> + '_ {
1492        self.component_conflicts.iter().map(|c| c.component_id)
1493    }
1494
1495    /// Returns an iterator over all conflicting resource IDs.
1496    #[inline]
1497    pub fn conflicting_resources(&self) -> impl Iterator<Item = ResourceId> + '_ {
1498        self.resource_conflicts.iter().map(|c| c.resource_id)
1499    }
1500
1501    /// Returns an iterator over all conflicting non-send resource IDs.
1502    #[inline]
1503    pub fn conflicting_non_send_resources(&self) -> impl Iterator<Item = NonSendResourceId> + '_ {
1504        self.non_send_conflicts.iter().map(|c| c.resource_id)
1505    }
1506}
1507
1508impl Default for AccessConflict {
1509    fn default() -> Self {
1510        Self::new()
1511    }
1512}
1513
1514impl fmt::Display for AccessConflict {
1515    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1516        write!(f, "AccessConflict(")?;
1517        let mut first = true;
1518
1519        for conflict in &self.component_conflicts {
1520            if !first {
1521                write!(f, ", ")?;
1522            }
1523            write!(f, "{}", conflict)?;
1524            first = false;
1525        }
1526
1527        for conflict in &self.resource_conflicts {
1528            if !first {
1529                write!(f, ", ")?;
1530            }
1531            write!(f, "{}", conflict)?;
1532            first = false;
1533        }
1534
1535        for conflict in &self.non_send_conflicts {
1536            if !first {
1537                write!(f, ", ")?;
1538            }
1539            write!(f, "{}", conflict)?;
1540            first = false;
1541        }
1542
1543        write!(f, ")")
1544    }
1545}
1546
1547// =============================================================================
1548// Tests
1549// =============================================================================
1550
1551#[cfg(test)]
1552mod tests {
1553    use super::*;
1554    use crate::ecs::Component;
1555
1556    // Test components
1557    #[derive(Debug, Clone, Copy, PartialEq)]
1558    struct Position {
1559        x: f32,
1560        y: f32,
1561    }
1562    impl Component for Position {}
1563
1564    #[derive(Debug, Clone, Copy, PartialEq)]
1565    struct Velocity {
1566        x: f32,
1567        y: f32,
1568    }
1569    impl Component for Velocity {}
1570
1571    #[derive(Debug, Clone, Copy)]
1572    struct Player;
1573    impl Component for Player {}
1574
1575    // =========================================================================
1576    // WorldQuery Trait Tests
1577    // =========================================================================
1578
1579    mod world_query_trait {
1580        use super::*;
1581
1582        #[test]
1583        fn test_entity_query_init_state() {
1584            let world = World::new();
1585            let _state: () = Entity::init_state(&world);
1586            // Entity state is unit type - assertion via type annotation
1587        }
1588
1589        #[test]
1590        fn test_entity_query_matches_all_archetypes() {
1591            use crate::ecs::archetype::{Archetype, ArchetypeId};
1592            use std::collections::BTreeSet;
1593
1594            let state = ();
1595
1596            // Empty archetype
1597            let empty_arch = Archetype::new(ArchetypeId::EMPTY, BTreeSet::new());
1598            assert!(Entity::matches_archetype(&state, &empty_arch));
1599
1600            // Archetype with components
1601            let mut components = BTreeSet::new();
1602            components.insert(ComponentId::of::<Position>());
1603            let pos_arch = Archetype::new(ArchetypeId::new(1), components);
1604            assert!(Entity::matches_archetype(&state, &pos_arch));
1605        }
1606
1607        #[test]
1608        fn test_entity_query_fetch_alive() {
1609            let mut world = World::new();
1610            let entity = world.spawn_empty();
1611
1612            let _state: () = Entity::init_state(&world);
1613            let fetched = Entity::fetch(&(), &world, entity);
1614
1615            assert_eq!(fetched, Some(entity));
1616        }
1617
1618        #[test]
1619        fn test_entity_query_fetch_dead() {
1620            let mut world = World::new();
1621            let entity = world.spawn_empty();
1622            world.despawn(entity);
1623
1624            let _state: () = Entity::init_state(&world);
1625            let fetched = Entity::fetch(&(), &world, entity);
1626
1627            assert_eq!(fetched, None);
1628        }
1629
1630        #[test]
1631        fn test_entity_query_is_read_only() {
1632            // Compile-time test: Entity implements ReadOnlyWorldQuery
1633            fn requires_read_only<Q: ReadOnlyWorldQuery>() {}
1634            requires_read_only::<Entity>();
1635        }
1636
1637        #[test]
1638        fn test_entity_query_component_access_empty() {
1639            let state = ();
1640            let access = Entity::component_access(&state);
1641            assert!(access.is_empty());
1642        }
1643    }
1644
1645    // =========================================================================
1646    // Unit Query Tests
1647    // =========================================================================
1648
1649    mod unit_query {
1650        use super::*;
1651
1652        #[test]
1653        fn test_unit_query_matches_all() {
1654            use crate::ecs::archetype::{Archetype, ArchetypeId};
1655            use std::collections::BTreeSet;
1656
1657            let state = ();
1658
1659            let empty_arch = Archetype::new(ArchetypeId::EMPTY, BTreeSet::new());
1660            assert!(<()>::matches_archetype(&state, &empty_arch));
1661        }
1662
1663        #[test]
1664        fn test_unit_query_fetch_always_succeeds() {
1665            let world = World::new();
1666            let _state: () = <()>::init_state(&world);
1667
1668            // Even with placeholder entity (doesn't need to exist for unit query)
1669            let entity = Entity::new(0, 1);
1670            let fetched = <()>::fetch(&(), &world, entity);
1671
1672            // Unit query always returns Some(())
1673            assert!(fetched.is_some());
1674        }
1675
1676        #[test]
1677        fn test_unit_query_is_read_only() {
1678            fn requires_read_only<Q: ReadOnlyWorldQuery>() {}
1679            requires_read_only::<()>();
1680        }
1681    }
1682
1683    // =========================================================================
1684    // QueryState Trait Tests
1685    // =========================================================================
1686
1687    mod query_state_trait {
1688        use super::*;
1689
1690        #[test]
1691        fn test_component_id_implements_query_state() {
1692            fn requires_query_state<S: QueryState>() {}
1693            requires_query_state::<ComponentId>();
1694        }
1695
1696        #[test]
1697        fn test_unit_implements_query_state() {
1698            fn requires_query_state<S: QueryState>() {}
1699            requires_query_state::<()>();
1700        }
1701
1702        #[test]
1703        fn test_query_state_is_send_sync() {
1704            fn requires_send_sync<S: Send + Sync>() {}
1705            requires_send_sync::<ComponentId>();
1706            requires_send_sync::<()>();
1707        }
1708    }
1709
1710    // =========================================================================
1711    // With Filter Tests
1712    // =========================================================================
1713
1714    mod with_filter {
1715        use super::*;
1716        use crate::ecs::archetype::{Archetype, ArchetypeId};
1717        use std::collections::BTreeSet;
1718
1719        #[test]
1720        fn test_with_init_state() {
1721            let world = World::new();
1722            let state = With::<Position>::init_state(&world);
1723            assert_eq!(state, ComponentId::of::<Position>());
1724        }
1725
1726        #[test]
1727        fn test_with_matches_archetype_with_component() {
1728            let mut components = BTreeSet::new();
1729            components.insert(ComponentId::of::<Position>());
1730            let archetype = Archetype::new(ArchetypeId::new(1), components);
1731
1732            let state = ComponentId::of::<Position>();
1733            assert!(With::<Position>::matches_archetype(&state, &archetype));
1734        }
1735
1736        #[test]
1737        fn test_with_does_not_match_archetype_without_component() {
1738            let mut components = BTreeSet::new();
1739            components.insert(ComponentId::of::<Velocity>());
1740            let archetype = Archetype::new(ArchetypeId::new(1), components);
1741
1742            let state = ComponentId::of::<Position>();
1743            assert!(!With::<Position>::matches_archetype(&state, &archetype));
1744        }
1745
1746        #[test]
1747        fn test_with_fetch_entity_with_component() {
1748            let mut world = World::new();
1749            let entity = world.spawn_empty();
1750            world.insert(entity, Position { x: 1.0, y: 2.0 });
1751
1752            let state = With::<Position>::init_state(&world);
1753            let result = With::<Position>::fetch(&state, &world, entity);
1754
1755            assert_eq!(result, Some(()));
1756        }
1757
1758        #[test]
1759        fn test_with_fetch_entity_without_component() {
1760            let mut world = World::new();
1761            let entity = world.spawn_empty();
1762            world.insert(entity, Velocity { x: 1.0, y: 2.0 });
1763
1764            let state = With::<Position>::init_state(&world);
1765            let result = With::<Position>::fetch(&state, &world, entity);
1766
1767            assert_eq!(result, None);
1768        }
1769
1770        #[test]
1771        fn test_with_is_read_only() {
1772            fn requires_read_only<Q: ReadOnlyWorldQuery>() {}
1773            requires_read_only::<With<Position>>();
1774        }
1775
1776        #[test]
1777        fn test_with_component_access_empty() {
1778            let state = ComponentId::of::<Position>();
1779            let access = With::<Position>::component_access(&state);
1780            // Filters don't access component data
1781            assert!(access.is_empty());
1782        }
1783    }
1784
1785    // =========================================================================
1786    // Without Filter Tests
1787    // =========================================================================
1788
1789    mod without_filter {
1790        use super::*;
1791        use crate::ecs::archetype::{Archetype, ArchetypeId};
1792        use std::collections::BTreeSet;
1793
1794        #[test]
1795        fn test_without_init_state() {
1796            let world = World::new();
1797            let state = Without::<Position>::init_state(&world);
1798            assert_eq!(state, ComponentId::of::<Position>());
1799        }
1800
1801        #[test]
1802        fn test_without_matches_archetype_without_component() {
1803            let mut components = BTreeSet::new();
1804            components.insert(ComponentId::of::<Velocity>());
1805            let archetype = Archetype::new(ArchetypeId::new(1), components);
1806
1807            let state = ComponentId::of::<Position>();
1808            assert!(Without::<Position>::matches_archetype(&state, &archetype));
1809        }
1810
1811        #[test]
1812        fn test_without_does_not_match_archetype_with_component() {
1813            let mut components = BTreeSet::new();
1814            components.insert(ComponentId::of::<Position>());
1815            let archetype = Archetype::new(ArchetypeId::new(1), components);
1816
1817            let state = ComponentId::of::<Position>();
1818            assert!(!Without::<Position>::matches_archetype(&state, &archetype));
1819        }
1820
1821        #[test]
1822        fn test_without_fetch_entity_without_component() {
1823            let mut world = World::new();
1824            let entity = world.spawn_empty();
1825            world.insert(entity, Velocity { x: 1.0, y: 2.0 });
1826
1827            let state = Without::<Position>::init_state(&world);
1828            let result = Without::<Position>::fetch(&state, &world, entity);
1829
1830            assert_eq!(result, Some(()));
1831        }
1832
1833        #[test]
1834        fn test_without_fetch_entity_with_component() {
1835            let mut world = World::new();
1836            let entity = world.spawn_empty();
1837            world.insert(entity, Position { x: 1.0, y: 2.0 });
1838
1839            let state = Without::<Position>::init_state(&world);
1840            let result = Without::<Position>::fetch(&state, &world, entity);
1841
1842            assert_eq!(result, None);
1843        }
1844
1845        #[test]
1846        fn test_without_is_read_only() {
1847            fn requires_read_only<Q: ReadOnlyWorldQuery>() {}
1848            requires_read_only::<Without<Position>>();
1849        }
1850
1851        #[test]
1852        fn test_without_matches_empty_archetype() {
1853            let archetype = Archetype::new(ArchetypeId::EMPTY, BTreeSet::new());
1854            let state = ComponentId::of::<Position>();
1855            assert!(Without::<Position>::matches_archetype(&state, &archetype));
1856        }
1857    }
1858
1859    // =========================================================================
1860    // Component Reference (&T) Tests
1861    // =========================================================================
1862
1863    mod component_ref {
1864        use super::*;
1865        use crate::ecs::archetype::{Archetype, ArchetypeId};
1866        use std::collections::BTreeSet;
1867
1868        #[test]
1869        fn test_ref_init_state() {
1870            let world = World::new();
1871            let state = <&Position>::init_state(&world);
1872            assert_eq!(state, ComponentId::of::<Position>());
1873        }
1874
1875        #[test]
1876        fn test_ref_matches_archetype_with_component() {
1877            let mut components = BTreeSet::new();
1878            components.insert(ComponentId::of::<Position>());
1879            let archetype = Archetype::new(ArchetypeId::new(1), components);
1880
1881            let state = ComponentId::of::<Position>();
1882            assert!(<&Position>::matches_archetype(&state, &archetype));
1883        }
1884
1885        #[test]
1886        fn test_ref_does_not_match_archetype_without_component() {
1887            let mut components = BTreeSet::new();
1888            components.insert(ComponentId::of::<Velocity>());
1889            let archetype = Archetype::new(ArchetypeId::new(1), components);
1890
1891            let state = ComponentId::of::<Position>();
1892            assert!(!<&Position>::matches_archetype(&state, &archetype));
1893        }
1894
1895        #[test]
1896        fn test_ref_does_not_match_empty_archetype() {
1897            let archetype = Archetype::new(ArchetypeId::EMPTY, BTreeSet::new());
1898
1899            let state = ComponentId::of::<Position>();
1900            assert!(!<&Position>::matches_archetype(&state, &archetype));
1901        }
1902
1903        #[test]
1904        fn test_ref_fetch_entity_with_component() {
1905            let mut world = World::new();
1906            let entity = world.spawn_empty();
1907            world.insert(entity, Position { x: 1.0, y: 2.0 });
1908
1909            let state = <&Position>::init_state(&world);
1910            let result = <&Position>::fetch(&state, &world, entity);
1911
1912            assert!(result.is_some());
1913            let pos = result.unwrap();
1914            assert_eq!(pos.x, 1.0);
1915            assert_eq!(pos.y, 2.0);
1916        }
1917
1918        #[test]
1919        fn test_ref_fetch_entity_without_component() {
1920            let mut world = World::new();
1921            let entity = world.spawn_empty();
1922            world.insert(entity, Velocity { x: 1.0, y: 2.0 });
1923
1924            let state = <&Position>::init_state(&world);
1925            let result = <&Position>::fetch(&state, &world, entity);
1926
1927            assert!(result.is_none());
1928        }
1929
1930        #[test]
1931        fn test_ref_fetch_dead_entity() {
1932            let mut world = World::new();
1933            let entity = world.spawn_empty();
1934            world.insert(entity, Position { x: 1.0, y: 2.0 });
1935            world.despawn(entity);
1936
1937            let state = <&Position>::init_state(&world);
1938            let result = <&Position>::fetch(&state, &world, entity);
1939
1940            assert!(result.is_none());
1941        }
1942
1943        #[test]
1944        fn test_ref_fetch_placeholder_entity() {
1945            let world = World::new();
1946
1947            let state = <&Position>::init_state(&world);
1948            let result = <&Position>::fetch(&state, &world, Entity::PLACEHOLDER);
1949
1950            assert!(result.is_none());
1951        }
1952
1953        #[test]
1954        fn test_ref_is_read_only() {
1955            fn requires_read_only<Q: ReadOnlyWorldQuery>() {}
1956            requires_read_only::<&Position>();
1957            requires_read_only::<&Velocity>();
1958        }
1959
1960        #[test]
1961        fn test_ref_component_access_contains_component_id() {
1962            let state = ComponentId::of::<Position>();
1963            let access = <&Position>::component_access(&state);
1964
1965            assert_eq!(access.len(), 1);
1966            assert!(access.contains(&ComponentId::of::<Position>()));
1967        }
1968
1969        #[test]
1970        fn test_ref_component_access_does_not_contain_other_components() {
1971            let state = ComponentId::of::<Position>();
1972            let access = <&Position>::component_access(&state);
1973
1974            assert!(!access.contains(&ComponentId::of::<Velocity>()));
1975        }
1976
1977        #[test]
1978        fn test_ref_multiple_entities_same_component() {
1979            let mut world = World::new();
1980
1981            let e1 = world.spawn_empty();
1982            world.insert(e1, Position { x: 1.0, y: 2.0 });
1983
1984            let e2 = world.spawn_empty();
1985            world.insert(e2, Position { x: 3.0, y: 4.0 });
1986
1987            let e3 = world.spawn_empty();
1988            world.insert(e3, Position { x: 5.0, y: 6.0 });
1989
1990            let state = <&Position>::init_state(&world);
1991
1992            let p1 = <&Position>::fetch(&state, &world, e1).unwrap();
1993            let p2 = <&Position>::fetch(&state, &world, e2).unwrap();
1994            let p3 = <&Position>::fetch(&state, &world, e3).unwrap();
1995
1996            assert_eq!(p1, &Position { x: 1.0, y: 2.0 });
1997            assert_eq!(p2, &Position { x: 3.0, y: 4.0 });
1998            assert_eq!(p3, &Position { x: 5.0, y: 6.0 });
1999        }
2000
2001        #[test]
2002        fn test_ref_different_component_types() {
2003            let mut world = World::new();
2004            let entity = world.spawn_empty();
2005            world.insert(entity, Position { x: 1.0, y: 2.0 });
2006            world.insert(entity, Velocity { x: 3.0, y: 4.0 });
2007
2008            let pos_state = <&Position>::init_state(&world);
2009            let vel_state = <&Velocity>::init_state(&world);
2010
2011            let pos = <&Position>::fetch(&pos_state, &world, entity).unwrap();
2012            let vel = <&Velocity>::fetch(&vel_state, &world, entity).unwrap();
2013
2014            assert_eq!(pos, &Position { x: 1.0, y: 2.0 });
2015            assert_eq!(vel, &Velocity { x: 3.0, y: 4.0 });
2016        }
2017
2018        #[test]
2019        fn test_ref_fetch_after_component_update() {
2020            let mut world = World::new();
2021            let entity = world.spawn_empty();
2022            world.insert(entity, Position { x: 1.0, y: 2.0 });
2023
2024            let state = <&Position>::init_state(&world);
2025
2026            // Fetch before update
2027            let pos1 = <&Position>::fetch(&state, &world, entity).unwrap();
2028            assert_eq!(pos1, &Position { x: 1.0, y: 2.0 });
2029
2030            // Update component
2031            world.insert(entity, Position { x: 10.0, y: 20.0 });
2032
2033            // Fetch after update
2034            let pos2 = <&Position>::fetch(&state, &world, entity).unwrap();
2035            assert_eq!(pos2, &Position { x: 10.0, y: 20.0 });
2036        }
2037
2038        #[test]
2039        fn test_ref_matches_archetype_with_multiple_components() {
2040            let mut components = BTreeSet::new();
2041            components.insert(ComponentId::of::<Position>());
2042            components.insert(ComponentId::of::<Velocity>());
2043            components.insert(ComponentId::of::<Player>());
2044            let archetype = Archetype::new(ArchetypeId::new(1), components);
2045
2046            let pos_state = ComponentId::of::<Position>();
2047            let vel_state = ComponentId::of::<Velocity>();
2048
2049            assert!(<&Position>::matches_archetype(&pos_state, &archetype));
2050            assert!(<&Velocity>::matches_archetype(&vel_state, &archetype));
2051        }
2052
2053        #[test]
2054        fn test_ref_fetch_returns_correct_reference_type() {
2055            let mut world = World::new();
2056            let entity = world.spawn_empty();
2057            world.insert(entity, Position { x: 42.0, y: 99.0 });
2058
2059            let state = <&Position>::init_state(&world);
2060            let result: Option<&Position> = <&Position>::fetch(&state, &world, entity);
2061
2062            // Verify it's actually a reference (compile-time check via type annotation)
2063            assert!(result.is_some());
2064        }
2065
2066        #[test]
2067        fn test_ref_fetch_stale_entity() {
2068            let mut world = World::new();
2069
2070            // Spawn and despawn to create a stale handle
2071            let entity = world.spawn_empty();
2072            world.insert(entity, Position { x: 1.0, y: 2.0 });
2073            world.despawn(entity);
2074
2075            // Respawn new entity at same index
2076            let new_entity = world.spawn_empty();
2077            world.insert(new_entity, Position { x: 99.0, y: 99.0 });
2078
2079            let state = <&Position>::init_state(&world);
2080
2081            // Old entity handle should not fetch the new entity's component
2082            let result = <&Position>::fetch(&state, &world, entity);
2083            assert!(result.is_none());
2084
2085            // New entity should fetch correctly
2086            let new_result = <&Position>::fetch(&state, &world, new_entity);
2087            assert!(new_result.is_some());
2088            assert_eq!(new_result.unwrap(), &Position { x: 99.0, y: 99.0 });
2089        }
2090
2091        #[test]
2092        fn test_ref_state_is_component_id() {
2093            // Verify that the state type is ComponentId
2094            fn check_state_type<T: crate::ecs::Component>() {
2095                let world = World::new();
2096                let state: ComponentId = <&T>::init_state(&world);
2097                assert_eq!(state, ComponentId::of::<T>());
2098            }
2099
2100            check_state_type::<Position>();
2101            check_state_type::<Velocity>();
2102        }
2103
2104        // Compile-time tests for trait bounds
2105
2106        #[test]
2107        fn test_ref_implements_world_query() {
2108            fn requires_world_query<Q: WorldQuery>() {}
2109            requires_world_query::<&Position>();
2110            requires_world_query::<&Velocity>();
2111            requires_world_query::<&Player>();
2112        }
2113
2114        #[test]
2115        fn test_ref_state_implements_query_state() {
2116            fn requires_query_state<S: QueryState>() {}
2117            // ComponentId should implement QueryState
2118            requires_query_state::<ComponentId>();
2119        }
2120    }
2121
2122    // =========================================================================
2123    // Mutable Component Reference (&mut T) Tests
2124    // =========================================================================
2125
2126    mod mut_component_ref {
2127        use super::*;
2128        use crate::ecs::archetype::{Archetype, ArchetypeId};
2129        use std::collections::BTreeSet;
2130
2131        #[test]
2132        fn test_mut_ref_init_state() {
2133            let world = World::new();
2134            let state = <&mut Position>::init_state(&world);
2135            assert_eq!(state.component_id, ComponentId::of::<Position>());
2136        }
2137
2138        #[test]
2139        fn test_mut_ref_state_is_mut_state() {
2140            // Verify that the state type is MutState
2141            fn check_state_type<T: crate::ecs::Component>() {
2142                let world = World::new();
2143                let state: MutState = <&mut T>::init_state(&world);
2144                assert_eq!(state.component_id, ComponentId::of::<T>());
2145            }
2146
2147            check_state_type::<Position>();
2148            check_state_type::<Velocity>();
2149        }
2150
2151        #[test]
2152        fn test_mut_ref_matches_archetype_with_component() {
2153            let mut components = BTreeSet::new();
2154            components.insert(ComponentId::of::<Position>());
2155            let archetype = Archetype::new(ArchetypeId::new(1), components);
2156
2157            let state = MutState::of::<Position>();
2158            assert!(<&mut Position>::matches_archetype(&state, &archetype));
2159        }
2160
2161        #[test]
2162        fn test_mut_ref_does_not_match_archetype_without_component() {
2163            let mut components = BTreeSet::new();
2164            components.insert(ComponentId::of::<Velocity>());
2165            let archetype = Archetype::new(ArchetypeId::new(1), components);
2166
2167            let state = MutState::of::<Position>();
2168            assert!(!<&mut Position>::matches_archetype(&state, &archetype));
2169        }
2170
2171        #[test]
2172        fn test_mut_ref_does_not_match_empty_archetype() {
2173            let archetype = Archetype::new(ArchetypeId::EMPTY, BTreeSet::new());
2174
2175            let state = MutState::of::<Position>();
2176            assert!(!<&mut Position>::matches_archetype(&state, &archetype));
2177        }
2178
2179        #[test]
2180        fn test_mut_ref_fetch_returns_none() {
2181            // fetch() should return None for mutable queries - use fetch_mut instead
2182            let mut world = World::new();
2183            let entity = world.spawn_empty();
2184            world.insert(entity, Position { x: 1.0, y: 2.0 });
2185
2186            let state = <&mut Position>::init_state(&world);
2187            let result = <&mut Position>::fetch(&state, &world, entity);
2188
2189            // Mutable fetch with immutable world returns None
2190            assert!(result.is_none());
2191        }
2192
2193        #[test]
2194        fn test_mut_ref_fetch_mut_entity_with_component() {
2195            let mut world = World::new();
2196            let entity = world.spawn_empty();
2197            world.insert(entity, Position { x: 1.0, y: 2.0 });
2198
2199            let state = <&mut Position>::init_state(&world);
2200            let result = <&mut Position>::fetch_mut(&state, &mut world, entity);
2201
2202            assert!(result.is_some());
2203            let pos = result.unwrap();
2204            assert_eq!(pos.x, 1.0);
2205            assert_eq!(pos.y, 2.0);
2206        }
2207
2208        #[test]
2209        fn test_mut_ref_fetch_mut_and_modify() {
2210            let mut world = World::new();
2211            let entity = world.spawn_empty();
2212            world.insert(entity, Position { x: 1.0, y: 2.0 });
2213
2214            let state = <&mut Position>::init_state(&world);
2215
2216            // Modify through fetch_mut
2217            if let Some(pos) = <&mut Position>::fetch_mut(&state, &mut world, entity) {
2218                pos.x += 10.0;
2219                pos.y += 20.0;
2220            }
2221
2222            // Verify modification persisted
2223            let pos = world.get::<Position>(entity).unwrap();
2224            assert_eq!(pos.x, 11.0);
2225            assert_eq!(pos.y, 22.0);
2226        }
2227
2228        #[test]
2229        fn test_mut_ref_fetch_mut_entity_without_component() {
2230            let mut world = World::new();
2231            let entity = world.spawn_empty();
2232            world.insert(entity, Velocity { x: 1.0, y: 2.0 });
2233
2234            let state = <&mut Position>::init_state(&world);
2235            let result = <&mut Position>::fetch_mut(&state, &mut world, entity);
2236
2237            assert!(result.is_none());
2238        }
2239
2240        #[test]
2241        fn test_mut_ref_fetch_mut_dead_entity() {
2242            let mut world = World::new();
2243            let entity = world.spawn_empty();
2244            world.insert(entity, Position { x: 1.0, y: 2.0 });
2245            world.despawn(entity);
2246
2247            let state = <&mut Position>::init_state(&world);
2248            let result = <&mut Position>::fetch_mut(&state, &mut world, entity);
2249
2250            assert!(result.is_none());
2251        }
2252
2253        #[test]
2254        fn test_mut_ref_fetch_mut_placeholder_entity() {
2255            let mut world = World::new();
2256
2257            let state = <&mut Position>::init_state(&world);
2258            let result = <&mut Position>::fetch_mut(&state, &mut world, Entity::PLACEHOLDER);
2259
2260            assert!(result.is_none());
2261        }
2262
2263        #[test]
2264        fn test_mut_ref_is_not_read_only() {
2265            // Compile-time test: &mut T does NOT implement ReadOnlyWorldQuery
2266            // This test ensures the trait bound fails - verified by the comment
2267            // fn requires_read_only<Q: ReadOnlyWorldQuery>() {}
2268            // requires_read_only::<&mut Position>(); // Should fail to compile
2269
2270            // Instead, verify that WorldQuery is implemented
2271            fn requires_world_query<Q: WorldQuery>() {}
2272            requires_world_query::<&mut Position>();
2273        }
2274
2275        #[test]
2276        fn test_mut_ref_component_access_contains_component_id() {
2277            let state = MutState::of::<Position>();
2278            let access = <&mut Position>::component_access(&state);
2279
2280            assert_eq!(access.len(), 1);
2281            assert!(access.contains(&ComponentId::of::<Position>()));
2282        }
2283
2284        #[test]
2285        fn test_mut_ref_component_access_does_not_contain_other_components() {
2286            let state = MutState::of::<Position>();
2287            let access = <&mut Position>::component_access(&state);
2288
2289            assert!(!access.contains(&ComponentId::of::<Velocity>()));
2290        }
2291
2292        #[test]
2293        fn test_mut_ref_fetch_mut_stale_entity() {
2294            let mut world = World::new();
2295
2296            // Spawn and despawn to create a stale handle
2297            let entity = world.spawn_empty();
2298            world.insert(entity, Position { x: 1.0, y: 2.0 });
2299            world.despawn(entity);
2300
2301            // Respawn new entity at same index
2302            let new_entity = world.spawn_empty();
2303            world.insert(new_entity, Position { x: 99.0, y: 99.0 });
2304
2305            let state = <&mut Position>::init_state(&world);
2306
2307            // Old entity handle should not fetch the new entity's component
2308            let result = <&mut Position>::fetch_mut(&state, &mut world, entity);
2309            assert!(result.is_none());
2310
2311            // New entity should fetch correctly
2312            let new_result = <&mut Position>::fetch_mut(&state, &mut world, new_entity);
2313            assert!(new_result.is_some());
2314            assert_eq!(new_result.unwrap().x, 99.0);
2315        }
2316
2317        #[test]
2318        fn test_mut_ref_implements_world_query() {
2319            fn requires_world_query<Q: WorldQuery>() {}
2320            requires_world_query::<&mut Position>();
2321            requires_world_query::<&mut Velocity>();
2322            requires_world_query::<&mut Player>();
2323        }
2324
2325        #[test]
2326        fn test_mut_state_implements_query_state() {
2327            fn requires_query_state<S: QueryState>() {}
2328            requires_query_state::<MutState>();
2329        }
2330
2331        #[test]
2332        fn test_mut_ref_matches_archetype_with_multiple_components() {
2333            let mut components = BTreeSet::new();
2334            components.insert(ComponentId::of::<Position>());
2335            components.insert(ComponentId::of::<Velocity>());
2336            components.insert(ComponentId::of::<Player>());
2337            let archetype = Archetype::new(ArchetypeId::new(1), components);
2338
2339            let pos_state = MutState::of::<Position>();
2340            let vel_state = MutState::of::<Velocity>();
2341
2342            assert!(<&mut Position>::matches_archetype(&pos_state, &archetype));
2343            assert!(<&mut Velocity>::matches_archetype(&vel_state, &archetype));
2344        }
2345
2346        #[test]
2347        fn test_mut_ref_fetch_mut_returns_correct_reference_type() {
2348            let mut world = World::new();
2349            let entity = world.spawn_empty();
2350            world.insert(entity, Position { x: 42.0, y: 99.0 });
2351
2352            let state = <&mut Position>::init_state(&world);
2353            let result: Option<&mut Position> =
2354                <&mut Position>::fetch_mut(&state, &mut world, entity);
2355
2356            // Verify it's actually a mutable reference (compile-time check via type annotation)
2357            assert!(result.is_some());
2358        }
2359
2360        #[test]
2361        fn test_mut_ref_different_component_types() {
2362            let mut world = World::new();
2363            let entity = world.spawn_empty();
2364            world.insert(entity, Position { x: 1.0, y: 2.0 });
2365            world.insert(entity, Velocity { x: 3.0, y: 4.0 });
2366
2367            let pos_state = <&mut Position>::init_state(&world);
2368
2369            // Modify position
2370            if let Some(pos) = <&mut Position>::fetch_mut(&pos_state, &mut world, entity) {
2371                pos.x = 100.0;
2372            }
2373
2374            // Velocity should be unchanged
2375            let vel = world.get::<Velocity>(entity).unwrap();
2376            assert_eq!(vel.x, 3.0);
2377            assert_eq!(vel.y, 4.0);
2378
2379            // Position should be modified
2380            let pos = world.get::<Position>(entity).unwrap();
2381            assert_eq!(pos.x, 100.0);
2382        }
2383    }
2384
2385    // =========================================================================
2386    // Access Conflict Detection Tests
2387    // =========================================================================
2388
2389    mod access_conflict {
2390        use super::*;
2391
2392        #[test]
2393        fn test_access_new_is_empty() {
2394            let access = Access::new();
2395            assert!(access.is_read_only());
2396            assert_eq!(access.writes().len(), 0);
2397            assert_eq!(access.reads().count(), 0);
2398        }
2399
2400        #[test]
2401        fn test_access_add_read() {
2402            let mut access = Access::new();
2403            let id = ComponentId::of::<Position>();
2404            access.add_read(id);
2405
2406            assert!(access.is_read_only());
2407            assert!(access.reads().any(|&x| x == id));
2408            assert!(!access.writes().contains(&id));
2409        }
2410
2411        #[test]
2412        fn test_access_add_write() {
2413            let mut access = Access::new();
2414            let id = ComponentId::of::<Position>();
2415            access.add_write(id);
2416
2417            assert!(!access.is_read_only());
2418            assert!(access.writes().contains(&id));
2419        }
2420
2421        #[test]
2422        fn test_access_write_counts_as_read() {
2423            let mut access = Access::new();
2424            let id = ComponentId::of::<Position>();
2425            access.add_write(id);
2426
2427            // writes() includes writes
2428            assert!(access.writes().contains(&id));
2429            // reads() includes both reads and writes
2430            assert!(access.reads().any(|&x| x == id));
2431        }
2432
2433        #[test]
2434        fn test_access_reads_only() {
2435            let mut access = Access::new();
2436            let pos_id = ComponentId::of::<Position>();
2437            let vel_id = ComponentId::of::<Velocity>();
2438
2439            access.add_read(pos_id);
2440            access.add_write(vel_id);
2441
2442            // reads_only should only include Position (read, not written)
2443            let reads_only: Vec<_> = access.reads_only().cloned().collect();
2444            assert!(reads_only.contains(&pos_id));
2445            assert!(!reads_only.contains(&vel_id));
2446        }
2447
2448        #[test]
2449        fn test_access_no_conflict_between_reads() {
2450            let mut access1 = Access::new();
2451            let mut access2 = Access::new();
2452            let id = ComponentId::of::<Position>();
2453
2454            access1.add_read(id);
2455            access2.add_read(id);
2456
2457            // Two reads of the same component don't conflict
2458            assert!(!access1.conflicts_with(&access2));
2459            assert!(!access2.conflicts_with(&access1));
2460        }
2461
2462        #[test]
2463        fn test_access_conflict_write_read() {
2464            let mut access1 = Access::new();
2465            let mut access2 = Access::new();
2466            let id = ComponentId::of::<Position>();
2467
2468            access1.add_write(id);
2469            access2.add_read(id);
2470
2471            // Write + Read of same component conflicts
2472            assert!(access1.conflicts_with(&access2));
2473            assert!(access2.conflicts_with(&access1));
2474        }
2475
2476        #[test]
2477        fn test_access_conflict_write_write() {
2478            let mut access1 = Access::new();
2479            let mut access2 = Access::new();
2480            let id = ComponentId::of::<Position>();
2481
2482            access1.add_write(id);
2483            access2.add_write(id);
2484
2485            // Two writes to same component conflict
2486            assert!(access1.conflicts_with(&access2));
2487            assert!(access2.conflicts_with(&access1));
2488        }
2489
2490        #[test]
2491        fn test_access_no_conflict_different_components() {
2492            let mut access1 = Access::new();
2493            let mut access2 = Access::new();
2494
2495            access1.add_write(ComponentId::of::<Position>());
2496            access2.add_write(ComponentId::of::<Velocity>());
2497
2498            // Writes to different components don't conflict
2499            assert!(!access1.conflicts_with(&access2));
2500            assert!(!access2.conflicts_with(&access1));
2501        }
2502
2503        #[test]
2504        fn test_access_no_conflict_read_different_write() {
2505            let mut access1 = Access::new();
2506            let mut access2 = Access::new();
2507
2508            access1.add_read(ComponentId::of::<Position>());
2509            access2.add_write(ComponentId::of::<Velocity>());
2510
2511            // Read Position, Write Velocity - no conflict
2512            assert!(!access1.conflicts_with(&access2));
2513            assert!(!access2.conflicts_with(&access1));
2514        }
2515
2516        #[test]
2517        fn test_access_extend() {
2518            let mut access1 = Access::new();
2519            let mut access2 = Access::new();
2520
2521            access1.add_read(ComponentId::of::<Position>());
2522            access2.add_write(ComponentId::of::<Velocity>());
2523
2524            access1.extend(&access2);
2525
2526            assert!(access1.reads().any(|&x| x == ComponentId::of::<Position>()));
2527            assert!(access1.writes().contains(&ComponentId::of::<Velocity>()));
2528        }
2529
2530        #[test]
2531        fn test_access_is_read_only() {
2532            let mut read_access = Access::new();
2533            read_access.add_read(ComponentId::of::<Position>());
2534            assert!(read_access.is_read_only());
2535
2536            let mut write_access = Access::new();
2537            write_access.add_write(ComponentId::of::<Position>());
2538            assert!(!write_access.is_read_only());
2539        }
2540
2541        #[test]
2542        fn test_access_complex_scenario() {
2543            // Simulate two systems:
2544            // System A: reads Position, writes Velocity
2545            // System B: reads Position, reads Velocity
2546            // Should NOT conflict (no same-component write conflicts)
2547
2548            let mut access_a = Access::new();
2549            access_a.add_read(ComponentId::of::<Position>());
2550            access_a.add_write(ComponentId::of::<Velocity>());
2551
2552            let mut access_b = Access::new();
2553            access_b.add_read(ComponentId::of::<Position>());
2554            access_b.add_read(ComponentId::of::<Velocity>());
2555
2556            // System B reads Velocity, System A writes Velocity - CONFLICT
2557            assert!(access_a.conflicts_with(&access_b));
2558            assert!(access_b.conflicts_with(&access_a));
2559        }
2560
2561        #[test]
2562        fn test_access_no_conflict_complex() {
2563            // System A: writes Position
2564            // System B: writes Velocity, reads Player
2565            // Should NOT conflict
2566
2567            let mut access_a = Access::new();
2568            access_a.add_write(ComponentId::of::<Position>());
2569
2570            let mut access_b = Access::new();
2571            access_b.add_write(ComponentId::of::<Velocity>());
2572            access_b.add_read(ComponentId::of::<Player>());
2573
2574            assert!(!access_a.conflicts_with(&access_b));
2575            assert!(!access_b.conflicts_with(&access_a));
2576        }
2577
2578        #[test]
2579        fn test_access_is_empty() {
2580            let access = Access::new();
2581            assert!(access.is_empty());
2582
2583            let mut not_empty = Access::new();
2584            not_empty.add_read(ComponentId::of::<Position>());
2585            assert!(!not_empty.is_empty());
2586        }
2587
2588        #[test]
2589        fn test_access_clear() {
2590            let mut access = Access::new();
2591            access.add_read(ComponentId::of::<Position>());
2592            access.add_write(ComponentId::of::<Velocity>());
2593
2594            assert!(!access.is_empty());
2595            access.clear();
2596            assert!(access.is_empty());
2597        }
2598
2599        // =====================================================================
2600        // get_conflicts tests
2601        // =====================================================================
2602
2603        #[test]
2604        fn test_get_conflicts_no_conflict() {
2605            let mut access1 = Access::new();
2606            access1.add_read(ComponentId::of::<Position>());
2607
2608            let mut access2 = Access::new();
2609            access2.add_read(ComponentId::of::<Position>());
2610
2611            assert!(access1.get_conflicts(&access2).is_none());
2612        }
2613
2614        #[test]
2615        fn test_get_conflicts_write_read() {
2616            let mut access1 = Access::new();
2617            access1.add_write(ComponentId::of::<Position>());
2618
2619            let mut access2 = Access::new();
2620            access2.add_read(ComponentId::of::<Position>());
2621
2622            let conflict = access1.get_conflicts(&access2);
2623            assert!(conflict.is_some());
2624
2625            let conflict = conflict.unwrap();
2626            assert_eq!(conflict.component_count(), 1);
2627            assert!(!conflict.has_write_write());
2628
2629            let comp_conflict = &conflict.component_conflicts()[0];
2630            assert_eq!(comp_conflict.component_id, ComponentId::of::<Position>());
2631            assert_eq!(comp_conflict.first_access, AccessType::Write);
2632            assert_eq!(comp_conflict.second_access, AccessType::Read);
2633        }
2634
2635        #[test]
2636        fn test_get_conflicts_write_write() {
2637            let mut access1 = Access::new();
2638            access1.add_write(ComponentId::of::<Position>());
2639
2640            let mut access2 = Access::new();
2641            access2.add_write(ComponentId::of::<Position>());
2642
2643            let conflict = access1.get_conflicts(&access2);
2644            assert!(conflict.is_some());
2645
2646            let conflict = conflict.unwrap();
2647            assert!(conflict.has_write_write());
2648
2649            let comp_conflict = &conflict.component_conflicts()[0];
2650            assert!(comp_conflict.is_write_write());
2651        }
2652
2653        #[test]
2654        fn test_get_conflicts_multiple_components() {
2655            let mut access1 = Access::new();
2656            access1.add_write(ComponentId::of::<Position>());
2657            access1.add_write(ComponentId::of::<Velocity>());
2658
2659            let mut access2 = Access::new();
2660            access2.add_read(ComponentId::of::<Position>());
2661            access2.add_read(ComponentId::of::<Velocity>());
2662
2663            let conflict = access1.get_conflicts(&access2).unwrap();
2664            assert_eq!(conflict.component_count(), 2);
2665            assert_eq!(conflict.total_count(), 2);
2666        }
2667
2668        #[test]
2669        fn test_get_conflicts_partial() {
2670            // access1 writes Position
2671            // access2 reads Position and writes Velocity
2672            let mut access1 = Access::new();
2673            access1.add_write(ComponentId::of::<Position>());
2674
2675            let mut access2 = Access::new();
2676            access2.add_read(ComponentId::of::<Position>());
2677            access2.add_write(ComponentId::of::<Velocity>());
2678
2679            let conflict = access1.get_conflicts(&access2).unwrap();
2680            // Only Position conflicts (access1 writes it, access2 reads it)
2681            assert_eq!(conflict.component_count(), 1);
2682
2683            let conflicting: Vec<_> = conflict.conflicting_components().collect();
2684            assert_eq!(conflicting.len(), 1);
2685            assert_eq!(conflicting[0], ComponentId::of::<Position>());
2686        }
2687
2688        #[test]
2689        fn test_get_conflicts_read_vs_write() {
2690            // access1 reads, access2 writes - should still conflict
2691            let mut access1 = Access::new();
2692            access1.add_read(ComponentId::of::<Position>());
2693
2694            let mut access2 = Access::new();
2695            access2.add_write(ComponentId::of::<Position>());
2696
2697            let conflict = access1.get_conflicts(&access2).unwrap();
2698            assert_eq!(conflict.component_count(), 1);
2699
2700            let comp_conflict = &conflict.component_conflicts()[0];
2701            assert_eq!(comp_conflict.first_access, AccessType::Read);
2702            assert_eq!(comp_conflict.second_access, AccessType::Write);
2703            assert!(comp_conflict.is_read_write());
2704        }
2705    }
2706
2707    // =========================================================================
2708    // ConflictInfo Tests
2709    // =========================================================================
2710
2711    mod conflict_info {
2712        use super::*;
2713
2714        #[test]
2715        fn test_conflict_info_new() {
2716            let info = ConflictInfo::new(
2717                ComponentId::of::<Position>(),
2718                AccessType::Write,
2719                AccessType::Read,
2720            );
2721
2722            assert_eq!(info.component_id, ComponentId::of::<Position>());
2723            assert_eq!(info.first_access, AccessType::Write);
2724            assert_eq!(info.second_access, AccessType::Read);
2725        }
2726
2727        #[test]
2728        fn test_conflict_info_is_write_write() {
2729            let write_write = ConflictInfo::new(
2730                ComponentId::of::<Position>(),
2731                AccessType::Write,
2732                AccessType::Write,
2733            );
2734            assert!(write_write.is_write_write());
2735
2736            let write_read = ConflictInfo::new(
2737                ComponentId::of::<Position>(),
2738                AccessType::Write,
2739                AccessType::Read,
2740            );
2741            assert!(!write_read.is_write_write());
2742        }
2743
2744        #[test]
2745        fn test_conflict_info_is_read_write() {
2746            let write_read = ConflictInfo::new(
2747                ComponentId::of::<Position>(),
2748                AccessType::Write,
2749                AccessType::Read,
2750            );
2751            assert!(write_read.is_read_write());
2752
2753            let read_write = ConflictInfo::new(
2754                ComponentId::of::<Position>(),
2755                AccessType::Read,
2756                AccessType::Write,
2757            );
2758            assert!(read_write.is_read_write());
2759
2760            let write_write = ConflictInfo::new(
2761                ComponentId::of::<Position>(),
2762                AccessType::Write,
2763                AccessType::Write,
2764            );
2765            assert!(!write_write.is_read_write());
2766        }
2767
2768        #[test]
2769        fn test_conflict_info_display() {
2770            let info = ConflictInfo::new(
2771                ComponentId::of::<Position>(),
2772                AccessType::Write,
2773                AccessType::Read,
2774            );
2775            let display = format!("{}", info);
2776            assert!(display.contains("Component"));
2777            assert!(display.contains("Write"));
2778            assert!(display.contains("Read"));
2779        }
2780    }
2781
2782    // =========================================================================
2783    // AccessConflict Tests
2784    // =========================================================================
2785
2786    mod access_conflict_struct {
2787        use super::*;
2788
2789        #[test]
2790        fn test_access_conflict_new() {
2791            let conflict = AccessConflict::new();
2792            assert!(conflict.is_empty());
2793            assert_eq!(conflict.component_count(), 0);
2794            assert_eq!(conflict.resource_count(), 0);
2795            assert_eq!(conflict.non_send_count(), 0);
2796            assert_eq!(conflict.total_count(), 0);
2797        }
2798
2799        #[test]
2800        fn test_access_conflict_default() {
2801            let conflict: AccessConflict = Default::default();
2802            assert!(conflict.is_empty());
2803        }
2804
2805        #[test]
2806        fn test_access_conflict_display() {
2807            let mut access1 = Access::new();
2808            access1.add_write(ComponentId::of::<Position>());
2809
2810            let mut access2 = Access::new();
2811            access2.add_read(ComponentId::of::<Position>());
2812
2813            let conflict = access1.get_conflicts(&access2).unwrap();
2814            let display = format!("{}", conflict);
2815
2816            assert!(display.contains("AccessConflict"));
2817            assert!(display.contains("Component"));
2818        }
2819
2820        #[test]
2821        fn test_access_conflict_has_write_write() {
2822            let mut access1 = Access::new();
2823            access1.add_write(ComponentId::of::<Position>());
2824
2825            let mut access2 = Access::new();
2826            access2.add_write(ComponentId::of::<Position>());
2827
2828            let conflict = access1.get_conflicts(&access2).unwrap();
2829            assert!(conflict.has_write_write());
2830        }
2831
2832        #[test]
2833        fn test_access_conflict_has_write_write_false() {
2834            let mut access1 = Access::new();
2835            access1.add_write(ComponentId::of::<Position>());
2836
2837            let mut access2 = Access::new();
2838            access2.add_read(ComponentId::of::<Position>());
2839
2840            let conflict = access1.get_conflicts(&access2).unwrap();
2841            assert!(!conflict.has_write_write());
2842        }
2843
2844        #[test]
2845        fn test_access_conflict_conflicting_components_iter() {
2846            let mut access1 = Access::new();
2847            access1.add_write(ComponentId::of::<Position>());
2848            access1.add_write(ComponentId::of::<Velocity>());
2849
2850            let mut access2 = Access::new();
2851            access2.add_read(ComponentId::of::<Position>());
2852            access2.add_read(ComponentId::of::<Velocity>());
2853
2854            let conflict = access1.get_conflicts(&access2).unwrap();
2855            let components: Vec<_> = conflict.conflicting_components().collect();
2856
2857            assert_eq!(components.len(), 2);
2858            assert!(components.contains(&ComponentId::of::<Position>()));
2859            assert!(components.contains(&ComponentId::of::<Velocity>()));
2860        }
2861
2862        #[test]
2863        fn test_access_conflict_clone() {
2864            let mut access1 = Access::new();
2865            access1.add_write(ComponentId::of::<Position>());
2866
2867            let mut access2 = Access::new();
2868            access2.add_read(ComponentId::of::<Position>());
2869
2870            let conflict = access1.get_conflicts(&access2).unwrap();
2871            let cloned = conflict.clone();
2872
2873            assert_eq!(conflict.total_count(), cloned.total_count());
2874        }
2875    }
2876
2877    // =========================================================================
2878    // MutState Tests
2879    // =========================================================================
2880
2881    mod mut_state {
2882        use super::*;
2883
2884        #[test]
2885        fn test_mut_state_of() {
2886            let state = MutState::of::<Position>();
2887            assert_eq!(state.component_id, ComponentId::of::<Position>());
2888        }
2889
2890        #[test]
2891        fn test_mut_state_different_types() {
2892            let pos_state = MutState::of::<Position>();
2893            let vel_state = MutState::of::<Velocity>();
2894
2895            assert_ne!(pos_state.component_id, vel_state.component_id);
2896        }
2897
2898        #[test]
2899        fn test_mut_state_implements_query_state() {
2900            fn requires_query_state<S: QueryState>() {}
2901            requires_query_state::<MutState>();
2902        }
2903
2904        #[test]
2905        fn test_mut_state_is_send_sync() {
2906            fn requires_send_sync<T: Send + Sync>() {}
2907            requires_send_sync::<MutState>();
2908        }
2909
2910        #[test]
2911        fn test_mut_state_is_clone() {
2912            let state = MutState::of::<Position>();
2913            let cloned = state.clone();
2914            assert_eq!(state, cloned);
2915        }
2916
2917        #[test]
2918        fn test_mut_state_debug() {
2919            let state = MutState::of::<Position>();
2920            let debug_str = format!("{:?}", state);
2921            // Should contain "MutState" and component_id info
2922            assert!(debug_str.contains("MutState"));
2923        }
2924    }
2925
2926    // =========================================================================
2927    // WriteAccess Tests
2928    // =========================================================================
2929
2930    mod write_access {
2931        use super::*;
2932
2933        #[test]
2934        fn test_write_access_new() {
2935            let id = ComponentId::of::<Position>();
2936            let access = WriteAccess(id);
2937            assert_eq!(access.0, id);
2938        }
2939
2940        #[test]
2941        fn test_write_access_equality() {
2942            let id1 = ComponentId::of::<Position>();
2943            let id2 = ComponentId::of::<Position>();
2944            let id3 = ComponentId::of::<Velocity>();
2945
2946            assert_eq!(WriteAccess(id1), WriteAccess(id2));
2947            assert_ne!(WriteAccess(id1), WriteAccess(id3));
2948        }
2949
2950        #[test]
2951        fn test_write_access_hash() {
2952            use std::collections::HashSet;
2953
2954            let id1 = ComponentId::of::<Position>();
2955            let id2 = ComponentId::of::<Velocity>();
2956
2957            let mut set = HashSet::new();
2958            set.insert(WriteAccess(id1));
2959            set.insert(WriteAccess(id2));
2960
2961            assert_eq!(set.len(), 2);
2962            assert!(set.contains(&WriteAccess(id1)));
2963            assert!(set.contains(&WriteAccess(id2)));
2964        }
2965
2966        #[test]
2967        fn test_write_access_ordering() {
2968            use std::collections::BTreeSet;
2969
2970            let id1 = ComponentId::of::<Position>();
2971            let id2 = ComponentId::of::<Velocity>();
2972
2973            let mut set = BTreeSet::new();
2974            set.insert(WriteAccess(id1));
2975            set.insert(WriteAccess(id2));
2976
2977            // Should be orderable (needed for deterministic conflict detection)
2978            assert_eq!(set.len(), 2);
2979        }
2980    }
2981
2982    // =========================================================================
2983    // Documentation Tests
2984    // =========================================================================
2985
2986    mod documentation {
2987        use super::*;
2988
2989        #[test]
2990        fn test_world_query_trait_documentation_example() {
2991            // From the trait documentation
2992            fn query_requires_world_query<Q: WorldQuery>() {}
2993            query_requires_world_query::<Entity>();
2994        }
2995
2996        #[test]
2997        fn test_query_state_documentation_example() {
2998            fn requires_query_state<S: QueryState>() {}
2999            requires_query_state::<ComponentId>();
3000        }
3001
3002        #[test]
3003        fn test_with_filter_usage_documentation() {
3004            // With<T> filters but doesn't fetch data
3005            let mut world = World::new();
3006            let e1 = world.spawn_empty();
3007            world.insert(e1, Position { x: 0.0, y: 0.0 });
3008            world.insert(e1, Player);
3009
3010            let e2 = world.spawn_empty();
3011            world.insert(e2, Position { x: 1.0, y: 1.0 });
3012            // e2 doesn't have Player
3013
3014            let state = With::<Player>::init_state(&world);
3015
3016            // e1 matches With<Player>
3017            assert!(With::<Player>::fetch(&state, &world, e1).is_some());
3018            // e2 doesn't match
3019            assert!(With::<Player>::fetch(&state, &world, e2).is_none());
3020        }
3021    }
3022
3023    // =========================================================================
3024    // Tuple Query Tests
3025    // =========================================================================
3026
3027    mod tuple_queries {
3028        use super::*;
3029
3030        #[derive(Debug, Clone, Copy, PartialEq)]
3031        struct Position {
3032            x: f32,
3033            y: f32,
3034        }
3035        impl Component for Position {}
3036
3037        #[derive(Debug, Clone, Copy, PartialEq)]
3038        struct Velocity {
3039            x: f32,
3040            y: f32,
3041        }
3042        impl Component for Velocity {}
3043
3044        #[derive(Debug, Clone, Copy)]
3045        struct Health(f32);
3046        impl Component for Health {}
3047
3048        #[test]
3049        fn test_tuple_2_init_state() {
3050            let mut world = World::new();
3051            let state = <(&Position, &Velocity)>::init_state(&world);
3052            let (pos_id, vel_id) = state;
3053            assert_eq!(pos_id, ComponentId::of::<Position>());
3054            assert_eq!(vel_id, ComponentId::of::<Velocity>());
3055        }
3056
3057        #[test]
3058        fn test_tuple_2_component_access() {
3059            let mut world = World::new();
3060            let state = <(&Position, &Velocity)>::init_state(&world);
3061            let access = <(&Position, &Velocity)>::component_access(&state);
3062
3063            assert_eq!(access.len(), 2);
3064            assert!(access.contains(&ComponentId::of::<Position>()));
3065            assert!(access.contains(&ComponentId::of::<Velocity>()));
3066        }
3067
3068        #[test]
3069        fn test_tuple_2_fetch() {
3070            let mut world = World::new();
3071            let entity = world.spawn_empty();
3072            world.insert(entity, Position { x: 1.0, y: 2.0 });
3073            world.insert(entity, Velocity { x: 3.0, y: 4.0 });
3074
3075            let state = <(&Position, &Velocity)>::init_state(&world);
3076            let result = <(&Position, &Velocity)>::fetch(&state, &world, entity);
3077
3078            assert!(result.is_some());
3079            let (pos, vel) = result.unwrap();
3080            assert_eq!(pos.x, 1.0);
3081            assert_eq!(pos.y, 2.0);
3082            assert_eq!(vel.x, 3.0);
3083            assert_eq!(vel.y, 4.0);
3084        }
3085
3086        #[test]
3087        fn test_tuple_2_fetch_missing_component() {
3088            let mut world = World::new();
3089            let entity = world.spawn_empty();
3090            world.insert(entity, Position { x: 1.0, y: 2.0 });
3091            // Missing Velocity
3092
3093            let state = <(&Position, &Velocity)>::init_state(&world);
3094            let result = <(&Position, &Velocity)>::fetch(&state, &world, entity);
3095
3096            assert!(result.is_none());
3097        }
3098
3099        #[test]
3100        fn test_tuple_3_fetch() {
3101            let mut world = World::new();
3102            let entity = world.spawn_empty();
3103            world.insert(entity, Position { x: 1.0, y: 2.0 });
3104            world.insert(entity, Velocity { x: 3.0, y: 4.0 });
3105            world.insert(entity, Health(100.0));
3106
3107            let state = <(&Position, &Velocity, &Health)>::init_state(&world);
3108            let result = <(&Position, &Velocity, &Health)>::fetch(&state, &world, entity);
3109
3110            assert!(result.is_some());
3111            let (pos, vel, health) = result.unwrap();
3112            assert_eq!(pos.x, 1.0);
3113            assert_eq!(vel.x, 3.0);
3114            assert_eq!(health.0, 100.0);
3115        }
3116
3117        #[test]
3118        fn test_tuple_with_entity() {
3119            let mut world = World::new();
3120            let entity = world.spawn_empty();
3121            world.insert(entity, Position { x: 1.0, y: 2.0 });
3122
3123            let state = <(Entity, &Position)>::init_state(&world);
3124            let result = <(Entity, &Position)>::fetch(&state, &world, entity);
3125
3126            assert!(result.is_some());
3127            let (e, pos) = result.unwrap();
3128            assert_eq!(e, entity);
3129            assert_eq!(pos.x, 1.0);
3130        }
3131
3132        #[test]
3133        fn test_tuple_is_read_only() {
3134            // Tuple of all ReadOnlyWorldQuery types should be ReadOnlyWorldQuery
3135            fn assert_read_only<T: ReadOnlyWorldQuery>() {}
3136            assert_read_only::<(&Position, &Velocity)>();
3137            assert_read_only::<(Entity, &Position)>();
3138        }
3139
3140        #[test]
3141        fn test_tuple_matches_archetype() {
3142            let mut world = World::new();
3143
3144            // Create entity with both components
3145            let entity = world.spawn_empty();
3146            world.insert(entity, Position { x: 1.0, y: 2.0 });
3147            world.insert(entity, Velocity { x: 3.0, y: 4.0 });
3148
3149            let archetype_id = world.entity_archetype(entity).unwrap();
3150            let archetype = world.archetypes().get(archetype_id).unwrap();
3151
3152            let state = <(&Position, &Velocity)>::init_state(&world);
3153            assert!(<(&Position, &Velocity)>::matches_archetype(
3154                &state, archetype
3155            ));
3156
3157            // Create entity with only Position
3158            let entity2 = world.spawn_empty();
3159            world.insert(entity2, Position { x: 5.0, y: 6.0 });
3160
3161            let archetype_id2 = world.entity_archetype(entity2).unwrap();
3162            let archetype2 = world.archetypes().get(archetype_id2).unwrap();
3163
3164            // Should not match because Velocity is missing
3165            assert!(!<(&Position, &Velocity)>::matches_archetype(
3166                &state, archetype2
3167            ));
3168        }
3169
3170        #[test]
3171        fn test_tuple_4_elements() {
3172            let mut world = World::new();
3173            let state = <(&Position, &Velocity, &Health, Entity)>::init_state(&world);
3174            let access = <(&Position, &Velocity, &Health, Entity)>::component_access(&state);
3175
3176            // Entity doesn't contribute to component access
3177            assert_eq!(access.len(), 3);
3178        }
3179
3180        #[test]
3181        fn test_tuple_with_filters() {
3182            let mut world = World::new();
3183            let state = <(&Position, With<Velocity>)>::init_state(&world);
3184            let access = <(&Position, With<Velocity>)>::component_access(&state);
3185
3186            // With<T> filter doesn't add to access (it's a filter, not data fetch)
3187            assert_eq!(access.len(), 1);
3188            assert!(access.contains(&ComponentId::of::<Position>()));
3189        }
3190    }
3191}