refactor!: retire Index, intern and lookup
`Index` was public, `History::intern` and `History::lookup` returned
one, and no public method anywhere accepted one. It was a handle with
nowhere to go — and `key_table.rs` advertised the hot-path story it was
meant to enable ("power users can promote `&K` to `Index` and skip the
lookup"), which was never reachable through the public API.
It also shadowed `std::ops::Index`, which `CompetitorStore` implements,
so `use trueskill_tt::*` alongside `use std::ops::*` collided.
All three are `pub(crate)` now. `intern` stays internal because
ingestion needs it; `lookup` is gone entirely, since `current_skill`,
`rating` and `learning_curve` already answer "does this history know
this key" and all three take a borrowed key.
The three tests that used them asserted things a caller cannot observe.
They now assert what the interning bought:
- `record_winner_creates_two_competitors` compares posteriors instead of
comparing two opaque indices for inequality.
- `intern_is_idempotent` becomes `a_repeated_key_is_one_competitor` — a
key appearing in two events gives one competitor with a two-point
learning curve, which is the observable form of the same claim.
- `lookup_returns_none_for_missing` becomes `an_unknown_key_is_unknown`.
Closes #73.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011hcFjNDmHXZF8URGLku5zZ
This commit is contained in:
+11
-12
@@ -290,23 +290,22 @@ pub(crate) const N_INF: Gaussian = Gaussian::from_ms(0.0, f64::INFINITY);
|
||||
|
||||
/// An interned competitor handle: a dense slot number, not a user key.
|
||||
///
|
||||
/// [`History`] stores skills and messages by `Index` rather than by `K`, so
|
||||
/// the hot path never hashes a key. [`History::intern`] promotes a key to one
|
||||
/// and [`History::lookup`] resolves an existing key without creating.
|
||||
/// `History` stores skills and messages by `Index` rather than by `K`, so the
|
||||
/// hot path never hashes a key. Indices are assigned in interning order and
|
||||
/// are stable for the life of a history; they are not portable between
|
||||
/// histories, since the same key interns to a different slot under a different
|
||||
/// ingestion order.
|
||||
///
|
||||
/// Indices are assigned in interning order and are stable for the life of a
|
||||
/// history. They are **not** portable between histories: the same key interns
|
||||
/// to different slots depending on ingestion order.
|
||||
/// Crate-internal. It was public, along with `History::intern` and
|
||||
/// `History::lookup` that produced one — and **nothing public ever accepted
|
||||
/// one**, so it was a handle with nowhere to go. It also shadowed
|
||||
/// `std::ops::Index`, which `CompetitorStore` implements. See #73.
|
||||
#[derive(Copy, Clone, Default, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)]
|
||||
pub struct Index(usize);
|
||||
pub(crate) struct Index(usize);
|
||||
|
||||
impl Index {
|
||||
/// The underlying slot number.
|
||||
///
|
||||
/// Indices are dense and assigned in interning order, so this is usable as
|
||||
/// a key into a caller-side side table.
|
||||
#[must_use]
|
||||
pub fn get(self) -> usize {
|
||||
pub(crate) fn get(self) -> usize {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user