minerva 0.2.0

Causal ordering for distributed systems
extern crate alloc;

use crate::metis::{Dot, DotFun, DotMap, DotSet, DotStore, Locus, Rhapsody};

mod kind;
mod reads;
mod store;

pub use kind::{Kind, KindPlurality, Kinds};
pub use reads::NodeContent;

/// The kind-closure store: every store shape under one identity, a *sparse
/// product* whose merge is componentwise and whose kind is a surfaced read,
/// never a merge choice.
///
/// A node carries a kind *tag* register beside one component for each shape:
/// register payload, caller-keyed children, and ordered sequence. All
/// components use the same causal pair. Thus,
/// `DotMap<K, Node<K, V>>` is a heterogeneous tree, and the node recurses
/// through its own map component (PRD 0020).
///
/// # Why a product and not a sum
///
/// The honest either-store does not exist. A sum-shaped merge of "an A" and
/// "a B" must discard one side's uncovered dots, and an uncovered present dot
/// *must* survive ([`DotStore`] law 2). So the smallest lawful object
/// containing the kind coproduct is this product: every component merges
/// independently under the pair's two contexts, nothing is discarded, and the
/// componentwise merge inherits the axis laws component by component. The
/// argument and its counterexample are `docs/metis-store-algebra.adoc`.
///
/// # The kind law
///
/// *Product-lawed merge, surfaced plurality, exclusivity as write
/// discipline.* Two replicas that concurrently decide what one node is
/// converge to a node honestly carrying both writes:
/// [`kinds_present`](Self::kinds_present) reads the surfaced set, and
/// [`sole`](Self::sole) refuses a plural node with a [`KindPlurality`]
/// witness rather than handing one kind's content out as undisputed. The
/// machine never chooses a winner.
///
/// Exclusivity is therefore a *write* discipline. A re-kind is one covered
/// delta carrying the fresh tag under a context that also covers everything
/// [`observed`](Self::observed) under the node, so both supersessions ride
/// one merge and no delivery order exposes a stale-subtree window;
/// [`Composer::compose_super`](crate::metis::Composer::compose_super) over
/// `observed` is the canonical flow. The superseded subtree drops under the
/// survivor law, while a sequence keeps its grow-only skeleton as recorded
/// residue. This residue gives no kind evidence because kind evidence requires
/// surviving support until [`condense`](crate::metis::Rhapsody::condense).
///
/// # Emptiness is representable
///
/// The tag rides the same pair as the content, so *tag present with bottom
/// content means empty*. A genuinely empty node holds its kind write and
/// nothing else. This is the one state that absence cannot express because
/// canonical form drops bottom stores. [`sole`](Self::sole) hands back the bottom
/// component, and the node itself is not bottom, so it survives in its
/// parent map.
///
/// # Support exactness across the sparse product
///
/// A dot names one write, so it lives under exactly one component. Every
/// write method refuses a dot another component already carries, the same
/// discipline [`DotMap::insert`](crate::metis::DotMap::insert) applies
/// across keys, reading causal support. Cross-*replica* straddling stays
/// ruled out by the honest basis. The checks scan the node's held dots, so
/// they cost what a map insert's disjointness scan costs.
///
/// # What this type refuses to own
///
/// This type supplies no schema or validation. The caller defines which kinds
/// a document admits and what they mean. There is no merge-time winner or wire
/// frame. A composed store travels as deltas under its pair's context frame. A
/// node codec would make merge and read depth attacker-controlled, so it
/// enters only as a sibling codec with a depth budget if at all. No display
/// order, no undo.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Node<K, V> {
    /// The kind tag register: dot-tagged kind assignments, concurrent
    /// assignments surviving as siblings (surfaced, never resolved).
    tag: DotFun<Kind>,
    /// Register content: per dot, the caller payload that write carried.
    register: DotFun<V>,
    /// Map content: caller-keyed children, each itself a node (the
    /// recursion; one pair's context vouches for every level).
    children: DotMap<K, Self>,
    /// Sequence content: ordered elements identified by dots.
    sequence: Rhapsody,
}

impl<K, V> Default for Node<K, V> {
    fn default() -> Self {
        Self {
            tag: DotFun::default(),
            register: DotFun::default(),
            children: DotMap::default(),
            sequence: Rhapsody::new(),
        }
    }
}

impl<K: Ord + Clone, V: Clone> Node<K, V> {
    /// Creates the empty node: no tag, no content under any shape, the
    /// lattice bottom.
    #[must_use]
    pub const fn new() -> Self {
        Self {
            tag: DotFun::new(),
            register: DotFun::new(),
            children: DotMap::new(),
            sequence: Rhapsody::new(),
        }
    }

    /// Records a kind assignment: `kind` under `dot` in the tag register,
    /// returning whether the node changed.
    ///
    /// Refused as a no-op (returning `false`, the node unchanged) for a dot
    /// any other component carries (a dot names one write and lives under one
    /// component, law 1) and for a dot the tag register already carries
    /// (content is never reassigned, law 3). The non-dot `0` needs no arm:
    /// [`Dot`] carries the one-based law (ruling R-91).
    ///
    /// A *bare* tag write asserts a kind without content: merged alone it
    /// makes the node an empty node of that kind. Exclusive re-kinding is the
    /// write discipline documented on the type: pair the fresh tag write with
    /// a context covering [`observed`](Self::observed), in one covered delta.
    #[must_use = "the write is refused (returns false) for a straddling or duplicate dot, which the caller must handle to keep support exactness"]
    pub fn write_tag(&mut self, dot: Dot, kind: Kind) -> bool {
        if self.register_holds(dot) || self.children_hold(dot) || self.sequence_holds(dot) {
            return false;
        }
        self.tag.insert(dot, kind)
    }

