corpora-core 0.1.0

Core domain types, immutable graph, and event bus for the corpora docs validator.
Documentation
//! The bus contract: every component is a [`Subscriber`] that reacts to [`Event`]s and
//! emits more through its [`Context`]. [`Interest`] is a cheap bitset prefilter.

use std::collections::VecDeque;

use crate::config::Config;
use crate::diagnostic::Diagnostic;
use crate::event::Event;

/// Event-kind bits for [`Interest`] prefiltering.
pub mod ek {
    pub const RUN_STARTED: u32 = 1 << 0;
    pub const DISCOVERED: u32 = 1 << 1;
    pub const CHANGED: u32 = 1 << 2;
    pub const REMOVED: u32 = 1 << 3;
    pub const SETTLED: u32 = 1 << 4;
    pub const PARSED: u32 = 1 << 5;
    pub const PARSE_FAILED: u32 = 1 << 6;
    pub const GRAPH_BUILT: u32 = 1 << 7;
    pub const DIAGNOSTIC: u32 = 1 << 8;
    pub const REPORT: u32 = 1 << 9;
    pub const RUN_FINISHED: u32 = 1 << 10;
}

fn event_bit(ev: &Event) -> u32 {
    match ev {
        Event::RunStarted { .. } => ek::RUN_STARTED,
        Event::Discovered(_) => ek::DISCOVERED,
        Event::Changed(_) => ek::CHANGED,
        Event::Removed(_) => ek::REMOVED,
        Event::Settled => ek::SETTLED,
        Event::Parsed(_) => ek::PARSED,
        Event::ParseFailed { .. } => ek::PARSE_FAILED,
        Event::GraphBuilt(_) => ek::GRAPH_BUILT,
        Event::Diagnostic(_) => ek::DIAGNOSTIC,
        Event::Report(_) => ek::REPORT,
        Event::RunFinished(_) => ek::RUN_FINISHED,
    }
}

#[derive(Clone, Copy, Debug)]
pub struct Interest(u32);

impl Interest {
    pub const ALL: Interest = Interest(u32::MAX);

    pub const fn only(bits: u32) -> Interest {
        Interest(bits)
    }

    pub fn wants(&self, ev: &Event) -> bool {
        self.0 & event_bit(ev) != 0
    }
}

pub trait Subscriber {
    fn name(&self) -> &'static str;

    fn interest(&self) -> Interest {
        Interest::ALL
    }

    fn handle(&mut self, ev: &Event, cx: &mut Context<'_>);
}

/// What a subscriber sees on the bus: read config, emit follow-on events.
pub struct Context<'a> {
    pub cfg: &'a Config,
    out: &'a mut VecDeque<Event>,
}

impl<'a> Context<'a> {
    pub fn new(cfg: &'a Config, out: &'a mut VecDeque<Event>) -> Self {
        Context { cfg, out }
    }

    pub fn emit(&mut self, ev: Event) {
        self.out.push_back(ev);
    }

    pub fn error(&mut self, d: Diagnostic) {
        self.emit(Event::Diagnostic(d));
    }
}