use std::sync::atomic::{AtomicU64, Ordering}; /// TickTracker is used for tracking changes of [`Component`]s and entities. /// /// TickTracker stores an [`AtomicU64`], making all operations on `TickTracker`, atomic as well. /// Note that [`Tick::Clone`] only clones the inner value of atomic, and not the atomic itself. #[derive(Debug, Default)] pub struct TickTracker { tick: AtomicU64, } impl Clone for TickTracker { fn clone(&self) -> Self { Self { tick: AtomicU64::from(self.tick.load(Ordering::Acquire)), } } } impl From for TickTracker { fn from(value: u64) -> Self { Self { tick: AtomicU64::from(value), } } } impl TickTracker { /// Create a new tracker starting at zero ticks. pub fn new() -> Self { Self::default() } /// Increment the tick counter, and return the new Tick. pub fn tick(&self) -> Tick { let old = self.tick.fetch_add(1, Ordering::Relaxed); Tick(old + 1) } /// If `when` is true, increment the tick counter. pub fn tick_when(&self, when: bool) -> Tick { if when { self.tick() } else { self.current() } } /// Sync this TickTracker with the provided `Tick`. /// /// This will only update the tracker if `Tick` is larger than self. pub fn tick_to(&self, other: &Tick) -> Tick { self.tick.fetch_max(other.0, Ordering::AcqRel); Tick(self.tick.load(Ordering::Acquire)) } /// Sync this TickTracker with the other tracker. /// /// This will only update the tracker if other is larger than self. pub fn sync_tracker(&self, other: &TickTracker) -> Tick { let other = other.tick.load(Ordering::Acquire); self.tick_to(&Tick(other)) } /// Gets the current Tick that the tracker is at. pub fn current(&self) -> Tick { Tick(self.tick.load(Ordering::Acquire)) } } /// A specific Tick that was resulted from ticking a [`TickTracker`]. #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Default, PartialOrd, Ord)] pub struct Tick(u64); impl std::ops::Deref for Tick { type Target = u64; fn deref(&self) -> &Self::Target { &self.0 } } impl Tick { /// Increment this Tick up to `other` pub fn tick_to(&mut self, other: &Tick) { self.0 = self.0.max(other.0); } }