1use std::fmt;
6use std::iter::Sum;
7use std::ops::{Add, AddAssign, Range, Sub, SubAssign};
8
9use malloc_size_of_derive::MallocSizeOf;
10
11pub use crate::unicode_block::{UnicodeBlock, UnicodeBlockMethod};
12
13pub fn is_bidi_control(c: char) -> bool {
14 matches!(c, '\u{202A}'..='\u{202E}' | '\u{2066}'..='\u{2069}' | '\u{200E}' | '\u{200F}' | '\u{061C}')
15}
16
17pub fn unicode_plane(codepoint: char) -> u32 {
18 (codepoint as u32) >> 16
19}
20
21pub fn is_cjk(codepoint: char) -> bool {
22 if let Some(
23 UnicodeBlock::CJKRadicalsSupplement |
24 UnicodeBlock::KangxiRadicals |
25 UnicodeBlock::IdeographicDescriptionCharacters |
26 UnicodeBlock::CJKSymbolsandPunctuation |
27 UnicodeBlock::Hiragana |
28 UnicodeBlock::Katakana |
29 UnicodeBlock::Bopomofo |
30 UnicodeBlock::HangulCompatibilityJamo |
31 UnicodeBlock::Kanbun |
32 UnicodeBlock::BopomofoExtended |
33 UnicodeBlock::CJKStrokes |
34 UnicodeBlock::KatakanaPhoneticExtensions |
35 UnicodeBlock::EnclosedCJKLettersandMonths |
36 UnicodeBlock::CJKCompatibility |
37 UnicodeBlock::CJKUnifiedIdeographsExtensionA |
38 UnicodeBlock::YijingHexagramSymbols |
39 UnicodeBlock::CJKUnifiedIdeographs |
40 UnicodeBlock::CJKCompatibilityIdeographs |
41 UnicodeBlock::CJKCompatibilityForms |
42 UnicodeBlock::HalfwidthandFullwidthForms,
43 ) = codepoint.block()
44 {
45 return true;
46 }
47
48 unicode_plane(codepoint) == 2 || unicode_plane(codepoint) == 3
51}
52
53#[derive(Clone, Copy, Eq, PartialEq, MallocSizeOf)]
55pub struct RangeAny<T>(RangeAnyInner<T>);
56
57#[derive(Clone, Copy, Eq, PartialEq, MallocSizeOf)]
58enum RangeAnyInner<T> {
59 Range { start: T, end: T },
60 RangeFrom { start: T },
61 RangeTo { end: T },
62 RangeFull,
63}
64
65size_of_test!(RangeAny<u32>, 12);
66size_of_test!(Option<RangeAny<u32>>, 12);
67
68impl<T: fmt::Debug> fmt::Debug for RangeAny<T> {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 match &self.0 {
71 RangeAnyInner::Range { start, end } => write!(f, "{start:?}..{end:?}"),
72 RangeAnyInner::RangeFrom { start } => write!(f, "{start:?}.."),
73 RangeAnyInner::RangeTo { end, .. } => write!(f, "..{end:?}"),
74 RangeAnyInner::RangeFull => write!(f, ".."),
75 }
76 }
77}
78
79impl<T> RangeAny<T> {
80 pub fn new(start: Option<T>, end: Option<T>) -> Self {
81 Self(match (start, end) {
82 (Some(start), Some(end)) => RangeAnyInner::Range { start, end },
83 (Some(start), None) => RangeAnyInner::RangeFrom { start },
84 (None, Some(end)) => RangeAnyInner::RangeTo { end },
85 (None, None) => RangeAnyInner::RangeFull,
86 })
87 }
88
89 pub fn from_start_to(end: T) -> Self {
91 Self(RangeAnyInner::RangeTo { end })
92 }
93
94 pub fn full() -> Self {
96 Self(RangeAnyInner::RangeFull)
97 }
98
99 pub fn start(&self) -> Option<T>
103 where
104 T: Copy,
105 {
106 match self.0 {
107 RangeAnyInner::Range { start, .. } | RangeAnyInner::RangeFrom { start } => Some(start),
108 RangeAnyInner::RangeTo { .. } | RangeAnyInner::RangeFull => None,
109 }
110 }
111
112 pub fn end(&self) -> Option<T>
113 where
114 T: Copy,
115 {
116 match self.0 {
117 RangeAnyInner::Range { end, .. } | RangeAnyInner::RangeTo { end, .. } => Some(end),
118 RangeAnyInner::RangeFrom { .. } | RangeAnyInner::RangeFull => None,
119 }
120 }
121
122 pub fn map<U>(&self, f: impl Fn(T) -> U + Copy) -> RangeAny<U>
124 where
125 T: Copy,
126 {
127 RangeAny::new(self.start().map(f), self.end().map(f))
128 }
129
130 pub fn intersect(&self, other: Self) -> Option<Self>
132 where
133 T: Copy + Ord,
134 {
135 let start = match (self.start(), other.start()) {
139 (None, None) => None,
140 (None, Some(b)) => Some(b),
141 (Some(a), None) => Some(a),
142 (Some(a), Some(b)) => Some(a.max(b)),
143 };
144 let end = match (self.end(), other.end()) {
145 (None, None) => None,
146 (None, Some(b)) => Some(b),
147 (Some(a), None) => Some(a),
148 (Some(a), Some(b)) => Some(a.min(b)),
149 };
150 if start
151 .as_ref()
152 .is_none_or(|start| end.as_ref().is_none_or(|end| start < end))
153 {
154 Some(Self::new(start, end))
155 } else {
156 None
158 }
159 }
160}
161
162impl<T> From<Range<T>> for RangeAny<T> {
163 fn from(value: Range<T>) -> Self {
164 Self::new(Some(value.start), Some(value.end))
165 }
166}
167
168pub struct AssumeUnder4GB;
174
175fn infallible_u32_to_usize(value: u32) -> usize {
176 const _: () = assert!(usize::BITS >= u32::BITS, "16-bit targets are not supported");
177 value as usize
178}
179
180macro_rules! unicode_length_type {
181 ($( #[$doc:meta] )+ $type_name:ident) => {
182 $( #[$doc] )+
183 #[derive(Clone, Copy, Default, Eq, MallocSizeOf, Ord, PartialEq, PartialOrd)]
184 pub struct $type_name(pub u32);
185
186 impl $type_name {
187 const ZERO: Self = Self(0);
188
189 #[inline]
190 pub fn saturating_sub(self, value: Self) -> Self {
191 Self(self.0.saturating_sub(value.0))
192 }
193
194 #[inline]
195 pub fn to_usize_range(range: &Range<Self>) -> Range<usize> {
196 usize::from(range.start)..usize::from(range.end)
197 }
198 }
199
200 impl From<u32> for $type_name {
201 #[inline]
202 fn from(value: u32) -> Self {
203 Self(value)
204 }
205 }
206
207 impl From<$type_name> for usize {
208 #[inline]
209 fn from(value: $type_name) -> usize {
210 infallible_u32_to_usize(value.0)
211 }
212 }
213
214 impl Add for $type_name {
215 type Output = Self;
216
217 #[inline]
218 fn add(self, other: Self) -> Self {
219 Self(self.0 + other.0)
220 }
221 }
222
223 impl AddAssign for $type_name {
224 #[inline]
225 fn add_assign(&mut self, other: Self) {
226 *self = Self(self.0 + other.0)
227 }
228 }
229
230 impl Sub for $type_name {
231 type Output = Self;
232
233 #[inline]
234 fn sub(self, value: Self) -> Self {
235 Self(self.0 - value.0)
236 }
237 }
238
239 impl SubAssign for $type_name {
240 #[inline]
241 fn sub_assign(&mut self, other: Self) {
242 *self = Self(self.0 - other.0)
243 }
244 }
245
246 impl Sum for $type_name {
247 #[inline]
248 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
249 iter.fold(Self::ZERO, |a, b| Self(a.0 + b.0))
250 }
251 }
252
253 impl fmt::Debug for $type_name {
255 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256 write!(f, concat!(stringify!($type_name), "({:?})"), self.0)
257 }
258 }
259 };
260}
261
262unicode_length_type! {
263 Utf8CodeUnits
266}
267
268unicode_length_type! {
269 Utf16CodeUnits
272}
273
274unicode_length_type! {
275 Utf32CodeUnits
279}
280
281unicode_length_type! {
282 Utf32CodeUnitsOrNodeOffset
285}
286
287impl Utf8CodeUnits {
288 pub fn length_of(_: AssumeUnder4GB, string: &str) -> Self {
290 Self(string.len() as u32)
291 }
292
293 pub fn length_of_char(char: char) -> Self {
294 Self(char.len_utf8() as u32)
296 }
297}
298
299impl Utf16CodeUnits {
300 pub fn length_of(_: AssumeUnder4GB, string: &str) -> Self {
302 Self(string.bytes().map(len_utf16_for_utf8_byte).sum())
303
304 }
310
311 pub fn length_of_char(char: char) -> Self {
312 Self(char.len_utf16() as u32)
314 }
315
316 pub fn to_utf8_code_units_in(self, _: AssumeUnder4GB, string: &str) -> Utf8CodeUnits {
318 self.to_utf8_code_units_in_iter(AssumeUnder4GB, std::iter::once(string))
319 }
320
321 pub fn to_utf8_code_units_in_iter<S>(
323 self,
324 _: AssumeUnder4GB,
325 iter: impl IntoIterator<Item = S>,
326 ) -> Utf8CodeUnits
327 where
328 S: AsRef<str>,
329 {
330 let mut current_utf16_offset = Utf16CodeUnits(0);
331 let mut current_utf8_offset = Utf8CodeUnits(0);
332 for string in iter {
333 for utf8_byte in string.as_ref().bytes() {
334 current_utf16_offset.0 += len_utf16_for_utf8_byte(utf8_byte);
335 if current_utf16_offset > self {
336 return current_utf8_offset;
337 }
338 current_utf8_offset.0 += len_utf8_for_utf8_byte(utf8_byte);
339 }
340 }
341 current_utf8_offset
342 }
343
344 pub fn to_utf32_code_units_in(self, string: &str) -> Utf32CodeUnits {
349 let mut current_utf16_offset = Utf16CodeUnits(0);
350 let mut current_utf32_offset = Utf32CodeUnits(0);
351 for utf8_byte in string.bytes() {
352 let len_utf16 = len_utf16_for_utf8_byte(utf8_byte);
353 current_utf16_offset.0 += len_utf16;
354 if current_utf16_offset > self {
355 break;
356 }
357 current_utf32_offset.0 += len_utf16_to_len_utf32_for_utf8_byte(len_utf16);
358 }
359 current_utf32_offset
360 }
361}
362
363fn len_utf16_for_utf8_byte(byte: u8) -> u32 {
364 if byte < 0b1000_0000 {
365 1
367 } else if byte < 0b1100_0000 {
368 0
370 } else if byte < 0b1111_0000 {
371 1
374 } else {
375 2
380 }
381}
382
383fn len_utf8_for_utf8_byte(byte: u8) -> u32 {
384 if byte < 0b1000_0000 {
385 1
387 } else if byte < 0b1100_0000 {
388 0
390 } else if byte < 0b1110_0000 {
391 2
393 } else if byte < 0b1111_0000 {
394 3
396 } else {
397 4
399 }
400}
401
402fn len_utf16_to_len_utf32_for_utf8_byte(len_utf16: u32) -> u32 {
403 if len_utf16 != 0 {
404 1
406 } else {
407 0
409 }
410}
411
412impl Utf32CodeUnits {
413 pub fn length_of(_: AssumeUnder4GB, string: &str) -> Self {
415 Self(string.chars().count() as u32)
418 }
419
420 pub fn to_utf8_code_units_in(self, _: AssumeUnder4GB, string: &str) -> Utf8CodeUnits {
422 let mut current_utf32_offset = Utf32CodeUnits(0);
423 for (current_utf8_offset, utf8_byte) in string.bytes().enumerate() {
424 if (utf8_byte & 0b1100_0000) == 0b1000_0000 {
425 continue;
427 }
428 if current_utf32_offset >= self {
429 return Utf8CodeUnits(current_utf8_offset as u32);
430 }
431 current_utf32_offset.0 += 1;
432 }
433 Utf8CodeUnits(string.len() as u32)
434 }
435
436 pub fn to_utf16_code_units_in(self, _: AssumeUnder4GB, string: &str) -> Utf16CodeUnits {
438 let mut current_utf32_offset = Utf32CodeUnits(0);
439 let mut current_utf16_offset = Utf16CodeUnits(0);
440 for utf8_byte in string.bytes() {
441 if current_utf32_offset >= self {
442 break;
443 }
444 let len_utf16 = len_utf16_for_utf8_byte(utf8_byte);
445 current_utf16_offset.0 += len_utf16;
446 current_utf32_offset.0 += len_utf16_to_len_utf32_for_utf8_byte(len_utf16);
447 }
448 current_utf16_offset
449 }
450}
451
452impl Utf32CodeUnitsOrNodeOffset {
453 pub fn to_utf16_code_units_in(self, _: AssumeUnder4GB, string: &str) -> Utf16CodeUnits {
455 Utf32CodeUnits(self.0).to_utf16_code_units_in(AssumeUnder4GB, string)
456 }
457}
458
459#[cfg(test)]
460mod test {
461 use super::*;
462
463 #[test]
464 fn test_is_cjk() {
465 assert_eq!(is_cjk('〇'), true);
467 assert_eq!(is_cjk('㐀'), true);
468 assert_eq!(is_cjk('あ'), true);
469 assert_eq!(is_cjk('ア'), true);
470 assert_eq!(is_cjk('㆒'), true);
471 assert_eq!(is_cjk('ㆣ'), true);
472 assert_eq!(is_cjk('龥'), true);
473 assert_eq!(is_cjk('𰾑'), true);
474 assert_eq!(is_cjk('𰻝'), true);
475
476 assert_eq!(is_cjk('a'), false);
478 assert_eq!(is_cjk('🙂'), false);
479 assert_eq!(is_cjk('©'), false);
480 }
481
482 #[test]
483 fn test_utf16_length() {
484 assert_eq!(
485 Utf16CodeUnits::length_of(AssumeUnder4GB, ""),
486 Utf16CodeUnits(0)
487 );
488 assert_eq!(
489 Utf16CodeUnits::length_of(AssumeUnder4GB, "a"),
490 Utf16CodeUnits(1)
491 );
492 assert_eq!(
493 Utf16CodeUnits::length_of(AssumeUnder4GB, "é"),
494 Utf16CodeUnits(1)
495 );
496 assert_eq!(
497 Utf16CodeUnits::length_of(AssumeUnder4GB, "字"),
498 Utf16CodeUnits(1)
499 );
500 assert_eq!(
501 Utf16CodeUnits::length_of(AssumeUnder4GB, "\u{1F4A9}"),
502 Utf16CodeUnits(2)
503 );
504 assert_eq!(
505 Utf16CodeUnits::length_of(AssumeUnder4GB, "\u{1F4A9}字éa"),
506 Utf16CodeUnits(5)
507 );
508 }
509
510 #[test]
511 fn test_utf16_to_utf32() {
512 let s = "aé字\u{1F4A9}";
513 assert_eq!(
514 Utf16CodeUnits(0).to_utf32_code_units_in(s),
515 Utf32CodeUnits(0)
516 );
517 assert_eq!(
518 Utf16CodeUnits(1).to_utf32_code_units_in(s),
519 Utf32CodeUnits(1)
520 );
521 assert_eq!(
522 Utf16CodeUnits(2).to_utf32_code_units_in(s),
523 Utf32CodeUnits(2)
524 );
525 assert_eq!(
526 Utf16CodeUnits(3).to_utf32_code_units_in(s),
527 Utf32CodeUnits(3)
528 );
529
530 assert_eq!(
533 Utf16CodeUnits(4).to_utf32_code_units_in(s),
534 Utf32CodeUnits(3)
535 );
536
537 assert_eq!(
538 Utf16CodeUnits(5).to_utf32_code_units_in(s),
539 Utf32CodeUnits(4)
540 );
541
542 assert_eq!(
545 Utf16CodeUnits(6).to_utf32_code_units_in(s),
546 Utf32CodeUnits(4)
547 );
548 assert_eq!(
549 Utf16CodeUnits(7).to_utf32_code_units_in(s),
550 Utf32CodeUnits(4)
551 );
552 }
553
554 #[test]
555 fn test_utf32_to_utf16() {
556 let string = "aé字\u{1F4A9}";
557 assert_eq!(
558 Utf32CodeUnits(0).to_utf16_code_units_in(AssumeUnder4GB, string),
559 Utf16CodeUnits(0),
560 );
561 assert_eq!(
562 Utf32CodeUnits(1).to_utf16_code_units_in(AssumeUnder4GB, string),
563 Utf16CodeUnits(1),
564 );
565 assert_eq!(
566 Utf32CodeUnits(2).to_utf16_code_units_in(AssumeUnder4GB, string),
567 Utf16CodeUnits(2),
568 );
569 assert_eq!(
570 Utf32CodeUnits(3).to_utf16_code_units_in(AssumeUnder4GB, string),
571 Utf16CodeUnits(3),
572 );
573
574 assert_eq!(
575 Utf32CodeUnits(4).to_utf16_code_units_in(AssumeUnder4GB, string),
576 Utf16CodeUnits(5),
577 );
578
579 assert_eq!(
582 Utf32CodeUnits(6).to_utf16_code_units_in(AssumeUnder4GB, string),
583 Utf16CodeUnits(5),
584 );
585 assert_eq!(
586 Utf32CodeUnits(1000).to_utf16_code_units_in(AssumeUnder4GB, string),
587 Utf16CodeUnits(5),
588 );
589 }
590}