use std::collections::BTreeMap;
use sim_kernel::{Error, Expr, Result, Symbol};
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RenderClass {
Structural,
Frame,
Data,
Evidence,
Review,
Vote,
Patch,
Fetch,
Return,
Receipt,
Extension,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum AuthorityClass {
Data,
Normative,
Callable,
Evidence,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum UnknownPolicy {
Reject,
PreserveDataOnly,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BridgePartSpec {
pub kind: Symbol,
pub shape_expr: Expr,
pub render_class: RenderClass,
pub authority_class: AuthorityClass,
pub unknown_policy: UnknownPolicy,
}
impl BridgePartSpec {
pub fn new(
kind: Symbol,
shape_expr: Expr,
render_class: RenderClass,
authority_class: AuthorityClass,
unknown_policy: UnknownPolicy,
) -> Self {
Self {
kind,
shape_expr,
render_class,
authority_class,
unknown_policy,
}
}
pub fn preserve_data_only(kind: Symbol, shape_expr: Expr) -> Self {
Self::new(
kind,
shape_expr,
RenderClass::Extension,
AuthorityClass::Data,
UnknownPolicy::PreserveDataOnly,
)
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct BridgePartBook {
specs: BTreeMap<Symbol, BridgePartSpec>,
}
impl BridgePartBook {
pub fn new() -> Self {
Self::default()
}
pub fn register(&mut self, spec: BridgePartSpec) {
self.specs.insert(spec.kind.clone(), spec);
}
pub fn spec(&self, kind: &Symbol) -> Option<&BridgePartSpec> {
self.specs.get(kind)
}
pub fn specs(&self) -> impl Iterator<Item = &BridgePartSpec> {
self.specs.values()
}
pub fn require_registered(&self, kind: &Symbol) -> Result<&BridgePartSpec> {
self.spec(kind)
.ok_or_else(|| Error::Eval(format!("unknown BRIDGE part kind {kind}")))
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BridgeBook {
pub parts: BridgePartBook,
pub moves: crate::BridgeMoveBook,
pub frames: crate::BridgeFrameBook,
pub profiles: crate::BridgeProfileBook,
pub warrant_policy: crate::BridgeWarrantPolicy,
}
impl BridgeBook {
pub fn new(
parts: BridgePartBook,
moves: crate::BridgeMoveBook,
frames: crate::BridgeFrameBook,
profiles: crate::BridgeProfileBook,
) -> Self {
Self {
parts,
moves,
frames,
profiles,
warrant_policy: crate::BridgeWarrantPolicy::SharedTrust,
}
}
pub fn standard() -> Self {
Self::new(
crate::standard_part_book(),
crate::standard_move_book(),
crate::standard_frame_book(),
crate::standard_profile_book(),
)
}
pub fn with_part(mut self, spec: BridgePartSpec) -> Self {
self.parts.register(spec);
self
}
pub fn with_frame(mut self, spec: crate::FrameSpec) -> Self {
self.frames.register(spec);
self
}
pub fn with_profile(mut self, spec: crate::BridgeProfileSpec) -> Self {
self.profiles.register(spec);
self
}
pub fn with_warrant_policy(mut self, policy: crate::BridgeWarrantPolicy) -> Self {
self.warrant_policy = policy;
self
}
}
pub fn standard_part_book() -> BridgePartBook {
let mut book = BridgePartBook::new();
for spec in [
spec("Given", RenderClass::Data, AuthorityClass::Data),
spec("Frame", RenderClass::Frame, AuthorityClass::Normative),
spec("Call", RenderClass::Structural, AuthorityClass::Callable),
spec("Weave", RenderClass::Structural, AuthorityClass::Normative),
spec("Check", RenderClass::Structural, AuthorityClass::Normative),
spec("Evidence", RenderClass::Evidence, AuthorityClass::Evidence),
spec("Review", RenderClass::Review, AuthorityClass::Evidence),
spec("Vote", RenderClass::Vote, AuthorityClass::Evidence),
spec("Patch", RenderClass::Patch, AuthorityClass::Normative),
spec("Fetch", RenderClass::Fetch, AuthorityClass::Callable),
spec("Return", RenderClass::Return, AuthorityClass::Normative),
spec("Receipt", RenderClass::Receipt, AuthorityClass::Evidence),
spec("Attest", RenderClass::Evidence, AuthorityClass::Evidence),
spec("Extension", RenderClass::Extension, AuthorityClass::Data),
] {
book.register(spec);
}
book
}
fn spec(name: &str, render_class: RenderClass, authority_class: AuthorityClass) -> BridgePartSpec {
let kind = Symbol::qualified("bridge", name);
BridgePartSpec::new(
kind.clone(),
Expr::Symbol(kind),
render_class,
authority_class,
UnknownPolicy::Reject,
)
}