minerva 0.2.0

Causal ordering for distributed systems
use crate::kairos::Kairos;

/// An element's identity: the crate's [`Dot`], re-exported so the whole
/// sequence subtree names one type (ruling R-91). The one-based counter law
/// rides on the type now, so no read here re-proves it.
///
/// Deliberately narrower than an [`Anchor`]'s coordinate: an anchor names a
/// place, which may dangle or spell the non-dot zero, so the two seats keep
/// different types (the S117 anchor law).
pub(super) use crate::metis::dot::Dot;
pub(super) use crate::metis::dot::RawDot;

/// Where a locus hangs: at the origin, immediately in the region after a dot,
/// or immediately in the region before it.
///
/// The Fugue sided anchor (S127): giving insert-before the same subtree
/// structure insert-after already has cures the backward-run interleaving a
/// single-sided left anchor suffers (two concurrent prepend runs merging as
/// "xayb" rather than block-contiguous). A locus can hang on either SIDE of its
/// anchor: an [`After`](Anchor::After) child reads (rank descending) right after
/// the dot, a [`Before`](Anchor::Before) child reads right before it. The
/// invalid state "before the origin" is unrepresentable: [`Origin`](Anchor::Origin)
/// carries no dot, so the enum, not an `(anchor, side)` pair, is the honest
/// domain.
///
/// The carried coordinate is a [`RawDot`], not a [`Dot`]: an anchor names a
/// *place*, not an identity claim. It may dangle (name a dot no replica here
/// holds) or spell the non-dot counter zero; reads over it are total, and a
/// decoder never refuses it (the S117 anchor law, typed at S346).
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum Anchor {
    /// The document start; the root region.
    Origin,
    /// Hangs in the region after the dot (the classic RGA anchor).
    After(RawDot),
    /// Hangs in the region before the dot (the Fugue left child).
    Before(RawDot),
}

impl Anchor {
    /// The anchoring dot, if any ([`Origin`](Anchor::Origin) has none).
    ///
    /// Side-agnostic: an [`After`](Anchor::After) and a [`Before`](Anchor::Before)
    /// on the same dot share this dot, which is what the fertility count and the
    /// reachability walk read (a dot is fertile, and an anchor edge, regardless
    /// of the side a locus hangs on).
    ///
    /// The coordinate is raw ([`RawDot`]): it may dangle or spell the
    /// non-dot zero, and the read stays total either way.
    #[must_use]
    pub const fn dot(self) -> Option<RawDot> {
        match self {
            Self::Origin => None,
            Self::After(dot) | Self::Before(dot) => Some(dot),
        }
    }
}

/// Where a woven element hangs and how it ranks among its siblings.
///
/// An element's identity is its [`Dot`]; its *place* is this
/// locus: the [`Anchor`] it hangs on (a dot and a side, or the origin), and the
/// rank that orders it against the other elements sharing that anchor. Loci are
/// the grow-forever ordering skeleton of a [`Rhapsody`](crate::metis::Rhapsody); a deleted element loses
/// visibility but keeps its locus (an *order tombstone*), because its descendants
/// still hang off it.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Locus {
    /// Where this element hangs: the origin, or a dot with a side (S127).
    pub anchor: Anchor,
    /// The sibling rank: elements sharing an anchor order by rank DESCENDING
    /// (the RGA rule: the newest write lands nearest its anchor). Kairos is
    /// a total order, so sibling order is deterministic, and the kairotic
    /// tag rides inside the rank.
    pub rank: Kairos,
}