despero_hecs/
tracked.rs

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