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}