edict/world/get.rs
1//! Methods for fetching components from specific entities.
2
3use crate::{
4 archetype::chunk_idx,
5 entity::{AliveEntity, Entity},
6 query::{DefaultQuery, DefaultSendQuery, Fetch, IntoQuery, IntoSendQuery, Query, QueryItem},
7 view::{ViewOne, ViewOneState},
8 EntityError, NoSuchEntity,
9};
10
11use super::{World, WorldLocal};
12
13impl World {
14 /// Queries components from specified entity.
15 ///
16 /// Returns query item.
17 ///
18 /// This method works only for default-constructed query types.
19 ///
20 /// Mutably borrows world for the duration of query item's lifetime,
21 /// avoiding runtime borrow checks.
22 ///
23 /// # Panics
24 ///
25 /// This method may panic if entity of another world is used.
26 #[inline(always)]
27 pub fn get<'a, Q>(&'a mut self, entity: impl Entity) -> Result<QueryItem<'a, Q>, EntityError>
28 where
29 Q: DefaultQuery,
30 {
31 self.get_with(entity, Q::default_query())
32 }
33
34 /// Queries components from specified entity.
35 ///
36 /// Returns query item.
37 ///
38 /// Mutably borrows world for the duration of query item's lifetime,
39 /// avoiding runtime borrow checks.
40 ///
41 /// # Panics
42 ///
43 /// This method may panic if entity of another world is used.
44 #[inline(always)]
45 pub fn get_with<'a, Q>(
46 &'a mut self,
47 entity: impl Entity,
48 query: Q,
49 ) -> Result<QueryItem<'a, Q::Query>, EntityError>
50 where
51 Q: IntoQuery,
52 {
53 unsafe { self.get_with_unchecked::<Q>(entity, query) }
54 }
55
56 /// Queries components from specified entity.
57 ///
58 /// Returns query item.
59 ///
60 /// # Safety
61 ///
62 /// Caller must guarantee to not create invalid aliasing of component
63 /// references.
64 ///
65 /// # Panics
66 ///
67 /// This method may panic if entity of another world is used.
68 #[inline(always)]
69 pub unsafe fn get_unchecked<'a, Q>(
70 &'a self,
71 entity: impl Entity,
72 ) -> Result<QueryItem<'a, Q::Query>, EntityError>
73 where
74 Q: DefaultQuery,
75 {
76 unsafe { self.get_with_unchecked(entity, Q::default_query()) }
77 }
78
79 /// Queries components from specified entity.
80 ///
81 /// Returns query item.
82 ///
83 /// # Safety
84 ///
85 /// Caller must guarantee to not create invalid aliasing of component
86 /// references.
87 ///
88 /// # Panics
89 ///
90 /// This method may panic if entity of another world is used.
91 #[inline(always)]
92 pub unsafe fn get_with_unchecked<'a, Q>(
93 &'a self,
94 entity: impl Entity,
95 query: Q,
96 ) -> Result<QueryItem<'a, Q::Query>, EntityError>
97 where
98 Q: IntoQuery,
99 {
100 let query = query.into_query();
101
102 let loc = entity
103 .lookup(&self.entities)
104 .ok_or(EntityError::NoSuchEntity)?;
105
106 if loc.arch == u32::MAX {
107 // Reserved entity
108 return query
109 .reserved_entity_item(entity.id(), loc.idx)
110 .ok_or(EntityError::Mismatch);
111 }
112
113 let archetype = &self.archetypes[loc.arch as usize];
114
115 debug_assert!(archetype.len() >= loc.idx as usize, "Entity index is valid");
116
117 if !query.visit_archetype(archetype) {
118 return Err(EntityError::Mismatch);
119 }
120
121 let epoch = self.epoch.next();
122
123 let mut fetch = unsafe { query.fetch(loc.arch, archetype, epoch) };
124
125 if !unsafe { fetch.visit_chunk(chunk_idx(loc.idx)) } {
126 return Err(EntityError::Mismatch);
127 }
128
129 unsafe { fetch.touch_chunk(chunk_idx(loc.idx)) };
130
131 if !unsafe { fetch.visit_item(loc.idx) } {
132 return Err(EntityError::Mismatch);
133 }
134
135 let item = unsafe { fetch.get_item(loc.idx) };
136
137 Ok(item)
138 }
139
140 /// Queries components from specified entity.
141 ///
142 /// Returns a wrapper from which query item can be fetched.
143 ///
144 /// The wrapper holds borrow locks for entity's archetype and releases them on drop.
145 ///
146 /// # Panics
147 ///
148 /// This method may panic if entity of another world is used.
149 #[inline(always)]
150 pub fn view_one<'a, Q>(&'a self, entity: impl AliveEntity) -> ViewOne<'a, Q>
151 where
152 Q: DefaultSendQuery,
153 {
154 ViewOneState::new(self, entity, Q::default_query(), ())
155 }
156
157 /// Queries components from specified entity.
158 ///
159 /// Returns a wrapper from which query item can be fetched.
160 ///
161 /// The wrapper holds borrow locks for entity's archetype and releases them on drop.
162 ///
163 /// # Panics
164 ///
165 /// This method may panic if entity of another world is used.
166 #[inline(always)]
167 pub fn try_view_one<'a, Q>(
168 &'a self,
169 entity: impl Entity,
170 ) -> Result<ViewOne<'a, Q>, NoSuchEntity>
171 where
172 Q: DefaultSendQuery,
173 {
174 let entity = self.lookup(entity)?;
175 Ok(self.view_one::<Q>(entity))
176 }
177
178 /// Queries components from specified entity.
179 /// This method accepts query instance to support stateful queries.
180 ///
181 /// This method works only for stateless query types.
182 /// Returned wrapper holds borrow locks for entity's archetype and releases them on drop.
183 ///
184 /// # Panics
185 ///
186 /// This method may panic if entity of another world is used.
187 #[inline(always)]
188 pub fn view_one_with<'a, Q>(&'a self, entity: impl AliveEntity, query: Q) -> ViewOne<'a, (Q,)>
189 where
190 Q: IntoSendQuery,
191 {
192 ViewOneState::new(self, entity, (query.into_query(),), ())
193 }
194
195 /// Queries components from specified entity.
196 /// This method accepts query instance to support stateful queries.
197 ///
198 /// This method works only for stateless query types.
199 /// Returned wrapper holds borrow locks for entity's archetype and releases them on drop.
200 ///
201 /// # Panics
202 ///
203 /// This method may panic if entity of another world is used.
204 #[inline(always)]
205 pub fn try_view_one_with<'a, Q>(
206 &'a self,
207 entity: impl Entity,
208 query: Q,
209 ) -> Result<ViewOne<'a, (Q,)>, NoSuchEntity>
210 where
211 Q: IntoSendQuery,
212 {
213 let entity = self.lookup(entity)?;
214 Ok(self.view_one_with::<Q>(entity, query))
215 }
216
217 /// Queries components from specified entity.
218 /// Where query item is a reference to value the implements [`ToOwned`].
219 /// Returns item converted to owned value.
220 ///
221 /// This method locks only archetype to which entity belongs for the duration of the method itself.
222 #[inline(always)]
223 pub fn get_cloned<T>(&self, entity: impl AliveEntity) -> Option<T>
224 where
225 T: Clone + Sync + 'static,
226 {
227 self.view_one::<&T>(entity).map(Clone::clone)
228 }
229
230 /// Queries components from specified entity.
231 /// Where query item is a reference to value the implements [`ToOwned`].
232 /// Returns item converted to owned value.
233 ///
234 /// This method locks only archetype to which entity belongs for the duration of the method itself.
235 #[inline(always)]
236 pub fn try_get_cloned<T>(&self, entity: impl Entity) -> Result<Option<T>, NoSuchEntity>
237 where
238 T: Clone + Sync + 'static,
239 {
240 let entity = self.lookup(entity)?;
241 Ok(self.get_cloned::<T>(entity))
242 }
243}
244
245impl WorldLocal {
246 /// Queries components from specified entity.
247 ///
248 /// Returns a wrapper from which query item can be fetched.
249 ///
250 /// The wrapper holds borrow locks for entity's archetype and releases them on drop.
251 ///
252 /// # Panics
253 ///
254 /// This method may panic if entity of another world is used.
255 #[inline(always)]
256 pub fn view_one<'a, Q>(&'a self, entity: impl AliveEntity) -> ViewOne<'a, Q>
257 where
258 Q: DefaultQuery,
259 {
260 ViewOneState::new(self, entity, Q::default_query(), ())
261 }
262
263 /// Queries components from specified entity.
264 ///
265 /// Returns a wrapper from which query item can be fetched.
266 ///
267 /// The wrapper holds borrow locks for entity's archetype and releases them on drop.
268 ///
269 /// # Panics
270 ///
271 /// This method may panic if entity of another world is used.
272 #[inline(always)]
273 pub fn try_view_one<'a, Q>(
274 &'a self,
275 entity: impl Entity,
276 ) -> Result<ViewOne<'a, Q>, NoSuchEntity>
277 where
278 Q: DefaultQuery,
279 {
280 let entity = self.lookup(entity)?;
281 Ok(self.view_one::<Q>(entity))
282 }
283
284 /// Queries components from specified entity.
285 /// This method accepts query instance to support stateful queries.
286 ///
287 /// This method works only for stateless query types.
288 /// Returned wrapper holds borrow locks for entity's archetype and releases them on drop.
289 ///
290 /// # Panics
291 ///
292 /// This method may panic if entity of another world is used.
293 #[inline(always)]
294 pub fn view_one_with<'a, Q>(&'a self, entity: impl AliveEntity, query: Q) -> ViewOne<'a, (Q,)>
295 where
296 Q: IntoQuery,
297 {
298 ViewOneState::new(self, entity, (query.into_query(),), ())
299 }
300
301 /// Queries components from specified entity.
302 /// This method accepts query instance to support stateful queries.
303 ///
304 /// This method works only for stateless query types.
305 /// Returned wrapper holds borrow locks for entity's archetype and releases them on drop.
306 ///
307 /// # Panics
308 ///
309 /// This method may panic if entity of another world is used.
310 #[inline(always)]
311 pub fn try_view_one_with<'a, Q>(
312 &'a self,
313 entity: impl Entity,
314 query: Q,
315 ) -> Result<ViewOne<'a, (Q,)>, NoSuchEntity>
316 where
317 Q: IntoQuery,
318 {
319 let entity = self.lookup(entity)?;
320 Ok(self.view_one_with::<Q>(entity, query))
321 }
322
323 /// Queries components from specified entity.
324 /// Where query item is a reference to value the implements [`ToOwned`].
325 /// Returns item converted to owned value.
326 ///
327 /// This method locks only archetype to which entity belongs for the duration of the method itself.
328 #[inline(always)]
329 pub fn get_cloned<T>(&self, entity: impl AliveEntity) -> Option<T>
330 where
331 T: Clone + 'static,
332 {
333 self.view_one::<&T>(entity).map(Clone::clone)
334 }
335
336 /// Queries components from specified entity.
337 /// Where query item is a reference to value the implements [`ToOwned`].
338 /// Returns item converted to owned value.
339 ///
340 /// This method locks only archetype to which entity belongs for the duration of the method itself.
341 #[inline(always)]
342 pub fn try_get_cloned<T>(&self, entity: impl Entity) -> Result<Option<T>, NoSuchEntity>
343 where
344 T: Clone + 'static,
345 {
346 let entity = self.lookup(entity)?;
347 Ok(self.get_cloned::<T>(entity))
348 }
349}