#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct CallHead {
pub(crate) name: String,
pub(crate) sep: char,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum UnitPayload {
Text { text: String },
FencedLine { text: String },
Block {
tag: String,
body: String,
head: Option<CallHead>,
reserved: bool,
},
UnclosedBlock {
tag: String,
body: String,
head: Option<CallHead>,
reserved: bool,
},
StrayClose { tag: String },
Wrapper { tag: String },
Markup { opener: String, text: String },
AngleCall {
name: String,
arguments: serde_json::Value,
},
HarmonyLine { text: String },
HarmonySkip,
Tag { raw: String, name: String },
}
impl UnitPayload {
pub(crate) fn kind(&self) -> &'static str {
match self {
UnitPayload::Text { .. } => "text",
UnitPayload::FencedLine { .. } => "fenced_line",
UnitPayload::Block { .. } => "block",
UnitPayload::UnclosedBlock { .. } => "unclosed_block",
UnitPayload::StrayClose { .. } => "stray_close",
UnitPayload::Wrapper { .. } => "wrapper",
UnitPayload::Markup { .. } => "markup",
UnitPayload::AngleCall { .. } => "angle_call",
UnitPayload::HarmonyLine { .. } => "harmony_line",
UnitPayload::HarmonySkip => "harmony_skip",
UnitPayload::Tag { .. } => "tag",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct Unit {
pub(crate) start: usize,
pub(crate) end: usize,
pub(crate) payload: UnitPayload,
}
impl Unit {
pub(crate) fn kind(&self) -> &'static str {
self.payload.kind()
}
pub(crate) fn to_json(&self) -> serde_json::Value {
let mut map = serde_json::Map::new();
map.insert("kind".to_string(), self.kind().into());
map.insert("start".to_string(), self.start.into());
map.insert("end".to_string(), self.end.into());
match &self.payload {
UnitPayload::Text { text } => {
map.insert("text".to_string(), text.as_str().into());
map.insert("fenced".to_string(), false.into());
}
UnitPayload::FencedLine { text } | UnitPayload::HarmonyLine { text } => {
map.insert("text".to_string(), text.as_str().into());
}
UnitPayload::Block {
tag,
body,
head,
reserved,
} => {
map.insert("tag".to_string(), tag.as_str().into());
map.insert("body".to_string(), body.as_str().into());
map.insert("closed".to_string(), true.into());
insert_head(&mut map, head);
insert_reserved(&mut map, *reserved);
}
UnitPayload::UnclosedBlock {
tag,
body,
head,
reserved,
} => {
map.insert("tag".to_string(), tag.as_str().into());
map.insert("body".to_string(), body.as_str().into());
map.insert("closed".to_string(), false.into());
insert_head(&mut map, head);
insert_reserved(&mut map, *reserved);
}
UnitPayload::StrayClose { tag } | UnitPayload::Wrapper { tag } => {
map.insert("tag".to_string(), tag.as_str().into());
}
UnitPayload::Markup { opener, text } => {
map.insert("opener".to_string(), opener.as_str().into());
map.insert("text".to_string(), text.as_str().into());
}
UnitPayload::AngleCall { name, arguments } => {
map.insert("name".to_string(), name.as_str().into());
map.insert("arguments".to_string(), arguments.clone());
}
UnitPayload::HarmonySkip => {}
UnitPayload::Tag { raw, name } => {
map.insert("raw".to_string(), raw.as_str().into());
map.insert("name".to_string(), name.as_str().into());
}
}
serde_json::Value::Object(map)
}
}
fn insert_head(map: &mut serde_json::Map<String, serde_json::Value>, head: &Option<CallHead>) {
if let Some(head) = head {
map.insert("head_name".to_string(), head.name.as_str().into());
map.insert("head_sep".to_string(), head.sep.to_string().into());
}
}
fn insert_reserved(map: &mut serde_json::Map<String, serde_json::Value>, reserved: bool) {
if reserved {
map.insert("reserved".to_string(), true.into());
}
}