minerva 0.2.0

Causal ordering for distributed systems
extern crate alloc;

use alloc::collections::{BTreeMap, BTreeSet};

use super::super::{DotSet, DotStore};
use super::{Dot, DotFun};

impl<V: Clone> DotStore for DotFun<V> {
    fn dots(&self) -> impl Iterator<Item = Dot> + '_ {
        // `BTreeMap` keys are already ascending dots, each once.
        self.entries.keys().copied()
    }

    fn is_bottom(&self) -> bool {
        self.entries.is_empty()
    }

    fn causal_merge(&self, self_context: &DotSet, other: &Self, other_context: &DotSet) -> Self {
        // The survivor law, per dot, content following the dot. A dot in both
        // stores carries equal content by the honest basis (keep-self, equal
        // by basis; see the type rustdoc for the discipline and its Byzantine
        // caveat), so we keep self's; a dot in one store and unseen on the
        // other side survives with its own content; a dot seen and dropped on
        // the other side is superseded.
        let mut entries = BTreeMap::new();
        for (&dot, value) in &self.entries {
            let in_both = other.entries.contains_key(&dot);
            if Self::survives(in_both, other_context.contains(dot)) {
                let _ = entries.insert(dot, value.clone());
            }
        }
        for (&dot, value) in &other.entries {
            if self.entries.contains_key(&dot) {
                continue; // already carried, self's content kept above
            }
            // Other's dot, unseen here: `in_both` is false (self did not carry
            // it above), so survival reduces to "self never saw it".
            if Self::survives(false, self_context.contains(dot)) {
                let _ = entries.insert(dot, value.clone());
            }
        }
        Self { entries }
    }

    fn restrict(&self, roster: impl IntoIterator<Item = u32>) -> Self {
        let roster: BTreeSet<u32> = roster.into_iter().collect();
        let entries = self
            .entries
            .iter()
            .filter(|(dot, _)| roster.contains(&dot.station()))
            .map(|(&dot, value)| (dot, value.clone()))
            .collect();
        Self { entries }
    }

    fn novel_to(&self, context: &DotSet) -> Self {
        // The sub-store of dots the peer context has never seen, content
        // following each dot (the S97 anti-entropy selection).
        let entries = self
            .entries
            .iter()
            .filter(|(dot, _)| !context.contains(**dot))
            .map(|(&dot, value)| (dot, value.clone()))
            .collect();
        Self { entries }
    }
}