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> {
56 pub start: Option<T>,
58 pub end: Option<T>,
60}
61
62impl<T: fmt::Debug> fmt::Debug for RangeAny<T> {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 match (&self.start, &self.end) {
65 (Some(start), Some(end)) => write!(f, "{start:?}..{end:?}"),
66 (Some(start), None) => write!(f, "{start:?}.."),
67 (None, Some(end)) => write!(f, "..{end:?}"),
68 (None, None) => write!(f, ".."),
69 }
70 }
71}
72
73impl<T> RangeAny<T> {
74 pub fn full() -> Self {
76 Self {
77 start: None,
78 end: None,
79 }
80 }
81
82 pub fn map<U>(self, f: impl Fn(T) -> U + Copy) -> RangeAny<U> {
84 let Self { start, end } = self;
85 RangeAny {
86 start: start.map(f),
87 end: end.map(f),
88 }
89 }
90
91 pub fn intersect(self, other: Self) -> Option<Self>
93 where
94 T: Ord,
95 {
96 let start = match (self.start, other.start) {
100 (None, None) => None,
101 (None, Some(b)) => Some(b),
102 (Some(a), None) => Some(a),
103 (Some(a), Some(b)) => Some(a.max(b)),
104 };
105 let end = match (self.end, other.end) {
106 (None, None) => None,
107 (None, Some(b)) => Some(b),
108 (Some(a), None) => Some(a),
109 (Some(a), Some(b)) => Some(a.min(b)),
110 };
111 if start
112 .as_ref()
113 .is_none_or(|start| end.as_ref().is_none_or(|end| start < end))
114 {
115 Some(RangeAny { start, end })
116 } else {
117 None
119 }
120 }
121}
122
123impl<T> From<Range<T>> for RangeAny<T> {
124 fn from(value: Range<T>) -> Self {
125 Self {
126 start: Some(value.start),
127 end: Some(value.end),
128 }
129 }
130}
131
132macro_rules! unicode_length_type {
133 ($( #[$doc:meta] )+ $type_name:ident) => {
134 $( #[$doc] )+
135 #[derive(Clone, Copy, Default, Eq, MallocSizeOf, Ord, PartialEq, PartialOrd)]
136 pub struct $type_name(pub usize);
137
138 impl $type_name {
139 pub fn zero() -> Self {
140 Self(0)
141 }
142
143 pub fn one() -> Self {
144 Self(1)
145 }
146
147 pub fn saturating_sub(self, value: Self) -> Self {
148 Self(self.0.saturating_sub(value.0))
149 }
150 }
151
152 impl From<u32> for $type_name {
153 fn from(value: u32) -> Self {
154 Self(value as usize)
155 }
156 }
157
158 impl From<isize> for $type_name {
159 fn from(value: isize) -> Self {
160 Self(value as usize)
161 }
162 }
163
164 impl Add for $type_name {
165 type Output = Self;
166 fn add(self, other: Self) -> Self {
167 Self(self.0 + other.0)
168 }
169 }
170
171 impl AddAssign for $type_name {
172 fn add_assign(&mut self, other: Self) {
173 *self = Self(self.0 + other.0)
174 }
175 }
176
177 impl Sub for $type_name {
178 type Output = Self;
179 fn sub(self, value: Self) -> Self {
180 Self(self.0 - value.0)
181 }
182 }
183
184 impl SubAssign for $type_name {
185 fn sub_assign(&mut self, other: Self) {
186 *self = Self(self.0 - other.0)
187 }
188 }
189
190 impl Sum for $type_name {
191 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
192 iter.fold(Self::zero(), |a, b| Self(a.0 + b.0))
193 }
194 }
195
196 impl fmt::Debug for $type_name {
198 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199 write!(f, concat!(stringify!($type_name), "({:?})"), self.0)
200 }
201 }
202 };
203}
204
205unicode_length_type! {
206 Utf8CodeUnits
209}
210
211unicode_length_type! {
212 Utf16CodeUnits
215}
216
217unicode_length_type! {
218 Utf32CodeUnits
222}
223
224unicode_length_type! {
225 Utf32CodeUnitsOrNodeOffset
228}
229
230impl Utf16CodeUnits {
231 pub fn length_of(string: &str) -> Self {
232 Self(string.bytes().map(len_utf16_for_utf8_byte).sum())
233
234 }
240
241 pub fn to_utf32_code_units_in(self, string: &str) -> Utf32CodeUnits {
242 let mut current_utf16_offset = Utf16CodeUnits(0);
243 let mut current_utf32_offset = Utf32CodeUnits(0);
244 for utf8_byte in string.bytes() {
245 if current_utf16_offset >= self {
246 break;
247 }
248 increment_offsets_for_utf8_byte(
249 utf8_byte,
250 &mut current_utf16_offset,
251 &mut current_utf32_offset,
252 );
253 }
254 current_utf32_offset
255 }
256}
257
258fn len_utf16_for_utf8_byte(byte: u8) -> usize {
259 if byte < 0b1000_0000 {
260 1
262 } else if byte < 0b1100_0000 {
263 0
265 } else if byte < 0b1111_0000 {
266 1
269 } else {
270 2
275 }
276}
277
278fn increment_offsets_for_utf8_byte(
279 utf8_byte: u8,
280 utf16_offset: &mut Utf16CodeUnits,
281 utf32_offset: &mut Utf32CodeUnits,
282) {
283 let len_utf16 = len_utf16_for_utf8_byte(utf8_byte);
284 utf16_offset.0 += len_utf16;
285 utf32_offset.0 += (len_utf16 != 0) as usize;
288}
289
290impl Utf32CodeUnits {
291 pub fn length_of(string: &str) -> Self {
292 Self(string.chars().count())
295 }
296
297 pub fn to_utf8_code_units_in(self, string: &str) -> Utf8CodeUnits {
298 let mut current_utf32_offset = Utf32CodeUnits(0);
299 for (current_utf8_offset, utf8_byte) in string.bytes().enumerate() {
300 if (utf8_byte & 0b1100_0000) == 0b1000_0000 {
301 continue;
303 }
304 if current_utf32_offset >= self {
305 return Utf8CodeUnits(current_utf8_offset);
306 }
307 current_utf32_offset.0 += 1;
308 }
309 Utf8CodeUnits(string.len())
310 }
311
312 pub fn to_utf16_code_units_in(self, string: &str) -> Utf16CodeUnits {
313 let mut current_utf32_offset = Utf32CodeUnits(0);
314 let mut current_utf16_offset = Utf16CodeUnits(0);
315 for utf8_byte in string.bytes() {
316 if current_utf32_offset >= self {
317 break;
318 }
319 increment_offsets_for_utf8_byte(
320 utf8_byte,
321 &mut current_utf16_offset,
322 &mut current_utf32_offset,
323 );
324 }
325 current_utf16_offset
326 }
327}
328
329impl Utf32CodeUnitsOrNodeOffset {
330 pub fn to_utf16_code_units_in(self, string: &str) -> Utf16CodeUnits {
331 Utf32CodeUnits(self.0).to_utf16_code_units_in(string)
332 }
333}
334
335#[cfg(test)]
336mod test {
337 use super::*;
338
339 #[test]
340 fn test_is_cjk() {
341 assert_eq!(is_cjk('〇'), true);
343 assert_eq!(is_cjk('㐀'), true);
344 assert_eq!(is_cjk('あ'), true);
345 assert_eq!(is_cjk('ア'), true);
346 assert_eq!(is_cjk('㆒'), true);
347 assert_eq!(is_cjk('ㆣ'), true);
348 assert_eq!(is_cjk('龥'), true);
349 assert_eq!(is_cjk('𰾑'), true);
350 assert_eq!(is_cjk('𰻝'), true);
351
352 assert_eq!(is_cjk('a'), false);
354 assert_eq!(is_cjk('🙂'), false);
355 assert_eq!(is_cjk('©'), false);
356 }
357
358 #[test]
359 fn test_utf16_length() {
360 assert_eq!(Utf16CodeUnits::length_of(""), Utf16CodeUnits(0));
361 assert_eq!(Utf16CodeUnits::length_of("a"), Utf16CodeUnits(1));
362 assert_eq!(Utf16CodeUnits::length_of("é"), Utf16CodeUnits(1));
363 assert_eq!(Utf16CodeUnits::length_of("字"), Utf16CodeUnits(1));
364 assert_eq!(Utf16CodeUnits::length_of("\u{1F4A9}"), Utf16CodeUnits(2));
365 assert_eq!(
366 Utf16CodeUnits::length_of("\u{1F4A9}字éa"),
367 Utf16CodeUnits(5)
368 );
369 }
370
371 #[test]
372 fn test_utf16_to_utf32() {
373 let s = "aé字\u{1F4A9}";
374 assert_eq!(
375 Utf16CodeUnits(0).to_utf32_code_units_in(s),
376 Utf32CodeUnits(0)
377 );
378 assert_eq!(
379 Utf16CodeUnits(1).to_utf32_code_units_in(s),
380 Utf32CodeUnits(1)
381 );
382 assert_eq!(
383 Utf16CodeUnits(2).to_utf32_code_units_in(s),
384 Utf32CodeUnits(2)
385 );
386 assert_eq!(
387 Utf16CodeUnits(3).to_utf32_code_units_in(s),
388 Utf32CodeUnits(3)
389 );
390
391 assert_eq!(
394 Utf16CodeUnits(4).to_utf32_code_units_in(s),
395 Utf32CodeUnits(4)
396 );
397
398 assert_eq!(
399 Utf16CodeUnits(5).to_utf32_code_units_in(s),
400 Utf32CodeUnits(4)
401 );
402
403 assert_eq!(
406 Utf16CodeUnits(6).to_utf32_code_units_in(s),
407 Utf32CodeUnits(4)
408 );
409 assert_eq!(
410 Utf16CodeUnits(7).to_utf32_code_units_in(s),
411 Utf32CodeUnits(4)
412 );
413 }
414
415 #[test]
416 fn test_utf32_to_utf16() {
417 let string = "aé字\u{1F4A9}";
418 assert_eq!(
419 Utf32CodeUnits(0).to_utf16_code_units_in(string),
420 Utf16CodeUnits(0),
421 );
422 assert_eq!(
423 Utf32CodeUnits(1).to_utf16_code_units_in(string),
424 Utf16CodeUnits(1),
425 );
426 assert_eq!(
427 Utf32CodeUnits(2).to_utf16_code_units_in(string),
428 Utf16CodeUnits(2),
429 );
430 assert_eq!(
431 Utf32CodeUnits(3).to_utf16_code_units_in(string),
432 Utf16CodeUnits(3),
433 );
434
435 assert_eq!(
436 Utf32CodeUnits(4).to_utf16_code_units_in(string),
437 Utf16CodeUnits(5),
438 );
439
440 assert_eq!(
443 Utf32CodeUnits(6).to_utf16_code_units_in(string),
444 Utf16CodeUnits(5),
445 );
446 assert_eq!(
447 Utf32CodeUnits(1000).to_utf16_code_units_in(string),
448 Utf16CodeUnits(5),
449 );
450 }
451}