minerva 0.2.0

Causal ordering for distributed systems
/// The clock's mutable state between mints: the `(physical, logical)` of the last
/// minted stamp, or "not yet minted".
///
/// Packed into one `u128` so the whole state advances with a single compare-and-swap.
/// Only `(physical, logical)` is needed to compute the next stamp: `station_id` is an
/// immutable [`Clock`](super::Clock) field and the kairotic is supplied per call, so neither
/// rides in this word.
///
/// "Uninitialized" is an explicit tag bit, not a magic physical value. The clock
/// once seeded a fresh state as a `Kairos` with `physical == u64::MAX`; that
/// collided with a real reading at the same physical time (the next mint misread
/// the state as uninitialized) and forced the property tests to keep readings
/// below the sentinel. With the tag bit, every `u64` physical is an ordinary
/// reading and no minted stamp can spell "uninitialized".
///
/// ```text
///   bit 80    bits 79..64   bits 63..0
/// +--------+-------------+--------------+
/// |  init  |   logical   |   physical   |
/// +--------+-------------+--------------+
/// ```
#[derive(Clone, Copy)]
pub(super) struct ClockState(pub(super) u128);

impl ClockState {
    /// Set once the clock has minted a stamp. Sits above the 80 payload bits, so
    /// no `(physical, logical)` pair can forge it.
    const INIT: u128 = 1 << 80;

    /// A clock that has not yet minted a stamp.
    pub(super) const UNINIT: Self = Self(0);

    /// The state after minting a stamp with these physical and logical parts.
    /// Not `const`: like `Kairos::new`, it packs via `u128::from`, which is not a
    /// const-stable trait call on the pinned toolchain.
    pub(super) fn minted(physical: u64, logical: u16) -> Self {
        Self(Self::INIT | (u128::from(logical) << 64) | u128::from(physical))
    }

    /// The last minted `(physical, logical)`, or `None` while uninitialized.
    pub(super) const fn last(self) -> Option<(u64, u16)> {
        if self.0 & Self::INIT == 0 {
            None
        } else {
            let physical = (self.0 & 0xFFFF_FFFF_FFFF_FFFF) as u64;
            let logical = ((self.0 >> 64) & 0xFFFF) as u16;
            Some((physical, logical))
        }
    }
}