use crate::data::PINYIN_DATA;
use crate::{get_block_and_index, PinyinData};
use std::convert::TryFrom;
use std::str::Chars;
#[derive(Copy, Clone)]
pub struct Pinyin(pub(crate) &'static PinyinData);
impl Pinyin {
#[cfg(feature = "plain")]
pub fn plain(self) -> &'static str {
self.0.plain
}
#[cfg(feature = "with_tone")]
pub fn with_tone(self) -> &'static str {
self.0.with_tone
}
#[cfg(feature = "with_tone_num")]
pub fn with_tone_num(self) -> &'static str {
self.0.with_tone_num
}
#[cfg(feature = "with_tone_num_end")]
pub fn with_tone_num_end(self) -> &'static str {
self.0.with_tone_num_end
}
#[cfg(feature = "plain")]
pub fn first_letter(self) -> &'static str {
let ch = self.0.plain.chars().next().unwrap();
&self.0.plain[..ch.len_utf8()]
}
#[cfg(feature = "compat")]
pub(crate) fn initials(self) -> &'static str {
&self.0.plain[..self.0.split]
}
#[cfg(feature = "compat")]
pub(crate) fn finals_plain(self) -> &'static str {
&self.0.plain[self.0.split..]
}
#[cfg(feature = "compat")]
pub(crate) fn finals_with_tone(self) -> &'static str {
&self.0.with_tone[self.0.split..]
}
#[cfg(feature = "compat")]
pub(crate) fn finals_with_tone_num(self) -> &'static str {
&self.0.with_tone_num[self.0.split..]
}
}
pub trait ToPinyin {
type Output;
fn to_pinyin(&self) -> Self::Output;
}
impl ToPinyin for char {
type Output = Option<Pinyin>;
fn to_pinyin(&self) -> Option<Pinyin> {
get_block_and_index(*self).and_then(|(block, index)| {
match usize::try_from(block.data[index]).unwrap() {
0 => None,
idx => Some(Pinyin(&PINYIN_DATA[idx])),
}
})
}
}
impl<'a> ToPinyin for &'a str {
type Output = PinyinStrIter<'a>;
#[inline]
fn to_pinyin(&self) -> Self::Output {
PinyinStrIter(self.chars())
}
}
pub struct PinyinStrIter<'a>(Chars<'a>);
impl<'a> Iterator for PinyinStrIter<'a> {
type Item = Option<Pinyin>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|c| c.to_pinyin())
}
}
#[cfg(test)]
mod tests {
use crate::ToPinyin;
#[test]
fn special_code_point() {
assert!('\u{10FFFF}'.to_pinyin().is_none());
}
}