    /// Records a register write: `value` under `dot`, returning whether the
    /// node changed.
    ///
    /// Refused as a no-op (returning `false`, the node unchanged) for a dot
    /// any other component carries and for a dot the register already
    /// carries, exactly as [`write_tag`](Self::write_tag).
    #[must_use = "the write is refused (returns false) for a straddling or duplicate dot, which the caller must handle to keep support exactness"]
    pub fn write_register(&mut self, dot: Dot, value: V) -> bool {
        if self.tag_holds(dot) || self.children_hold(dot) || self.sequence_holds(dot) {
            return false;
        }
        self.register.insert(dot, value)
    }

    /// Sets `child` under `key` in the map component, returning whether it
    /// was held.
    ///
    /// Refused as a no-op (returning `false`, the node unchanged) when any of
    /// the child's dots is carried by the tag, register, or sequence
    /// component (law 1 across the sparse product), and under
    /// [`DotMap::insert`](crate::metis::DotMap::insert)'s own refusals (a
    /// bottom child, a dot straddling two keys). Deltas compose bottom-up:
    /// build the child node first, then insert it here.
    #[must_use = "the insertion is refused (returns false) on a bottom child or a straddling dot, which the caller must handle to keep support exactness"]
    pub fn insert_child(&mut self, key: K, child: Self) -> bool {
        let straddles = child
            .dots()
            .any(|dot| self.tag_holds(dot) || self.register_holds(dot) || self.sequence_holds(dot));
        if straddles {
            return false;
        }
        self.children.insert(key, child)
    }

    /// Weaves a sequence element: `dot` at `locus` in the sequence component,
    /// returning whether it was recorded.
    ///
    /// Refused as a no-op (returning `false`, the node unchanged) for a dot
    /// any other component carries, and under
    /// [`Rhapsody::weave`](crate::metis::Rhapsody::weave)'s own refusals (an
    /// already-woven dot; a dangling anchor is accepted and placed when its
    /// anchor arrives).
    #[must_use = "the weave is refused (returns false) for a straddling or already-woven dot, which the caller must handle to keep support exactness"]
    pub fn weave(&mut self, dot: Dot, locus: Locus) -> bool {
        if self.tag_holds(dot) || self.register_holds(dot) || self.children_hold(dot) {
            return false;
        }
        self.sequence.weave(dot, locus)
    }

    /// The kind tag register: every surviving kind assignment, concurrent
    /// ones as siblings. Raw component read; the honest summary is
    /// [`kinds_present`](Self::kinds_present).
    #[must_use]
    pub const fn tag(&self) -> &DotFun<Kind> {
        &self.tag
    }

    /// The register component: per surviving dot, its payload.
    #[must_use]
    pub const fn register(&self) -> &DotFun<V> {
        &self.register
    }

    /// The map component: the live caller-keyed children.
    #[must_use]
    pub const fn children(&self) -> &DotMap<K, Self> {
        &self.children
    }

    /// The sequence component: the ordered elements.
    #[must_use]
    pub const fn sequence(&self) -> &Rhapsody {
        &self.sequence
    }

    /// The supersede-set of an exclusive write: exactly the dots this node
    /// currently carries, across every component and the whole subtree, as a
    /// [`DotSet`].
    ///
    /// The node-level twin of
    /// [`DotFun::observed`](crate::metis::DotFun::observed), and the canonical
    /// supersede read for the re-kinding discipline. Take a delta whose store
    /// carries the fresh tag write and whose context also covers this set.
    /// That one covered delta retires the old tag and every observed content
    /// dot. Drive it through
    /// [`Composer::compose_super`](crate::metis::Composer::compose_super).
    /// Passing dots you have not observed is a remove-wins posture, and which
    /// dots ride a supersession is the caller's semantics, exactly as for
    /// [`retract`](crate::metis::Composer::retract).
    #[must_use]
    pub fn observed(&self) -> DotSet {
        let mut set = DotSet::new();
        for dot in self.dots() {
            let _ = set.insert(dot);
        }
        set
    }

    /// Whether the tag register carries `dot` (causal support, not history).
    fn tag_holds(&self, dot: Dot) -> bool {
        self.tag.get(dot).is_some()
    }

    /// Whether the register component carries `dot`.
    fn register_holds(&self, dot: Dot) -> bool {
        self.register.get(dot).is_some()
    }

    /// Whether any child (transitively) carries `dot`. Scans the subtree's
    /// support, the map-insert disjointness cost shape.
    fn children_hold(&self, dot: Dot) -> bool {
        self.children.dots().any(|held| held == dot)
    }

    /// Whether the sequence component carries `dot` as a live element (the
    /// causal coordinate; an order tombstone is not support).
    fn sequence_holds(&self, dot: Dot) -> bool {
        self.sequence.is_visible(dot)
    }
}