use modular_bitfield::prelude::{bitfield, BitfieldSpecifier};
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::str::FromStr;
#[derive(
Debug,
Clone,
Copy,
Eq,
PartialEq,
BitfieldSpecifier,
strum_macros::Display,
strum_macros::AsRefStr,
strum_macros::EnumIter,
)]
#[bits = 5]
#[strum(serialize_all = "snake_case")]
pub enum Initials {
#[strum(serialize = "")]
None,
B,
P,
M,
F,
D,
T,
N,
L,
G,
K,
H,
J,
Q,
X,
ZH,
CH,
SH,
R,
Z,
C,
S,
Y,
W,
}
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
BitfieldSpecifier,
strum_macros::Display,
strum_macros::EnumIter,
strum_macros::AsRefStr,
strum_macros::IntoStaticStr,
)]
#[bits = 8]
#[repr(u8)]
#[strum(serialize_all = "snake_case")]
pub enum Finals {
None,
A,
O,
E,
U,
I,
AI,
AO,
EI,
OU,
Ong,
AN,
EN,
Ang,
Eng,
ER,
IA,
IE,
Iao,
Ian,
Ing,
Iang,
IN,
Iou,
Iong,
IU,
UI,
UA,
Uai,
UN,
Uan,
Uang,
UO,
UE,
#[strum(serialize = "ü")]
V,
#[strum(serialize = "üe")]
VE,
#[strum(serialize = "üan")]
Van,
}
#[derive(
Debug,
Copy,
Clone,
PartialEq,
Eq,
BitfieldSpecifier,
strum_macros::Display,
strum_macros::EnumIter,
)]
#[bits = 3]
pub enum Tones {
#[strum(serialize = "")]
None,
#[strum(serialize = "1")]
One,
#[strum(serialize = "2")]
Two,
#[strum(serialize = "3")]
Three,
#[strum(serialize = "4")]
Four,
}
#[bitfield]
#[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
pub struct Pinyin {
tones: Tones,
initials: Initials,
finals: Finals,
}
impl From<Pinyin> for u16 {
fn from(p: Pinyin) -> Self {
let bytes = p.into_bytes();
u16::from_be_bytes(bytes)
}
}
impl From<u16> for Pinyin {
fn from(value: u16) -> Self {
let bytes = value.to_be_bytes();
Pinyin::from_bytes(bytes)
}
}
pub fn py(initials: Initials, finals: Finals, tones: Tones) -> Pinyin {
let mut r = Pinyin::new();
r.set_initials(initials);
r.set_finals(finals);
r.set_tones(tones);
r
}
impl Display for Pinyin {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
PinyinDisplay::UnicodeTone(*self).fmt(f)
}
}
pub enum PinyinDisplay {
UnicodeTone(Pinyin),
NumberedTone(Pinyin),
NoTones(Pinyin),
FirstLetter(Pinyin),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) struct FinalWithTones(pub(crate) Finals, pub(crate) Tones);
#[derive(Debug)]
pub(crate) struct FinalWithTonesFromStrError(String);
impl Display for FinalWithTonesFromStrError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "invalid final with tones: '{}'", self.0)
}
}
impl Error for FinalWithTonesFromStrError {}
impl FromStr for FinalWithTones {
type Err = FinalWithTonesFromStrError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let r = match s {
"a" => FinalWithTones(Finals::A, Tones::None),
"o" => FinalWithTones(Finals::O, Tones::None),
"e" => FinalWithTones(Finals::E, Tones::None),
"u" => FinalWithTones(Finals::U, Tones::None),
"i" => FinalWithTones(Finals::I, Tones::None),
"ai" => FinalWithTones(Finals::AI, Tones::None),
"ei" => FinalWithTones(Finals::EI, Tones::None),
"ou" => FinalWithTones(Finals::OU, Tones::None),
"an" => FinalWithTones(Finals::AN, Tones::None),
"en" => FinalWithTones(Finals::EN, Tones::None),
"ang" => FinalWithTones(Finals::Ang, Tones::None),
"eng" => FinalWithTones(Finals::Eng, Tones::None),
"er" => FinalWithTones(Finals::ER, Tones::None),
"ia" => FinalWithTones(Finals::IA, Tones::None),
"iā" => FinalWithTones(Finals::IA, Tones::One),
"iá" => FinalWithTones(Finals::IA, Tones::Two),
"iǎ" => FinalWithTones(Finals::IA, Tones::Three),
"ià" => FinalWithTones(Finals::IA, Tones::Four),
"ie" => FinalWithTones(Finals::IE, Tones::None),
"iē" => FinalWithTones(Finals::IE, Tones::One),
"ié" => FinalWithTones(Finals::IE, Tones::Two),
"iě" => FinalWithTones(Finals::IE, Tones::Three),
"iè" => FinalWithTones(Finals::IE, Tones::Four),
"iao" => FinalWithTones(Finals::Iao, Tones::None),
"iāo" => FinalWithTones(Finals::Iao, Tones::One),
"iáo" => FinalWithTones(Finals::Iao, Tones::Two),
"iǎo" => FinalWithTones(Finals::Iao, Tones::Three),
"iào" => FinalWithTones(Finals::Iao, Tones::Four),
"ao" => FinalWithTones(Finals::AO, Tones::None),
"āo" => FinalWithTones(Finals::AO, Tones::One),
"áo" => FinalWithTones(Finals::AO, Tones::Two),
"ǎo" => FinalWithTones(Finals::AO, Tones::Three),
"ào" => FinalWithTones(Finals::AO, Tones::Four),
"ian" => FinalWithTones(Finals::Ian, Tones::None),
"iān" => FinalWithTones(Finals::Ian, Tones::One),
"ián" => FinalWithTones(Finals::Ian, Tones::Two),
"iǎn" => FinalWithTones(Finals::Ian, Tones::Three),
"iàn" => FinalWithTones(Finals::Ian, Tones::Four),
"ing" => FinalWithTones(Finals::Ing, Tones::None),
"īng" => FinalWithTones(Finals::Ing, Tones::One),
"íng" => FinalWithTones(Finals::Ing, Tones::Two),
"ǐng" => FinalWithTones(Finals::Ing, Tones::Three),
"ìng" => FinalWithTones(Finals::Ing, Tones::Four),
"iang" => FinalWithTones(Finals::Iang, Tones::None),
"iāng" => FinalWithTones(Finals::Iang, Tones::One),
"iáng" => FinalWithTones(Finals::Iang, Tones::Two),
"iǎng" => FinalWithTones(Finals::Iang, Tones::Three),
"iàng" => FinalWithTones(Finals::Iang, Tones::Four),
"in" => FinalWithTones(Finals::IN, Tones::None),
"īn" => FinalWithTones(Finals::IN, Tones::One),
"ín" => FinalWithTones(Finals::IN, Tones::Two),
"ǐn" => FinalWithTones(Finals::IN, Tones::Three),
"ìn" => FinalWithTones(Finals::IN, Tones::Four),
"ui" => FinalWithTones(Finals::UI, Tones::None),
"uī" => FinalWithTones(Finals::UI, Tones::One),
"uí" => FinalWithTones(Finals::UI, Tones::Two),
"uǐ" => FinalWithTones(Finals::UI, Tones::Three),
"uì" => FinalWithTones(Finals::UI, Tones::Four),
"iou" => FinalWithTones(Finals::Iou, Tones::None),
"iōu" => FinalWithTones(Finals::Iou, Tones::One),
"ióu" => FinalWithTones(Finals::Iou, Tones::Two),
"iǒu" => FinalWithTones(Finals::Iou, Tones::Three),
"iòu" => FinalWithTones(Finals::Iou, Tones::Four),
"iong" => FinalWithTones(Finals::Iong, Tones::None),
"iōng" => FinalWithTones(Finals::Iong, Tones::One),
"ióng" => FinalWithTones(Finals::Iong, Tones::Two),
"iǒng" => FinalWithTones(Finals::Iong, Tones::Three),
"iòng" => FinalWithTones(Finals::Iong, Tones::Four),
"iu" => FinalWithTones(Finals::IU, Tones::None),
"iū" => FinalWithTones(Finals::IU, Tones::One),
"iú" => FinalWithTones(Finals::IU, Tones::Two),
"iǔ" => FinalWithTones(Finals::IU, Tones::Three),
"iù" => FinalWithTones(Finals::IU, Tones::Four),
"ua" => FinalWithTones(Finals::UA, Tones::None),
"uā" => FinalWithTones(Finals::UA, Tones::One),
"uá" => FinalWithTones(Finals::UA, Tones::Two),
"uǎ" => FinalWithTones(Finals::UA, Tones::Three),
"uà" => FinalWithTones(Finals::UA, Tones::Four),
"uai" => FinalWithTones(Finals::Uai, Tones::None),
"uāi" => FinalWithTones(Finals::Uai, Tones::One),
"uái" => FinalWithTones(Finals::Uai, Tones::Two),
"uǎi" => FinalWithTones(Finals::Uai, Tones::Three),
"uài" => FinalWithTones(Finals::Uai, Tones::Four),
"uan" => FinalWithTones(Finals::Uan, Tones::None),
"uān" => FinalWithTones(Finals::Uan, Tones::One),
"uán" => FinalWithTones(Finals::Uan, Tones::Two),
"uǎn" => FinalWithTones(Finals::Uan, Tones::Three),
"uàn" => FinalWithTones(Finals::Uan, Tones::Four),
"un" => FinalWithTones(Finals::UN, Tones::None),
"ūn" => FinalWithTones(Finals::UN, Tones::One),
"ún" => FinalWithTones(Finals::UN, Tones::Two),
"ǔn" => FinalWithTones(Finals::UN, Tones::Three),
"ùn" => FinalWithTones(Finals::UN, Tones::Four),
"uang" => FinalWithTones(Finals::Uang, Tones::None),
"uāng" => FinalWithTones(Finals::Uang, Tones::One),
"uáng" => FinalWithTones(Finals::Uang, Tones::Two),
"uǎng" => FinalWithTones(Finals::Uang, Tones::Three),
"uàng" => FinalWithTones(Finals::Uang, Tones::Four),
"uo" => FinalWithTones(Finals::UO, Tones::None),
"uō" => FinalWithTones(Finals::UO, Tones::One),
"uó" => FinalWithTones(Finals::UO, Tones::Two),
"uǒ" => FinalWithTones(Finals::UO, Tones::Three),
"uò" => FinalWithTones(Finals::UO, Tones::Four),
"ü" => FinalWithTones(Finals::V, Tones::None),
"ǖ" => FinalWithTones(Finals::V, Tones::One),
"ǘ" => FinalWithTones(Finals::V, Tones::Two),
"ǚ" => FinalWithTones(Finals::V, Tones::Three),
"ǜ" => FinalWithTones(Finals::V, Tones::Four),
"üe" => FinalWithTones(Finals::VE, Tones::None),
"üē" => FinalWithTones(Finals::VE, Tones::One),
"üé" => FinalWithTones(Finals::VE, Tones::Two),
"üě" => FinalWithTones(Finals::VE, Tones::Three),
"üè" => FinalWithTones(Finals::VE, Tones::Four),
"ue" => FinalWithTones(Finals::UE, Tones::None),
"uē" => FinalWithTones(Finals::UE, Tones::One),
"ué" => FinalWithTones(Finals::UE, Tones::Two),
"uě" => FinalWithTones(Finals::UE, Tones::Three),
"uè" => FinalWithTones(Finals::UE, Tones::Four),
"üan" => FinalWithTones(Finals::Van, Tones::None),
"ǖan" => FinalWithTones(Finals::Van, Tones::One),
"ǘan" => FinalWithTones(Finals::Van, Tones::Two),
"ǚan" => FinalWithTones(Finals::Van, Tones::Three),
"ǜan" => FinalWithTones(Finals::Van, Tones::Four),
"ā" => FinalWithTones(Finals::A, Tones::One),
"á" => FinalWithTones(Finals::A, Tones::Two),
"ǎ" => FinalWithTones(Finals::A, Tones::Three),
"à" => FinalWithTones(Finals::A, Tones::Four),
"ō" => FinalWithTones(Finals::O, Tones::One),
"ó" => FinalWithTones(Finals::O, Tones::Two),
"ǒ" => FinalWithTones(Finals::O, Tones::Three),
"ò" => FinalWithTones(Finals::O, Tones::Four),
"ē" => FinalWithTones(Finals::E, Tones::One),
"é" => FinalWithTones(Finals::E, Tones::Two),
"ě" => FinalWithTones(Finals::E, Tones::Three),
"è" => FinalWithTones(Finals::E, Tones::Four),
"ū" => FinalWithTones(Finals::U, Tones::One),
"ú" => FinalWithTones(Finals::U, Tones::Two),
"ǔ" => FinalWithTones(Finals::U, Tones::Three),
"ù" => FinalWithTones(Finals::U, Tones::Four),
"ī" => FinalWithTones(Finals::I, Tones::One),
"í" => FinalWithTones(Finals::I, Tones::Two),
"ǐ" => FinalWithTones(Finals::I, Tones::Three),
"ì" => FinalWithTones(Finals::I, Tones::Four),
"āi" => FinalWithTones(Finals::AI, Tones::One),
"ái" => FinalWithTones(Finals::AI, Tones::Two),
"ǎi" => FinalWithTones(Finals::AI, Tones::Three),
"ài" => FinalWithTones(Finals::AI, Tones::Four),
"ēi" => FinalWithTones(Finals::EI, Tones::One),
"éi" => FinalWithTones(Finals::EI, Tones::Two),
"ěi" => FinalWithTones(Finals::EI, Tones::Three),
"èi" => FinalWithTones(Finals::EI, Tones::Four),
"ōu" => FinalWithTones(Finals::OU, Tones::One),
"óu" => FinalWithTones(Finals::OU, Tones::Two),
"ǒu" => FinalWithTones(Finals::OU, Tones::Three),
"òu" => FinalWithTones(Finals::OU, Tones::Four),
"ong" => FinalWithTones(Finals::Ong, Tones::None),
"ōng" => FinalWithTones(Finals::Ong, Tones::One),
"óng" => FinalWithTones(Finals::Ong, Tones::Two),
"ǒng" => FinalWithTones(Finals::Ong, Tones::Three),
"òng" => FinalWithTones(Finals::Ong, Tones::Four),
"ān" => FinalWithTones(Finals::AN, Tones::One),
"án" => FinalWithTones(Finals::AN, Tones::Two),
"ǎn" => FinalWithTones(Finals::AN, Tones::Three),
"àn" => FinalWithTones(Finals::AN, Tones::Four),
"ēn" => FinalWithTones(Finals::EN, Tones::One),
"én" => FinalWithTones(Finals::EN, Tones::Two),
"ěn" => FinalWithTones(Finals::EN, Tones::Three),
"èn" => FinalWithTones(Finals::EN, Tones::Four),
"āng" => FinalWithTones(Finals::Ang, Tones::One),
"áng" => FinalWithTones(Finals::Ang, Tones::Two),
"ǎng" => FinalWithTones(Finals::Ang, Tones::Three),
"àng" => FinalWithTones(Finals::Ang, Tones::Four),
"ēng" => FinalWithTones(Finals::Eng, Tones::One),
"éng" => FinalWithTones(Finals::Eng, Tones::Two),
"ěng" => FinalWithTones(Finals::Eng, Tones::Three),
"èng" => FinalWithTones(Finals::Eng, Tones::Four),
"ēr" => FinalWithTones(Finals::ER, Tones::One),
"ér" => FinalWithTones(Finals::ER, Tones::Two),
"ěr" => FinalWithTones(Finals::ER, Tones::Three),
"èr" => FinalWithTones(Finals::ER, Tones::Four),
"ń" => FinalWithTones(Finals::EN, Tones::Two),
"ň" => FinalWithTones(Finals::EN, Tones::Three),
"ǹ" => FinalWithTones(Finals::EN, Tones::Four),
"ńg" => FinalWithTones(Finals::Eng, Tones::Two),
"ňg" => FinalWithTones(Finals::Eng, Tones::Three),
"ǹg" => FinalWithTones(Finals::Eng, Tones::Four),
_ => FinalWithTones(Finals::None, Tones::None),
};
if let FinalWithTones(Finals::None, Tones::None) = r {
Err(FinalWithTonesFromStrError(s.to_string()))
} else {
Ok(r)
}
}
}
impl From<FinalWithTones> for &'static str {
fn from(value: FinalWithTones) -> Self {
match (value.0, value.1) {
(_, Tones::None) => value.0.into(),
(Finals::A, Tones::One) => "ā",
(Finals::A, Tones::Two) => "á",
(Finals::A, Tones::Three) => "ǎ",
(Finals::A, Tones::Four) => "à",
(Finals::O, Tones::One) => "ō",
(Finals::O, Tones::Two) => "ó",
(Finals::O, Tones::Three) => "ǒ",
(Finals::O, Tones::Four) => "ò",
(Finals::E, Tones::One) => "ē",
(Finals::E, Tones::Two) => "é",
(Finals::E, Tones::Three) => "ě",
(Finals::E, Tones::Four) => "è",
(Finals::U, Tones::One) => "ū",
(Finals::U, Tones::Two) => "ú",
(Finals::U, Tones::Three) => "ǔ",
(Finals::U, Tones::Four) => "ù",
(Finals::I, Tones::One) => "ī",
(Finals::I, Tones::Two) => "í",
(Finals::I, Tones::Three) => "ǐ",
(Finals::I, Tones::Four) => "ì",
(Finals::AI, Tones::One) => "āi",
(Finals::AI, Tones::Two) => "ái",
(Finals::AI, Tones::Three) => "ǎi",
(Finals::AI, Tones::Four) => "ài",
(Finals::AO, Tones::One) => "āo",
(Finals::AO, Tones::Two) => "áo",
(Finals::AO, Tones::Three) => "ǎo",
(Finals::AO, Tones::Four) => "ào",
(Finals::EI, Tones::One) => "ēi",
(Finals::EI, Tones::Two) => "éi",
(Finals::EI, Tones::Three) => "ěi",
(Finals::EI, Tones::Four) => "èi",
(Finals::OU, Tones::One) => "ōu",
(Finals::OU, Tones::Two) => "óu",
(Finals::OU, Tones::Three) => "ǒu",
(Finals::OU, Tones::Four) => "òu",
(Finals::Ong, Tones::One) => "ōng",
(Finals::Ong, Tones::Two) => "óng",
(Finals::Ong, Tones::Three) => "ǒng",
(Finals::Ong, Tones::Four) => "òng",
(Finals::AN, Tones::One) => "ān",
(Finals::AN, Tones::Two) => "án",
(Finals::AN, Tones::Three) => "ǎn",
(Finals::AN, Tones::Four) => "àn",
(Finals::EN, Tones::One) => "ēn",
(Finals::EN, Tones::Two) => "én",
(Finals::EN, Tones::Three) => "ěn",
(Finals::EN, Tones::Four) => "èn",
(Finals::Ang, Tones::One) => "āng",
(Finals::Ang, Tones::Two) => "áng",
(Finals::Ang, Tones::Three) => "ǎng",
(Finals::Ang, Tones::Four) => "àng",
(Finals::Eng, Tones::One) => "ēng",
(Finals::Eng, Tones::Two) => "éng",
(Finals::Eng, Tones::Three) => "ěng",
(Finals::Eng, Tones::Four) => "èng",
(Finals::ER, Tones::One) => "ēr",
(Finals::ER, Tones::Two) => "ér",
(Finals::ER, Tones::Three) => "ěr",
(Finals::ER, Tones::Four) => "èr",
(Finals::IA, Tones::One) => "iā",
(Finals::IA, Tones::Two) => "iá",
(Finals::IA, Tones::Three) => "iǎ",
(Finals::IA, Tones::Four) => "ià",
(Finals::IE, Tones::One) => "iē",
(Finals::IE, Tones::Two) => "ié",
(Finals::IE, Tones::Three) => "iě",
(Finals::IE, Tones::Four) => "iè",
(Finals::Iao, Tones::One) => "iāo",
(Finals::Iao, Tones::Two) => "iáo",
(Finals::Iao, Tones::Three) => "iǎo",
(Finals::Iao, Tones::Four) => "iào",
(Finals::Iou, Tones::One) => "iōu",
(Finals::Iou, Tones::Two) => "ióu",
(Finals::Iou, Tones::Three) => "iǒu",
(Finals::Iou, Tones::Four) => "iòu",
(Finals::Ian, Tones::One) => "iān",
(Finals::Ian, Tones::Two) => "ián",
(Finals::Ian, Tones::Three) => "iǎn",
(Finals::Ian, Tones::Four) => "iàn",
(Finals::IN, Tones::One) => "īn",
(Finals::IN, Tones::Two) => "ín",
(Finals::IN, Tones::Three) => "ǐn",
(Finals::IN, Tones::Four) => "ìn",
(Finals::UI, Tones::One) => "uī",
(Finals::UI, Tones::Two) => "uí",
(Finals::UI, Tones::Three) => "uǐ",
(Finals::UI, Tones::Four) => "uì",
(Finals::Iang, Tones::One) => "iāng",
(Finals::Iang, Tones::Two) => "iáng",
(Finals::Iang, Tones::Three) => "iǎng",
(Finals::Iang, Tones::Four) => "iàng",
(Finals::Ing, Tones::One) => "īng",
(Finals::Ing, Tones::Two) => "íng",
(Finals::Ing, Tones::Three) => "ǐng",
(Finals::Ing, Tones::Four) => "ìng",
(Finals::Iong, Tones::One) => "iōng",
(Finals::Iong, Tones::Two) => "ióng",
(Finals::Iong, Tones::Three) => "iǒng",
(Finals::Iong, Tones::Four) => "iòng",
(Finals::IU, Tones::One) => "iū",
(Finals::IU, Tones::Two) => "iú",
(Finals::IU, Tones::Three) => "iǔ",
(Finals::IU, Tones::Four) => "iù",
(Finals::UA, Tones::One) => "uā",
(Finals::UA, Tones::Two) => "uá",
(Finals::UA, Tones::Three) => "uǎ",
(Finals::UA, Tones::Four) => "uà",
(Finals::Uai, Tones::One) => "uāi",
(Finals::Uai, Tones::Two) => "uái",
(Finals::Uai, Tones::Three) => "uǎi",
(Finals::Uai, Tones::Four) => "uài",
(Finals::UN, Tones::One) => "ūn",
(Finals::UN, Tones::Two) => "ún",
(Finals::UN, Tones::Three) => "ǔn",
(Finals::UN, Tones::Four) => "ùn",
(Finals::Uan, Tones::One) => "uān",
(Finals::Uan, Tones::Two) => "uán",
(Finals::Uan, Tones::Three) => "uǎn",
(Finals::Uan, Tones::Four) => "uàn",
(Finals::Uang, Tones::One) => "uāng",
(Finals::Uang, Tones::Two) => "uáng",
(Finals::Uang, Tones::Three) => "uǎng",
(Finals::Uang, Tones::Four) => "uàng",
(Finals::UO, Tones::One) => "uō",
(Finals::UO, Tones::Two) => "uó",
(Finals::UO, Tones::Three) => "uǒ",
(Finals::UO, Tones::Four) => "uò",
(Finals::V, Tones::One) => "ǖ",
(Finals::V, Tones::Two) => "ǘ",
(Finals::V, Tones::Three) => "ǚ",
(Finals::V, Tones::Four) => "ǜ",
(Finals::VE, Tones::One) => "üē",
(Finals::VE, Tones::Two) => "üé",
(Finals::VE, Tones::Three) => "üě",
(Finals::VE, Tones::Four) => "üè",
(Finals::UE, Tones::One) => "uē",
(Finals::UE, Tones::Two) => "ué",
(Finals::UE, Tones::Three) => "uě",
(Finals::UE, Tones::Four) => "uè",
(Finals::Van, Tones::One) => "ǖan",
(Finals::Van, Tones::Two) => "ǘan",
(Finals::Van, Tones::Three) => "ǚan",
(Finals::Van, Tones::Four) => "ǜan",
(Finals::None, Tones::One) => unreachable!(),
(Finals::None, Tones::Two) => unreachable!(),
(Finals::None, Tones::Three) => unreachable!(),
(Finals::None, Tones::Four) => unreachable!(),
}
}
}
impl Display for PinyinDisplay {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
PinyinDisplay::UnicodeTone(p) => {
f.write_fmt(format_args!("{}", p.initials()))?;
if p.tones() == Tones::None {
f.write_fmt(format_args!("{}", p.finals()))
} else {
f.write_str(FinalWithTones(p.finals(), p.tones()).into())
}
}
PinyinDisplay::NumberedTone(p) => {
f.write_fmt(format_args!("{}", p.initials()))?;
f.write_fmt(format_args!("{}", p.finals()))?;
f.write_fmt(format_args!("{}", p.tones()))
}
PinyinDisplay::NoTones(p) => {
f.write_fmt(format_args!("{}", p.initials()))?;
f.write_fmt(format_args!("{}", p.finals()))
}
PinyinDisplay::FirstLetter(p) => match p.initials() {
Initials::None => f.write_str(&p.finals().as_ref()[0..1]),
_ => f.write_str(&p.initials().as_ref()[0..1]),
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use rstest::rstest;
use strum::IntoEnumIterator;
#[rstest]
#[case("", Initials::None)]
#[case("b", Initials::B)]
#[case("zh", Initials::ZH)]
fn initials_display(#[case] exp: &str, #[case] val: Initials) {
assert_eq!(exp, val.to_string());
}
#[rstest]
#[case("a", Finals::A)]
#[case("eng", Finals::Eng)]
#[case("ü", Finals::V)]
#[case("üan", Finals::Van)]
fn finals_display(#[case] exp: &str, #[case] val: Finals) {
assert_eq!(exp, val.to_string());
}
#[rstest]
#[case("a", py(Initials::None, Finals::A, Tones::None))]
#[case("beng", py(Initials::B, Finals::Eng, Tones::None))]
#[case("zhǖ", py(Initials::ZH, Finals::V, Tones::One))]
#[case("ēr", py(Initials::None, Finals::ER, Tones::One))]
fn pinyin_unicode_format(#[case] exp: &str, #[case] val: Pinyin) {
assert_eq!(exp, val.to_string());
}
#[rstest]
#[case("a", py(Initials::None, Finals::A, Tones::None))]
#[case("beng", py(Initials::B, Finals::Eng, Tones::None))]
#[case("zhü1", py(Initials::ZH, Finals::V, Tones::One))]
#[case("a1", py(Initials::None, Finals::A, Tones::One))]
#[case("a2", py(Initials::None, Finals::A, Tones::Two))]
#[case("a3", py(Initials::None, Finals::A, Tones::Three))]
#[case("a4", py(Initials::None, Finals::A, Tones::Four))]
fn pinyin_numbered_format(#[case] exp: &str, #[case] val: Pinyin) {
assert_eq!(exp, PinyinDisplay::NumberedTone(val).to_string());
}
#[rstest]
#[case("a", py(Initials::None, Finals::A, Tones::None))]
#[case("beng", py(Initials::B, Finals::Eng, Tones::None))]
#[case("zhü", py(Initials::ZH, Finals::V, Tones::One))]
#[case("a", py(Initials::None, Finals::A, Tones::One))]
fn no_tones_format(#[case] exp: &str, #[case] val: Pinyin) {
assert_eq!(exp, PinyinDisplay::NoTones(val).to_string());
}
#[rstest]
#[case("a", py(Initials::None, Finals::A, Tones::Two))]
#[case("b", py(Initials::B, Finals::Eng, Tones::None))]
#[case("z", py(Initials::ZH, Finals::V, Tones::One))]
#[case("a", py(Initials::None, Finals::A, Tones::One))]
#[case("e", py(Initials::None, Finals::ER, Tones::One))]
#[case("s", py(Initials::SH, Finals::I, Tones::One))]
fn first_letter_format(#[case] exp: &str, #[case] val: Pinyin) {
assert_eq!(exp, PinyinDisplay::FirstLetter(val).to_string());
}
#[test]
fn final_and_tones_to_from_str() {
itertools::iproduct!(Finals::iter(), Tones::iter()).for_each(|(f, t)| {
if f != Finals::None {
let s: &str = FinalWithTones(f, t).into();
let fwt = s.parse::<FinalWithTones>().unwrap();
assert_eq!(fwt, FinalWithTones(f, t));
}
});
}
#[test]
fn pinyin_into_u16() {
itertools::iproduct!(Initials::iter(), Finals::iter(), Tones::iter()).for_each(
|(i, f, t)| {
let p = py(i, f, t);
let n: u16 = p.into();
assert_eq!(p, n.into());
},
);
}
}