|
1 | 1 | //! Types that detect when their internal data mutate.
|
2 | 2 |
|
| 3 | +use crate::ptr::{ |
| 4 | + batch::AlignedBatch, |
| 5 | + elain::{Align, Alignment}, |
| 6 | +}; |
| 7 | + |
3 | 8 | use crate::{component::ComponentTicks, ptr::PtrMut, system::Resource};
|
4 |
| -use std::ops::{Deref, DerefMut}; |
| 9 | +use std::{ |
| 10 | + marker::PhantomData, |
| 11 | + ops::{Deref, DerefMut}, |
| 12 | +}; |
5 | 13 |
|
6 | 14 | /// The (arbitrarily chosen) minimum number of world tick increments between `check_tick` scans.
|
7 | 15 | ///
|
@@ -229,6 +237,15 @@ pub(crate) struct Ticks<'a> {
|
229 | 237 | pub(crate) change_tick: u32,
|
230 | 238 | }
|
231 | 239 |
|
| 240 | +pub(crate) struct TicksBatch<'a, const N: usize, const MIN_ALIGN: usize> |
| 241 | +where |
| 242 | + Align<MIN_ALIGN>: Alignment, |
| 243 | +{ |
| 244 | + pub(crate) component_ticks: &'a mut AlignedBatch<ComponentTicks, N, MIN_ALIGN>, |
| 245 | + pub(crate) last_change_tick: u32, |
| 246 | + pub(crate) change_tick: u32, |
| 247 | +} |
| 248 | + |
232 | 249 | /// Unique mutable borrow of a [`Resource`].
|
233 | 250 | ///
|
234 | 251 | /// See the [`Resource`] documentation for usage.
|
@@ -352,6 +369,132 @@ change_detection_impl!(Mut<'a, T>, T,);
|
352 | 369 | impl_methods!(Mut<'a, T>, T,);
|
353 | 370 | impl_debug!(Mut<'a, T>,);
|
354 | 371 |
|
| 372 | +/// Unique mutable borrow of an entity's component (batched version). |
| 373 | +/// Each batch changes in unison: a batch has changed if any of its elements have changed. |
| 374 | +pub struct MutBatch<'a, T, const N: usize, const MIN_ALIGN: usize> |
| 375 | +where |
| 376 | + Align<MIN_ALIGN>: Alignment, |
| 377 | +{ |
| 378 | + pub(crate) value: &'a mut AlignedBatch<T, N, MIN_ALIGN>, |
| 379 | + pub(crate) ticks: TicksBatch<'a, N, MIN_ALIGN>, |
| 380 | + pub(crate) _marker: PhantomData<T>, |
| 381 | +} |
| 382 | + |
| 383 | +impl<'a, T, const N: usize, const MIN_ALIGN: usize> DetectChanges for MutBatch<'a, T, N, MIN_ALIGN> |
| 384 | +where |
| 385 | + Align<MIN_ALIGN>: Alignment, |
| 386 | +{ |
| 387 | + #[inline] |
| 388 | + fn is_added(&self) -> bool { |
| 389 | + self.ticks |
| 390 | + .component_ticks |
| 391 | + .as_array() |
| 392 | + .iter() |
| 393 | + .any(|x| x.is_added(self.ticks.last_change_tick, self.ticks.change_tick)) |
| 394 | + } |
| 395 | + |
| 396 | + #[inline] |
| 397 | + fn is_changed(&self) -> bool { |
| 398 | + self.ticks |
| 399 | + .component_ticks |
| 400 | + .as_array() |
| 401 | + .iter() |
| 402 | + .any(|x| x.is_changed(self.ticks.last_change_tick, self.ticks.change_tick)) |
| 403 | + } |
| 404 | + |
| 405 | + #[inline] |
| 406 | + fn set_changed(&mut self) { |
| 407 | + for ticks in self.ticks.component_ticks.as_array_mut().iter_mut() { |
| 408 | + ticks.set_changed(self.ticks.change_tick); |
| 409 | + } |
| 410 | + } |
| 411 | + |
| 412 | + #[inline] |
| 413 | + fn last_changed(&self) -> u32 { |
| 414 | + self.ticks.last_change_tick |
| 415 | + } |
| 416 | + |
| 417 | + type Inner = AlignedBatch<T, N, MIN_ALIGN>; |
| 418 | + |
| 419 | + fn set_last_changed(&mut self, last_change_tick: u32) { |
| 420 | + self.ticks.last_change_tick = last_change_tick; |
| 421 | + } |
| 422 | + |
| 423 | + fn bypass_change_detection(&mut self) -> &mut Self::Inner { |
| 424 | + self.value |
| 425 | + } |
| 426 | +} |
| 427 | + |
| 428 | +impl<'a, T, const N: usize, const MIN_ALIGN: usize> Deref for MutBatch<'a, T, N, MIN_ALIGN> |
| 429 | +where |
| 430 | + Align<MIN_ALIGN>: Alignment, |
| 431 | +{ |
| 432 | + type Target = AlignedBatch<T, N, MIN_ALIGN>; |
| 433 | + |
| 434 | + #[inline] |
| 435 | + fn deref(&self) -> &Self::Target { |
| 436 | + self.value |
| 437 | + } |
| 438 | +} |
| 439 | + |
| 440 | +impl<'a, T, const N: usize, const MIN_ALIGN: usize> DerefMut for MutBatch<'a, T, N, MIN_ALIGN> |
| 441 | +where |
| 442 | + Align<MIN_ALIGN>: Alignment, |
| 443 | +{ |
| 444 | + #[inline] |
| 445 | + fn deref_mut(&mut self) -> &mut Self::Target { |
| 446 | + self.set_changed(); |
| 447 | + self.value |
| 448 | + } |
| 449 | +} |
| 450 | + |
| 451 | +impl<'a, T, const N: usize, const MIN_ALIGN: usize> AsRef<AlignedBatch<T, N, MIN_ALIGN>> |
| 452 | + for MutBatch<'a, T, N, MIN_ALIGN> |
| 453 | +where |
| 454 | + Align<MIN_ALIGN>: Alignment, |
| 455 | +{ |
| 456 | + #[inline] |
| 457 | + fn as_ref(&self) -> &AlignedBatch<T, N, MIN_ALIGN> { |
| 458 | + self.deref() |
| 459 | + } |
| 460 | +} |
| 461 | + |
| 462 | +impl<'a, T, const N: usize, const MIN_ALIGN: usize> AsMut<AlignedBatch<T, N, MIN_ALIGN>> |
| 463 | + for MutBatch<'a, T, N, MIN_ALIGN> |
| 464 | +where |
| 465 | + Align<MIN_ALIGN>: Alignment, |
| 466 | +{ |
| 467 | + #[inline] |
| 468 | + fn as_mut(&mut self) -> &mut AlignedBatch<T, N, MIN_ALIGN> { |
| 469 | + self.deref_mut() |
| 470 | + } |
| 471 | +} |
| 472 | + |
| 473 | +impl<'a, T, const N: usize, const MIN_ALIGN: usize> MutBatch<'a, T, N, MIN_ALIGN> |
| 474 | +where |
| 475 | + Align<MIN_ALIGN>: Alignment, |
| 476 | +{ |
| 477 | + /// Consume `self` and return a mutable reference to the |
| 478 | + /// contained value while marking `self` as "changed". |
| 479 | + #[inline] |
| 480 | + pub fn into_inner(mut self) -> &'a mut AlignedBatch<T, N, MIN_ALIGN> { |
| 481 | + self.set_changed(); |
| 482 | + self.value |
| 483 | + } |
| 484 | +} |
| 485 | + |
| 486 | +impl<'a, T, const N: usize, const MIN_ALIGN: usize> std::fmt::Debug |
| 487 | + for MutBatch<'a, T, N, MIN_ALIGN> |
| 488 | +where |
| 489 | + Align<MIN_ALIGN>: Alignment, |
| 490 | + AlignedBatch<T, N, MIN_ALIGN>: std::fmt::Debug, |
| 491 | + T: std::fmt::Debug, |
| 492 | +{ |
| 493 | + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 494 | + f.debug_tuple(stringify!($name)).field(&self.value).finish() |
| 495 | + } |
| 496 | +} |
| 497 | + |
355 | 498 | /// Unique mutable borrow of resources or an entity's component.
|
356 | 499 | ///
|
357 | 500 | /// Similar to [`Mut`], but not generic over the component type, instead
|
|
0 commit comments