use std::borrow::Cow;
use serde::{Deserialize, Serialize};
use crate::phoneme::allophone::AllophoneRule;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct LanguageVariety {
pub code: Cow<'static, str>,
pub name: Cow<'static, str>,
pub parent: Cow<'static, str>,
pub kind: VarietyKind,
pub added_phonemes: Vec<Cow<'static, str>>,
pub removed_phonemes: Vec<Cow<'static, str>>,
pub allophone_overrides: Vec<AllophoneRule>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub enum VarietyKind {
Regional,
NationalStandard,
Historical,
Sociolect,
Creole,
}
impl LanguageVariety {
#[must_use]
pub fn adds(&self, ipa: &str) -> bool {
self.added_phonemes.iter().any(|p| p.as_ref() == ipa)
}
#[must_use]
pub fn removes(&self, ipa: &str) -> bool {
self.removed_phonemes.iter().any(|p| p.as_ref() == ipa)
}
#[must_use]
pub fn apply(
&self,
parent: &crate::phoneme::PhonemeInventory,
) -> crate::phoneme::PhonemeInventory {
tracing::debug!(variety = %self.code, parent = %parent.language_code, "applying variety overlay");
let mut inv = parent.clone();
inv.language_code = self.code.clone();
inv.language_name = self.name.clone();
inv.phonemes.retain(|p| !self.removes(&p.ipa));
for ipa in &self.added_phonemes {
if !inv.phonemes.iter().any(|p| p.ipa == *ipa) {
inv.phonemes.push(crate::phoneme::Phoneme::vowel(
ipa.clone(),
crate::phoneme::Height::Mid,
crate::phoneme::Backness::Central,
false,
));
}
}
inv
}
}
#[must_use]
pub fn british_english() -> LanguageVariety {
use crate::phoneme::allophone::{AllophoneRule, Environment};
LanguageVariety {
code: Cow::Borrowed("en-GB"),
name: Cow::Borrowed("British English (RP)"),
parent: Cow::Borrowed("en"),
kind: VarietyKind::NationalStandard,
added_phonemes: vec![
Cow::Borrowed("ɒ"), ],
removed_phonemes: vec![
Cow::Borrowed("ɹ"), ],
allophone_overrides: vec![
AllophoneRule {
phoneme: Cow::Borrowed("t"),
allophone: Cow::Borrowed("t"),
environment: Environment::Intervocalic,
obligatory: true,
},
],
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_british_english() {
let rp = british_english();
assert_eq!(rp.parent, "en");
assert_eq!(rp.kind, VarietyKind::NationalStandard);
assert!(rp.adds("ɒ"));
assert!(rp.removes("ɹ"));
assert!(!rp.adds("xyz"));
}
#[test]
fn test_variety_serde_roundtrip() {
let rp = british_english();
let json = serde_json::to_string(&rp).unwrap();
let back: LanguageVariety = serde_json::from_str(&json).unwrap();
assert_eq!(rp, back);
}
}