use super::{kanji::KanjiRef, traits::AsSegment, Segment};
use tinyvec::TinyVec;
#[derive(Clone, PartialEq, Debug, Eq, Hash)]
#[cfg_attr(feature = "with_serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SegmentRef<'a> {
Kana(&'a str),
Kanji(KanjiRef<'a>),
}
impl<'a> SegmentRef<'a> {
#[inline]
pub fn new_kana(kana: &'a str) -> Self {
Self::Kana(kana)
}
#[inline]
pub fn new_kanji(lits: &'a str, readings: &[&'a str]) -> Self {
Self::Kanji(KanjiRef::new(lits, readings))
}
#[inline]
pub fn new_kanji_raw(lits: &'a str, readings: TinyVec<[&'a str; 1]>) -> Self {
Self::Kanji(KanjiRef::new_raw(lits, readings))
}
pub fn from_str_checked(str: &'a str) -> Result<SegmentRef, ()> {
if str.starts_with('[') && str.ends_with(']') {
Self::parse_kanji_str(str, true).ok_or(())
} else {
Ok(SegmentRef::Kana(str))
}
}
pub fn from_str_unchecked(str: &'a str) -> SegmentRef {
if str.starts_with('[') && str.ends_with(']') {
Self::parse_kanji_str(str, false).unwrap()
} else {
SegmentRef::Kana(str)
}
}
fn parse_kanji_str(s: &'a str, checked: bool) -> Option<SegmentRef> {
let mut split = s[1..s.len() - 1].split('|');
let kanji = split.next()?;
let readings = split.collect::<TinyVec<[&str; 1]>>();
if readings.is_empty() && checked {
return None;
}
if readings.len() == 1 {
return Some(SegmentRef::new_kanji_raw(kanji, readings));
} else if checked && kanji.chars().count() != readings.len() {
return None;
}
Some(SegmentRef::Kanji(KanjiRef::new_raw(kanji, readings)))
}
#[inline]
pub fn to_owned(&self) -> Segment {
match self {
SegmentRef::Kana(k) => Segment::Kana(k.to_string()),
SegmentRef::Kanji(k) => Segment::Kanji(k.to_owned()),
}
}
pub(crate) fn parse_str(str: &'a str, kanji: bool, checked: bool) -> Result<SegmentRef, ()> {
if kanji {
Self::parse_kanji_str(str, checked).ok_or(())
} else {
Ok(SegmentRef::Kana(str))
}
}
}
impl<'a> AsSegment for SegmentRef<'a> {
type StrType = &'a str;
type KanjiType = KanjiRef<'a>;
#[inline]
fn is_kana(&self) -> bool {
matches!(self, Self::Kana(..))
}
#[inline]
fn is_kanji(&self) -> bool {
matches!(self, Self::Kanji(..))
}
#[inline]
fn as_kana(&self) -> Option<&Self::StrType> {
if let Self::Kana(v) = self {
Some(v)
} else {
None
}
}
#[inline]
fn as_kanji(&self) -> Option<&Self::KanjiType> {
if let Self::Kanji(v) = self {
Some(v)
} else {
None
}
}
}
impl<'a> PartialEq<Segment> for SegmentRef<'a> {
#[inline]
fn eq(&self, other: &Segment) -> bool {
other.eq(self)
}
}
impl<'a> PartialEq<Segment> for &'a SegmentRef<'a> {
#[inline]
fn eq(&self, other: &Segment) -> bool {
other.eq(*self)
}
}