qubit_codec_text/charset/utf8.rs
1// =============================================================================
2// Copyright (c) 2026 Haixing Hu.
3//
4// SPDX-License-Identifier: Apache-2.0
5//
6// Licensed under the Apache License, Version 2.0.
7// =============================================================================
8/// Namespace for UTF-8 constants and byte classification helpers.
9pub enum Utf8 {}
10
11impl Utf8 {
12 /// Maximum number of UTF-8 bytes needed for one Unicode scalar value.
13 pub const MAX_UNITS_PER_CHAR: usize = 4;
14
15 /// Maximum number of UTF-8 bytes needed for one Unicode scalar value.
16 pub const MAX_BYTES_PER_CHAR: usize = Self::MAX_UNITS_PER_CHAR;
17
18 /// Tests whether a byte encodes an ASCII scalar value by itself.
19 ///
20 /// # Parameters
21 ///
22 /// - `byte`: The byte to test.
23 ///
24 /// # Returns
25 ///
26 /// Returns `true` if `byte` is in `0x00..=0x7F`.
27 #[inline(always)]
28 pub const fn is_single_byte(byte: u8) -> bool {
29 byte <= 0x7f
30 }
31
32 /// Tests whether a byte can lead a multi-byte UTF-8 sequence.
33 ///
34 /// # Parameters
35 ///
36 /// - `byte`: The byte to test.
37 ///
38 /// # Returns
39 ///
40 /// Returns `true` if `byte` is in `0xC2..=0xF4`.
41 #[inline(always)]
42 pub const fn is_leading_byte(byte: u8) -> bool {
43 byte >= 0xc2 && byte <= 0xf4
44 }
45
46 /// Tests whether a byte is a UTF-8 continuation byte.
47 ///
48 /// # Parameters
49 ///
50 /// - `byte`: The byte to test.
51 ///
52 /// # Returns
53 ///
54 /// Returns `true` if `byte` matches the `10xxxxxx` continuation pattern.
55 #[inline(always)]
56 pub const fn is_continuation_byte(byte: u8) -> bool {
57 (byte & 0xc0) == 0x80
58 }
59
60 /// Returns the complete UTF-8 sequence length implied by a leading byte.
61 ///
62 /// # Parameters
63 ///
64 /// - `byte`: The first byte of the UTF-8 sequence.
65 ///
66 /// # Returns
67 ///
68 /// Returns `Some(1..=4)` for valid ASCII or leading bytes, and `None` for
69 /// continuation bytes or invalid leading bytes.
70 #[inline(always)]
71 pub const fn byte_len_from_leading_byte(byte: u8) -> Option<usize> {
72 if byte <= 0x7f {
73 Some(1)
74 } else if byte >= 0xc2 && byte <= 0xdf {
75 Some(2)
76 } else if byte >= 0xe0 && byte <= 0xef {
77 Some(3)
78 } else if byte >= 0xf0 && byte <= 0xf4 {
79 Some(4)
80 } else {
81 None
82 }
83 }
84
85 /// Returns the number of UTF-8 bytes needed for `ch`.
86 ///
87 /// # Parameters
88 ///
89 /// - `ch`: The character to size.
90 ///
91 /// # Returns
92 ///
93 /// Returns `1`, `2`, `3`, or `4`.
94 #[inline(always)]
95 pub const fn byte_len(ch: char) -> usize {
96 let code_point = ch as u32;
97 if code_point <= 0x7f {
98 1
99 } else if code_point <= 0x7ff {
100 2
101 } else if code_point <= 0xffff {
102 3
103 } else {
104 4
105 }
106 }
107}