1use crate::formatting::{hex_as_ascii, HexFormatting};
2
3#[cfg(any(test, feature = "fmt"))]
4pub(crate) const fn char_display_len(c: char) -> usize {
5 match c as u32 {
6 0..=127 => 1,
7 0x80..=0x7FF => 2,
8 0x800..=0xFFFF => 3,
9 0x10000..=u32::MAX => 4,
10 }
11}
12
13#[cfg(any(test, feature = "fmt"))]
14pub(crate) const fn char_debug_len(c: char) -> usize {
15 let inner = match c {
16 '\t' | '\r' | '\n' | '\\' | '\'' | '\"' => 2,
17 '\x00'..='\x1F' => 4,
18 _ => char_display_len(c),
19 };
20 inner + 2
21}
22
23const fn char_to_utf8(char: char) -> ([u8; 4], usize) {
24 let u32: u32 = char as u32;
25 match u32 {
26 0..=127 => ([u32 as u8, 0, 0, 0], 1),
27 0x80..=0x7FF => {
28 let b0: u8 = 0b1100_0000 | (u32 >> 6) as u8;
29 let b1: u8 = 0b1000_0000 | (u32 & 0b0011_1111) as u8;
30 ([b0, b1, 0, 0], 2)
31 }
32 0x800..=0xFFFF => {
33 let b0: u8 = 0b1110_0000 | (u32 >> 12) as u8;
34 let b1: u8 = 0b1000_0000 | ((u32 >> 6) & 0b0011_1111) as u8;
35 let b2: u8 = 0b1000_0000 | (u32 & 0b0011_1111) as u8;
36 ([b0, b1, b2, 0], 3)
37 }
38 0x10000..=u32::MAX => {
39 let b0: u8 = 0b1111_0000 | (u32 >> 18) as u8;
40 let b1: u8 = 0b1000_0000 | ((u32 >> 12) & 0b0011_1111) as u8;
41 let b2: u8 = 0b1000_0000 | ((u32 >> 6) & 0b0011_1111) as u8;
42 let b3: u8 = 0b1000_0000 | (u32 & 0b0011_1111) as u8;
43 ([b0, b1, b2, b3], 4)
44 }
45 }
46}
47
48pub(crate) const fn char_to_display(char: char) -> FmtChar {
49 let ([b0: u8, b1: u8, b2: u8, b3: u8], len: usize) = char_to_utf8(char);
50 FmtChar {
51 encoded: [b0, b1, b2, b3, 0, 0],
52 len: len as u8,
53 }
54}
55
56pub(crate) const fn char_to_debug(c: char) -> FmtChar {
57 let ([b0, b1, b2, b3], len) = match c {
58 '\t' => (*br#"\t "#, 2),
59 '\r' => (*br#"\r "#, 2),
60 '\n' => (*br#"\n "#, 2),
61 '\\' => (*br#"\\ "#, 2),
62 '\'' => (*br#"\' "#, 2),
63 '\"' => (*br#"\" "#, 2),
64 '\x00'..='\x1F' => {
65 let n = c as u8;
66 (
67 [
68 b'\\',
69 b'x',
70 hex_as_ascii(n >> 4, HexFormatting::Upper),
71 hex_as_ascii(n & 0b1111, HexFormatting::Upper),
72 ],
73 4,
74 )
75 }
76 _ => char_to_utf8(c),
77 };
78
79 let mut encoded = [b'\'', b0, b1, b2, b3, 0];
80 encoded[len + 1] = b'\'';
81
82 FmtChar {
83 encoded,
84 len: (len as u8) + 2,
85 }
86}
87
88#[derive(Copy, Clone)]
89pub struct FmtChar {
90 encoded: [u8; 6],
91 len: u8,
92}
93
94impl FmtChar {
95 /// Array which contains the pre-len display/debug-formatted `char`,
96 /// only `&self.encoded[][..self.len()]` should be copied.
97 pub const fn encoded(&self) -> &[u8; 6] {
98 &self.encoded
99 }
100
101 pub const fn len(&self) -> usize {
102 self.len as usize
103 }
104
105 pub(crate) const fn as_bytes(&self) -> &[u8] {
106 #[cfg(not(feature = "rust_1_64"))]
107 {
108 match self.len() {
109 1 => {
110 let [ret @ .., _, _, _, _, _] = &self.encoded;
111 ret
112 }
113 2 => {
114 let [ret @ .., _, _, _, _] = &self.encoded;
115 ret
116 }
117 3 => {
118 let [ret @ .., _, _, _] = &self.encoded;
119 ret
120 }
121 4 => {
122 let [ret @ .., _, _] = &self.encoded;
123 ret
124 }
125 5 => {
126 let [ret @ .., _] = &self.encoded;
127 ret
128 }
129 6 => &self.encoded,
130 x => [/*bug WTF*/][x],
131 }
132 }
133
134 #[cfg(feature = "rust_1_64")]
135 {
136 ::konst::slice::slice_up_to(&self.encoded, self.len())
137 }
138 }
139}
140
141#[cfg(all(test, not(miri)))]
142mod tests;
143