#[cfg(test)]
mod tests {
use super::*;
const TEST_CASES: [&'static str; 329] = [
"a", "a", "a", "ap1", "am", "am", "at", "ak1", "ai2", "aip1", "aim2", "aik2", "aik2",
"aum2", "auk2", "ia1", "iam1", "iat1", "ian1", "iak1", "ua", "ua", "uai1", "uaip2", "i2",
"im1", "in2", "ik2", "y", "y1", "yp", "yt2", "yn2", "yk2", "ut2", "un1", "em", "et2", "o1",
"om2", "ie", "iei2", "io", "io1", "io2", "ue1", "uep", "uep1", "uet", "uo1", "pa2", "pai2",
"pau1", "pia2", "pua2", "puat2", "pit1", "py", "put", "pui1", "pet2", "pek1", "pek2",
"po1", "po1", "pok", "bap", "bai2", "bait", "bau2", "bia1", "bu1", "bu1", "bup2", "bum1",
"be1", "bet2", "bo1", "bot1", "bon2", "buo1", "ma1", "mam1", "man1", "mak1", "mak2",
"maun1", "mua2", "muak1", "mit", "mit2", "mut2", "mun1", "mui1", "mo1", "mot2", "mok1",
"muo1", "can2", "cai1", "cuau2", "cy2", "cuk2", "cet2", "cei2", "cei2", "co1", "co1",
"cue", "cue1", "cuet", "cuop2", "sa1", "sam1", "sat2", "sak2", "sak2", "sau2", "saup1",
"sia1", "sip1", "sit1", "sin1", "sik2", "sy2", "sy2", "syt2", "su1", "sui1", "sep", "so1",
"son1", "sue1", "suo2", "xa2", "xai1", "xau1", "xi1", "xit2", "xy1", "xep2", "xem1", "xo1",
"xo2", "xom1", "xom1", "xot1", "xuo1", "zap2", "zat1", "zau", "zip1", "zit1", "zui1",
"zuit2", "ze1", "zep1", "zo1", "zie1", "zuo1", "ta", "ta1", "tam2", "tat2", "tan1", "tak1",
"tak1", "tai", "tau2", "taun1", "tauk1", "tia1", "tia2", "tua1", "tua1", "tuai2", "tim1",
"tit1", "tin1", "ty", "tyn1", "tu2", "tum1", "tut1", "tun2", "tuk2", "tuk2", "tui2",
"tuik1", "tet", "ten1", "to2", "dat2", "dau2", "daut1", "dit1", "dui", "det", "dop1",
"na1", "nap1", "nam2", "nan2", "naip2", "nau", "nua2", "nuak1", "ni1", "nim2", "nim2",
"nin1", "nik2", "num1", "nut2", "nun1", "nui2", "ne2", "ne2", "net2", "no1", "nom2",
"non1", "nie", "niek1", "nuok2", "la1", "lai1", "lia1", "lua1", "li1", "li2", "lip",
"lit1", "lin", "ly", "lu2", "lup1", "let1", "lek1", "lo", "lo1", "lot2", "lok1", "lok1",
"liok1", "ka1", "kat1", "kat2", "kan1", "kan1", "kak", "kai1", "kait", "kaik", "kaun1",
"kauk2", "kia1", "kiak1", "kua2", "kuak1", "kuak1", "kuai1", "kuai1", "kuai2", "ki1",
"kit", "kit1", "kit1", "kin2", "kin2", "kik1", "kik1", "ky1", "ky2", "ku", "kut2", "kun2",
"ket", "ko1", "kop1", "kot", "kot2", "kok1", "kue", "kuo1", "kuot1", "gat2", "gak1",
"gau2", "giau1", "gua2", "gy1", "guk2", "gui2", "ge", "gek", "hak2", "hau2", "hauk1",
"hia1", "hua1", "huap1", "huat1", "huai2", "hi1", "hy2", "hup1", "hut2", "hui2", "he",
"hem", "hem1", "hem1", "hen", "hei2", "ho", "ho1", "ho2", "hop1", "hon1", "hok1", "hio1",
"hue", "hue1", "huep2", "huet", "huo2", "huok1", "huok2",
];
#[test]
fn parse_all_and_check_equality() {
for index in 0..TEST_CASES.len() {
let syll = PekZepSyllable::parse(TEST_CASES[index]).unwrap();
assert_eq!(TEST_CASES[index], syll.to_string())
}
}
#[test]
#[should_panic]
fn parse_xizi() {
PekZepSyllable::parse("xici").unwrap();
}
}
#[derive(PartialEq, Eq, Debug, Clone)]
pub enum Tone {
No,
First,
Second,
}
#[derive(PartialEq, Eq, Debug, Clone)]
pub enum Onset {
P,
B,
M,
C,
S,
X,
Z,
T,
D,
N,
L,
K,
G,
H,
Zero,
}
#[derive(PartialEq, Eq, Debug, Clone)]
pub enum Vowel {
A,
IA,
UA,
AI,
UAI,
AU,
IAU,
UAU,
E,
IE,
UE,
EI,
IEI,
O,
IO,
UO,
I,
UI,
U,
Y,
}
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
pub enum Coda {
P,
T,
K,
M,
N,
Zero,
}
use std::fmt;
impl fmt::Display for Tone {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match self {
Tone::First => "1",
Tone::Second => "2",
Tone::No => "",
}
)
}
}
impl fmt::Display for Coda {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match self {
Coda::P => "p",
Coda::T => "t",
Coda::K => "k",
Coda::M => "m",
Coda::N => "n",
Coda::Zero => "",
}
)
}
}
impl fmt::Display for Onset {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match self {
Onset::P => "p",
Onset::T => "t",
Onset::K => "k",
Onset::M => "m",
Onset::N => "n",
Onset::Zero => "",
Onset::B => "b",
Onset::G => "g",
Onset::C => "c",
Onset::S => "s",
Onset::X => "x",
Onset::H => "h",
Onset::Z => "z",
Onset::L => "l",
Onset::D => "d",
}
)
}
}
impl fmt::Display for Vowel {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match self {
Vowel::A => "a",
Vowel::IA => "ia",
Vowel::UA => "ua",
Vowel::AI => "ai",
Vowel::UAI => "uai",
Vowel::AU => "au",
Vowel::IAU => "iau",
Vowel::UAU => "uau",
Vowel::E => "e",
Vowel::IE => "ie",
Vowel::UE => "ue",
Vowel::EI => "ei",
Vowel::IEI => "iei",
Vowel::O => "o",
Vowel::IO => "io",
Vowel::UO => "uo",
Vowel::I => "i",
Vowel::UI => "ui",
Vowel::U => "u",
Vowel::Y => "y",
}
)
}
}
impl Vowel {
fn first_tone_rerrliratixka(self) -> &'static str {
match self {
Vowel::A => "ar",
Vowel::IA => "iar",
Vowel::UA => "uar",
Vowel::AI => "ari",
Vowel::UAI => "uari",
Vowel::AU => "aru",
Vowel::IAU => "iaru",
Vowel::UAU => "uaru",
Vowel::E => "er",
Vowel::IE => "ier",
Vowel::UE => "uer",
Vowel::EI => "eri",
Vowel::IEI => "ieri",
Vowel::O => "or",
Vowel::IO => "ior",
Vowel::UO => "uor",
Vowel::I => "ir",
Vowel::UI => "uir",
Vowel::U => "ur",
Vowel::Y => "yr",
}
}
}
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct PekZepSyllable {
onset: Onset,
vowel: Vowel,
coda: Coda,
tone: Tone,
}
impl fmt::Display for PekZepSyllable {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}{}{}{}",
self.onset.to_string(),
self.vowel.to_string(),
self.coda.to_string(),
self.tone.to_string(),
)
}
}
impl PekZepSyllable {
pub fn to_rerrliratixka(self) -> String {
format!(
"{}{}{}{}",
self.onset.to_string(),
if self.tone == Tone::Second { "r" } else { "" },
if self.tone == Tone::First {
self.vowel.first_tone_rerrliratixka().to_string()
} else {
self.vowel.to_string()
},
self.coda.to_string()
)
}
pub fn parse(s: &str) -> Option<PekZepSyllable> {
let chars: Vec<char> = s.chars().collect();
let tone = match chars[chars.len() - 1] {
'1' => Tone::First,
'2' => Tone::Second,
_ => Tone::No,
};
let onset = match chars[0] {
'p' => Onset::P,
'b' => Onset::B,
'm' => Onset::M,
'c' => Onset::C,
's' => Onset::S,
'x' => Onset::X,
'z' => Onset::Z,
't' => Onset::T,
'd' => Onset::D,
'n' => Onset::N,
'l' => Onset::L,
'k' => Onset::K,
'g' => Onset::G,
'h' => Onset::H,
'a' | 'e' | 'i' | 'u' | 'o' | 'y' => Onset::Zero,
_ => return None,
};
let remaining = chars[(if onset == Onset::Zero { 0 } else { 1 })
..chars.len() - (if tone == Tone::No { 0 } else { 1 })]
.to_vec();
let coda = match remaining[remaining.len() - 1] {
'p' => Coda::P,
't' => Coda::T,
'k' => Coda::K,
'm' => Coda::M,
'n' => Coda::N,
_ => Coda::Zero,
};
let vow = remaining[0..remaining.len() - (if coda == Coda::Zero { 0 } else { 1 })].to_vec();
let vowel = match vow.as_slice() {
['a'] => Vowel::A,
['i', 'a'] => Vowel::IA,
['u', 'a'] => Vowel::UA,
['a', 'i'] => Vowel::AI,
['u', 'a', 'i'] => Vowel::UAI,
['a', 'u'] => Vowel::AU,
['i', 'a', 'u'] => Vowel::IAU,
['u', 'a', 'u'] => Vowel::UAU,
['e'] => Vowel::E,
['i', 'e'] => Vowel::IE,
['u', 'e'] => Vowel::UE,
['e', 'i'] => Vowel::EI,
['i', 'e', 'i'] => Vowel::IEI,
['o'] => Vowel::O,
['i', 'o'] => Vowel::IO,
['u', 'o'] => Vowel::UO,
['i'] => Vowel::I,
['u', 'i'] => Vowel::UI,
['u'] => Vowel::U,
['y'] => Vowel::Y,
_ => return None,
};
Some(PekZepSyllable {
onset,
vowel,
coda,
tone,
})
}
}