use crate::utils::FromStaticStr; pub enum Stanza { Entry(&'static str), Defn(&'static str), Note(&'static str), Synonym(&'static str), Bullet(&'static str), SubBullet(&'static str), } impl Stanza { fn is_entry(s: &str) -> bool { s.chars().all(|c| c.is_uppercase() || c.is_ascii_whitespace() || "-;'.".contains(c)) } fn is_defn(s: &str) -> bool { s.starts_with("Defn") } fn is_note(s: &str) -> bool { s.starts_with("Note") } fn is_synonym(s: &str) -> bool { s.starts_with("Syn") } fn is_bullet(s: &str) -> bool { s.find('.').map(|idx| s[..idx].chars().all(char::is_numeric)).unwrap_or_default() } fn is_sub_bullet(s: &str) -> bool { let mut chars = s.chars(); chars.next().map(|c| c == '(').unwrap_or_default() && chars.next().map(char::is_alphabetic).unwrap_or_default() && chars.next().map(|c| c == ')').unwrap_or_default() } } pub struct StanzaLexError { pub data: String, } impl FromStaticStr for Stanza { type Err = StanzaLexError; fn from_str(s: &'static str) -> Result { let mut lines = s.split("\n"); if let Some(first_line) = lines.next() { if !first_line.is_empty() { if Stanza::is_entry(first_line) { Ok(Self::Entry(s)) } else if Stanza::is_defn(first_line) { Ok(Self::Defn(s)) } else if Stanza::is_note(first_line) { Ok(Self::Note(s)) } else if Stanza::is_synonym(first_line) { Ok(Self::Synonym(s)) } else if Stanza::is_bullet(first_line) { Ok(Self::Bullet(s)) } else if Stanza::is_sub_bullet(first_line) { Ok(Self::SubBullet(s)) } else { Err(Self::Err { data: format!("weird stanza: {}", s), }) } } else { Err(Self::Err { data: format!("empty first line: {}", s), }) } } else { Err(Self::Err { data: format!("empty stanza: {}", s), }) } } }