Skip to main content

elevator_core/query/
fetch.rs

1//! The `WorldQuery` trait and implementations for fetching component data.
2
3use std::marker::PhantomData;
4
5use crate::entity::EntityId;
6use crate::world::World;
7
8/// Describes what data a query fetches for each matching entity.
9///
10/// Implementations exist for:
11/// - `EntityId` — passes through the entity ID
12/// - `&T` for built-in components — reads from the component's `SecondaryMap`
13/// - `Option<&T>` for built-in components — optional read (always matches)
14/// - `&Ext<T>` for extension components — read from extension storage
15/// - Tuples of the above (up to arity 8)
16pub trait WorldQuery {
17    /// The item yielded per entity.
18    type Item<'w>;
19
20    /// Try to fetch data for a single entity. Returns `None` if missing.
21    fn fetch(world: &World, id: EntityId) -> Option<Self::Item<'_>>;
22
23    /// Check component presence without extracting data.
24    fn contains(world: &World, id: EntityId) -> bool;
25}
26
27/// Marker type for querying extension components.
28///
29/// Extension values are read by reference from type-erased storage.
30pub struct Ext<T>(PhantomData<T>);
31
32/// Marker type for mutable extension queries.
33pub struct ExtMut<T>(PhantomData<T>);
34
35impl WorldQuery for EntityId {
36    type Item<'w> = Self;
37
38    fn fetch(_world: &World, id: EntityId) -> Option<Self::Item<'_>> {
39        Some(id)
40    }
41
42    fn contains(_world: &World, _id: EntityId) -> bool {
43        true
44    }
45}
46
47/// Generate `WorldQuery` impls for a built-in component stored as a `SecondaryMap` field.
48macro_rules! impl_builtin_query {
49    ($comp:ty, $field:ident) => {
50        impl WorldQuery for &$comp {
51            type Item<'w> = &'w $comp;
52
53            fn fetch(world: &World, id: EntityId) -> Option<Self::Item<'_>> {
54                world.$field.get(id)
55            }
56
57            fn contains(world: &World, id: EntityId) -> bool {
58                world.$field.contains_key(id)
59            }
60        }
61
62        impl WorldQuery for Option<&$comp> {
63            type Item<'w> = Option<&'w $comp>;
64
65            fn fetch(world: &World, id: EntityId) -> Option<Self::Item<'_>> {
66                Some(world.$field.get(id))
67            }
68
69            fn contains(_world: &World, _id: EntityId) -> bool {
70                true
71            }
72        }
73    };
74}
75
76impl_builtin_query!(crate::components::Position, positions);
77impl_builtin_query!(crate::components::Velocity, velocities);
78impl_builtin_query!(crate::components::Elevator, elevators);
79impl_builtin_query!(crate::components::Stop, stops);
80impl_builtin_query!(crate::components::Rider, riders);
81impl_builtin_query!(crate::components::Route, routes);
82impl_builtin_query!(crate::components::Line, lines);
83impl_builtin_query!(crate::components::Patience, patience);
84impl_builtin_query!(crate::components::Preferences, preferences);
85
86impl<T: 'static + Send + Sync> WorldQuery for &Ext<T> {
87    type Item<'w> = &'w T;
88
89    fn fetch(world: &World, id: EntityId) -> Option<Self::Item<'_>> {
90        world.ext_map::<T>()?.get(id)
91    }
92
93    fn contains(world: &World, id: EntityId) -> bool {
94        world.ext_map::<T>().is_some_and(|m| m.contains_key(id))
95    }
96}
97
98/// Generate `WorldQuery` for tuples of queries.
99macro_rules! impl_tuple_query {
100    ($($name:ident),+) => {
101        #[allow(non_snake_case)]
102        impl<$($name: WorldQuery),+> WorldQuery for ($($name,)+) {
103            type Item<'w> = ($($name::Item<'w>,)+);
104
105            fn fetch(world: &World, id: EntityId) -> Option<Self::Item<'_>> {
106                Some(($($name::fetch(world, id)?,)+))
107            }
108
109            fn contains(world: &World, id: EntityId) -> bool {
110                $($name::contains(world, id) &&)+ true
111            }
112        }
113    };
114}
115
116impl_tuple_query!(A);
117impl_tuple_query!(A, B);
118impl_tuple_query!(A, B, C);
119impl_tuple_query!(A, B, C, D);
120impl_tuple_query!(A, B, C, D, E);
121impl_tuple_query!(A, B, C, D, E, F);
122impl_tuple_query!(A, B, C, D, E, F, G);
123impl_tuple_query!(A, B, C, D, E, F, G, H);