//! Generic time axis for `History`. //! //! Users pick the `Time` type based on their domain: `Untimed` when no //! time axis is meaningful, `i64` for integer day/second timestamps. //! Additional impls can be added behind feature flags. /// A timestamp on the global ordering axis. /// /// Must be `Ord + Copy` so slices can sort events, and `'static` so /// `History` can store it by value without lifetimes. pub trait Time: Copy + Ord + Send + Sync + 'static { /// How much time elapsed between `self` and `later`. /// /// Used by `Drift::variance_delta` to compute skill drift. Returning /// zero means no drift accumulates between the two points. Return value /// must be non-negative for `self <= later`. fn elapsed_to(&self, later: &Self) -> i64; } /// Zero-sized type representing "no time axis." /// /// Used as the default `Time` when events are unordered. Elapsed is always 0, /// so no drift accumulates across slices. #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Untimed; impl Time for Untimed { fn elapsed_to(&self, _later: &Self) -> i64 { 0 } } impl Time for i64 { fn elapsed_to(&self, later: &Self) -> i64 { later - self } } #[cfg(test)] mod tests { use super::*; #[test] fn untimed_elapsed_is_zero() { assert_eq!(Untimed.elapsed_to(&Untimed), 0); } #[test] fn i64_elapsed_is_difference() { assert_eq!(5i64.elapsed_to(&10), 5); assert_eq!(10i64.elapsed_to(&5), -5); assert_eq!(0i64.elapsed_to(&0), 0); } }