Skip to main content

core/char/
mod.rs

1//! Utilities for the `char` primitive type.
2//!
3//! *[See also the `char` primitive type](primitive@char).*
4//!
5//! The `char` type represents a single character. More specifically, since
6//! 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode
7//! scalar value]', which is similar to, but not the same as, a '[Unicode code
8//! point]'.
9//!
10//! [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value
11//! [Unicode code point]: https://www.unicode.org/glossary/#code_point
12//!
13//! This module exists for technical reasons, the primary documentation for
14//! `char` is directly on [the `char` primitive type][char] itself.
15//!
16//! This module is the home of the iterator implementations for the iterators
17//! implemented on `char`, as well as some useful constants and conversion
18//! functions that convert various types to `char`.
19
20#![allow(non_snake_case)]
21#![stable(feature = "rust1", since = "1.0.0")]
22
23mod convert;
24mod decode;
25mod methods;
26
27// stable re-exports
28#[rustfmt::skip]
29#[stable(feature = "try_from", since = "1.34.0")]
30pub use self::convert::CharTryFromError;
31#[stable(feature = "char_from_str", since = "1.20.0")]
32pub use self::convert::ParseCharError;
33#[stable(feature = "decode_utf16", since = "1.9.0")]
34pub use self::decode::{DecodeUtf16, DecodeUtf16Error};
35
36// perma-unstable re-exports
37#[rustfmt::skip]
38#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
39pub use self::methods::encode_utf16_raw; // perma-unstable
40#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
41pub use self::methods::{encode_utf8_raw, encode_utf8_raw_unchecked}; // perma-unstable
42
43#[rustfmt::skip]
44use crate::ascii;
45pub(crate) use self::methods::EscapeDebugExtArgs;
46use crate::error::Error;
47use crate::escape::{AlwaysEscaped, EscapeIterInner, MaybeEscaped};
48use crate::fmt::{self, Write};
49use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
50use crate::num::NonZero;
51
52// UTF-8 ranges and tags for encoding characters
53const TAG_CONT: u8 = 0b1000_0000;
54const TAG_TWO_B: u8 = 0b1100_0000;
55const TAG_THREE_B: u8 = 0b1110_0000;
56const TAG_FOUR_B: u8 = 0b1111_0000;
57const MAX_ONE_B: u32 = 0x80;
58const MAX_TWO_B: u32 = 0x800;
59const MAX_THREE_B: u32 = 0x10000;
60
61/*
62    Lu  Uppercase_Letter        an uppercase letter
63    Ll  Lowercase_Letter        a lowercase letter
64    Lt  Titlecase_Letter        a digraphic character, with first part uppercase
65    Lm  Modifier_Letter         a modifier letter
66    Lo  Other_Letter            other letters, including syllables and ideographs
67    Mn  Nonspacing_Mark         a nonspacing combining mark (zero advance width)
68    Mc  Spacing_Mark            a spacing combining mark (positive advance width)
69    Me  Enclosing_Mark          an enclosing combining mark
70    Nd  Decimal_Number          a decimal digit
71    Nl  Letter_Number           a letterlike numeric character
72    No  Other_Number            a numeric character of other type
73    Pc  Connector_Punctuation   a connecting punctuation mark, like a tie
74    Pd  Dash_Punctuation        a dash or hyphen punctuation mark
75    Ps  Open_Punctuation        an opening punctuation mark (of a pair)
76    Pe  Close_Punctuation       a closing punctuation mark (of a pair)
77    Pi  Initial_Punctuation     an initial quotation mark
78    Pf  Final_Punctuation       a final quotation mark
79    Po  Other_Punctuation       a punctuation mark of other type
80    Sm  Math_Symbol             a symbol of primarily mathematical use
81    Sc  Currency_Symbol         a currency sign
82    Sk  Modifier_Symbol         a non-letterlike modifier symbol
83    So  Other_Symbol            a symbol of other type
84    Zs  Space_Separator         a space character (of various non-zero widths)
85    Zl  Line_Separator          U+2028 LINE SEPARATOR only
86    Zp  Paragraph_Separator     U+2029 PARAGRAPH SEPARATOR only
87    Cc  Control                 a C0 or C1 control code
88    Cf  Format                  a format control character
89    Cs  Surrogate               a surrogate code point
90    Co  Private_Use             a private-use character
91    Cn  Unassigned              a reserved unassigned code point or a noncharacter
92*/
93
94/// The highest valid code point a `char` can have, `'\u{10FFFF}'`. Use [`char::MAX`] instead.
95#[stable(feature = "rust1", since = "1.0.0")]
96#[deprecated(since = "TBD", note = "replaced by the `MAX` associated constant on `char`")]
97pub const MAX: char = char::MAX;
98
99/// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a
100/// decoding error. Use [`char::REPLACEMENT_CHARACTER`] instead.
101#[stable(feature = "decode_utf16", since = "1.9.0")]
102#[deprecated(
103    since = "TBD",
104    note = "replaced by the `REPLACEMENT_CHARACTER` associated constant on `char`"
105)]
106pub const REPLACEMENT_CHARACTER: char = char::REPLACEMENT_CHARACTER;
107
108/// The version of [Unicode](https://www.unicode.org/) that the Unicode parts of
109/// `char` and `str` methods are based on. Use [`char::UNICODE_VERSION`] instead.
110#[stable(feature = "unicode_version", since = "1.45.0")]
111#[deprecated(
112    since = "TBD",
113    note = "replaced by the `UNICODE_VERSION` associated constant on `char`"
114)]
115pub const UNICODE_VERSION: (u8, u8, u8) = char::UNICODE_VERSION;
116
117/// Creates an iterator over the UTF-16 encoded code points in `iter`, returning
118/// unpaired surrogates as `Err`s. Use [`char::decode_utf16`] instead.
119#[stable(feature = "decode_utf16", since = "1.9.0")]
120#[deprecated(since = "TBD", note = "replaced by the `decode_utf16` method on `char`")]
121#[inline]
122pub fn decode_utf16<I: IntoIterator<Item = u16>>(iter: I) -> DecodeUtf16<I::IntoIter> {
123    self::decode::decode_utf16(iter)
124}
125
126/// Converts a `u32` to a `char`. Use [`char::from_u32`] instead.
127#[stable(feature = "rust1", since = "1.0.0")]
128#[rustc_const_stable(feature = "const_char_convert", since = "1.67.0")]
129#[deprecated(since = "TBD", note = "replaced by the `from_u32` method on `char`")]
130#[must_use]
131#[inline]
132pub const fn from_u32(i: u32) -> Option<char> {
133    self::convert::from_u32(i)
134}
135
136/// Converts a `u32` to a `char`, ignoring validity. Use [`char::from_u32_unchecked`]
137/// instead.
138#[stable(feature = "char_from_unchecked", since = "1.5.0")]
139#[rustc_const_stable(feature = "const_char_from_u32_unchecked", since = "1.81.0")]
140#[deprecated(since = "TBD", note = "replaced by the `from_u32_unchecked` method on `char`")]
141#[must_use]
142#[inline]
143pub const unsafe fn from_u32_unchecked(i: u32) -> char {
144    // SAFETY: the safety contract must be upheld by the caller.
145    unsafe { self::convert::from_u32_unchecked(i) }
146}
147
148/// Converts a digit in the given radix to a `char`. Use [`char::from_digit`] instead.
149#[stable(feature = "rust1", since = "1.0.0")]
150#[rustc_const_stable(feature = "const_char_convert", since = "1.67.0")]
151#[deprecated(since = "TBD", note = "replaced by the `from_digit` method on `char`")]
152#[must_use]
153#[inline]
154pub const fn from_digit(num: u32, radix: u32) -> Option<char> {
155    self::convert::from_digit(num, radix)
156}
157
158/// Returns an iterator that yields the hexadecimal Unicode escape of a
159/// character, as `char`s.
160///
161/// This `struct` is created by the [`escape_unicode`] method on [`char`]. See
162/// its documentation for more.
163///
164/// [`escape_unicode`]: char::escape_unicode
165#[derive(Clone, Debug)]
166#[stable(feature = "rust1", since = "1.0.0")]
167pub struct EscapeUnicode(EscapeIterInner<10, AlwaysEscaped>);
168
169impl EscapeUnicode {
170    #[inline]
171    #[ferrocene::prevalidated]
172    const fn new(c: char) -> Self {
173        Self(EscapeIterInner::unicode(c))
174    }
175}
176
177#[stable(feature = "rust1", since = "1.0.0")]
178impl Iterator for EscapeUnicode {
179    type Item = char;
180
181    #[inline]
182    fn next(&mut self) -> Option<char> {
183        self.0.next().map(char::from)
184    }
185
186    #[inline]
187    fn size_hint(&self) -> (usize, Option<usize>) {
188        let n = self.0.len();
189        (n, Some(n))
190    }
191
192    #[inline]
193    fn count(self) -> usize {
194        self.0.len()
195    }
196
197    #[inline]
198    fn last(mut self) -> Option<char> {
199        self.0.next_back().map(char::from)
200    }
201
202    #[inline]
203    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
204        self.0.advance_by(n)
205    }
206}
207
208#[stable(feature = "exact_size_escape", since = "1.11.0")]
209impl ExactSizeIterator for EscapeUnicode {
210    #[inline]
211    fn len(&self) -> usize {
212        self.0.len()
213    }
214}
215
216#[stable(feature = "fused", since = "1.26.0")]
217impl FusedIterator for EscapeUnicode {}
218
219#[stable(feature = "char_struct_display", since = "1.16.0")]
220impl fmt::Display for EscapeUnicode {
221    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222        fmt::Display::fmt(&self.0, f)
223    }
224}
225
226/// An iterator that yields the literal escape code of a `char`.
227///
228/// This `struct` is created by the [`escape_default`] method on [`char`]. See
229/// its documentation for more.
230///
231/// [`escape_default`]: char::escape_default
232#[derive(Clone, Debug)]
233#[stable(feature = "rust1", since = "1.0.0")]
234pub struct EscapeDefault(EscapeIterInner<10, AlwaysEscaped>);
235
236impl EscapeDefault {
237    #[inline]
238    #[ferrocene::prevalidated]
239    const fn printable(c: ascii::Char) -> Self {
240        Self(EscapeIterInner::ascii(c.to_u8()))
241    }
242
243    #[inline]
244    #[ferrocene::prevalidated]
245    const fn backslash(c: ascii::Char) -> Self {
246        Self(EscapeIterInner::backslash(c))
247    }
248
249    #[inline]
250    #[ferrocene::prevalidated]
251    const fn unicode(c: char) -> Self {
252        Self(EscapeIterInner::unicode(c))
253    }
254}
255
256#[stable(feature = "rust1", since = "1.0.0")]
257impl Iterator for EscapeDefault {
258    type Item = char;
259
260    #[inline]
261    fn next(&mut self) -> Option<char> {
262        self.0.next().map(char::from)
263    }
264
265    #[inline]
266    fn size_hint(&self) -> (usize, Option<usize>) {
267        let n = self.0.len();
268        (n, Some(n))
269    }
270
271    #[inline]
272    fn count(self) -> usize {
273        self.0.len()
274    }
275
276    #[inline]
277    fn last(mut self) -> Option<char> {
278        self.0.next_back().map(char::from)
279    }
280
281    #[inline]
282    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
283        self.0.advance_by(n)
284    }
285}
286
287#[stable(feature = "exact_size_escape", since = "1.11.0")]
288impl ExactSizeIterator for EscapeDefault {
289    #[inline]
290    fn len(&self) -> usize {
291        self.0.len()
292    }
293}
294
295#[stable(feature = "fused", since = "1.26.0")]
296impl FusedIterator for EscapeDefault {}
297
298#[stable(feature = "char_struct_display", since = "1.16.0")]
299impl fmt::Display for EscapeDefault {
300    #[inline]
301    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
302        fmt::Display::fmt(&self.0, f)
303    }
304}
305
306/// An iterator that yields the literal escape code of a `char`.
307///
308/// This `struct` is created by the [`escape_debug`] method on [`char`]. See its
309/// documentation for more.
310///
311/// [`escape_debug`]: char::escape_debug
312#[stable(feature = "char_escape_debug", since = "1.20.0")]
313#[derive(Clone, Debug)]
314#[ferrocene::prevalidated]
315pub struct EscapeDebug(EscapeIterInner<10, MaybeEscaped>);
316
317impl EscapeDebug {
318    #[inline]
319    #[ferrocene::prevalidated]
320    const fn printable(chr: char) -> Self {
321        Self(EscapeIterInner::printable(chr))
322    }
323
324    #[inline]
325    #[ferrocene::prevalidated]
326    const fn backslash(c: ascii::Char) -> Self {
327        Self(EscapeIterInner::backslash(c))
328    }
329
330    #[inline]
331    #[ferrocene::prevalidated]
332    const fn unicode(c: char) -> Self {
333        Self(EscapeIterInner::unicode(c))
334    }
335}
336
337#[stable(feature = "char_escape_debug", since = "1.20.0")]
338impl Iterator for EscapeDebug {
339    type Item = char;
340
341    #[inline]
342    #[ferrocene::prevalidated]
343    fn next(&mut self) -> Option<char> {
344        self.0.next()
345    }
346
347    #[inline]
348    #[ferrocene::prevalidated]
349    fn size_hint(&self) -> (usize, Option<usize>) {
350        let n = self.len();
351        (n, Some(n))
352    }
353
354    #[inline]
355    #[ferrocene::prevalidated]
356    fn count(self) -> usize {
357        self.len()
358    }
359}
360
361#[stable(feature = "char_escape_debug", since = "1.20.0")]
362impl ExactSizeIterator for EscapeDebug {
363    #[ferrocene::prevalidated]
364    fn len(&self) -> usize {
365        self.0.len()
366    }
367}
368
369#[stable(feature = "fused", since = "1.26.0")]
370impl FusedIterator for EscapeDebug {}
371
372#[stable(feature = "char_escape_debug", since = "1.20.0")]
373impl fmt::Display for EscapeDebug {
374    #[inline]
375    #[ferrocene::prevalidated]
376    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
377        fmt::Display::fmt(&self.0, f)
378    }
379}
380
381macro_rules! casemappingiter_impls {
382    (
383        #[$stab:meta]
384        #[$dendstab:meta]
385        #[$fusedstab:meta]
386        #[$exactstab:meta]
387        #[$displaystab:meta]
388        $(#[$attr:meta])*
389        $ITER_NAME:ident
390    ) => {
391        $(#[$attr])*
392        #[$stab]
393        #[derive(Debug, Clone)]
394        pub struct $ITER_NAME(CaseMappingIter);
395
396        #[$stab]
397        impl Iterator for $ITER_NAME {
398            type Item = char;
399            fn next(&mut self) -> Option<char> {
400                self.0.next()
401            }
402
403            fn size_hint(&self) -> (usize, Option<usize>) {
404                self.0.size_hint()
405            }
406
407            fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
408            where
409                Fold: FnMut(Acc, Self::Item) -> Acc,
410            {
411                self.0.fold(init, fold)
412            }
413
414            fn count(self) -> usize {
415                self.0.count()
416            }
417
418            fn last(self) -> Option<Self::Item> {
419                self.0.last()
420            }
421
422            fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
423                self.0.advance_by(n)
424            }
425
426            unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
427                // SAFETY: just forwarding requirements to caller
428                unsafe { self.0.__iterator_get_unchecked(idx) }
429            }
430        }
431
432        #[$dendstab]
433        impl DoubleEndedIterator for $ITER_NAME {
434            fn next_back(&mut self) -> Option<char> {
435                self.0.next_back()
436            }
437
438            fn rfold<Acc, Fold>(self, init: Acc, rfold: Fold) -> Acc
439            where
440                Fold: FnMut(Acc, Self::Item) -> Acc,
441            {
442                self.0.rfold(init, rfold)
443            }
444
445            fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
446                self.0.advance_back_by(n)
447            }
448        }
449
450        #[$fusedstab]
451        impl FusedIterator for $ITER_NAME {}
452
453        #[$exactstab]
454        impl ExactSizeIterator for $ITER_NAME {
455            fn len(&self) -> usize {
456                self.0.len()
457            }
458
459            fn is_empty(&self) -> bool {
460                self.0.is_empty()
461            }
462        }
463
464        // SAFETY: forwards to inner `array::IntoIter`
465        #[unstable(feature = "trusted_len", issue = "37572")]
466        unsafe impl TrustedLen for $ITER_NAME {}
467
468        // SAFETY: forwards to inner `array::IntoIter`
469        #[doc(hidden)]
470        #[unstable(feature = "std_internals", issue = "none")]
471        unsafe impl TrustedRandomAccessNoCoerce for $ITER_NAME {
472            const MAY_HAVE_SIDE_EFFECT: bool = false;
473        }
474
475        // SAFETY: this iter has no subtypes/supertypes
476        #[doc(hidden)]
477        #[unstable(feature = "std_internals", issue = "none")]
478        unsafe impl TrustedRandomAccess for $ITER_NAME {}
479
480        #[$displaystab]
481        impl fmt::Display for $ITER_NAME {
482            #[inline]
483            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
484                fmt::Display::fmt(&self.0, f)
485            }
486        }
487    }
488}
489
490casemappingiter_impls! {
491    #[stable(feature = "rust1", since = "1.0.0")]
492    #[stable(feature = "case_mapping_double_ended", since = "1.59.0")]
493    #[stable(feature = "fused", since = "1.26.0")]
494    #[stable(feature = "exact_size_case_mapping_iter", since = "1.35.0")]
495    #[stable(feature = "char_struct_display", since = "1.16.0")]
496    /// Returns an iterator that yields the uppercase equivalent of a `char`.
497    ///
498    /// This `struct` is created by the [`to_uppercase`] method on [`char`]. See
499    /// its documentation for more.
500    ///
501    /// [`to_uppercase`]: char::to_uppercase
502    ToUppercase
503}
504
505casemappingiter_impls! {
506    #[unstable(feature = "titlecase", issue = "153892")]
507    #[unstable(feature = "titlecase", issue = "153892")]
508    #[unstable(feature = "titlecase", issue = "153892")]
509    #[unstable(feature = "titlecase", issue = "153892")]
510    #[unstable(feature = "titlecase", issue = "153892")]
511    /// Returns an iterator that yields the titlecase equivalent of a `char`.
512    ///
513    /// This `struct` is created by the [`to_titlecase`] method on [`char`]. See
514    /// its documentation for more.
515    ///
516    /// [`to_titlecase`]: char::to_titlecase
517    ToTitlecase
518}
519
520casemappingiter_impls! {
521    #[stable(feature = "rust1", since = "1.0.0")]
522    #[stable(feature = "case_mapping_double_ended", since = "1.59.0")]
523    #[stable(feature = "fused", since = "1.26.0")]
524    #[stable(feature = "exact_size_case_mapping_iter", since = "1.35.0")]
525    #[stable(feature = "char_struct_display", since = "1.16.0")]
526    /// Returns an iterator that yields the lowercase equivalent of a `char`.
527    ///
528    /// This `struct` is created by the [`to_lowercase`] method on [`char`]. See
529    /// its documentation for more.
530    ///
531    /// [`to_lowercase`]: char::to_lowercase
532    ToLowercase
533}
534
535#[derive(Debug, Clone)]
536struct CaseMappingIter(core::array::IntoIter<char, 3>);
537
538impl CaseMappingIter {
539    #[inline]
540    fn new(chars: [char; 3]) -> CaseMappingIter {
541        let mut iter = chars.into_iter();
542        if chars[2] == '\0' {
543            iter.next_back();
544            if chars[1] == '\0' {
545                iter.next_back();
546
547                // Deliberately don't check `chars[0]`,
548                // as '\0' lowercases to itself
549            }
550        }
551        CaseMappingIter(iter)
552    }
553}
554
555impl Iterator for CaseMappingIter {
556    type Item = char;
557
558    fn next(&mut self) -> Option<char> {
559        self.0.next()
560    }
561
562    fn size_hint(&self) -> (usize, Option<usize>) {
563        self.0.size_hint()
564    }
565
566    fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
567    where
568        Fold: FnMut(Acc, Self::Item) -> Acc,
569    {
570        self.0.fold(init, fold)
571    }
572
573    fn count(self) -> usize {
574        self.0.count()
575    }
576
577    fn last(self) -> Option<Self::Item> {
578        self.0.last()
579    }
580
581    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
582        self.0.advance_by(n)
583    }
584
585    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
586        // SAFETY: just forwarding requirements to caller
587        unsafe { self.0.__iterator_get_unchecked(idx) }
588    }
589}
590
591impl DoubleEndedIterator for CaseMappingIter {
592    fn next_back(&mut self) -> Option<char> {
593        self.0.next_back()
594    }
595
596    fn rfold<Acc, Fold>(self, init: Acc, rfold: Fold) -> Acc
597    where
598        Fold: FnMut(Acc, Self::Item) -> Acc,
599    {
600        self.0.rfold(init, rfold)
601    }
602
603    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
604        self.0.advance_back_by(n)
605    }
606}
607
608impl ExactSizeIterator for CaseMappingIter {
609    fn len(&self) -> usize {
610        self.0.len()
611    }
612
613    fn is_empty(&self) -> bool {
614        self.0.is_empty()
615    }
616}
617
618impl FusedIterator for CaseMappingIter {}
619
620// SAFETY: forwards to inner `array::IntoIter`
621unsafe impl TrustedLen for CaseMappingIter {}
622
623// SAFETY: forwards to inner `array::IntoIter`
624unsafe impl TrustedRandomAccessNoCoerce for CaseMappingIter {
625    const MAY_HAVE_SIDE_EFFECT: bool = false;
626}
627
628// SAFETY: `CaseMappingIter` has no subtypes/supertypes
629unsafe impl TrustedRandomAccess for CaseMappingIter {}
630
631impl fmt::Display for CaseMappingIter {
632    #[inline]
633    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
634        for c in self.0.clone() {
635            f.write_char(c)?;
636        }
637        Ok(())
638    }
639}
640
641/// The error type returned when a checked char conversion fails.
642#[stable(feature = "u8_from_char", since = "1.59.0")]
643#[derive(Debug, Copy, Clone, PartialEq, Eq)]
644pub struct TryFromCharError(pub(crate) ());
645
646#[stable(feature = "u8_from_char", since = "1.59.0")]
647impl fmt::Display for TryFromCharError {
648    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
649        "unicode code point out of range".fmt(fmt)
650    }
651}
652
653#[stable(feature = "u8_from_char", since = "1.59.0")]
654impl Error for TryFromCharError {}
655
656/// The case of a cased character,
657/// as returned by [`char::case`].
658///
659/// Titlecase characters conceptually are composed of an uppercase portion
660/// followed by a lowercase portion.
661/// The variant discriminants represent this:
662/// the most significant bit represents whether the case
663/// conceptually starts as uppercase, while the least significant bit
664/// represents whether it conceptually ends as uppercase.
665#[unstable(feature = "titlecase", issue = "153892")]
666#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
667pub enum CharCase {
668    /// Lowercase. Corresponds to the `Lowercase` Unicode property.
669    Lower = 0b00,
670    /// Titlecase. Corresponds to the `Titlecase_Letter` Unicode general category.
671    Title = 0b10,
672    /// Uppercase. Corresponds to the `Uppercase` Unicode property.
673    Upper = 0b11,
674}