use serde::Deserialize;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StressPlacement {
Initial,
Final,
Penultimate,
Antepenultimate,
LatinRule,
}
impl StressPlacement {
pub fn parse(s: &str) -> Option<Self> {
match s.trim().to_ascii_lowercase().as_str() {
"initial" | "first" => Some(Self::Initial),
"final" | "last" | "ultimate" => Some(Self::Final),
"penultimate" | "penult" => Some(Self::Penultimate),
"antepenultimate" | "antepenult" => Some(Self::Antepenultimate),
"latin" | "weight_sensitive" | "quantity_sensitive" => Some(Self::LatinRule),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StressRule {
pub primary: StressPlacement,
}
#[derive(Deserialize)]
#[serde(untagged)]
enum RawStress {
Short(String),
Full { primary: String },
}
impl<'de> Deserialize<'de> for StressRule {
fn deserialize<D>(d: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let name = match RawStress::deserialize(d)? {
RawStress::Short(s) => s,
RawStress::Full { primary } => primary,
};
let primary = StressPlacement::parse(&name).ok_or_else(|| {
serde::de::Error::custom(format!(
"unknown stress placement `{name}` (initial | final | penultimate | \
antepenultimate | latin)"
))
})?;
Ok(StressRule { primary })
}
}