feat(api): add Time trait with Untimed and i64 impls
Foundation for generic History time axis. Untimed is the ZST case (no drift across slices); i64 is the standard timestamp case. Additional impls (time::OffsetDateTime, chrono) can be added behind feature flags in follow-up work. The trait is not yet wired into History — that happens in Task 7 along with generifying Drift over T. Part of T2 of docs/superpowers/specs/2026-04-23-trueskill-engine-redesign-design.md.
This commit is contained in:
@@ -6,6 +6,7 @@ use std::{
|
||||
#[cfg(feature = "approx")]
|
||||
mod approx;
|
||||
pub(crate) mod arena;
|
||||
mod time;
|
||||
mod time_slice;
|
||||
pub use time_slice::TimeSlice;
|
||||
mod competitor;
|
||||
@@ -31,6 +32,7 @@ pub use key_table::KeyTable;
|
||||
use matrix::Matrix;
|
||||
pub use rating::Rating;
|
||||
pub use schedule::ScheduleReport;
|
||||
pub use time::{Time, Untimed};
|
||||
|
||||
pub const BETA: f64 = 1.0;
|
||||
pub const MU: f64 = 0.0;
|
||||
|
||||
54
src/time.rs
Normal file
54
src/time.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
//! 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 + '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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user