bevy_trait_query/all/core/
write.rs

1use bevy_ecs::{
2    change_detection::{DetectChanges, Mut, Ref},
3    component::{ComponentId, Tick},
4    entity::Entity,
5    ptr::UnsafeCellDeref,
6    storage::{SparseSets, Table, TableRow},
7};
8
9use crate::{
10    zip_exact, CombinedReadTraitsIter, ReadSparseTraitsIter, ReadTableTraitsIter, TraitImplMeta,
11    TraitImplRegistry, TraitQuery,
12};
13
14/// Write-access to all components implementing a trait for a given entity.
15///
16/// This supports change detection and detection for added objects via
17///
18/// - [`WriteTraits::iter_changed`]
19/// - [`WriteTraits::iter_added`]
20pub struct WriteTraits<'a, Trait: ?Sized + TraitQuery> {
21    // Read-only access to the global trait registry.
22    // Since no one outside of the crate can name the registry type,
23    // we can be confident that no write accesses will conflict with this.
24    pub(crate) registry: &'a TraitImplRegistry<Trait>,
25
26    pub(crate) table: &'a Table,
27    pub(crate) table_row: TableRow,
28
29    pub(crate) last_run: Tick,
30    pub(crate) this_run: Tick,
31
32    /// This grants shared mutable access to all sparse set components,
33    /// but in practice we will only modify the components specified in `self.registry`.
34    /// The fetch impl registers write-access for all of these components,
35    /// guaranteeing us exclusive access at runtime.
36    pub(crate) sparse_sets: &'a SparseSets,
37}
38
39#[doc(hidden)]
40pub type CombinedWriteTraitsIter<'a, Trait> =
41    std::iter::Chain<WriteTableTraitsIter<'a, Trait>, WriteSparseTraitsIter<'a, Trait>>;
42
43#[doc(hidden)]
44pub struct WriteTableTraitsIter<'a, Trait: ?Sized> {
45    // SAFETY: These two iterators must have equal length.
46    pub(crate) components: std::slice::Iter<'a, ComponentId>,
47    pub(crate) meta: std::slice::Iter<'a, TraitImplMeta<Trait>>,
48    pub(crate) table: &'a Table,
49    /// SAFETY: Given the same trait type and same archetype,
50    /// no two instances of this struct may have the same `table_row`.
51    pub(crate) table_row: TableRow,
52    pub(crate) last_run: Tick,
53    pub(crate) this_run: Tick,
54}
55
56impl<'a, Trait: ?Sized + TraitQuery> Iterator for WriteTableTraitsIter<'a, Trait> {
57    type Item = Mut<'a, Trait>;
58    fn next(&mut self) -> Option<Self::Item> {
59        // Iterate the remaining table components that are registered,
60        // until we find one that exists in the table.
61        let (ptr, component_id, meta) = unsafe { zip_exact(&mut self.components, &mut self.meta) }
62            .find_map(|(&component, meta)| {
63                // SAFETY: we know that the `table_row` is a valid index.
64                let ptr = unsafe { self.table.get_component(component, self.table_row) }?;
65                Some((ptr, component, meta))
66            })?;
67        // SAFETY: The instance of `WriteTraits` that created this iterator
68        // has exclusive access to all table components registered with the trait.
69        //
70        // Since `self.table_row` is guaranteed to be unique, we know that other instances
71        // of `WriteTableTraitsIter` will not conflict with this pointer.
72        let ptr = unsafe { ptr.assert_unique() };
73        let trait_object = unsafe { meta.dyn_ctor.cast_mut(ptr) };
74        // SAFETY: We have exclusive access to the component, so by extension
75        // we have exclusive access to the corresponding `ComponentTicks`.
76        let added = unsafe {
77            self.table
78                .get_added_tick(component_id, self.table_row)?
79                .deref_mut()
80        };
81        let changed = unsafe {
82            self.table
83                .get_changed_tick(component_id, self.table_row)?
84                .deref_mut()
85        };
86        let location = unsafe {
87            self.table
88                .get_changed_by(component_id, self.table_row)
89                .transpose()?
90                .map(|loc| loc.deref_mut())
91        };
92        Some(Mut::new(
93            trait_object,
94            added,
95            changed,
96            self.last_run,
97            self.this_run,
98            location,
99        ))
100    }
101}
102
103#[doc(hidden)]
104pub struct WriteSparseTraitsIter<'a, Trait: ?Sized> {
105    // SAFETY: These two iterators must have equal length.
106    pub(crate) components: std::slice::Iter<'a, ComponentId>,
107    pub(crate) meta: std::slice::Iter<'a, TraitImplMeta<Trait>>,
108    /// SAFETY: Given the same trait type and same archetype,
109    /// no two instances of this struct may have the same `entity`.
110    pub(crate) entity: Entity,
111    pub(crate) sparse_sets: &'a SparseSets,
112    pub(crate) last_run: Tick,
113    pub(crate) this_run: Tick,
114}
115
116impl<'a, Trait: ?Sized + TraitQuery> Iterator for WriteSparseTraitsIter<'a, Trait> {
117    type Item = Mut<'a, Trait>;
118    fn next(&mut self) -> Option<Self::Item> {
119        // Iterate the remaining sparse set components we have registered,
120        // until we find one that exists in the archetype.
121        let (ptr, component_ticks, meta, location) =
122            unsafe { zip_exact(&mut self.components, &mut self.meta) }.find_map(
123                |(&component, meta)| {
124                    let set = self.sparse_sets.get(component)?;
125                    let (ptr, ticks, location) = set.get_with_ticks(self.entity)?;
126                    Some((ptr, ticks, meta, location))
127                },
128            )?;
129
130        // SAFETY: The instance of `WriteTraits` that created this iterator
131        // has exclusive access to all sparse set components registered with the trait.
132        //
133        // Since `self.entity` is guaranteed to be unique, we know that other instances
134        // of `WriteSparseTraitsIter` will not conflict with this pointer.
135        let ptr = unsafe { ptr.assert_unique() };
136        let trait_object = unsafe { meta.dyn_ctor.cast_mut(ptr) };
137        // SAFETY: We have exclusive access to the component, so by extension
138        // we have exclusive access to the corresponding `ComponentTicks`.
139        let added = unsafe { component_ticks.added.deref_mut() };
140        let changed = unsafe { component_ticks.changed.deref_mut() };
141
142        Some(Mut::new(
143            trait_object,
144            added,
145            changed,
146            self.last_run,
147            self.this_run,
148            location.map(|loc| unsafe { loc.deref_mut() }),
149        ))
150    }
151}
152
153impl<Trait: ?Sized + TraitQuery> WriteTraits<'_, Trait> {
154    /// Returns an iterator over the components implementing `Trait` for the current entity.
155    pub fn iter(&self) -> CombinedReadTraitsIter<'_, Trait> {
156        self.into_iter()
157    }
158
159    /// Returns a mutable iterator over the components implementing `Trait` for the current entity.
160    pub fn iter_mut(&mut self) -> CombinedWriteTraitsIter<'_, Trait> {
161        self.into_iter()
162    }
163
164    /// Returns an iterator over the components implementing `Trait` for the current entity
165    /// that were added since the last time the system was run.
166    pub fn iter_added(&self) -> impl Iterator<Item = Ref<'_, Trait>> {
167        self.iter().filter(DetectChanges::is_added)
168    }
169
170    /// Returns an iterator over the components implementing `Trait` for the current entity
171    /// whose values were changed since the last time the system was run.
172    pub fn iter_changed(&self) -> impl Iterator<Item = Ref<'_, Trait>> {
173        self.iter().filter(DetectChanges::is_changed)
174    }
175
176    /// Returns a mutable iterator over the components implementing `Trait` for the current entity
177    /// that were added since the last time the system was run.
178    pub fn iter_added_mut(&mut self) -> impl Iterator<Item = Mut<'_, Trait>> {
179        self.iter_mut().filter(DetectChanges::is_added)
180    }
181
182    /// Returns a mutable iterator over the components implementing `Trait` for the current entity
183    /// whose values were changed since the last time the system was run.
184    pub fn iter_changed_mut(&mut self) -> impl Iterator<Item = Mut<'_, Trait>> {
185        self.iter_mut().filter(DetectChanges::is_changed)
186    }
187}
188
189impl<'w, Trait: ?Sized + TraitQuery> IntoIterator for WriteTraits<'w, Trait> {
190    type Item = Mut<'w, Trait>;
191    type IntoIter = CombinedWriteTraitsIter<'w, Trait>;
192    #[inline]
193    fn into_iter(self) -> Self::IntoIter {
194        let table = WriteTableTraitsIter {
195            components: self.registry.table_components.iter(),
196            meta: self.registry.table_meta.iter(),
197            table: self.table,
198            table_row: self.table_row,
199            last_run: self.last_run,
200            this_run: self.this_run,
201        };
202        let sparse = WriteSparseTraitsIter {
203            components: self.registry.sparse_components.iter(),
204            meta: self.registry.sparse_meta.iter(),
205            entity: self.table.entities()[self.table_row.as_usize()],
206            sparse_sets: self.sparse_sets,
207            last_run: self.last_run,
208            this_run: self.this_run,
209        };
210        table.chain(sparse)
211    }
212}
213
214impl<'local, Trait: ?Sized + TraitQuery> IntoIterator for &'local WriteTraits<'_, Trait> {
215    type Item = Ref<'local, Trait>;
216    type IntoIter = CombinedReadTraitsIter<'local, Trait>;
217    #[inline]
218    fn into_iter(self) -> Self::IntoIter {
219        let table = ReadTableTraitsIter {
220            components: self.registry.table_components.iter(),
221            meta: self.registry.table_meta.iter(),
222            table: self.table,
223            table_row: self.table_row,
224            last_run: self.last_run,
225            this_run: self.this_run,
226        };
227        let sparse = ReadSparseTraitsIter {
228            components: self.registry.sparse_components.iter(),
229            meta: self.registry.sparse_meta.iter(),
230            entity: self.table.entities()[self.table_row.as_usize()],
231            sparse_sets: self.sparse_sets,
232            last_run: self.last_run,
233            this_run: self.this_run,
234        };
235        table.chain(sparse)
236    }
237}
238
239impl<'local, Trait: ?Sized + TraitQuery> IntoIterator for &'local mut WriteTraits<'_, Trait> {
240    type Item = Mut<'local, Trait>;
241    type IntoIter = CombinedWriteTraitsIter<'local, Trait>;
242    #[inline]
243    fn into_iter(self) -> Self::IntoIter {
244        let table = WriteTableTraitsIter {
245            components: self.registry.table_components.iter(),
246            meta: self.registry.table_meta.iter(),
247            table: self.table,
248            table_row: self.table_row,
249            last_run: self.last_run,
250            this_run: self.this_run,
251        };
252        let sparse = WriteSparseTraitsIter {
253            components: self.registry.sparse_components.iter(),
254            meta: self.registry.sparse_meta.iter(),
255            entity: self.table.entities()[self.table_row.as_usize()],
256            sparse_sets: self.sparse_sets,
257            last_run: self.last_run,
258            this_run: self.this_run,
259        };
260        table.chain(sparse)
261    }
262}