|
2 | 2 |
|
3 | 3 | use crate::{
|
4 | 4 | component::{Tick, TickCells},
|
5 |
| - ptr::PtrMut, |
| 5 | + ptr::{Batch, PtrMut, UnsafeCellDeref}, |
6 | 6 | system::Resource,
|
7 | 7 | };
|
8 |
| -use bevy_ptr::UnsafeCellDeref; |
| 8 | +use core::marker::PhantomData; |
9 | 9 | use std::ops::{Deref, DerefMut};
|
10 | 10 |
|
11 | 11 | /// The (arbitrarily chosen) minimum number of world tick increments between `check_tick` scans.
|
@@ -283,6 +283,12 @@ impl<'a> Ticks<'a> {
|
283 | 283 | }
|
284 | 284 | }
|
285 | 285 | }
|
| 286 | +pub(crate) struct TicksBatch<'a, const N: usize> { |
| 287 | + pub(crate) added_ticks: &'a mut Batch<Tick, N>, |
| 288 | + pub(crate) changed_ticks: &'a mut Batch<Tick, N>, |
| 289 | + pub(crate) last_change_tick: u32, |
| 290 | + pub(crate) change_tick: u32, |
| 291 | +} |
286 | 292 |
|
287 | 293 | /// Unique mutable borrow of a [`Resource`].
|
288 | 294 | ///
|
@@ -407,6 +413,118 @@ change_detection_impl!(Mut<'a, T>, T,);
|
407 | 413 | impl_methods!(Mut<'a, T>, T,);
|
408 | 414 | impl_debug!(Mut<'a, T>,);
|
409 | 415 |
|
| 416 | +/// Unique mutable borrow of an entity's component (batched version). |
| 417 | +/// Each batch changes in unison: a batch has changed if any of its elements have changed. |
| 418 | +pub struct MutBatch<'a, T, const N: usize> { |
| 419 | + pub(crate) value: &'a mut Batch<T, N>, |
| 420 | + pub(crate) ticks: TicksBatch<'a, N>, |
| 421 | + pub(crate) _marker: PhantomData<T>, |
| 422 | +} |
| 423 | + |
| 424 | +impl<'a, T, const N: usize> DetectChanges for MutBatch<'a, T, N> { |
| 425 | + #[inline] |
| 426 | + fn is_added(&self) -> bool { |
| 427 | + self.ticks |
| 428 | + .added_ticks |
| 429 | + .iter() |
| 430 | + .any(|x| x.is_older_than(self.ticks.last_change_tick, self.ticks.change_tick)) |
| 431 | + } |
| 432 | + |
| 433 | + #[inline] |
| 434 | + fn is_changed(&self) -> bool { |
| 435 | + self.ticks |
| 436 | + .changed_ticks |
| 437 | + .iter() |
| 438 | + .any(|x| x.is_older_than(self.ticks.last_change_tick, self.ticks.change_tick)) |
| 439 | + } |
| 440 | + |
| 441 | + #[inline] |
| 442 | + fn set_changed(&mut self) { |
| 443 | + for ticks in self.ticks.changed_ticks.iter_mut() { |
| 444 | + ticks.set_changed(self.ticks.change_tick); |
| 445 | + } |
| 446 | + } |
| 447 | + |
| 448 | + #[inline] |
| 449 | + fn last_changed(&self) -> u32 { |
| 450 | + self.ticks.last_change_tick |
| 451 | + } |
| 452 | + |
| 453 | + type Inner = Batch<T, N>; |
| 454 | + |
| 455 | + fn set_last_changed(&mut self, last_change_tick: u32) { |
| 456 | + self.ticks.last_change_tick = last_change_tick; |
| 457 | + } |
| 458 | + |
| 459 | + fn bypass_change_detection(&mut self) -> &mut Self::Inner { |
| 460 | + self.value |
| 461 | + } |
| 462 | + |
| 463 | + #[inline] |
| 464 | + fn set_if_neq<Target>(&mut self, value: Target) |
| 465 | + where |
| 466 | + Self: Deref<Target = Target> + DerefMut<Target = Target>, |
| 467 | + Target: PartialEq, |
| 468 | + { |
| 469 | + // This dereference is immutable, so does not trigger change detection |
| 470 | + if *<Self as Deref>::deref(self) != value { |
| 471 | + // `DerefMut` usage triggers change detection |
| 472 | + *<Self as DerefMut>::deref_mut(self) = value; |
| 473 | + } |
| 474 | + } |
| 475 | +} |
| 476 | + |
| 477 | +impl<'a, T, const N: usize> Deref for MutBatch<'a, T, N> { |
| 478 | + type Target = Batch<T, N>; |
| 479 | + |
| 480 | + #[inline] |
| 481 | + fn deref(&self) -> &Self::Target { |
| 482 | + self.value |
| 483 | + } |
| 484 | +} |
| 485 | + |
| 486 | +impl<'a, T, const N: usize> DerefMut for MutBatch<'a, T, N> { |
| 487 | + #[inline] |
| 488 | + fn deref_mut(&mut self) -> &mut Self::Target { |
| 489 | + self.set_changed(); |
| 490 | + self.value |
| 491 | + } |
| 492 | +} |
| 493 | + |
| 494 | +impl<'a, T, const N: usize> AsRef<Batch<T, N>> for MutBatch<'a, T, N> { |
| 495 | + #[inline] |
| 496 | + fn as_ref(&self) -> &Batch<T, N> { |
| 497 | + self.deref() |
| 498 | + } |
| 499 | +} |
| 500 | + |
| 501 | +impl<'a, T, const N: usize> AsMut<Batch<T, N>> for MutBatch<'a, T, N> { |
| 502 | + #[inline] |
| 503 | + fn as_mut(&mut self) -> &mut Batch<T, N> { |
| 504 | + self.deref_mut() |
| 505 | + } |
| 506 | +} |
| 507 | + |
| 508 | +impl<'a, T, const N: usize> MutBatch<'a, T, N> { |
| 509 | + /// Consume `self` and return a mutable reference to the |
| 510 | + /// contained value while marking `self` as "changed". |
| 511 | + #[inline] |
| 512 | + pub fn into_inner(mut self) -> &'a mut Batch<T, N> { |
| 513 | + self.set_changed(); |
| 514 | + self.value |
| 515 | + } |
| 516 | +} |
| 517 | + |
| 518 | +impl<'a, T, const N: usize> std::fmt::Debug for MutBatch<'a, T, N> |
| 519 | +where |
| 520 | + Batch<T, N>: std::fmt::Debug, |
| 521 | + T: std::fmt::Debug, |
| 522 | +{ |
| 523 | + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 524 | + f.debug_tuple(stringify!($name)).field(&self.value).finish() |
| 525 | + } |
| 526 | +} |
| 527 | + |
410 | 528 | /// Unique mutable borrow of resources or an entity's component.
|
411 | 529 | ///
|
412 | 530 | /// Similar to [`Mut`], but not generic over the component type, instead
|
|
0 commit comments