corpora-engine 0.1.0

Bus orchestrator and IO edges (parser, fs walk, writer, git oracle) for corpora.
Documentation
//! Bytes → [`Record`]. The front-matter format is pluggable; v0 ships a [`TomlFormat`]
//! stub so the wiring is real even though parsing lands in plan Phase 2.

use std::fs;
use std::sync::Arc;

use corpora_core::subscriber::ek;
use corpora_core::{Context, DocPath, Event, Interest, ParseError, Record, Subscriber};

use crate::toml_format::TomlFormat;

pub trait FrontMatterFormat {
    fn parse(&self, path: &DocPath, text: &str) -> Result<Record, ParseError>;
}

pub struct Parser {
    fmt: Box<dyn FrontMatterFormat>,
}

impl Parser {
    pub fn new(fmt: Box<dyn FrontMatterFormat>) -> Self {
        Parser { fmt }
    }

    pub fn toml() -> Self {
        Parser {
            fmt: Box::new(TomlFormat),
        }
    }
}

impl Subscriber for Parser {
    fn name(&self) -> &'static str {
        "parser"
    }

    fn interest(&self) -> Interest {
        Interest::only(ek::DISCOVERED | ek::CHANGED)
    }

    fn handle(&mut self, ev: &Event, cx: &mut Context<'_>) {
        let path = match ev {
            Event::Discovered(p) | Event::Changed(p) => p,
            _ => return,
        };
        let text = match fs::read_to_string(&path.0) {
            Ok(t) => t,
            Err(e) => {
                cx.emit(Event::ParseFailed {
                    path: path.clone(),
                    error: ParseError(e.to_string()),
                });
                return;
            }
        };
        match self.fmt.parse(path, &text) {
            Ok(r) => cx.emit(Event::Parsed(Arc::new(r))),
            Err(e) => cx.emit(Event::ParseFailed {
                path: path.clone(),
                error: e,
            }),
        }
    }
}