1mod r_ref;
2pub mod traits;
3
4pub use r_ref::ReadingRef;
5
6use self::traits::AsReadingRef;
7
8#[cfg(feature = "furigana")]
9use crate::furi::segment::kanji::as_kanji::AsKanjiSegment;
10#[cfg(feature = "furigana")]
11use crate::furi::{parse::reading::FuriToReadingParser, Furigana};
12#[cfg(feature = "furigana")]
13use crate::furi::{segment::AsSegment, segment::Segment, seq::FuriSequence};
14
15#[derive(Debug, Clone, PartialEq, Eq, Default)]
19#[cfg_attr(feature = "with_serde", derive(serde::Serialize, serde::Deserialize))]
20pub struct Reading {
21 kana: String,
22 kanji: Option<String>,
23}
24
25impl Reading {
26 #[inline]
28 pub fn new(kana: String) -> Self {
29 Self { kana, kanji: None }
30 }
31
32 #[inline]
34 pub fn new_with_kanji(kana: String, kanji: String) -> Self {
35 Self {
36 kana,
37 kanji: Some(kanji),
38 }
39 }
40
41 #[inline]
43 pub fn new_raw(kana: String, kanji: Option<String>) -> Self {
44 Self { kana, kanji }
45 }
46
47 #[inline]
49 pub fn has_kanji(&self) -> bool {
50 self.kanji.is_some()
51 }
52
53 #[inline]
55 pub fn kanji_or_kana(&self) -> &str {
56 self.kanji.as_deref().unwrap_or(&self.kana)
57 }
58
59 #[inline]
61 pub fn kanji(&self) -> Option<&str> {
62 self.kanji.as_deref()
63 }
64
65 #[inline]
67 pub fn kana(&self) -> &str {
68 &self.kana
69 }
70
71 #[inline]
74 pub fn into_inner(self) -> (String, Option<String>) {
75 (self.kana, self.kanji)
76 }
77}
78
79impl AsReadingRef for Reading {
80 #[inline]
81 fn as_reading_ref(&self) -> ReadingRef {
82 ReadingRef::new_raw(&self.kana, self.kanji.as_deref())
83 }
84}
85
86impl PartialEq<ReadingRef<'_>> for Reading {
87 #[inline]
88 fn eq(&self, other: &ReadingRef) -> bool {
89 self.kana.as_str() == other.kana() && self.kanji.as_deref() == other.kanji()
90 }
91}
92
93#[cfg(feature = "furigana")]
94impl From<&FuriSequence<Segment>> for Reading {
95 #[inline]
96 fn from(value: &FuriSequence<Segment>) -> Self {
97 let kana = value.kana_reading().to_string();
98 let kanji = value.has_kanji().then(|| value.kanji_reading().to_string());
99 Self { kana, kanji }
100 }
101}
102
103#[cfg(feature = "furigana")]
104impl<T: AsRef<str>> From<&Furigana<T>> for Reading {
105 #[inline]
106 fn from(value: &Furigana<T>) -> Self {
107 let (kana, kanji) = FuriToReadingParser::parse_kanji_and_kana(value.raw());
108 Self::new_raw(kana, kanji)
109 }
110}
111
112#[cfg(feature = "furigana")]
113impl<T: AsRef<str>> From<Furigana<T>> for Reading {
114 #[inline]
115 fn from(value: Furigana<T>) -> Self {
116 let (kana, kanji) = FuriToReadingParser::parse_kanji_and_kana(value.raw());
117 Self::new_raw(kana, kanji)
118 }
119}
120
121#[cfg(feature = "furigana")]
122impl From<FuriSequence<Segment>> for Reading {
123 #[inline]
124 fn from(value: FuriSequence<Segment>) -> Self {
125 let kana = value.kana_reading().to_string();
126 let kanji = value.has_kanji().then(|| value.kanji_reading().to_string());
127 Self { kana, kanji }
128 }
129}
130
131#[cfg(feature = "furigana")]
132impl<S: AsSegment> FromIterator<S> for Reading {
133 fn from_iter<T: IntoIterator<Item = S>>(iter: T) -> Reading {
134 let mut kana = String::with_capacity(20);
135 let mut kanji = String::new();
136 let mut has_kanji = false;
137
138 for i in iter {
139 if let Some(k) = i.as_kanji() {
140 if !has_kanji {
141 kanji = kana.clone();
143 has_kanji = true;
144 }
145
146 let readings = k.readings();
147 if readings.is_empty() || readings[0].as_ref().is_empty() {
148 kana.push_str(k.literals().as_ref());
149 kanji.push_str(k.literals().as_ref());
150 continue;
151 }
152
153 kanji.push_str(k.literals().as_ref());
154 for r in readings {
155 kana.push_str(r.as_ref());
156 }
157 } else if let Some(k) = i.as_kana() {
158 let k = k.as_ref();
159 kana.push_str(k);
160 if has_kanji {
161 kanji.push_str(k);
162 }
163 }
164 }
165 let kanji = has_kanji.then_some(kanji);
166 Reading::new_raw(kana, kanji)
167 }
168}
169
170#[cfg(feature = "furigana")]
171impl<A> From<A> for Reading
172where
173 A: AsSegment,
174{
175 #[inline]
176 fn from(value: A) -> Self {
177 let kana = value.get_kana_reading();
178 let kanji = value.as_kanji().map(|i| i.literals().as_ref().to_string());
179 Self { kana, kanji }
180 }
181}