minerva 0.2.0

Causal ordering for distributed systems
extern crate alloc;

use alloc::collections::BTreeMap;

use crate::kairos::{Clock, TickCounter};
use crate::metis::{Composer, Dot, DotFun, DotMap, Rhapsody};

/// A block's identity: the dot its order-pair weave minted. Content pairs use
/// it as an opaque *key* (never as a dot of their own contexts), which is the
/// key-space duplication the probe records: one identity, four key spaces.
pub type BlockDot = Dot;

/// The uniform per-block field keys. Caller-opaque to minerva, exactly as an
/// `Event` payload is; the probe keeps them small and `Ord`.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Field {
    /// The kind tag register: which content map(s) this block's writers chose.
    Kind,
    /// The title register.
    Title,
}

/// The uniform field layer: per block, a map of multi-value field registers.
pub type FieldStore = DotMap<BlockDot, DotMap<Field, DotFun<&'static str>>>;

/// The paragraph-kind content layer: per block, a character sequence (the
/// first in-tree composition of [`Rhapsody`] *under* [`DotMap`]).
pub type ParaStore = DotMap<BlockDot, Rhapsody>;

/// The table-kind content layer: per block, rows of cell registers.
pub type TableStore = DotMap<BlockDot, DotMap<u32, DotFun<&'static str>>>;

/// One replica of the block document, composed from shipped parts: four
/// causal pairs (order, fields, paragraph content, table content), each with
/// its own context, which is exactly the cross-pair seam the probe measures.
/// Fields are `pub(super)` so the sibling write/read/gossip impls stay small
/// (the editor harness keeps its fields private to its own module tree the
/// same way).
pub struct Page {
    /// This replica's station id (>= 1, the crate convention).
    pub(super) station: u32,
    /// The block sequence: elements are block dots, order is the read.
    pub(super) order: Composer<Rhapsody>,
    /// The uniform field registers, keyed by block dot.
    pub(super) fields: Composer<FieldStore>,
    /// Paragraph-kind content, keyed by block dot.
    pub(super) para: Composer<ParaStore>,
    /// Table-kind content, keyed by block dot.
    pub(super) table: Composer<TableStore>,
    /// Paragraph character payloads keyed by para-pair dot: the caller's
    /// out-of-band payload channel (the editor harness's char-buffer
    /// precedent; a rhapsody carries identity and order, never the char).
    pub(super) chars: BTreeMap<Dot, char>,
    /// This replica's clock, minting one rank per weave (the support.rs
    /// build).
    pub(super) clock: Clock<TickCounter>,
}

impl Page {
    /// A fresh page replica for `station`.
    #[must_use]
    pub fn new(station: u32) -> Self {
        let clock = Clock::with_default_config(TickCounter::new(), station).unwrap();
        Self {
            station,
            order: Composer::new(station),
            fields: Composer::new(station),
            para: Composer::new(station),
            table: Composer::new(station),
            chars: BTreeMap::new(),
            clock,
        }
    }

    /// This replica's station id.
    #[must_use]
    pub const fn station(&self) -> u32 {
        self.station
    }

    /// The paragraph char payloads, shared with peers so an absorbed para
    /// delta's payloads can be learned.
    #[must_use]
    pub const fn chars(&self) -> &BTreeMap<Dot, char> {
        &self.chars
    }
}