1use std::iter::Sum;
6use std::ops::{Add, AddAssign, Range, Sub, SubAssign};
7
8use malloc_size_of_derive::MallocSizeOf;
9
10pub use crate::unicode_block::{UnicodeBlock, UnicodeBlockMethod};
11
12pub fn is_bidi_control(c: char) -> bool {
13 matches!(c, '\u{202A}'..='\u{202E}' | '\u{2066}'..='\u{2069}' | '\u{200E}' | '\u{200F}' | '\u{061C}')
14}
15
16pub fn unicode_plane(codepoint: char) -> u32 {
17 (codepoint as u32) >> 16
18}
19
20pub fn is_cjk(codepoint: char) -> bool {
21 if let Some(
22 UnicodeBlock::CJKRadicalsSupplement |
23 UnicodeBlock::KangxiRadicals |
24 UnicodeBlock::IdeographicDescriptionCharacters |
25 UnicodeBlock::CJKSymbolsandPunctuation |
26 UnicodeBlock::Hiragana |
27 UnicodeBlock::Katakana |
28 UnicodeBlock::Bopomofo |
29 UnicodeBlock::HangulCompatibilityJamo |
30 UnicodeBlock::Kanbun |
31 UnicodeBlock::BopomofoExtended |
32 UnicodeBlock::CJKStrokes |
33 UnicodeBlock::KatakanaPhoneticExtensions |
34 UnicodeBlock::EnclosedCJKLettersandMonths |
35 UnicodeBlock::CJKCompatibility |
36 UnicodeBlock::CJKUnifiedIdeographsExtensionA |
37 UnicodeBlock::YijingHexagramSymbols |
38 UnicodeBlock::CJKUnifiedIdeographs |
39 UnicodeBlock::CJKCompatibilityIdeographs |
40 UnicodeBlock::CJKCompatibilityForms |
41 UnicodeBlock::HalfwidthandFullwidthForms,
42 ) = codepoint.block()
43 {
44 return true;
45 }
46
47 unicode_plane(codepoint) == 2 || unicode_plane(codepoint) == 3
50}
51
52#[derive(Clone, Copy)]
54pub struct RangeAny<T> {
55 pub start: Option<T>,
57 pub end: Option<T>,
59}
60
61impl<T> RangeAny<T> {
62 pub fn map<U>(self, f: impl Fn(T) -> U + Copy) -> RangeAny<U> {
64 let Self { start, end } = self;
65 RangeAny {
66 start: start.map(f),
67 end: end.map(f),
68 }
69 }
70
71 pub fn intersect(self, other: Self) -> Option<Self>
73 where
74 T: Ord,
75 {
76 let start = match (self.start, other.start) {
80 (None, None) => None,
81 (None, Some(b)) => Some(b),
82 (Some(a), None) => Some(a),
83 (Some(a), Some(b)) => Some(a.max(b)),
84 };
85 let end = match (self.end, other.end) {
86 (None, None) => None,
87 (None, Some(b)) => Some(b),
88 (Some(a), None) => Some(a),
89 (Some(a), Some(b)) => Some(a.min(b)),
90 };
91 if start
92 .as_ref()
93 .is_none_or(|start| end.as_ref().is_none_or(|end| start < end))
94 {
95 Some(RangeAny { start, end })
96 } else {
97 None
99 }
100 }
101}
102
103impl<T> From<Range<T>> for RangeAny<T> {
104 fn from(value: Range<T>) -> Self {
105 Self {
106 start: Some(value.start),
107 end: Some(value.end),
108 }
109 }
110}
111
112macro_rules! unicode_length_type {
113 ($( #[$doc:meta] )+ $type_name:ident) => {
114 $( #[$doc] )+
115 #[derive(Clone, Copy, Debug, Default, Eq, MallocSizeOf, Ord, PartialEq, PartialOrd)]
116 pub struct $type_name(pub usize);
117
118 impl $type_name {
119 pub fn zero() -> Self {
120 Self(0)
121 }
122
123 pub fn one() -> Self {
124 Self(1)
125 }
126
127 pub fn saturating_sub(self, value: Self) -> Self {
128 Self(self.0.saturating_sub(value.0))
129 }
130 }
131
132 impl From<u32> for $type_name {
133 fn from(value: u32) -> Self {
134 Self(value as usize)
135 }
136 }
137
138 impl From<isize> for $type_name {
139 fn from(value: isize) -> Self {
140 Self(value as usize)
141 }
142 }
143
144 impl Add for $type_name {
145 type Output = Self;
146 fn add(self, other: Self) -> Self {
147 Self(self.0 + other.0)
148 }
149 }
150
151 impl AddAssign for $type_name {
152 fn add_assign(&mut self, other: Self) {
153 *self = Self(self.0 + other.0)
154 }
155 }
156
157 impl Sub for $type_name {
158 type Output = Self;
159 fn sub(self, value: Self) -> Self {
160 Self(self.0 - value.0)
161 }
162 }
163
164 impl SubAssign for $type_name {
165 fn sub_assign(&mut self, other: Self) {
166 *self = Self(self.0 - other.0)
167 }
168 }
169
170 impl Sum for $type_name {
171 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
172 iter.fold(Self::zero(), |a, b| Self(a.0 + b.0))
173 }
174 }
175 };
176}
177
178unicode_length_type! {
179 Utf8CodeUnits
182}
183
184unicode_length_type! {
185 Utf16CodeUnits
188}
189
190unicode_length_type! {
191 Utf32CodeUnits
195}
196
197impl Utf16CodeUnits {
198 pub fn length_of(string: &str) -> Self {
199 Self(string.bytes().map(len_utf16_for_utf8_byte).sum())
200
201 }
207
208 pub fn to_utf32_code_units_in(self, string: &str) -> Utf32CodeUnits {
209 let mut current_utf16_offset = Utf16CodeUnits(0);
210 let mut current_utf32_offset = Utf32CodeUnits(0);
211 for utf8_byte in string.bytes() {
212 if current_utf16_offset >= self {
213 break;
214 }
215 let len_utf16 = len_utf16_for_utf8_byte(utf8_byte);
216 current_utf16_offset.0 += len_utf16;
217 current_utf32_offset.0 += (len_utf16 != 0) as usize;
220 }
221 current_utf32_offset
222 }
223}
224
225fn len_utf16_for_utf8_byte(byte: u8) -> usize {
226 if byte < 0b1000_0000 {
227 1
229 } else if byte < 0b1100_0000 {
230 0
232 } else if byte < 0b1111_0000 {
233 1
236 } else {
237 2
242 }
243}
244
245impl Utf32CodeUnits {
246 pub fn length_of(string: &str) -> Self {
247 Self(string.chars().count())
250 }
251
252 pub fn to_utf8_code_units_in(self, string: &str) -> Utf8CodeUnits {
253 let mut current_utf32_offset = Utf32CodeUnits(0);
254 for (current_utf8_offset, byte) in string.bytes().enumerate() {
255 if (byte & 0b1100_0000) == 0b1000_0000 {
256 continue;
258 }
259 if current_utf32_offset >= self {
260 return Utf8CodeUnits(current_utf8_offset);
261 }
262 current_utf32_offset.0 += 1;
263 }
264 Utf8CodeUnits(string.len())
265 }
266}
267
268#[cfg(test)]
269mod test {
270 use super::*;
271
272 #[test]
273 fn test_is_cjk() {
274 assert_eq!(is_cjk('〇'), true);
276 assert_eq!(is_cjk('㐀'), true);
277 assert_eq!(is_cjk('あ'), true);
278 assert_eq!(is_cjk('ア'), true);
279 assert_eq!(is_cjk('㆒'), true);
280 assert_eq!(is_cjk('ㆣ'), true);
281 assert_eq!(is_cjk('龥'), true);
282 assert_eq!(is_cjk('𰾑'), true);
283 assert_eq!(is_cjk('𰻝'), true);
284
285 assert_eq!(is_cjk('a'), false);
287 assert_eq!(is_cjk('🙂'), false);
288 assert_eq!(is_cjk('©'), false);
289 }
290
291 #[test]
292 fn test_utf16_length() {
293 assert_eq!(Utf16CodeUnits::length_of(""), Utf16CodeUnits(0));
294 assert_eq!(Utf16CodeUnits::length_of("a"), Utf16CodeUnits(1));
295 assert_eq!(Utf16CodeUnits::length_of("é"), Utf16CodeUnits(1));
296 assert_eq!(Utf16CodeUnits::length_of("字"), Utf16CodeUnits(1));
297 assert_eq!(Utf16CodeUnits::length_of("\u{1F4A9}"), Utf16CodeUnits(2));
298 assert_eq!(
299 Utf16CodeUnits::length_of("\u{1F4A9}字éa"),
300 Utf16CodeUnits(5)
301 );
302 }
303
304 #[test]
305 fn test_utf16_to_utf32() {
306 let s = "aé字\u{1F4A9}";
307 assert_eq!(
308 Utf16CodeUnits(0).to_utf32_code_units_in(s),
309 Utf32CodeUnits(0)
310 );
311 assert_eq!(
312 Utf16CodeUnits(1).to_utf32_code_units_in(s),
313 Utf32CodeUnits(1)
314 );
315 assert_eq!(
316 Utf16CodeUnits(2).to_utf32_code_units_in(s),
317 Utf32CodeUnits(2)
318 );
319 assert_eq!(
320 Utf16CodeUnits(3).to_utf32_code_units_in(s),
321 Utf32CodeUnits(3)
322 );
323
324 assert_eq!(
327 Utf16CodeUnits(4).to_utf32_code_units_in(s),
328 Utf32CodeUnits(4)
329 );
330
331 assert_eq!(
332 Utf16CodeUnits(5).to_utf32_code_units_in(s),
333 Utf32CodeUnits(4)
334 );
335
336 assert_eq!(
339 Utf16CodeUnits(6).to_utf32_code_units_in(s),
340 Utf32CodeUnits(4)
341 );
342 assert_eq!(
343 Utf16CodeUnits(7).to_utf32_code_units_in(s),
344 Utf32CodeUnits(4)
345 );
346 }
347}