1use core::{any::TypeId, marker::PhantomData, ptr::NonNull};
2
3use crate::{
4 archetype::Archetype,
5 component::ComponentInfo,
6 entity::EntityId,
7 epoch::EpochId,
8 query::{AsQuery, Fetch, ImmutableQuery, IntoQuery, Query, Read, SendQuery, Write, WriteAlias},
9 relation::{OriginComponent, Relation},
10 type_id, Access,
11};
12
13pub struct RelatesTo<R> {
17 target: EntityId,
18 phantom: PhantomData<R>,
19}
20
21impl_debug!(RelatesTo<R> { target });
22impl_copy!(RelatesTo<R>);
23
24impl<R> RelatesTo<R> {
25 pub fn new(target: EntityId) -> Self {
27 RelatesTo {
28 target,
29 phantom: PhantomData,
30 }
31 }
32}
33
34pub struct FetchRelatesToRead<'a, R: Relation> {
36 target: EntityId,
37 item_idx: usize,
38 ptr: NonNull<OriginComponent<R>>,
39 marker: PhantomData<&'a OriginComponent<R>>,
40}
41
42unsafe impl<'a, R> Fetch<'a> for FetchRelatesToRead<'a, R>
43where
44 R: Relation,
45{
46 type Item = &'a R;
47
48 #[inline(always)]
49 fn dangling() -> Self {
50 FetchRelatesToRead {
51 target: EntityId::dangling(),
52 ptr: NonNull::dangling(),
53 item_idx: 0,
54 marker: PhantomData,
55 }
56 }
57
58 #[inline(always)]
59 unsafe fn visit_item(&mut self, idx: u32) -> bool {
60 let origin_component = unsafe { &*self.ptr.as_ptr().add(idx as usize) };
61 let item_idx = origin_component
62 .relations()
63 .iter()
64 .position(|origin| origin.target == self.target);
65
66 match item_idx {
67 None => false,
68 Some(item_idx) => {
69 self.item_idx = item_idx;
70 true
71 }
72 }
73 }
74
75 #[inline(always)]
76 unsafe fn get_item(&mut self, idx: u32) -> &'a R {
77 let origin_component = unsafe { &*self.ptr.as_ptr().add(idx as usize) };
78 &origin_component.relations()[self.item_idx].relation
79 }
80}
81
82impl<R> AsQuery for RelatesTo<&R>
83where
84 R: Relation + 'static,
85{
86 type Query = RelatesTo<Read<R>>;
87}
88
89impl<R> AsQuery for RelatesTo<Read<R>>
90where
91 R: Relation + 'static,
92{
93 type Query = Self;
94}
95
96impl<R> IntoQuery for RelatesTo<Read<R>>
97where
98 R: Relation + 'static,
99{
100 #[inline(always)]
101 fn into_query(self) -> Self {
102 self
103 }
104}
105
106unsafe impl<R> Query for RelatesTo<Read<R>>
107where
108 R: Relation,
109{
110 type Item<'a> = &'a R;
111 type Fetch<'a> = FetchRelatesToRead<'a, R>;
112
113 const MUTABLE: bool = false;
114 const FILTERS_ENTITIES: bool = true;
115
116 #[inline(always)]
117 fn component_access(&self, comp: &ComponentInfo) -> Result<Option<Access>, WriteAlias> {
118 if comp.id() == type_id::<OriginComponent<R>>() {
119 Ok(Some(Access::Read))
120 } else {
121 Ok(None)
122 }
123 }
124
125 fn visit_archetype(&self, archetype: &Archetype) -> bool {
126 archetype.has_component(type_id::<OriginComponent<R>>())
127 }
128
129 #[inline(always)]
130 unsafe fn access_archetype(&self, _archetype: &Archetype, mut f: impl FnMut(TypeId, Access)) {
131 f(type_id::<OriginComponent<R>>(), Access::Read)
132 }
133
134 #[inline(always)]
135 unsafe fn fetch<'a>(
136 &self,
137 _arch_idx: u32,
138 archetype: &'a Archetype,
139 _epoch: EpochId,
140 ) -> FetchRelatesToRead<'a, R> {
141 let component = unsafe {
142 archetype
143 .component(type_id::<OriginComponent<R>>())
144 .unwrap_unchecked()
145 };
146 debug_assert_eq!(component.id(), type_id::<OriginComponent<R>>());
147
148 let data = unsafe { component.data() };
149
150 FetchRelatesToRead {
151 target: self.target,
152 ptr: data.ptr.cast(),
153 item_idx: 0,
154 marker: PhantomData,
155 }
156 }
157}
158
159unsafe impl<R> ImmutableQuery for RelatesTo<Read<R>> where R: Relation {}
160unsafe impl<R> SendQuery for RelatesTo<Read<R>> where R: Relation + Sync {}
161
162pub struct FetchRelatesToWrite<'a, R: Relation> {
164 target: EntityId,
165 item_idx: usize,
166 epoch: EpochId,
167 ptr: NonNull<OriginComponent<R>>,
168 entity_epochs: NonNull<EpochId>,
169 chunk_epochs: NonNull<EpochId>,
170 marker: PhantomData<&'a mut OriginComponent<R>>,
171}
172
173unsafe impl<'a, R> Fetch<'a> for FetchRelatesToWrite<'a, R>
174where
175 R: Relation,
176{
177 type Item = &'a mut R;
178
179 #[inline(always)]
180 fn dangling() -> Self {
181 FetchRelatesToWrite {
182 item_idx: 0,
183 target: EntityId::dangling(),
184 epoch: EpochId::start(),
185 ptr: NonNull::dangling(),
186 entity_epochs: NonNull::dangling(),
187 chunk_epochs: NonNull::dangling(),
188 marker: PhantomData,
189 }
190 }
191
192 #[inline(always)]
193 unsafe fn touch_chunk(&mut self, chunk_idx: u32) {
194 let chunk_epoch = unsafe { &mut *self.chunk_epochs.as_ptr().add(chunk_idx as usize) };
195 chunk_epoch.bump(self.epoch);
196 }
197
198 #[inline(always)]
199 unsafe fn visit_item(&mut self, idx: u32) -> bool {
200 let origin_component = unsafe { &*self.ptr.as_ptr().add(idx as usize) };
201 let item_idx = origin_component
202 .relations()
203 .iter()
204 .position(|origin| origin.target == self.target);
205
206 match item_idx {
207 None => false,
208 Some(item_idx) => {
209 self.item_idx = item_idx;
210 true
211 }
212 }
213 }
214
215 #[inline(always)]
216 unsafe fn get_item(&mut self, idx: u32) -> &'a mut R {
217 let entity_epoch = unsafe { &mut *self.entity_epochs.as_ptr().add(idx as usize) };
218 entity_epoch.bump(self.epoch);
219
220 let origin_component = unsafe { &mut *self.ptr.as_ptr().add(idx as usize) };
221 &mut origin_component.relations_mut()[self.item_idx].relation
222 }
223}
224
225impl<R> AsQuery for RelatesTo<&mut R>
226where
227 R: Relation,
228{
229 type Query = RelatesTo<Write<R>>;
230}
231
232impl<R> AsQuery for RelatesTo<Write<R>>
233where
234 R: Relation,
235{
236 type Query = Self;
237}
238
239impl<R> IntoQuery for RelatesTo<Write<R>>
240where
241 R: Relation,
242{
243 #[inline(always)]
244 fn into_query(self) -> Self {
245 self
246 }
247}
248
249unsafe impl<R> Query for RelatesTo<Write<R>>
250where
251 R: Relation,
252{
253 type Item<'a> = &'a mut R;
254 type Fetch<'a> = FetchRelatesToWrite<'a, R>;
255
256 const MUTABLE: bool = true;
257 const FILTERS_ENTITIES: bool = true;
258
259 #[inline(always)]
260 fn component_access(&self, comp: &ComponentInfo) -> Result<Option<Access>, WriteAlias> {
261 if comp.id() == type_id::<OriginComponent<R>>() {
262 Ok(Some(Access::Write))
263 } else {
264 Ok(None)
265 }
266 }
267
268 fn visit_archetype(&self, archetype: &Archetype) -> bool {
269 archetype.has_component(type_id::<OriginComponent<R>>())
270 }
271
272 #[inline(always)]
273 unsafe fn access_archetype(&self, _archetype: &Archetype, mut f: impl FnMut(TypeId, Access)) {
274 f(type_id::<OriginComponent<R>>(), Access::Write)
275 }
276
277 #[inline(always)]
278 unsafe fn fetch<'a>(
279 &self,
280 _arch_idx: u32,
281 archetype: &'a Archetype,
282 epoch: EpochId,
283 ) -> FetchRelatesToWrite<'a, R> {
284 let component = unsafe {
285 archetype
286 .component(type_id::<OriginComponent<R>>())
287 .unwrap_unchecked()
288 };
289 debug_assert_eq!(component.id(), type_id::<OriginComponent<R>>());
290
291 let data = unsafe { component.data_mut() };
292 data.epoch.bump(epoch);
293
294 FetchRelatesToWrite {
295 target: self.target,
296 item_idx: 0,
297 epoch,
298 ptr: data.ptr.cast(),
299 entity_epochs: unsafe { NonNull::new_unchecked(data.entity_epochs.as_mut_ptr()) },
300 chunk_epochs: unsafe { NonNull::new_unchecked(data.chunk_epochs.as_mut_ptr()) },
301 marker: PhantomData,
302 }
303 }
304}
305
306unsafe impl<R> SendQuery for RelatesTo<Write<R>> where R: Relation + Send {}