bevy_ecs/world/entity_access/
component_fetch.rs

1use crate::{
2    change_detection::MutUntyped,
3    component::ComponentId,
4    world::{error::EntityComponentError, unsafe_world_cell::UnsafeEntityCell},
5};
6
7use alloc::vec::Vec;
8use bevy_platform::collections::{HashMap, HashSet};
9use bevy_ptr::Ptr;
10use core::mem::MaybeUninit;
11
12/// Types that can be used to fetch components from an entity dynamically by
13/// [`ComponentId`]s.
14///
15/// Provided implementations are:
16/// - [`ComponentId`]: Returns a single untyped reference.
17/// - `[ComponentId; N]` and `&[ComponentId; N]`: Returns a same-sized array of untyped references.
18/// - `&[ComponentId]`: Returns a [`Vec`] of untyped references.
19/// - [`&HashSet<ComponentId>`](HashSet): Returns a [`HashMap`] of IDs to untyped references.
20///
21/// # Performance
22///
23/// - The slice and array implementations perform an aliased mutability check in
24///   [`DynamicComponentFetch::fetch_mut`] that is `O(N^2)`.
25/// - The [`HashSet`] implementation performs no such check as the type itself
26///   guarantees unique IDs.
27/// - The single [`ComponentId`] implementation performs no such check as only
28///   one reference is returned.
29///
30/// # Safety
31///
32/// Implementor must ensure that:
33/// - No aliased mutability is caused by the returned references.
34/// - [`DynamicComponentFetch::fetch_ref`] returns only read-only references.
35pub unsafe trait DynamicComponentFetch {
36    /// The read-only reference type returned by [`DynamicComponentFetch::fetch_ref`].
37    type Ref<'w>;
38
39    /// The mutable reference type returned by [`DynamicComponentFetch::fetch_mut`].
40    type Mut<'w>;
41
42    /// Returns untyped read-only reference(s) to the component(s) with the
43    /// given [`ComponentId`]s, as determined by `self`.
44    ///
45    /// # Safety
46    ///
47    /// It is the caller's responsibility to ensure that:
48    /// - The given [`UnsafeEntityCell`] has read-only access to the fetched components.
49    /// - No other mutable references to the fetched components exist at the same time.
50    ///
51    /// # Errors
52    ///
53    /// - Returns [`EntityComponentError::MissingComponent`] if a component is missing from the entity.
54    unsafe fn fetch_ref(
55        self,
56        cell: UnsafeEntityCell<'_>,
57    ) -> Result<Self::Ref<'_>, EntityComponentError>;
58
59    /// Returns untyped mutable reference(s) to the component(s) with the
60    /// given [`ComponentId`]s, as determined by `self`.
61    ///
62    /// # Safety
63    ///
64    /// It is the caller's responsibility to ensure that:
65    /// - The given [`UnsafeEntityCell`] has mutable access to the fetched components.
66    /// - No other references to the fetched components exist at the same time.
67    ///
68    /// # Errors
69    ///
70    /// - Returns [`EntityComponentError::MissingComponent`] if a component is missing from the entity.
71    /// - Returns [`EntityComponentError::AliasedMutability`] if a component is requested multiple times.
72    unsafe fn fetch_mut(
73        self,
74        cell: UnsafeEntityCell<'_>,
75    ) -> Result<Self::Mut<'_>, EntityComponentError>;
76
77    /// Returns untyped mutable reference(s) to the component(s) with the
78    /// given [`ComponentId`]s, as determined by `self`.
79    /// Assumes all [`ComponentId`]s refer to mutable components.
80    ///
81    /// # Safety
82    ///
83    /// It is the caller's responsibility to ensure that:
84    /// - The given [`UnsafeEntityCell`] has mutable access to the fetched components.
85    /// - No other references to the fetched components exist at the same time.
86    /// - The requested components are all mutable.
87    ///
88    /// # Errors
89    ///
90    /// - Returns [`EntityComponentError::MissingComponent`] if a component is missing from the entity.
91    /// - Returns [`EntityComponentError::AliasedMutability`] if a component is requested multiple times.
92    unsafe fn fetch_mut_assume_mutable(
93        self,
94        cell: UnsafeEntityCell<'_>,
95    ) -> Result<Self::Mut<'_>, EntityComponentError>;
96}
97
98// SAFETY:
99// - No aliased mutability is caused because a single reference is returned.
100// - No mutable references are returned by `fetch_ref`.
101unsafe impl DynamicComponentFetch for ComponentId {
102    type Ref<'w> = Ptr<'w>;
103    type Mut<'w> = MutUntyped<'w>;
104
105    unsafe fn fetch_ref(
106        self,
107        cell: UnsafeEntityCell<'_>,
108    ) -> Result<Self::Ref<'_>, EntityComponentError> {
109        // SAFETY: caller ensures that the cell has read access to the component.
110        unsafe { cell.get_by_id(self) }.ok_or(EntityComponentError::MissingComponent(self))
111    }
112
113    unsafe fn fetch_mut(
114        self,
115        cell: UnsafeEntityCell<'_>,
116    ) -> Result<Self::Mut<'_>, EntityComponentError> {
117        // SAFETY: caller ensures that the cell has mutable access to the component.
118        unsafe { cell.get_mut_by_id(self) }
119            .map_err(|_| EntityComponentError::MissingComponent(self))
120    }
121
122    unsafe fn fetch_mut_assume_mutable(
123        self,
124        cell: UnsafeEntityCell<'_>,
125    ) -> Result<Self::Mut<'_>, EntityComponentError> {
126        // SAFETY: caller ensures that the cell has mutable access to the component.
127        unsafe { cell.get_mut_assume_mutable_by_id(self) }
128            .map_err(|_| EntityComponentError::MissingComponent(self))
129    }
130}
131
132// SAFETY:
133// - No aliased mutability is caused because the array is checked for duplicates.
134// - No mutable references are returned by `fetch_ref`.
135unsafe impl<const N: usize> DynamicComponentFetch for [ComponentId; N] {
136    type Ref<'w> = [Ptr<'w>; N];
137    type Mut<'w> = [MutUntyped<'w>; N];
138
139    unsafe fn fetch_ref(
140        self,
141        cell: UnsafeEntityCell<'_>,
142    ) -> Result<Self::Ref<'_>, EntityComponentError> {
143        // SAFETY: Uphelp by caller.
144        unsafe { <&Self>::fetch_ref(&self, cell) }
145    }
146
147    unsafe fn fetch_mut(
148        self,
149        cell: UnsafeEntityCell<'_>,
150    ) -> Result<Self::Mut<'_>, EntityComponentError> {
151        // SAFETY: Uphelp by caller.
152        unsafe { <&Self>::fetch_mut(&self, cell) }
153    }
154
155    unsafe fn fetch_mut_assume_mutable(
156        self,
157        cell: UnsafeEntityCell<'_>,
158    ) -> Result<Self::Mut<'_>, EntityComponentError> {
159        // SAFETY: Uphelp by caller.
160        unsafe { <&Self>::fetch_mut_assume_mutable(&self, cell) }
161    }
162}
163
164// SAFETY:
165// - No aliased mutability is caused because the array is checked for duplicates.
166// - No mutable references are returned by `fetch_ref`.
167unsafe impl<const N: usize> DynamicComponentFetch for &'_ [ComponentId; N] {
168    type Ref<'w> = [Ptr<'w>; N];
169    type Mut<'w> = [MutUntyped<'w>; N];
170
171    unsafe fn fetch_ref(
172        self,
173        cell: UnsafeEntityCell<'_>,
174    ) -> Result<Self::Ref<'_>, EntityComponentError> {
175        let mut ptrs = [const { MaybeUninit::uninit() }; N];
176        for (ptr, &id) in core::iter::zip(&mut ptrs, self) {
177            *ptr = MaybeUninit::new(
178                // SAFETY: caller ensures that the cell has read access to the component.
179                unsafe { cell.get_by_id(id) }.ok_or(EntityComponentError::MissingComponent(id))?,
180            );
181        }
182
183        // SAFETY: Each ptr was initialized in the loop above.
184        let ptrs = ptrs.map(|ptr| unsafe { MaybeUninit::assume_init(ptr) });
185
186        Ok(ptrs)
187    }
188
189    unsafe fn fetch_mut(
190        self,
191        cell: UnsafeEntityCell<'_>,
192    ) -> Result<Self::Mut<'_>, EntityComponentError> {
193        // Check for duplicate component IDs.
194        for i in 0..self.len() {
195            for j in 0..i {
196                if self[i] == self[j] {
197                    return Err(EntityComponentError::AliasedMutability(self[i]));
198                }
199            }
200        }
201
202        let mut ptrs = [const { MaybeUninit::uninit() }; N];
203        for (ptr, &id) in core::iter::zip(&mut ptrs, self) {
204            *ptr = MaybeUninit::new(
205                // SAFETY: caller ensures that the cell has mutable access to the component.
206                unsafe { cell.get_mut_by_id(id) }
207                    .map_err(|_| EntityComponentError::MissingComponent(id))?,
208            );
209        }
210
211        // SAFETY: Each ptr was initialized in the loop above.
212        let ptrs = ptrs.map(|ptr| unsafe { MaybeUninit::assume_init(ptr) });
213
214        Ok(ptrs)
215    }
216
217    unsafe fn fetch_mut_assume_mutable(
218        self,
219        cell: UnsafeEntityCell<'_>,
220    ) -> Result<Self::Mut<'_>, EntityComponentError> {
221        // Check for duplicate component IDs.
222        for i in 0..self.len() {
223            for j in 0..i {
224                if self[i] == self[j] {
225                    return Err(EntityComponentError::AliasedMutability(self[i]));
226                }
227            }
228        }
229
230        let mut ptrs = [const { MaybeUninit::uninit() }; N];
231        for (ptr, &id) in core::iter::zip(&mut ptrs, self) {
232            *ptr = MaybeUninit::new(
233                // SAFETY: caller ensures that the cell has mutable access to the component.
234                unsafe { cell.get_mut_assume_mutable_by_id(id) }
235                    .map_err(|_| EntityComponentError::MissingComponent(id))?,
236            );
237        }
238
239        // SAFETY: Each ptr was initialized in the loop above.
240        let ptrs = ptrs.map(|ptr| unsafe { MaybeUninit::assume_init(ptr) });
241
242        Ok(ptrs)
243    }
244}
245
246// SAFETY:
247// - No aliased mutability is caused because the slice is checked for duplicates.
248// - No mutable references are returned by `fetch_ref`.
249unsafe impl DynamicComponentFetch for &'_ [ComponentId] {
250    type Ref<'w> = Vec<Ptr<'w>>;
251    type Mut<'w> = Vec<MutUntyped<'w>>;
252
253    unsafe fn fetch_ref(
254        self,
255        cell: UnsafeEntityCell<'_>,
256    ) -> Result<Self::Ref<'_>, EntityComponentError> {
257        let mut ptrs = Vec::with_capacity(self.len());
258        for &id in self {
259            ptrs.push(
260                // SAFETY: caller ensures that the cell has read access to the component.
261                unsafe { cell.get_by_id(id) }.ok_or(EntityComponentError::MissingComponent(id))?,
262            );
263        }
264        Ok(ptrs)
265    }
266
267    unsafe fn fetch_mut(
268        self,
269        cell: UnsafeEntityCell<'_>,
270    ) -> Result<Self::Mut<'_>, EntityComponentError> {
271        // Check for duplicate component IDs.
272        for i in 0..self.len() {
273            for j in 0..i {
274                if self[i] == self[j] {
275                    return Err(EntityComponentError::AliasedMutability(self[i]));
276                }
277            }
278        }
279
280        let mut ptrs = Vec::with_capacity(self.len());
281        for &id in self {
282            ptrs.push(
283                // SAFETY: caller ensures that the cell has mutable access to the component.
284                unsafe { cell.get_mut_by_id(id) }
285                    .map_err(|_| EntityComponentError::MissingComponent(id))?,
286            );
287        }
288        Ok(ptrs)
289    }
290
291    unsafe fn fetch_mut_assume_mutable(
292        self,
293        cell: UnsafeEntityCell<'_>,
294    ) -> Result<Self::Mut<'_>, EntityComponentError> {
295        // Check for duplicate component IDs.
296        for i in 0..self.len() {
297            for j in 0..i {
298                if self[i] == self[j] {
299                    return Err(EntityComponentError::AliasedMutability(self[i]));
300                }
301            }
302        }
303
304        let mut ptrs = Vec::with_capacity(self.len());
305        for &id in self {
306            ptrs.push(
307                // SAFETY: caller ensures that the cell has mutable access to the component.
308                unsafe { cell.get_mut_assume_mutable_by_id(id) }
309                    .map_err(|_| EntityComponentError::MissingComponent(id))?,
310            );
311        }
312        Ok(ptrs)
313    }
314}
315
316// SAFETY:
317// - No aliased mutability is caused because `HashSet` guarantees unique elements.
318// - No mutable references are returned by `fetch_ref`.
319unsafe impl DynamicComponentFetch for &'_ HashSet<ComponentId> {
320    type Ref<'w> = HashMap<ComponentId, Ptr<'w>>;
321    type Mut<'w> = HashMap<ComponentId, MutUntyped<'w>>;
322
323    unsafe fn fetch_ref(
324        self,
325        cell: UnsafeEntityCell<'_>,
326    ) -> Result<Self::Ref<'_>, EntityComponentError> {
327        let mut ptrs = HashMap::with_capacity_and_hasher(self.len(), Default::default());
328        for &id in self {
329            ptrs.insert(
330                id,
331                // SAFETY: caller ensures that the cell has read access to the component.
332                unsafe { cell.get_by_id(id) }.ok_or(EntityComponentError::MissingComponent(id))?,
333            );
334        }
335        Ok(ptrs)
336    }
337
338    unsafe fn fetch_mut(
339        self,
340        cell: UnsafeEntityCell<'_>,
341    ) -> Result<Self::Mut<'_>, EntityComponentError> {
342        let mut ptrs = HashMap::with_capacity_and_hasher(self.len(), Default::default());
343        for &id in self {
344            ptrs.insert(
345                id,
346                // SAFETY: caller ensures that the cell has mutable access to the component.
347                unsafe { cell.get_mut_by_id(id) }
348                    .map_err(|_| EntityComponentError::MissingComponent(id))?,
349            );
350        }
351        Ok(ptrs)
352    }
353
354    unsafe fn fetch_mut_assume_mutable(
355        self,
356        cell: UnsafeEntityCell<'_>,
357    ) -> Result<Self::Mut<'_>, EntityComponentError> {
358        let mut ptrs = HashMap::with_capacity_and_hasher(self.len(), Default::default());
359        for &id in self {
360            ptrs.insert(
361                id,
362                // SAFETY: caller ensures that the cell has mutable access to the component.
363                unsafe { cell.get_mut_assume_mutable_by_id(id) }
364                    .map_err(|_| EntityComponentError::MissingComponent(id))?,
365            );
366        }
367        Ok(ptrs)
368    }
369}