Skip to main content

gloss_hecs/
tracked.rs

1use crate::stabletypeid::StableTypeId;
2use core::{marker::PhantomData, ptr::NonNull};
3
4use crate::{Access, Archetype, Component, Fetch, Query};
5
6/// Query that retrieves mutation state of type `T` component.
7/// Added components do not count as mutated.
8///
9/// It is your responsibility to clear trackers with
10/// [`World::clear_trackers()`](crate::World::clear_trackers()) at the start of
11/// the frame (or any other suitable moment).
12///
13/// # Example
14/// ```
15/// # use gloss_hecs::*;
16/// let mut world = World::new();
17/// let e = world.spawn((123,));
18/// for (_id, (value, value_mut)) in world.query::<(&i32, Mutated<i32>)>().iter() {
19///     assert_eq!(*value, 123, "!1");
20///     assert_eq!(value_mut, false, "!2");
21/// }
22/// for (_id, mut value) in world.query::<&mut i32>().iter() {
23///     *value = 42;
24/// }
25/// for (_id, (value, value_mut)) in world.query::<(&i32, Mutated<i32>)>().iter() {
26///     assert_eq!(*value, 42, "!3");
27///     assert_eq!(value_mut, true, "!3a");
28/// }
29/// world.clear_trackers();
30/// for (_id, value_mut) in world.query::<Mutated<i32>>().iter() {
31///     assert_eq!(value_mut, false, "!4");
32/// }
33/// ```
34pub struct Mutated<T>(PhantomData<fn(T)>);
35
36impl<T: Component> Query for Mutated<T> {
37    type Fetch = FetchMutated<T>;
38}
39
40#[doc(hidden)]
41pub struct FetchMutated<T>(NonNull<bool>, PhantomData<fn(T)>);
42
43unsafe impl<'a, T: Component> Fetch<'a> for FetchMutated<T> {
44    type Item = bool;
45
46    type State = usize;
47
48    fn dangling() -> Self {
49        Self(NonNull::dangling(), PhantomData)
50    }
51
52    fn access(archetype: &Archetype) -> Option<Access> {
53        if archetype.has::<T>() {
54            Some(Access::Read)
55        } else {
56            None
57        }
58    }
59
60    fn borrow(_archetype: &Archetype, _state: Self::State) {}
61    fn prepare(archetype: &Archetype) -> Option<Self::State> {
62        archetype.get_state::<T>()
63    }
64    fn execute(archetype: &'a Archetype, state: Self::State) -> Self {
65        Self(archetype.get_mutated(state), PhantomData)
66    }
67    fn release(_archetype: &Archetype, _state: Self::State) {}
68
69    fn for_each_borrow(mut f: impl FnMut(StableTypeId, bool)) {
70        f(StableTypeId::of::<T>(), false);
71    }
72
73    unsafe fn get(&self, n: usize) -> Self::Item {
74        *self.0.as_ptr().add(n)
75    }
76}
77
78/// Query that retrieves added state of type `T` component.
79///
80/// It is your responsibility to clear trackers with
81/// [`World::clear_trackers()`](crate::World::clear_trackers()) at the start of
82/// the frame (or any other suitable moment).
83///
84/// # Example
85/// ```
86/// # use gloss_hecs::*;
87/// let mut world = World::new();
88/// let e = world.spawn((123,));
89/// for (_id, (value, value_add)) in world.query::<(&i32, Added<i32>)>().iter() {
90///     assert_eq!(*value, 123);
91///     assert_eq!(value_add, true);
92/// }
93/// world.clear_trackers();
94/// for (_id, value_add) in world.query::<Added<i32>>().iter() {
95///     assert_eq!(value_add, false);
96/// }
97/// ```
98pub struct Added<T>(PhantomData<fn(T)>);
99
100impl<T: Component> Query for Added<T> {
101    type Fetch = FetchAdded<T>;
102}
103
104#[doc(hidden)]
105pub struct FetchAdded<T>(NonNull<bool>, PhantomData<fn(T)>);
106
107unsafe impl<'a, T: Component> Fetch<'a> for FetchAdded<T> {
108    type Item = bool;
109
110    type State = usize;
111
112    fn dangling() -> Self {
113        Self(NonNull::dangling(), PhantomData)
114    }
115
116    fn access(archetype: &Archetype) -> Option<Access> {
117        if archetype.has::<T>() {
118            Some(Access::Read)
119        } else {
120            None
121        }
122    }
123
124    fn borrow(_archetype: &Archetype, _state: Self::State) {}
125    fn prepare(archetype: &Archetype) -> Option<Self::State> {
126        archetype.get_state::<T>()
127    }
128    fn execute(archetype: &'a Archetype, state: Self::State) -> Self {
129        Self(archetype.get_added(state), PhantomData)
130    }
131    fn release(_archetype: &Archetype, _state: Self::State) {}
132
133    fn for_each_borrow(mut f: impl FnMut(StableTypeId, bool)) {
134        f(StableTypeId::of::<T>(), false);
135    }
136
137    unsafe fn get(&self, n: usize) -> Self::Item {
138        *self.0.as_ptr().add(n)
139    }
140}
141
142/// Query that retrieves changed state of type `T` component.
143/// Changed component is one that have either been mutated or added.
144///
145/// It is your responsibility to clear trackers with
146/// [`World::clear_trackers()`](crate::World::clear_trackers()) at the start of
147/// the frame (or any other suitable moment).
148///
149/// # Example
150/// ```
151/// # use gloss_hecs::*;
152/// let mut world = World::new();
153/// let e = world.spawn((123,));
154/// for (_id, (value, value_ch)) in world.query::<(&i32, Changed<i32>)>().iter() {
155///     assert_eq!(*value, 123);
156///     assert_eq!(value_ch, true);
157/// }
158/// world.clear_trackers();
159/// for (_id, value_ch) in world.query::<Changed<i32>>().iter() {
160///     assert_eq!(value_ch, false);
161/// }
162/// for (_id, mut value) in world.query::<&mut i32>().iter() {
163///     *value = 42;
164/// }
165/// for (_id, (value, value_ch)) in world.query::<(&i32, Changed<i32>)>().iter() {
166///     assert_eq!(*value, 42);
167///     assert_eq!(value_ch, true);
168/// }
169/// world.clear_trackers();
170/// for (_id, value_ch) in world.query::<Changed<i32>>().iter() {
171///     assert_eq!(value_ch, false);
172/// }
173/// ```
174pub struct Changed<T>(PhantomData<fn(T)>);
175
176impl<T: Component> Query for Changed<T> {
177    type Fetch = FetchChanged<T>;
178}
179
180#[doc(hidden)]
181pub struct FetchChanged<T>(NonNull<bool>, NonNull<bool>, PhantomData<fn(T)>);
182
183unsafe impl<'a, T: Component> Fetch<'a> for FetchChanged<T> {
184    type Item = bool;
185
186    type State = usize;
187
188    fn dangling() -> Self {
189        Self(NonNull::dangling(), NonNull::dangling(), PhantomData)
190    }
191
192    fn access(archetype: &Archetype) -> Option<Access> {
193        if archetype.has::<T>() {
194            Some(Access::Read)
195        } else {
196            None
197        }
198    }
199
200    fn borrow(_archetype: &Archetype, _state: Self::State) {}
201    fn prepare(archetype: &Archetype) -> Option<Self::State> {
202        archetype.get_state::<T>()
203    }
204    fn execute(archetype: &'a Archetype, state: Self::State) -> Self {
205        Self(archetype.get_mutated(state), archetype.get_added(state), PhantomData)
206    }
207    fn release(_archetype: &Archetype, _state: Self::State) {}
208
209    fn for_each_borrow(mut f: impl FnMut(StableTypeId, bool)) {
210        f(StableTypeId::of::<T>(), false);
211    }
212
213    unsafe fn get(&self, n: usize) -> Self::Item {
214        *self.0.as_ptr().add(n) || *self.1.as_ptr().add(n)
215    }
216}