Skip to main content

qubit_text_codec/charset/
utf8.rs

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