Rollup merge of #124307 - reitermarkus:escape-debug-size-hint-inline,… · rust-lang/rust@3873a74

@@ -6,56 +6,79 @@ use crate::ops::Range;

6677

const HEX_DIGITS: [ascii::Char; 16] = *b"0123456789abcdef".as_ascii().unwrap();

889-

/// 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<u8> {

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<const N: usize>(a: ascii::Char) -> ([ascii::Char; N], Range<u8>) {

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+

}

162017-

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<const N: usize>(byte: u8) -> ([ascii::Char; N], Range<u8>) {

25+

const { assert!(N >= 4) };

26+27+

match byte {

1828

b'\t' => backslash(ascii::Char::SmallT),

1929

b'\r' => backslash(ascii::Char::SmallR),

2030

b'\n' => backslash(ascii::Char::SmallN),

2131

b'\\' => backslash(ascii::Char::ReverseSolidus),

2232

b'\'' => backslash(ascii::Char::Apostrophe),

2333

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()

2638

&& !byte.is_ascii_control()

2739

{

28-

([a, ascii::Char::Null, ascii::Char::Null, ascii::Char::Null], 1)

40+

output[0] = c;

41+

(output, 0..1)

2942

} 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)

3352

}

3453

}

35-

};

36-

*output = data;

37-

0..len

54+

}

3855

}

395640-

/// 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<u8> {

57+

/// Escapes a character `\u{NNNN}` representation.

58+

///

59+

/// Returns a buffer and the length of the escaped representation.

60+

const fn escape_unicode<const N: usize>(c: char) -> ([ascii::Char; N], Range<u8>) {

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];

4276

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;

438044-

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))

5982

}

60836184

/// 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

6588

#[derive(Clone, Debug)]

6689

pub(crate) struct EscapeIterInner<const N: usize> {

6790

// 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],

699270-

// Invariant: alive.start <= alive.end <= N.

71-

pub(crate) alive: Range<u8>,

93+

// Invariant: `alive.start <= alive.end <= N`

94+

alive: Range<u8>,

7295

}

73967497

impl<const N: usize> EscapeIterInner<N> {

75-

pub fn new(data: [ascii::Char; N], alive: Range<u8>) -> 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 }

79106

}

8010781-

pub fn from_array<const M: usize>(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+

}

8311284-

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 }

87116

}

88117118+

#[inline]

89119

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+

}

91124

}

92125126+

#[inline]

93127

pub fn as_str(&self) -> &str {

94128

self.as_ascii().as_str()

95129

}

96130131+

#[inline]

97132

pub fn len(&self) -> usize {

98133

usize::from(self.alive.end - self.alive.start)

99134

}

100135101136

pub fn next(&mut self) -> Option<u8> {

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()) }

103141

}

104142105143

pub fn next_back(&mut self) -> Option<u8> {

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()) }

107148

}

108149109150

pub fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {