lyra-engine/lyra-ecs/src/tick.rs

88 lines
2.3 KiB
Rust

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<u64> 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);
}
}