minerva 0.2.0

Causal ordering for distributed systems
extern crate alloc;

use alloc::string::String;
use alloc::vec::Vec;

use crate::metis::{DotMap, DotSet, Rhapsody};

use super::page::{BlockDot, Field, Page};

impl Page {
    /// The visible block order.
    #[must_use]
    pub fn block_order(&self) -> Vec<BlockDot> {
        self.order.state().store().order()
    }

    /// The surviving kind siblings for `block`, ascending by dot: one entry
    /// for an uncontended block, several after concurrent kind writes (the
    /// surfaced conflict, never resolved by the machine).
    #[must_use]
    pub fn kinds(&self, block: BlockDot) -> Vec<&'static str> {
        self.fields
            .state()
            .store()
            .get(&block)
            .and_then(|fields| fields.get(&Field::Kind))
            .map(|register| register.values().copied().collect())
            .unwrap_or_default()
    }

    /// The surviving title siblings for `block`.
    #[must_use]
    pub fn titles(&self, block: BlockDot) -> Vec<&'static str> {
        self.fields
            .state()
            .store()
            .get(&block)
            .and_then(|fields| fields.get(&Field::Title))
            .map(|register| register.values().copied().collect())
            .unwrap_or_default()
    }

    /// Whether the field layer holds any state for `block`.
    #[must_use]
    pub fn fields_present(&self, block: BlockDot) -> bool {
        self.fields.state().store().get(&block).is_some()
    }

    /// `block`'s paragraph text in visible sequence order (empty when the
    /// paragraph map holds nothing under the block).
    #[must_use]
    pub fn para_text(&self, block: BlockDot) -> String {
        self.para
            .state()
            .store()
            .get(&block)
            .map(|rhapsody| {
                rhapsody
                    .order()
                    .into_iter()
                    .filter_map(|dot| self.chars.get(&dot).copied())
                    .collect()
            })
            .unwrap_or_default()
    }

    /// Whether the paragraph layer holds any state for `block` (visible chars
    /// or tombstoned sequence skeleton alike: the key survives while either
    /// does, which is what keeps late anchors resolvable).
    #[must_use]
    pub fn para_present(&self, block: BlockDot) -> bool {
        self.para.state().store().get(&block).is_some()
    }

    /// The visible char count under `block`'s paragraph.
    #[must_use]
    pub fn para_visible_len(&self, block: BlockDot) -> usize {
        self.para
            .state()
            .store()
            .get(&block)
            .map(Rhapsody::visible_len)
            .unwrap_or_default()
    }

    /// The sequence skeleton size under `block`'s paragraph (tombstones
    /// included): the per-container walk cost, the tree-viewport quantity.
    #[must_use]
    pub fn para_skeleton_len(&self, block: BlockDot) -> usize {
        self.para
            .state()
            .store()
            .get(&block)
            .map(Rhapsody::skeleton_len)
            .unwrap_or_default()
    }

    /// Whether the table layer holds any state for `block`.
    #[must_use]
    pub fn table_present(&self, block: BlockDot) -> bool {
        self.table.state().store().get(&block).is_some()
    }

    /// The live row count under `block`'s table.
    #[must_use]
    pub fn table_rows(&self, block: BlockDot) -> usize {
        self.table
            .state()
            .store()
            .get(&block)
            .map(DotMap::len)
            .unwrap_or_default()
    }

    /// The surviving cell values at `(block, row)`, ascending by dot.
    #[must_use]
    pub fn cell(&self, block: BlockDot, row: u32) -> Vec<&'static str> {
        self.table
            .state()
            .store()
            .get(&block)
            .and_then(|rows| rows.get(&row))
            .map(|register| register.values().copied().collect())
            .unwrap_or_default()
    }

    /// The order pair's context (everything this replica's order layer has
    /// seen).
    #[must_use]
    pub fn order_context(&self) -> &DotSet {
        self.order.state().context()
    }

    /// The field pair's context.
    #[must_use]
    pub fn fields_context(&self) -> &DotSet {
        self.fields.state().context()
    }

    /// The paragraph pair's context.
    #[must_use]
    pub fn para_context(&self) -> &DotSet {
        self.para.state().context()
    }

    /// The table pair's context.
    #[must_use]
    pub fn table_context(&self) -> &DotSet {
        self.table.state().context()
    }
}