1use anyhow::Context as _;
9
10use crate::message_spec::MessageSpecification;
11
12pub mod deserialize;
13pub mod message_spec;
14
15fn parse_schema_name(line: &str) -> Option<&str> {
17 line.trim().strip_prefix("MSG: ").map(str::trim)
18}
19
20#[derive(Debug, Clone, PartialEq)]
21pub struct MessageSchema {
22 pub spec: MessageSpecification,
24
25 pub dependencies: Vec<MessageSpecification>, }
28
29impl MessageSchema {
30 pub fn parse(name: &str, input: &str) -> anyhow::Result<Self> {
31 let main_spec_content = extract_main_msg_spec(input);
32 let specs = extract_msg_specs(input);
33
34 let main_spec = MessageSpecification::parse(name, &main_spec_content)
35 .with_context(|| format!("failed to parse main message spec `{name}`"))?;
36
37 let mut dependencies = Vec::new();
38 for (dep_name, dep_content) in specs {
39 let dep_spec = MessageSpecification::parse(&dep_name, &dep_content)
40 .with_context(|| format!("failed to parse dependent message spec `{dep_name}`"))?;
41 dependencies.push(dep_spec);
42 }
43
44 Ok(Self {
45 spec: main_spec,
46 dependencies,
47 })
48 }
49}
50
51pub fn is_schema_separator(line: &str) -> bool {
53 let line = line.trim();
54 line.len() >= 3 && line.chars().all(|c| c == '=')
55}
56
57fn extract_main_msg_spec(input: &str) -> String {
61 input
62 .lines()
63 .take_while(|line| !is_schema_separator(line))
64 .filter(|line| !line.is_empty())
65 .collect::<Vec<_>>()
66 .join("\n")
67}
68
69fn extract_msg_specs(input: &str) -> Vec<(String, String)> {
74 let mut specs = Vec::new();
75 let mut current_section = Vec::new();
76
77 for line in input.lines() {
78 if is_schema_separator(line) {
79 if let Some(spec) = parse_section(¤t_section) {
80 specs.push(spec);
81 }
82 current_section.clear();
83 } else {
84 current_section.push(line);
85 }
86 }
87
88 if let Some(spec) = parse_section(¤t_section) {
90 specs.push(spec);
91 }
92
93 specs
94}
95
96fn parse_section(lines: &[&str]) -> Option<(String, String)> {
100 if lines.len() < 2 {
101 return None;
102 }
103
104 let first_line = lines[0].trim();
105 let name = parse_schema_name(first_line)?;
106 let body = lines[1..].join("\n");
107
108 Some((name.to_owned(), body))
109}