Skip to main content

corpora_engine/
parser.rs

1//! Bytes → [`Record`]. The front-matter format is pluggable; v0 ships a [`TomlFormat`]
2//! stub so the wiring is real even though parsing lands in plan Phase 2.
3
4use std::fs;
5use std::sync::Arc;
6
7use corpora_core::subscriber::ek;
8use corpora_core::{Context, DocPath, Event, Interest, ParseError, Record, Subscriber};
9
10use crate::toml_format::TomlFormat;
11
12pub trait FrontMatterFormat {
13    fn parse(&self, path: &DocPath, text: &str) -> Result<Record, ParseError>;
14}
15
16pub struct Parser {
17    fmt: Box<dyn FrontMatterFormat>,
18}
19
20impl Parser {
21    pub fn new(fmt: Box<dyn FrontMatterFormat>) -> Self {
22        Parser { fmt }
23    }
24
25    pub fn toml() -> Self {
26        Parser {
27            fmt: Box::new(TomlFormat),
28        }
29    }
30}
31
32impl Subscriber for Parser {
33    fn name(&self) -> &'static str {
34        "parser"
35    }
36
37    fn interest(&self) -> Interest {
38        Interest::only(ek::DISCOVERED | ek::CHANGED)
39    }
40
41    fn handle(&mut self, ev: &Event, cx: &mut Context<'_>) {
42        let path = match ev {
43            Event::Discovered(p) | Event::Changed(p) => p,
44            _ => return,
45        };
46        let text = match fs::read_to_string(&path.0) {
47            Ok(t) => t,
48            Err(e) => {
49                cx.emit(Event::ParseFailed {
50                    path: path.clone(),
51                    error: ParseError(e.to_string()),
52                });
53                return;
54            }
55        };
56        match self.fmt.parse(path, &text) {
57            Ok(r) => cx.emit(Event::Parsed(Arc::new(r))),
58            Err(e) => cx.emit(Event::ParseFailed {
59                path: path.clone(),
60                error: e,
61            }),
62        }
63    }
64}
65