minerva 0.2.0

Causal ordering for distributed systems
extern crate alloc;

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

use super::super::super::super::support::dot;
use crate::kairos::Kairos;
use crate::metis::{
    Anchor, Dot, DotMap, DotSet, Kind, Locus, Metatheses, Metathesis, Node, Scholia, Scholion,
    Verge,
};
use proptest::prelude::*;

use super::super::Inscribed;
use super::harness::Covered;
use crate::metis::dot::RawDot;

/// A seed for one covered pair: seen dots plus whether each dot survives.
pub(super) type Seed = Vec<((u32, u64), bool)>;

pub(super) fn arb_seed() -> impl Strategy<Value = Seed> {
    prop::collection::vec(((0u32..3, 1u64..8), prop::bool::ANY), 0..12)
}

/// A deterministic value for a dot, so equal dots imply equal strings.
pub(super) fn value_for(station: u32, counter: u64) -> String {
    alloc::format!("v{station}-{counter}")
}

pub(super) fn covered_inscribed(seed: &Seed) -> Covered<Inscribed> {
    let mut context = DotSet::new();
    let mut entries: BTreeMap<Dot, String> = BTreeMap::new();
    for &((station, counter), keep) in seed {
        let _ = context.insert(dot(station, counter));
        if keep {
            let _ = entries.insert(dot(station, counter), value_for(station, counter));
        }
    }
    Covered::new(Inscribed::from_entries(entries), context)
}

/// A covered mark store built from a seed: each surviving dot carries a
/// scholion whose verges are a deterministic function of the dot (so equal
/// dots imply equal content, the honest basis), spanning every verge shape
/// across the seed space.
pub(super) fn covered_scholia(seed: &Seed) -> Covered<Scholia<String>> {
    let mut context = DotSet::new();
    let mut store = Scholia::new();
    for &((station, counter), keep) in seed {
        let _ = context.insert(dot(station, counter));
        if keep {
            let start = match counter % 3 {
                0 => Verge::Origin,
                1 => Verge::Before(RawDot { station, counter }),
                _ => Verge::After(RawDot { station, counter }),
            };
            let end = match (u64::from(station) + counter) % 3 {
                0 => Verge::Terminus,
                1 => Verge::After(RawDot {
                    station,
                    counter: counter + 1,
                }),
                _ => Verge::Before(RawDot {
                    station,
                    counter: counter + 1,
                }),
            };
            let _ = store.insert(
                dot(station, counter),
                Scholion {
                    start,
                    end,
                    tag: value_for(station, counter),
                },
            );
        }
    }
    Covered::new(store, context)
}

/// A covered move record built from a seed: each surviving dot carries a
/// testimony whose target and locus are deterministic functions of the dot
/// (equal dots imply equal content, the honest basis).
pub(super) fn covered_metatheses(seed: &Seed) -> Covered<Metatheses> {
    let mut context = DotSet::new();
    let mut record = Metatheses::new();
    for &((station, counter), keep) in seed {
        let _ = context.insert(dot(station, counter));
        if keep {
            let anchor = match counter % 3 {
                0 => Anchor::Origin,
                1 => Anchor::After(RawDot {
                    station,
                    counter: counter + 1,
                }),
                _ => Anchor::Before(RawDot {
                    station,
                    counter: counter + 1,
                }),
            };
            let _ = record.insert(
                dot(station, counter),
                Metathesis {
                    target: RawDot::new(station, counter.wrapping_add(7)),
                    to: Locus {
                        anchor,
                        rank: Kairos::new(counter, 0u16, station, 0u16),
                    },
                },
            );
        }
    }
    Covered::new(record, context)
}

pub(super) fn covered_dot_set(seed: &Seed) -> Covered<DotSet> {
    let mut context = DotSet::new();
    let mut store = DotSet::new();
    for &((station, counter), keep) in seed {
        let _ = context.insert(dot(station, counter));
        if keep {
            let _ = store.insert(dot(station, counter));
        }
    }
    Covered::new(store, context)
}

/// A covered sparse-product node built from a seed: the component a dot
/// lands under is a deterministic function of the dot (so a repeated dot
/// never straddles components), and every component is exercised across the
/// seed space (tag, register, a child under the station's key, a woven
/// sequence element).
pub(super) fn covered_node(seed: &Seed) -> Covered<Node<u8, String>> {
    let mut context = DotSet::new();
    let mut node: Node<u8, String> = Node::new();
    for &((station, counter), keep) in seed {
        let _ = context.insert(dot(station, counter));
        if !keep {
            continue;
        }
        match counter % 4 {
            0 => {
                let kind = match (u64::from(station) + counter) % 3 {
                    0 => Kind::Register,
                    1 => Kind::Map,
                    _ => Kind::Sequence,
                };
                let _ = node.write_tag(dot(station, counter), kind);
            }
            1 => {
                let _ = node.write_register(dot(station, counter), value_for(station, counter));
            }
            2 => {
                let key = u8::try_from(station).unwrap();
                let mut held: Node<u8, String> =
                    node.children().get(&key).cloned().unwrap_or_default();
                let _ = held.write_register(dot(station, counter), value_for(station, counter));
                let _ = node.insert_child(key, held);
            }
            _ => {
                let _ = node.weave(
                    dot(station, counter),
                    Locus {
                        anchor: Anchor::Origin,
                        rank: Kairos::new(counter, 0u16, 1, 0u16),
                    },
                );
            }
        }
    }
    Covered::new(node, context)
}

pub(super) fn covered_dot_map(seed: &Seed) -> Covered<DotMap<u8, DotSet>> {
    let mut context = DotSet::new();
    let mut store = DotMap::new();
    for &((station, counter), keep) in seed {
        let _ = context.insert(dot(station, counter));
        if keep {
            let key = u8::try_from(station).unwrap();
            let mut held: DotSet = store.get(&key).cloned().unwrap_or_default();
            let _ = held.insert(dot(station, counter));
            let _ = store.insert(key, held);
        }
    }
    Covered::new(store, context)
}