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
197unicode_length_type! {
198 Utf32CodeUnitsOrNodeOffset
201}
202
203impl Utf16CodeUnits {
204 pub fn length_of(string: &str) -> Self {
205 Self(string.bytes().map(len_utf16_for_utf8_byte).sum())
206
207 }
213
214 pub fn to_utf32_code_units_in(self, string: &str) -> Utf32CodeUnits {
215 let mut current_utf16_offset = Utf16CodeUnits(0);
216 let mut current_utf32_offset = Utf32CodeUnits(0);
217 for utf8_byte in string.bytes() {
218 if current_utf16_offset >= self {
219 break;
220 }
221 increment_offsets_for_utf8_byte(
222 utf8_byte,
223 &mut current_utf16_offset,
224 &mut current_utf32_offset,
225 );
226 }
227 current_utf32_offset
228 }
229}
230
231fn len_utf16_for_utf8_byte(byte: u8) -> usize {
232 if byte < 0b1000_0000 {
233 1
235 } else if byte < 0b1100_0000 {
236 0
238 } else if byte < 0b1111_0000 {
239 1
242 } else {
243 2
248 }
249}
250
251fn increment_offsets_for_utf8_byte(
252 utf8_byte: u8,
253 utf16_offset: &mut Utf16CodeUnits,
254 utf32_offset: &mut Utf32CodeUnits,
255) {
256 let len_utf16 = len_utf16_for_utf8_byte(utf8_byte);
257 utf16_offset.0 += len_utf16;
258 utf32_offset.0 += (len_utf16 != 0) as usize;
261}
262
263impl Utf32CodeUnits {
264 pub fn length_of(string: &str) -> Self {
265 Self(string.chars().count())
268 }
269
270 pub fn to_utf8_code_units_in(self, string: &str) -> Utf8CodeUnits {
271 let mut current_utf32_offset = Utf32CodeUnits(0);
272 for (current_utf8_offset, utf8_byte) in string.bytes().enumerate() {
273 if (utf8_byte & 0b1100_0000) == 0b1000_0000 {
274 continue;
276 }
277 if current_utf32_offset >= self {
278 return Utf8CodeUnits(current_utf8_offset);
279 }
280 current_utf32_offset.0 += 1;
281 }
282 Utf8CodeUnits(string.len())
283 }
284
285 pub fn to_utf16_code_units_in(self, string: &str) -> Utf16CodeUnits {
286 let mut current_utf32_offset = Utf32CodeUnits(0);
287 let mut current_utf16_offset = Utf16CodeUnits(0);
288 for utf8_byte in string.bytes() {
289 if current_utf32_offset >= self {
290 break;
291 }
292 increment_offsets_for_utf8_byte(
293 utf8_byte,
294 &mut current_utf16_offset,
295 &mut current_utf32_offset,
296 );
297 }
298 current_utf16_offset
299 }
300}
301
302impl Utf32CodeUnitsOrNodeOffset {
303 pub fn to_utf16_code_units_in(self, string: &str) -> Utf16CodeUnits {
304 Utf32CodeUnits(self.0).to_utf16_code_units_in(string)
305 }
306}
307
308#[cfg(test)]
309mod test {
310 use super::*;
311
312 #[test]
313 fn test_is_cjk() {
314 assert_eq!(is_cjk('〇'), true);
316 assert_eq!(is_cjk('㐀'), true);
317 assert_eq!(is_cjk('あ'), true);
318 assert_eq!(is_cjk('ア'), true);
319 assert_eq!(is_cjk('㆒'), true);
320 assert_eq!(is_cjk('ㆣ'), true);
321 assert_eq!(is_cjk('龥'), true);
322 assert_eq!(is_cjk('𰾑'), true);
323 assert_eq!(is_cjk('𰻝'), true);
324
325 assert_eq!(is_cjk('a'), false);
327 assert_eq!(is_cjk('🙂'), false);
328 assert_eq!(is_cjk('©'), false);
329 }
330
331 #[test]
332 fn test_utf16_length() {
333 assert_eq!(Utf16CodeUnits::length_of(""), Utf16CodeUnits(0));
334 assert_eq!(Utf16CodeUnits::length_of("a"), Utf16CodeUnits(1));
335 assert_eq!(Utf16CodeUnits::length_of("é"), Utf16CodeUnits(1));
336 assert_eq!(Utf16CodeUnits::length_of("字"), Utf16CodeUnits(1));
337 assert_eq!(Utf16CodeUnits::length_of("\u{1F4A9}"), Utf16CodeUnits(2));
338 assert_eq!(
339 Utf16CodeUnits::length_of("\u{1F4A9}字éa"),
340 Utf16CodeUnits(5)
341 );
342 }
343
344 #[test]
345 fn test_utf16_to_utf32() {
346 let s = "aé字\u{1F4A9}";
347 assert_eq!(
348 Utf16CodeUnits(0).to_utf32_code_units_in(s),
349 Utf32CodeUnits(0)
350 );
351 assert_eq!(
352 Utf16CodeUnits(1).to_utf32_code_units_in(s),
353 Utf32CodeUnits(1)
354 );
355 assert_eq!(
356 Utf16CodeUnits(2).to_utf32_code_units_in(s),
357 Utf32CodeUnits(2)
358 );
359 assert_eq!(
360 Utf16CodeUnits(3).to_utf32_code_units_in(s),
361 Utf32CodeUnits(3)
362 );
363
364 assert_eq!(
367 Utf16CodeUnits(4).to_utf32_code_units_in(s),
368 Utf32CodeUnits(4)
369 );
370
371 assert_eq!(
372 Utf16CodeUnits(5).to_utf32_code_units_in(s),
373 Utf32CodeUnits(4)
374 );
375
376 assert_eq!(
379 Utf16CodeUnits(6).to_utf32_code_units_in(s),
380 Utf32CodeUnits(4)
381 );
382 assert_eq!(
383 Utf16CodeUnits(7).to_utf32_code_units_in(s),
384 Utf32CodeUnits(4)
385 );
386 }
387
388 #[test]
389 fn test_utf32_to_utf16() {
390 let string = "aé字\u{1F4A9}";
391 assert_eq!(
392 Utf32CodeUnits(0).to_utf16_code_units_in(string),
393 Utf16CodeUnits(0),
394 );
395 assert_eq!(
396 Utf32CodeUnits(1).to_utf16_code_units_in(string),
397 Utf16CodeUnits(1),
398 );
399 assert_eq!(
400 Utf32CodeUnits(2).to_utf16_code_units_in(string),
401 Utf16CodeUnits(2),
402 );
403 assert_eq!(
404 Utf32CodeUnits(3).to_utf16_code_units_in(string),
405 Utf16CodeUnits(3),
406 );
407
408 assert_eq!(
409 Utf32CodeUnits(4).to_utf16_code_units_in(string),
410 Utf16CodeUnits(5),
411 );
412
413 assert_eq!(
416 Utf32CodeUnits(6).to_utf16_code_units_in(string),
417 Utf16CodeUnits(5),
418 );
419 assert_eq!(
420 Utf32CodeUnits(1000).to_utf16_code_units_in(string),
421 Utf16CodeUnits(5),
422 );
423 }
424}