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}