simploxide_bindgen/
events.rs1use crate::{parse_utils, types::DisjointedDisriminatedUnionVariant};
4
5pub fn parse(
6 events_md: &str,
7) -> impl Iterator<Item = Result<DisjointedDisriminatedUnionVariant, String>> {
8 let mut parser = Parser::default();
9
10 events_md
11 .split("---")
12 .skip(1)
13 .filter_map(|s| {
14 let trimmed = s.trim();
15 (!trimmed.is_empty()).then_some(trimmed)
16 })
17 .map(move |blk| parser.parse_block(blk))
18}
19
20#[derive(Default)]
21struct Parser {
22 current_doc_section: Option<DocSection>,
23}
24
25impl Parser {
26 pub fn parse_block(
27 &mut self,
28 block: &str,
29 ) -> Result<DisjointedDisriminatedUnionVariant, String> {
30 self.parser(block.lines().map(str::trim))
31 .map_err(|e| format!("{e} in block\n```\n{block}\n```"))
32 }
33
34 fn parser<'a>(
35 &mut self,
36 mut lines: impl Iterator<Item = &'a str>,
37 ) -> Result<DisjointedDisriminatedUnionVariant, String> {
38 const DOC_SECTION_PAT: &str = parse_utils::H2;
39 const TYPENAME_PAT: &str = parse_utils::H3;
40 const TYPEKIND_PAT: &str = parse_utils::BOLD;
41
42 let mut next =
43 parse_utils::skip_empty(&mut lines).ok_or_else(|| "Got an empty block".to_owned())?;
44
45 let mut inner_docs: Vec<String> = Vec::new();
46
47 loop {
48 if let Some(section_name) = next.strip_prefix(DOC_SECTION_PAT) {
49 let mut doc_section = DocSection::new(section_name.to_owned());
50
51 next = parse_utils::parse_doc_lines(&mut lines, &mut doc_section.contents, |s| {
52 s.starts_with(TYPENAME_PAT)
53 })
54 .ok_or_else(|| format!("Failed to find a typename by pattern {TYPENAME_PAT:?} after the doc section"))?;
55
56 self.current_doc_section.replace(doc_section);
57 } else if let Some(_name) = next.strip_prefix(TYPENAME_PAT) {
58 parse_utils::parse_doc_lines(&mut lines, &mut inner_docs, |s| {
59 s.starts_with(TYPEKIND_PAT)
60 }).ok_or_else(|| format!("Failed to find a typekind by pattern {TYPEKIND_PAT:?} after the inner docs "))?;
61
62 break;
63 }
64 }
65
66 let (variant, _) = parse_utils::parse_discriminated_union_variant(&mut lines)?;
67 let mut disjointed = variant.disjoin();
68
69 if let Some(ref outer_docs) = self.current_doc_section {
72 disjointed
73 .variant
74 .doc_comments
75 .push(outer_docs.header.clone());
76
77 disjointed
78 .record
79 .doc_comments
80 .push(format!("### {}", outer_docs.header.clone()));
81
82 disjointed.record.doc_comments.push(String::new());
83
84 disjointed
85 .record
86 .doc_comments
87 .extend(outer_docs.contents.iter().cloned());
88
89 disjointed.record.doc_comments.push(String::new());
90 disjointed.record.doc_comments.push("----".to_owned());
91 disjointed.record.doc_comments.push(String::new());
92 }
93
94 disjointed.record.doc_comments.extend(inner_docs);
95 Ok(disjointed)
96 }
97}
98
99#[derive(Default, Clone)]
100struct DocSection {
101 header: String,
102 contents: Vec<String>,
103}
104
105impl DocSection {
106 fn new(header: String) -> Self {
107 Self {
108 header,
109 contents: Vec::new(),
110 }
111 }
112}