use crate::ast::DirectiveKind;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NotationKind {
Abc,
Lilypond,
MusicXml,
Svg,
}
impl NotationKind {
#[must_use]
pub fn label(self) -> &'static str {
match self {
Self::Abc => "ABC",
Self::Lilypond => "Lilypond",
Self::MusicXml => "MusicXML",
Self::Svg => "SVG",
}
}
#[must_use]
pub fn tag(self) -> &'static str {
match self {
Self::Abc => "abc",
Self::Lilypond => "ly",
Self::MusicXml => "musicxml",
Self::Svg => "svg",
}
}
#[must_use]
pub fn from_start_directive(kind: &DirectiveKind) -> Option<Self> {
match kind {
DirectiveKind::StartOfAbc => Some(Self::Abc),
DirectiveKind::StartOfLy => Some(Self::Lilypond),
DirectiveKind::StartOfMusicxml => Some(Self::MusicXml),
DirectiveKind::StartOfSvg => Some(Self::Svg),
_ => None,
}
}
#[must_use]
pub fn is_end_directive(self, kind: &DirectiveKind) -> bool {
matches!(
(self, kind),
(Self::Abc, DirectiveKind::EndOfAbc)
| (Self::Lilypond, DirectiveKind::EndOfLy)
| (Self::MusicXml, DirectiveKind::EndOfMusicxml)
| (Self::Svg, DirectiveKind::EndOfSvg),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn label_is_the_display_name() {
assert_eq!(NotationKind::Abc.label(), "ABC");
assert_eq!(NotationKind::Lilypond.label(), "Lilypond");
assert_eq!(NotationKind::MusicXml.label(), "MusicXML");
assert_eq!(NotationKind::Svg.label(), "SVG");
}
#[test]
fn tag_is_the_directive_token() {
assert_eq!(NotationKind::Abc.tag(), "abc");
assert_eq!(NotationKind::Lilypond.tag(), "ly");
assert_eq!(NotationKind::MusicXml.tag(), "musicxml");
assert_eq!(NotationKind::Svg.tag(), "svg");
}
#[test]
fn from_start_directive_matches_every_variant() {
assert_eq!(
NotationKind::from_start_directive(&DirectiveKind::StartOfAbc),
Some(NotationKind::Abc)
);
assert_eq!(
NotationKind::from_start_directive(&DirectiveKind::StartOfLy),
Some(NotationKind::Lilypond)
);
assert_eq!(
NotationKind::from_start_directive(&DirectiveKind::StartOfMusicxml),
Some(NotationKind::MusicXml)
);
assert_eq!(
NotationKind::from_start_directive(&DirectiveKind::StartOfSvg),
Some(NotationKind::Svg)
);
}
#[test]
fn from_start_directive_ignores_unrelated_directives() {
assert_eq!(
NotationKind::from_start_directive(&DirectiveKind::StartOfChorus),
None
);
assert_eq!(
NotationKind::from_start_directive(&DirectiveKind::StartOfTextblock),
None,
"StartOfTextblock is NOT a notation block — the text and PDF \
renderers render its body as plain text",
);
assert_eq!(
NotationKind::from_start_directive(&DirectiveKind::EndOfAbc),
None
);
}
#[test]
fn is_end_directive_matches_only_the_paired_end() {
assert!(NotationKind::Abc.is_end_directive(&DirectiveKind::EndOfAbc));
assert!(NotationKind::Lilypond.is_end_directive(&DirectiveKind::EndOfLy));
assert!(NotationKind::MusicXml.is_end_directive(&DirectiveKind::EndOfMusicxml));
assert!(NotationKind::Svg.is_end_directive(&DirectiveKind::EndOfSvg));
}
#[test]
fn is_end_directive_rejects_mismatched_pairs() {
assert!(!NotationKind::Abc.is_end_directive(&DirectiveKind::EndOfLy));
assert!(!NotationKind::Lilypond.is_end_directive(&DirectiveKind::EndOfAbc));
assert!(!NotationKind::MusicXml.is_end_directive(&DirectiveKind::EndOfSvg));
assert!(!NotationKind::Svg.is_end_directive(&DirectiveKind::EndOfMusicxml));
assert!(!NotationKind::Abc.is_end_directive(&DirectiveKind::EndOfChorus));
}
}