1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
use super::{
encode::FuriEncoder,
iter::{flatten::FlattenIter, SegmentIter},
kanji::as_kanji::AsKanjiSegment,
s_ref::SegmentRef,
};
use crate::reading::{traits::AsReadingRef, Reading};
/// Defines shared behaivor segments.
pub trait AsSegment {
type StrType: AsRef<str> + Default;
type KanjiType: AsKanjiSegment<StrType = Self::StrType>;
/// Returns `true` if the segment is a kana segment.
fn is_kana(&self) -> bool;
/// Returns `true` if the segment is a kanji segment.
fn is_kanji(&self) -> bool;
/// Returns the segment as kana.
fn as_kana(&self) -> Option<&Self::StrType>;
/// Returns the segment as kanji.
fn as_kanji(&self) -> Option<&Self::KanjiType>;
/// Returns the kana reading of the segment. The output is equal to `as_kana()` for kana
/// segments and `as_kanji().full_reading()` for kanji segments.
fn get_kana_reading(&self) -> String {
if let Some(kana) = self.as_kana() {
return kana.as_ref().to_string();
}
// Safe as there can only be kanji or kana and in case of kana this function had early
// returned.
unsafe { self.as_kanji().unwrap_unchecked() }.full_reading()
}
/// Returns a ReadingOwned representing the reading of the part.
fn to_reading(&self) -> Reading {
if let Some(kana) = self.as_kana() {
return Reading::new(kana.as_ref().to_string());
}
// Safe as there can only be kanji or kana and in case of kana this function had early
// returned.
let kanji = unsafe { self.as_kanji().unwrap_unchecked() };
Reading::new_with_kanji(kanji.full_reading(), kanji.literals().as_ref().to_string())
}
/// Returns an Iterator over all readings of the Segment.
#[inline]
fn reading_iter(&self) -> SegmentIter<Self>
where
Self: Sized,
{
SegmentIter::new(self)
}
/// Returns `true` if the segment is empty.
fn is_empty(&self) -> bool {
if let Some(kana) = self.as_kana() {
return kana.as_ref().is_empty();
}
// Safe as there can only be kanji or kana and in case of kana this function had early
// returned.
unsafe { self.as_kanji().unwrap_unchecked() }.is_empty()
}
/// Encodes the segment into a buffer.
fn encode_into(&self, buf: &mut String) {
let mut enc = FuriEncoder::new(buf);
if let Some(s) = self.as_kana() {
enc.write_kana(s.as_ref());
return;
}
// Safe as there can only be kanji or kana and in case of kana this function had early
// returned.
enc.write_kanji(unsafe { self.as_kanji().unwrap_unchecked() });
}
/// Encodes the segment into a newly allocated String. This shouldn't be used in loops or
/// situations where `encode_into` would work too as this does less allocations.
fn encode(&self) -> String {
let mut buf = String::with_capacity(8);
self.encode_into(&mut buf);
buf
}
/// Returns the main reading of the part. This is the Kanji reading if the part is a kanji or
/// the kana reading if the part is a kana part.
fn main_reading(&self) -> &Self::StrType {
if let Some(kana) = self.as_kana() {
return &kana;
}
// Safe as there can only be kanji or kana and in case of kana this function had early
// returned.
unsafe { self.as_kanji().unwrap_unchecked().literals() }
}
/// Returns an iterator over flattened readings
#[inline]
fn reading_flattened(&self) -> FlattenIter<'_, Self::StrType, Self::KanjiType>
where
Self: Sized,
{
FlattenIter::new(self)
}
/// Returns `true` if the segment holds equal reading data as `reading`.
fn eq_reading<R>(&self, reading: R) -> bool
where
R: AsReadingRef,
{
let reading = reading.as_reading_ref();
if let Some(kana) = self.as_kana() {
return kana.as_ref() == reading.kana() && !reading.has_kanji();
}
if !reading.has_kanji() {
return false;
}
let reading_kanji = match reading.kanji() {
Some(k) => k,
None => return false,
};
// Safety:
// A reading is either a kanji or kana. This is unreachable if its not kanji.
let kanji = unsafe { self.as_kanji().unwrap_unchecked() };
kanji.literals().as_ref() == reading_kanji && self.get_kana_reading() == reading.kana()
}
}
impl<T> AsSegment for &T
where
T: AsSegment,
{
type StrType = T::StrType;
type KanjiType = T::KanjiType;
#[inline]
fn is_kana(&self) -> bool {
(*self).is_kana()
}
#[inline]
fn is_kanji(&self) -> bool {
(*self).is_kanji()
}
#[inline]
fn as_kana(&self) -> Option<&T::StrType> {
(*self).as_kana()
}
#[inline]
fn as_kanji(&self) -> Option<&Self::KanjiType> {
(*self).as_kanji()
}
}
pub trait AsSegmentRef<'a> {
fn as_seg_ref(&self) -> SegmentRef<'a>;
}