Auto merge of #125144 - fmease:rollup-4uft293, r=fmease · rust-lang/rust@ade234d (original) (raw)
`@@ -6,56 +6,79 @@ use crate::ops::Range;
`
6
6
``
7
7
`const HEX_DIGITS: [ascii::Char; 16] = *b"0123456789abcdef".as_ascii().unwrap();
`
8
8
``
9
``
`-
/// Escapes a byte into provided buffer; returns length of escaped
`
10
``
`-
/// representation.
`
11
``
`-
pub(crate) fn escape_ascii_into(output: &mut [ascii::Char; 4], byte: u8) -> Range {
`
12
``
`-
#[inline]
`
13
``
`-
fn backslash(a: ascii::Char) -> ([ascii::Char; 4], u8) {
`
14
``
`-
([ascii::Char::ReverseSolidus, a, ascii::Char::Null, ascii::Char::Null], 2)
`
15
``
`-
}
`
``
9
`+
#[inline]
`
``
10
`+
const fn backslash(a: ascii::Char) -> ([ascii::Char; N], Range) {
`
``
11
`+
const { assert!(N >= 2) };
`
``
12
+
``
13
`+
let mut output = [ascii::Char::Null; N];
`
``
14
+
``
15
`+
output[0] = ascii::Char::ReverseSolidus;
`
``
16
`+
output[1] = a;
`
``
17
+
``
18
`+
(output, 0..2)
`
``
19
`+
}
`
16
20
``
17
``
`-
let (data, len) = match byte {
`
``
21
`+
/// Escapes an ASCII character.
`
``
22
`+
///
`
``
23
`+
/// Returns a buffer and the length of the escaped representation.
`
``
24
`+
const fn escape_ascii(byte: u8) -> ([ascii::Char; N], Range) {
`
``
25
`+
const { assert!(N >= 4) };
`
``
26
+
``
27
`+
match byte {
`
18
28
`b'\t' => backslash(ascii::Char::SmallT),
`
19
29
`b'\r' => backslash(ascii::Char::SmallR),
`
20
30
`b'\n' => backslash(ascii::Char::SmallN),
`
21
31
`b'\' => backslash(ascii::Char::ReverseSolidus),
`
22
32
`b''' => backslash(ascii::Char::Apostrophe),
`
23
33
`b'"' => backslash(ascii::Char::QuotationMark),
`
24
``
`-
_ => {
`
25
``
`-
if let Some(a) = byte.as_ascii()
`
``
34
`+
byte => {
`
``
35
`+
let mut output = [ascii::Char::Null; N];
`
``
36
+
``
37
`+
if let Some(c) = byte.as_ascii()
`
26
38
` && !byte.is_ascii_control()
`
27
39
`{
`
28
``
`-
([a, ascii::Char::Null, ascii::Char::Null, ascii::Char::Null], 1)
`
``
40
`+
output[0] = c;
`
``
41
`+
(output, 0..1)
`
29
42
`} else {
`
30
``
`-
let hi = HEX_DIGITS[usize::from(byte >> 4)];
`
31
``
`-
let lo = HEX_DIGITS[usize::from(byte & 0xf)];
`
32
``
`-
([ascii::Char::ReverseSolidus, ascii::Char::SmallX, hi, lo], 4)
`
``
43
`+
let hi = HEX_DIGITS[(byte >> 4) as usize];
`
``
44
`+
let lo = HEX_DIGITS[(byte & 0xf) as usize];
`
``
45
+
``
46
`+
output[0] = ascii::Char::ReverseSolidus;
`
``
47
`+
output[1] = ascii::Char::SmallX;
`
``
48
`+
output[2] = hi;
`
``
49
`+
output[3] = lo;
`
``
50
+
``
51
`+
(output, 0..4)
`
33
52
`}
`
34
53
`}
`
35
``
`-
};
`
36
``
`-
*output = data;
`
37
``
`-
0..len
`
``
54
`+
}
`
38
55
`}
`
39
56
``
40
``
`` -
/// Escapes a character into provided buffer using \u{NNNN}
representation.
``
41
``
`-
pub(crate) fn escape_unicode_into(output: &mut [ascii::Char; 10], ch: char) -> Range {
`
``
57
`` +
/// Escapes a character \u{NNNN}
representation.
``
``
58
`+
///
`
``
59
`+
/// Returns a buffer and the length of the escaped representation.
`
``
60
`+
const fn escape_unicode(c: char) -> ([ascii::Char; N], Range) {
`
``
61
`+
const { assert!(N >= 10 && N < u8::MAX as usize) };
`
``
62
+
``
63
`+
let c = u32::from(c);
`
``
64
+
``
65
`` +
// OR-ing 1
ensures that for c == 0
the code computes that
``
``
66
`+
// one digit should be printed.
`
``
67
`+
let start = (c | 1).leading_zeros() as usize / 4 - 2;
`
``
68
+
``
69
`+
let mut output = [ascii::Char::Null; N];
`
``
70
`+
output[3] = HEX_DIGITS[((c >> 20) & 15) as usize];
`
``
71
`+
output[4] = HEX_DIGITS[((c >> 16) & 15) as usize];
`
``
72
`+
output[5] = HEX_DIGITS[((c >> 12) & 15) as usize];
`
``
73
`+
output[6] = HEX_DIGITS[((c >> 8) & 15) as usize];
`
``
74
`+
output[7] = HEX_DIGITS[((c >> 4) & 15) as usize];
`
``
75
`+
output[8] = HEX_DIGITS[((c >> 0) & 15) as usize];
`
42
76
` output[9] = ascii::Char::RightCurlyBracket;
`
``
77
`+
output[start + 0] = ascii::Char::ReverseSolidus;
`
``
78
`+
output[start + 1] = ascii::Char::SmallU;
`
``
79
`+
output[start + 2] = ascii::Char::LeftCurlyBracket;
`
43
80
``
44
``
`-
let ch = ch as u32;
`
45
``
`-
output[3] = HEX_DIGITS[((ch >> 20) & 15) as usize];
`
46
``
`-
output[4] = HEX_DIGITS[((ch >> 16) & 15) as usize];
`
47
``
`-
output[5] = HEX_DIGITS[((ch >> 12) & 15) as usize];
`
48
``
`-
output[6] = HEX_DIGITS[((ch >> 8) & 15) as usize];
`
49
``
`-
output[7] = HEX_DIGITS[((ch >> 4) & 15) as usize];
`
50
``
`-
output[8] = HEX_DIGITS[((ch >> 0) & 15) as usize];
`
51
``
-
52
``
`-
// or-ing 1 ensures that for ch==0 the code computes that one digit should
`
53
``
`-
// be printed.
`
54
``
`-
let start = (ch | 1).leading_zeros() as usize / 4 - 2;
`
55
``
`-
const UNICODE_ESCAPE_PREFIX: &[ascii::Char; 3] = b"\u{".as_ascii().unwrap();
`
56
``
`-
output[start..][..3].copy_from_slice(UNICODE_ESCAPE_PREFIX);
`
57
``
-
58
``
`-
(start as u8)..10
`
``
81
`+
(output, (start as u8)..(N as u8))
`
59
82
`}
`
60
83
``
61
84
`/// An iterator over an fixed-size array.
`
`@@ -65,45 +88,63 @@ pub(crate) fn escape_unicode_into(output: &mut [ascii::Char; 10], ch: char) -> R
`
65
88
`#[derive(Clone, Debug)]
`
66
89
`pub(crate) struct EscapeIterInner {
`
67
90
`// The element type ensures this is always ASCII, and thus also valid UTF-8.
`
68
``
`-
pub(crate) data: [ascii::Char; N],
`
``
91
`+
data: [ascii::Char; N],
`
69
92
``
70
``
`-
// Invariant: alive.start <= alive.end <= N.
`
71
``
`-
pub(crate) alive: Range,
`
``
93
`` +
// Invariant: alive.start <= alive.end <= N
``
``
94
`+
alive: Range,
`
72
95
`}
`
73
96
``
74
97
`impl EscapeIterInner {
`
75
``
`-
pub fn new(data: [ascii::Char; N], alive: Range) -> Self {
`
76
``
`-
const { assert!(N < 256) };
`
77
``
`-
debug_assert!(alive.start <= alive.end && usize::from(alive.end) <= N, "{alive:?}");
`
78
``
`-
Self { data, alive }
`
``
98
`+
pub const fn backslash(c: ascii::Char) -> Self {
`
``
99
`+
let (data, range) = backslash(c);
`
``
100
`+
Self { data, alive: range }
`
``
101
`+
}
`
``
102
+
``
103
`+
pub const fn ascii(c: u8) -> Self {
`
``
104
`+
let (data, range) = escape_ascii(c);
`
``
105
`+
Self { data, alive: range }
`
79
106
`}
`
80
107
``
81
``
`-
pub fn from_array(array: [ascii::Char; M]) -> Self {
`
82
``
`-
const { assert!(M <= N) };
`
``
108
`+
pub const fn unicode(c: char) -> Self {
`
``
109
`+
let (data, range) = escape_unicode(c);
`
``
110
`+
Self { data, alive: range }
`
``
111
`+
}
`
83
112
``
84
``
`-
let mut data = [ascii::Char::Null; N];
`
85
``
`-
data[..M].copy_from_slice(&array);
`
86
``
`-
Self::new(data, 0..M as u8)
`
``
113
`+
#[inline]
`
``
114
`+
pub const fn empty() -> Self {
`
``
115
`+
Self { data: [ascii::Char::Null; N], alive: 0..0 }
`
87
116
`}
`
88
117
``
``
118
`+
#[inline]
`
89
119
`pub fn as_ascii(&self) -> &[ascii::Char] {
`
90
``
`-
&self.data[usize::from(self.alive.start)..usize::from(self.alive.end)]
`
``
120
`` +
// SAFETY: self.alive
is guaranteed to be a valid range for indexing self.data
.
``
``
121
`+
unsafe {
`
``
122
`+
self.data.get_unchecked(usize::from(self.alive.start)..usize::from(self.alive.end))
`
``
123
`+
}
`
91
124
`}
`
92
125
``
``
126
`+
#[inline]
`
93
127
`pub fn as_str(&self) -> &str {
`
94
128
`self.as_ascii().as_str()
`
95
129
`}
`
96
130
``
``
131
`+
#[inline]
`
97
132
`pub fn len(&self) -> usize {
`
98
133
` usize::from(self.alive.end - self.alive.start)
`
99
134
`}
`
100
135
``
101
136
`pub fn next(&mut self) -> Option {
`
102
``
`-
self.alive.next().map(|i| self.data[usize::from(i)].to_u8())
`
``
137
`+
let i = self.alive.next()?;
`
``
138
+
``
139
`` +
// SAFETY: i
is guaranteed to be a valid index for self.data
.
``
``
140
`+
unsafe { Some(self.data.get_unchecked(usize::from(i)).to_u8()) }
`
103
141
`}
`
104
142
``
105
143
`pub fn next_back(&mut self) -> Option {
`
106
``
`-
self.alive.next_back().map(|i| self.data[usize::from(i)].to_u8())
`
``
144
`+
let i = self.alive.next_back()?;
`
``
145
+
``
146
`` +
// SAFETY: i
is guaranteed to be a valid index for self.data
.
``
``
147
`+
unsafe { Some(self.data.get_unchecked(usize::from(i)).to_u8()) }
`
107
148
`}
`
108
149
``
109
150
`pub fn advance_by(&mut self, n: usize) -> Result<(), NonZero> {
`