#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq)]
pub struct ChangeRecord {
pub field: String,
pub dirty: bool,
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct ChangeTrackerConfig {
pub max_records: usize,
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct ChangeTracker {
pub config: ChangeTrackerConfig,
pub records: Vec<ChangeRecord>,
}
#[allow(dead_code)]
pub fn default_change_tracker_config() -> ChangeTrackerConfig {
ChangeTrackerConfig { max_records: 0 }
}
#[allow(dead_code)]
pub fn new_change_tracker(cfg: &ChangeTrackerConfig) -> ChangeTracker {
ChangeTracker {
config: cfg.clone(),
records: Vec::new(),
}
}
#[allow(dead_code)]
pub fn tracker_mark_changed(tracker: &mut ChangeTracker, field: &str) {
if let Some(rec) = tracker.records.iter_mut().find(|r| r.field == field) {
rec.dirty = true;
} else {
tracker.records.push(ChangeRecord {
field: field.to_string(),
dirty: true,
});
}
}
#[allow(dead_code)]
pub fn tracker_is_changed(tracker: &ChangeTracker, field: &str) -> bool {
tracker
.records
.iter()
.any(|r| r.field == field && r.dirty)
}
#[allow(dead_code)]
pub fn tracker_changed_fields(tracker: &ChangeTracker) -> Vec<&str> {
tracker
.records
.iter()
.filter(|r| r.dirty)
.map(|r| r.field.as_str())
.collect()
}
#[allow(dead_code)]
pub fn tracker_flush(tracker: &mut ChangeTracker) {
for rec in &mut tracker.records {
rec.dirty = false;
}
}
#[allow(dead_code)]
pub fn tracker_change_count(tracker: &ChangeTracker) -> usize {
tracker.records.iter().filter(|r| r.dirty).count()
}
#[allow(dead_code)]
pub fn tracker_any_changed(tracker: &ChangeTracker) -> bool {
tracker.records.iter().any(|r| r.dirty)
}
#[allow(dead_code)]
pub fn tracker_mark_all_clean(tracker: &mut ChangeTracker) {
tracker_flush(tracker);
}
#[allow(dead_code)]
pub fn tracker_record_count(tracker: &ChangeTracker) -> usize {
tracker.records.len()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let cfg = default_change_tracker_config();
assert_eq!(cfg.max_records, 0);
}
#[test]
fn test_new_tracker_empty() {
let cfg = default_change_tracker_config();
let tracker = new_change_tracker(&cfg);
assert_eq!(tracker_record_count(&tracker), 0);
assert!(!tracker_any_changed(&tracker));
}
#[test]
fn test_mark_and_is_changed() {
let cfg = default_change_tracker_config();
let mut tracker = new_change_tracker(&cfg);
tracker_mark_changed(&mut tracker, "position");
assert!(tracker_is_changed(&tracker, "position"));
assert!(!tracker_is_changed(&tracker, "rotation"));
}
#[test]
fn test_changed_fields() {
let cfg = default_change_tracker_config();
let mut tracker = new_change_tracker(&cfg);
tracker_mark_changed(&mut tracker, "x");
tracker_mark_changed(&mut tracker, "y");
let fields = tracker_changed_fields(&tracker);
assert_eq!(fields.len(), 2);
assert!(fields.contains(&"x"));
assert!(fields.contains(&"y"));
}
#[test]
fn test_flush() {
let cfg = default_change_tracker_config();
let mut tracker = new_change_tracker(&cfg);
tracker_mark_changed(&mut tracker, "scale");
assert!(tracker_any_changed(&tracker));
tracker_flush(&mut tracker);
assert!(!tracker_any_changed(&tracker));
assert_eq!(tracker_record_count(&tracker), 1);
}
#[test]
fn test_change_count() {
let cfg = default_change_tracker_config();
let mut tracker = new_change_tracker(&cfg);
tracker_mark_changed(&mut tracker, "a");
tracker_mark_changed(&mut tracker, "b");
tracker_mark_changed(&mut tracker, "c");
assert_eq!(tracker_change_count(&tracker), 3);
}
#[test]
fn test_mark_all_clean() {
let cfg = default_change_tracker_config();
let mut tracker = new_change_tracker(&cfg);
tracker_mark_changed(&mut tracker, "alpha");
tracker_mark_changed(&mut tracker, "beta");
tracker_mark_all_clean(&mut tracker);
assert_eq!(tracker_change_count(&tracker), 0);
assert_eq!(tracker_record_count(&tracker), 2);
}
#[test]
fn test_mark_changed_idempotent() {
let cfg = default_change_tracker_config();
let mut tracker = new_change_tracker(&cfg);
tracker_mark_changed(&mut tracker, "x");
tracker_mark_changed(&mut tracker, "x"); assert_eq!(tracker_record_count(&tracker), 1);
assert_eq!(tracker_change_count(&tracker), 1);
}
#[test]
fn test_any_changed_false_after_flush() {
let cfg = default_change_tracker_config();
let mut tracker = new_change_tracker(&cfg);
tracker_mark_changed(&mut tracker, "color");
tracker_flush(&mut tracker);
assert!(!tracker_any_changed(&tracker));
tracker_mark_changed(&mut tracker, "color");
assert!(tracker_any_changed(&tracker));
}
}