use std::collections::HashMap;
use std::time::{SystemTime, UNIX_EPOCH};
use crate::plugins::wow::wotlk::realm::object::PackedGuid;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ObjectLifecycle {
created_at: u64,
updated_at: u64,
removed_at: Option<u64>,
removal_reason: Option<ObjectRemovalReason>,
}
impl ObjectLifecycle {
#[inline]
pub fn created_at(&self) -> u64 {
self.created_at
}
#[inline]
pub fn updated_at(&self) -> u64 {
self.updated_at
}
#[inline]
pub fn removed_at(&self) -> Option<u64> {
self.removed_at
}
#[inline]
pub fn removal_reason(&self) -> Option<ObjectRemovalReason> {
self.removal_reason
}
#[inline]
pub fn is_removed(&self) -> bool {
self.removed_at.is_some()
}
#[inline]
pub(crate) fn created(now: u64) -> Self {
Self {
created_at: now,
updated_at: now,
removed_at: None,
removal_reason: None,
}
}
#[inline]
pub(crate) fn mark_updated(&mut self, now: u64) {
self.updated_at = now;
}
#[inline]
pub(crate) fn mark_removed(&mut self, now: u64, reason: ObjectRemovalReason) {
if self.removed_at.is_none() {
self.removed_at = Some(now);
self.removal_reason = Some(reason);
}
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ObjectRemovalReason {
Destroyed,
OutOfRange,
}
pub type ObjectLifecycleRegistry = HashMap<PackedGuid, ObjectLifecycle>;
#[inline]
pub(crate) fn now_millis() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as u64
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn created_lifecycle_starts_active_with_matching_timestamps() {
let lifecycle = ObjectLifecycle::created(123);
assert_eq!(lifecycle.created_at(), 123);
assert_eq!(lifecycle.updated_at(), 123);
assert_eq!(lifecycle.removed_at(), None);
assert_eq!(lifecycle.removal_reason(), None);
assert!(!lifecycle.is_removed());
}
#[test]
fn first_removal_is_stable_and_later_removals_do_not_rewrite_history() {
let mut lifecycle = ObjectLifecycle::created(100);
lifecycle.mark_updated(150);
lifecycle.mark_removed(200, ObjectRemovalReason::OutOfRange);
lifecycle.mark_removed(300, ObjectRemovalReason::Destroyed);
assert_eq!(lifecycle.created_at(), 100);
assert_eq!(lifecycle.updated_at(), 150);
assert_eq!(lifecycle.removed_at(), Some(200));
assert_eq!(
lifecycle.removal_reason(),
Some(ObjectRemovalReason::OutOfRange)
);
assert!(lifecycle.is_removed());
}
}