//! 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<T>::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);
    }
}
