lyra-engine/src/change_tracker.rs

119 lines
2.7 KiB
Rust
Raw Normal View History

2023-09-16 15:52:20 +00:00
use std::ops::{DerefMut, Deref};
/// A change tracker. This tracks changes of the data it owns.
/// Tracking changes can cause false positives since it actually tracks calls to `deref_mut()`
/// If you mutably dereference this, make sure its only when you change the data.
pub struct Ct<T> {
data: T,
changed: bool,
}
impl<T> Ct<T> {
pub fn new(data: T) -> Self {
Self {
data,
changed: false,
}
}
/// Create a new change tracker with data
pub fn new_true(data: T) -> Self {
Self {
data,
changed: true,
}
}
/// Returns true if there was a change. Will reset back to false after this is called.
pub fn changed(&mut self) -> bool {
let before = self.changed;
self.reset();
before
}
/// Returns true if there was a change, will NOT reset back to false.
pub fn peek_changed(&self) -> bool {
self.changed
}
2023-09-16 15:52:20 +00:00
/// Resets the changed tracker to be false
pub fn reset(&mut self) {
self.changed = false;
}
/// Triggers the change tracker to be true
pub fn trigger(&mut self) {
self.changed = true;
}
2023-09-16 15:52:20 +00:00
/// Silently mutate the inner data, this wont be tracked
pub fn silently_mutate(&mut self) -> &mut T {
2023-09-16 15:52:20 +00:00
&mut self.data
}
/// Consumes self and returns the data stored inside.
pub fn take(self) -> T {
self.data
}
}
impl<T> Deref for Ct<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<T> DerefMut for Ct<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.changed = true;
&mut self.data
}
}
#[cfg(test)]
mod tests {
use super::Ct;
#[test]
fn new() {
let mut c = Ct::new(100);
assert!(!c.changed());
let mut c = Ct::new_true(100);
assert!(c.changed());
assert!(!c.changed()); // it should've reset itself
2023-09-16 15:52:20 +00:00
}
#[test]
fn change_tracking() {
let mut c = Ct::new(100);
assert!(!c.changed());
*c = 10;
assert!(c.changed());
assert!(!c.changed()); // should now be not changed
}
#[test]
fn silent_mutate() {
let mut c = Ct::new(100);
let a = c.silently_mutate();
2023-09-16 15:52:20 +00:00
*a = 10;
assert!(!c.changed());
}
#[test]
fn reset_trigger() {
2023-09-16 15:52:20 +00:00
let mut c = Ct::new(100);
*c = 10;
c.reset();
assert!(!c.changed()); // should not be changed because of reset
let mut c = Ct::new(100);
c.trigger();
assert!(c.changed()); // should changed because of trigger
assert!(!c.changed()); // should've reset itself
2023-09-16 15:52:20 +00:00
}
}