shipyard/views/view_mut.rs
1use crate::all_storages::AllStorages;
2use crate::atomic_refcell::{ARef, ARefMut, ExclusiveBorrow, SharedBorrow};
3use crate::component::Component;
4use crate::entity_id::EntityId;
5use crate::error;
6use crate::get::Get;
7use crate::r#mut::Mut;
8use crate::sparse_set::{SparseSet, SparseSetDrain};
9use crate::storage::StorageId;
10use crate::track;
11use crate::tracking::{
12 DeletionTracking, Inserted, InsertedOrModified, InsertionTracking, ModificationTracking,
13 Modified, RemovalOrDeletionTracking, RemovalTracking, Tracking, TrackingTimestamp,
14};
15use crate::views::view::View;
16use core::fmt;
17use core::marker::PhantomData;
18use core::ops::{Deref, DerefMut};
19
20/// Exclusive view over a component storage.
21pub struct ViewMut<'a, T: Component, Track = <T as Component>::Tracking> {
22 pub(crate) sparse_set: &'a mut SparseSet<T>,
23 pub(crate) all_borrow: Option<SharedBorrow<'a>>,
24 pub(crate) borrow: ExclusiveBorrow<'a>,
25 pub(crate) last_insertion: TrackingTimestamp,
26 pub(crate) last_modification: TrackingTimestamp,
27 pub(crate) last_removal_or_deletion: TrackingTimestamp,
28 pub(crate) current: TrackingTimestamp,
29 pub(crate) phantom: PhantomData<Track>,
30}
31
32impl<'a, T: Component, Track> ViewMut<'a, T, Track>
33where
34 Track: Tracking,
35{
36 /// Returns a `View` reborrowing from `ViewMut`.
37 ///
38 /// There are often alternatives to calling this method, like reborrow.\
39 /// One case where this method shines is for calling a system in another system.\
40 /// `sys_b` cannot use a reference or it wouldn't work as a system anymore.
41 /// ```rust
42 /// # use shipyard::{track ,Component, View, ViewMut, World};
43 /// # let mut world = World::new();
44 /// # struct A;
45 /// # impl Component for A { type Tracking = track::Untracked; };
46 /// # struct B;
47 /// # impl Component for B { type Tracking = track::Untracked; };
48 ///
49 /// fn sys_a(vm_compA: ViewMut<A>) {
50 /// // -- SNIP --
51 ///
52 /// sys_b(vm_compA.as_view());
53 /// }
54 ///
55 /// fn sys_b(v_compA: View<A>) {}
56 ///
57 /// world.run(sys_a);
58 /// world.run(sys_b);
59 /// ```
60 pub fn as_view(&self) -> View<'_, T, Track> {
61 View {
62 sparse_set: self.sparse_set,
63 all_borrow: self.all_borrow.as_ref().cloned(),
64 borrow: self.borrow.shared_reborrow(),
65 last_insertion: self.last_insertion,
66 last_modification: self.last_modification,
67 last_removal_or_deletion: self.last_removal_or_deletion,
68 current: self.current,
69 phantom: PhantomData,
70 }
71 }
72
73 /// Replaces the timestamp starting the tracking time window for insertions.
74 ///
75 /// Tracking works based on a time window. From the last time the system ran (in workloads)
76 /// or since the last clear.
77 ///
78 /// Sometimes this automatic time window isn't what you need.
79 /// This can happen when you want to keep the same tracking information for multiple runs
80 /// of the same system.
81 ///
82 /// For example if you interpolate movement between frames, you might run an interpolation workload
83 /// multiple times but not change the [`World`](crate::World) during its execution.\
84 /// In this case you want the same tracking information for all runs of this workload
85 /// which would have disappeared using the automatic window.
86 pub fn override_last_insertion(
87 &mut self,
88 new_timestamp: TrackingTimestamp,
89 ) -> TrackingTimestamp {
90 core::mem::replace(&mut self.last_insertion, new_timestamp)
91 }
92
93 /// Replaces the timestamp starting the tracking time window for modifications.
94 ///
95 /// Tracking works based on a time window. From the last time the system ran (in workloads)
96 /// or since the last clear.
97 ///
98 /// Sometimes this automatic time window isn't what you need.
99 /// This can happen when you want to keep the same tracking information for multiple runs
100 /// of the same system.
101 ///
102 /// For example if you interpolate movement between frames, you might run an interpolation workload
103 /// multiple times but not change the [`World`](crate::World) during its execution.\
104 /// In this case you want the same tracking information for all runs of this workload
105 /// which would have disappeared using the automatic window.
106 pub fn override_last_modification(
107 &mut self,
108 new_timestamp: TrackingTimestamp,
109 ) -> TrackingTimestamp {
110 core::mem::replace(&mut self.last_modification, new_timestamp)
111 }
112
113 /// Replaces the timestamp starting the tracking time window for removals and deletions.
114 ///
115 /// Tracking works based on a time window. From the last time the system ran (in workloads)
116 /// or since the last clear.
117 ///
118 /// Sometimes this automatic time window isn't what you need.
119 /// This can happen when you want to keep the same tracking information for multiple runs
120 /// of the same system.
121 ///
122 /// For example if you interpolate movement between frames, you might run an interpolation workload
123 /// multiple times but not change the [`World`](crate::World) during its execution.\
124 /// In this case you want the same tracking information for all runs of this workload
125 /// which would have disappeared using the automatic window.
126 pub fn override_last_removal_or_deletion(
127 &mut self,
128 new_timestamp: TrackingTimestamp,
129 ) -> TrackingTimestamp {
130 core::mem::replace(&mut self.last_removal_or_deletion, new_timestamp)
131 }
132}
133
134impl<'a, T: Component> ViewMut<'a, T, track::Untracked> {
135 /// Creates a new [`ViewMut`] for custom [`SparseSet`] storage.
136 ///
137 /// ```
138 /// use shipyard::{track, advanced::StorageId, Component, sparse_set::SparseSet, ViewMut, World};
139 ///
140 /// struct ScriptingComponent(Vec<u8>);
141 /// impl Component for ScriptingComponent {
142 /// type Tracking = track::Untracked;
143 /// }
144 ///
145 /// let world = World::new();
146 ///
147 /// world.add_custom_storage(
148 /// StorageId::Custom(0),
149 /// SparseSet::<ScriptingComponent>::new_custom_storage(),
150 /// ).unwrap();
151 ///
152 /// let all_storages = world.all_storages().unwrap();
153 /// let scripting_storage =
154 /// ViewMut::<ScriptingComponent>::new_for_custom_storage(StorageId::Custom(0), all_storages)
155 /// .unwrap();
156 /// ```
157 pub fn new_for_custom_storage(
158 storage_id: StorageId,
159 all_storages: ARef<'a, &'a AllStorages>,
160 ) -> Result<Self, error::CustomStorageView> {
161 use crate::all_storages::CustomStorageAccess;
162
163 let (all_storages, all_borrow) = unsafe { ARef::destructure(all_storages) };
164
165 let storage = all_storages.custom_storage_mut_by_id(storage_id)?;
166 let (storage, borrow) = unsafe { ARefMut::destructure(storage) };
167
168 let name = storage.name();
169
170 if let Some(sparse_set) = storage.any_mut().downcast_mut() {
171 Ok(ViewMut {
172 sparse_set,
173 all_borrow: Some(all_borrow),
174 borrow,
175 last_insertion: TrackingTimestamp::new(0),
176 last_modification: TrackingTimestamp::new(0),
177 last_removal_or_deletion: TrackingTimestamp::new(0),
178 current: TrackingTimestamp::new(0),
179 phantom: PhantomData,
180 })
181 } else {
182 Err(error::CustomStorageView::WrongType(name))
183 }
184 }
185}
186
187impl<'a, T: Component, Track> ViewMut<'a, T, Track>
188where
189 Track: Tracking,
190{
191 /// Deletes all components in this storage.
192 pub fn clear(&mut self) {
193 self.sparse_set.private_clear(self.current);
194 }
195 /// Creates a draining iterator that empties the storage and yields the removed items.
196 pub fn drain(&mut self) -> SparseSetDrain<'_, T> {
197 self.sparse_set.private_drain(self.current)
198 }
199 /// Applies the given function `f` to the entities `a` and `b`.\
200 /// The two entities shouldn't point to the same component.
201 ///
202 /// ### Panics
203 ///
204 /// - MissingComponent - if one of the entity doesn't have any component in the storage.
205 /// - IdenticalIds - if the two entities point to the same component.
206 #[track_caller]
207 pub fn apply<R, F: FnOnce(&mut T, &T) -> R>(&mut self, a: EntityId, b: EntityId, f: F) -> R {
208 self.sparse_set.private_apply(a, b, f, self.current)
209 }
210 /// Applies the given function `f` to the entities `a` and `b`.\
211 /// The two entities shouldn't point to the same component.
212 ///
213 /// ### Panics
214 ///
215 /// - MissingComponent - if one of the entity doesn't have any component in the storage.
216 /// - IdenticalIds - if the two entities point to the same component.
217 #[track_caller]
218 pub fn apply_mut<R, F: FnOnce(&mut T, &mut T) -> R>(
219 &mut self,
220 a: EntityId,
221 b: EntityId,
222 f: F,
223 ) -> R {
224 self.sparse_set.private_apply_mut(a, b, f, self.current)
225 }
226
227 /// Deletes all components for which `f(id, &component)` returns `false`.
228 pub fn retain<F: FnMut(EntityId, &T) -> bool>(&mut self, f: F) {
229 self.sparse_set.private_retain(self.current, f);
230 }
231
232 /// Deletes all components for which `f(id, Mut<component>)` returns `false`.
233 pub fn retain_mut<F: FnMut(EntityId, Mut<'_, T>) -> bool>(&mut self, f: F) {
234 self.sparse_set.private_retain_mut(self.current, f);
235 }
236}
237
238impl<'v, Track, T: Component + Default> ViewMut<'v, T, Track>
239where
240 for<'a> &'a mut ViewMut<'v, T, Track>: Get,
241{
242 /// Retrieve `entity` component.
243 ///
244 /// If the entity doesn't have the component, insert its `Default` value.
245 ///
246 /// ### Errors
247 ///
248 /// Returns `None` when `entity` is dead and a component is already present for an entity with the same index.
249 #[inline]
250 pub fn get_or_default<'a>(
251 &'a mut self,
252 entity: EntityId,
253 ) -> Option<<&'a mut ViewMut<'v, T, Track> as Get>::Out> {
254 self.get_or_insert_with(entity, T::default)
255 }
256}
257
258impl<'v, Track, T: Component> ViewMut<'v, T, Track>
259where
260 for<'a> &'a mut ViewMut<'v, T, Track>: Get,
261{
262 /// Retrieve `entity` component.
263 ///
264 /// If the entity doesn't have the component, insert `component`.
265 ///
266 /// ### Errors
267 ///
268 /// Returns `None` when `entity` is dead and a component is already present for an entity with the same index.
269 #[inline]
270 pub fn get_or_insert<'a>(
271 &'a mut self,
272 entity: EntityId,
273 component: T,
274 ) -> Option<<&'a mut ViewMut<'v, T, Track> as Get>::Out> {
275 self.get_or_insert_with(entity, || component)
276 }
277 /// Retrieve `entity` component.
278 ///
279 /// If the entity doesn't have the component, insert the result of `f`.
280 ///
281 /// ### Errors
282 ///
283 /// Returns `None` when `entity` is dead and a component is already present for an entity with the same index.
284 #[inline]
285 pub fn get_or_insert_with<'a, F: FnOnce() -> T>(
286 &'a mut self,
287 entity: EntityId,
288 f: F,
289 ) -> Option<<&'a mut ViewMut<'v, T, Track> as Get>::Out> {
290 if !self.sparse_set.contains(entity) {
291 let was_inserted = self
292 .sparse_set
293 .insert(entity, f(), self.current)
294 .was_inserted();
295
296 if !was_inserted {
297 return None;
298 }
299 }
300
301 // At this point, it is not possible for the entity to not have a component of this type.
302 let component = unsafe { Get::get(self, entity).unwrap_unchecked() };
303
304 Some(component)
305 }
306}
307
308impl<Track, T: Component> ViewMut<'_, T, Track>
309where
310 Track: InsertionTracking,
311{
312 /// Inside a workload returns `true` if `entity`'s component was inserted since the last run of this system.\
313 /// Outside workloads returns `true` if `entity`'s component was inserted since the last call to [`clear_all_inserted`](ViewMut::clear_all_inserted).\
314 /// Returns `false` if `entity` does not have a component in this storage.
315 #[inline]
316 pub fn is_inserted(&self, entity: EntityId) -> bool {
317 Track::is_inserted(self.sparse_set, entity, self.last_insertion, self.current)
318 }
319 /// Wraps this view to be able to iterate *inserted* components.
320 #[inline]
321 pub fn inserted(&self) -> Inserted<&Self> {
322 Inserted(self)
323 }
324 /// Wraps this view to be able to iterate *inserted* components.
325 #[inline]
326 pub fn inserted_mut(&mut self) -> Inserted<&mut Self> {
327 Inserted(self)
328 }
329 /// Removes the *inserted* flag on all components of this storage.
330 #[inline]
331 pub fn clear_all_inserted(self) {
332 self.sparse_set.private_clear_all_inserted(self.current);
333 }
334}
335
336impl<Track, T: Component> ViewMut<'_, T, Track>
337where
338 Track: ModificationTracking,
339{
340 /// Inside a workload returns `true` if `entity`'s component was modified since the last run of this system.\
341 /// Outside workloads returns `true` if `entity`'s component was modified since the last call to [`clear_all_modified`](ViewMut::clear_all_modified).\
342 /// Returns `false` if `entity` does not have a component in this storage.
343 #[inline]
344 pub fn is_modified(&self, entity: EntityId) -> bool {
345 Track::is_modified(
346 self.sparse_set,
347 entity,
348 self.last_modification,
349 self.current,
350 )
351 }
352 /// Wraps this view to be able to iterate *modified* components.
353 #[inline]
354 pub fn modified(&self) -> Modified<&Self> {
355 Modified(self)
356 }
357 /// Wraps this view to be able to iterate *modified* components.
358 #[inline]
359 pub fn modified_mut(&mut self) -> Modified<&mut Self> {
360 Modified(self)
361 }
362 /// Removes the *modified* flag on all components of this storage.
363 #[inline]
364 pub fn clear_all_modified(self) {
365 self.sparse_set.private_clear_all_modified(self.current);
366 }
367}
368
369impl<Track, T: Component> ViewMut<'_, T, Track>
370where
371 Track: InsertionTracking + ModificationTracking,
372{
373 /// Inside a workload returns `true` if `entity`'s component was inserted or modified since the last run of this system.\
374 /// Outside workloads returns `true` if `entity`'s component was inserted or modified since the last call to [`clear_all_inserted`](ViewMut::clear_all_inserted).\
375 /// Returns `false` if `entity` does not have a component in this storage.
376 #[inline]
377 pub fn is_inserted_or_modified(&self, entity: EntityId) -> bool {
378 self.is_inserted(entity) || self.is_modified(entity)
379 }
380 /// Wraps this view to be able to iterate *inserted* and *modified* components.
381 #[inline]
382 pub fn inserted_or_modified(&self) -> InsertedOrModified<&Self> {
383 InsertedOrModified(self)
384 }
385 /// Wraps this view to be able to iterate *inserted* and *modified* components.
386 #[inline]
387 pub fn inserted_or_modified_mut(&mut self) -> InsertedOrModified<&mut Self> {
388 InsertedOrModified(self)
389 }
390 /// Removes the *inserted* and *modified* flags on all components of this storage.
391 #[inline]
392 pub fn clear_all_inserted_and_modified(self) {
393 self.sparse_set
394 .private_clear_all_inserted_and_modified(self.current);
395 }
396}
397
398impl<Track, T: Component> ViewMut<'_, T, Track>
399where
400 Track: DeletionTracking,
401{
402 /// Inside a workload returns `true` if `entity`'s component was deleted since the last run of this system.\
403 /// Outside workloads returns `true` if `entity`'s component was deleted since the last call to [`clear_all_deleted`](SparseSet::clear_all_deleted).\
404 /// Returns `false` if `entity` does not have a component in this storage.
405 #[inline]
406 pub fn is_deleted(&self, entity: EntityId) -> bool {
407 Track::is_deleted(self, entity, self.last_removal_or_deletion, self.current)
408 }
409 /// Returns the *deleted* components of a storage tracking deletion.
410 pub fn deleted(&self) -> impl Iterator<Item = (EntityId, &T)> + '_ {
411 self.sparse_set
412 .deletion_data
413 .iter()
414 .filter_map(move |(entity, timestamp, component)| {
415 if timestamp.is_within(self.last_removal_or_deletion, self.current) {
416 Some((*entity, component))
417 } else {
418 None
419 }
420 })
421 }
422}
423
424impl<Track, T: Component> ViewMut<'_, T, Track>
425where
426 Track: RemovalTracking,
427{
428 /// Inside a workload returns `true` if `entity`'s component was removed since the last run of this system.\
429 /// Outside workloads returns `true` if `entity`'s component was removed since the last call to [`clear_all_removed`](SparseSet::clear_all_removed).\
430 /// Returns `false` if `entity` does not have a component in this storage.
431 #[inline]
432 pub fn is_removed(&self, entity: EntityId) -> bool {
433 Track::is_removed(self, entity, self.last_removal_or_deletion, self.current)
434 }
435 /// Returns the ids of *removed* components of a storage tracking removal.
436 pub fn removed(&self) -> impl Iterator<Item = EntityId> + '_ {
437 self.sparse_set
438 .removal_data
439 .iter()
440 .filter_map(move |(entity, timestamp)| {
441 if timestamp.is_within(self.last_removal_or_deletion, self.current) {
442 Some(*entity)
443 } else {
444 None
445 }
446 })
447 }
448}
449
450impl<Track, T: Component> ViewMut<'_, T, Track>
451where
452 Track: RemovalOrDeletionTracking,
453{
454 /// Inside a workload returns `true` if `entity`'s component was deleted or removed since the last run of this system.\
455 /// Outside workloads returns `true` if `entity`'s component was deleted or removed since the last clear call.\
456 /// Returns `false` if `entity` does not have a component in this storage.
457 #[inline]
458 pub fn is_removed_or_deleted(&self, entity: EntityId) -> bool {
459 Track::is_removed(self, entity, self.last_removal_or_deletion, self.current)
460 || Track::is_deleted(self, entity, self.last_removal_or_deletion, self.current)
461 }
462 /// Returns the ids of *removed* or *deleted* components of a storage tracking removal and/or deletion.
463 pub fn removed_or_deleted(&self) -> impl Iterator<Item = EntityId> + '_ {
464 Track::removed_or_deleted(self.sparse_set).filter_map(move |(entity, timestamp)| {
465 if timestamp.is_within(self.last_removal_or_deletion, self.current) {
466 Some(entity)
467 } else {
468 None
469 }
470 })
471 }
472}
473
474impl<T: Component, Track> Deref for ViewMut<'_, T, Track> {
475 type Target = SparseSet<T>;
476
477 #[inline]
478 fn deref(&self) -> &Self::Target {
479 self.sparse_set
480 }
481}
482
483impl<T: Component, Track> DerefMut for ViewMut<'_, T, Track> {
484 #[inline]
485 fn deref_mut(&mut self) -> &mut Self::Target {
486 self.sparse_set
487 }
488}
489
490impl<'a, T: Component, Track> AsRef<SparseSet<T>> for ViewMut<'a, T, Track> {
491 #[inline]
492 fn as_ref(&self) -> &SparseSet<T> {
493 self.sparse_set
494 }
495}
496
497impl<'a, T: Component, Track> AsMut<SparseSet<T>> for ViewMut<'a, T, Track> {
498 #[inline]
499 fn as_mut(&mut self) -> &mut SparseSet<T> {
500 self.sparse_set
501 }
502}
503
504impl<'a, T: Component, Track> AsMut<Self> for ViewMut<'a, T, Track> {
505 #[inline]
506 fn as_mut(&mut self) -> &mut Self {
507 self
508 }
509}
510
511impl<T: fmt::Debug + Component, Track> fmt::Debug for ViewMut<'_, T, Track> {
512 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
513 self.sparse_set.fmt(f)
514 }
515}
516
517impl<'a, T: Component, Track> core::ops::Index<EntityId> for ViewMut<'a, T, Track> {
518 type Output = T;
519 #[inline]
520 fn index(&self, entity: EntityId) -> &Self::Output {
521 self.get(entity).unwrap()
522 }
523}
524
525impl<'a, T: Component, Track> core::ops::IndexMut<EntityId> for ViewMut<'a, T, Track> {
526 #[inline]
527 fn index_mut(&mut self, entity: EntityId) -> &mut Self::Output {
528 let index = self
529 .index_of(entity)
530 .ok_or_else(|| error::MissingComponent {
531 id: entity,
532 name: core::any::type_name::<T>(),
533 })
534 .unwrap();
535
536 let SparseSet {
537 data,
538 modification_data,
539 is_tracking_modification,
540 ..
541 } = self.sparse_set;
542
543 if *is_tracking_modification {
544 unsafe {
545 *modification_data.get_unchecked_mut(index) = self.current;
546 };
547 }
548
549 unsafe { data.get_unchecked_mut(index) }
550 }
551}