Skip to content

Commit 6f58228

Browse files
committed
core: optimise Debug impl for ascii::Char
Rather than writing character at a time, optimise Debug implementation for core::ascii::Char such that it writes the entire representation as with a single write_str call. With that, add tests for Display and Debug implementations.
1 parent cd6d8f2 commit 6f58228

File tree

3 files changed

+83
-20
lines changed

3 files changed

+83
-20
lines changed

library/core/src/ascii/ascii_char.rs

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//! suggestions from rustc if you get anything slightly wrong in here, and overall
44
//! helps with clarity as we're also referring to `char` intentionally in here.
55
6-
use crate::fmt::{self, Write};
6+
use crate::fmt;
77
use crate::mem::transmute;
88

99
/// One of the 128 Unicode characters from U+0000 through U+007F,
@@ -567,9 +567,10 @@ impl fmt::Display for AsciiChar {
567567
#[unstable(feature = "ascii_char", issue = "110998")]
568568
impl fmt::Debug for AsciiChar {
569569
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
570-
#[inline]
571-
fn backslash(a: AsciiChar) -> ([AsciiChar; 4], u8) {
572-
([AsciiChar::ReverseSolidus, a, AsciiChar::Null, AsciiChar::Null], 2)
570+
use AsciiChar::{Apostrophe, Null, ReverseSolidus as Backslash};
571+
572+
fn backslash(a: AsciiChar) -> ([AsciiChar; 6], usize) {
573+
([Apostrophe, Backslash, a, Apostrophe, Null, Null], 4)
573574
}
574575

575576
let (buf, len) = match self {
@@ -579,24 +580,17 @@ impl fmt::Debug for AsciiChar {
579580
AsciiChar::LineFeed => backslash(AsciiChar::SmallN),
580581
AsciiChar::ReverseSolidus => backslash(AsciiChar::ReverseSolidus),
581582
AsciiChar::Apostrophe => backslash(AsciiChar::Apostrophe),
582-
_ => {
583-
let byte = self.to_u8();
584-
if !byte.is_ascii_control() {
585-
([*self, AsciiChar::Null, AsciiChar::Null, AsciiChar::Null], 1)
586-
} else {
587-
const HEX_DIGITS: [AsciiChar; 16] = *b"0123456789abcdef".as_ascii().unwrap();
583+
_ if self.to_u8().is_ascii_control() => {
584+
const HEX_DIGITS: [AsciiChar; 16] = *b"0123456789abcdef".as_ascii().unwrap();
588585

589-
let hi = HEX_DIGITS[usize::from(byte >> 4)];
590-
let lo = HEX_DIGITS[usize::from(byte & 0xf)];
591-
([AsciiChar::ReverseSolidus, AsciiChar::SmallX, hi, lo], 4)
592-
}
593-
}
586+
let byte = self.to_u8();
587+
let hi = HEX_DIGITS[usize::from(byte >> 4)];
588+
let lo = HEX_DIGITS[usize::from(byte & 0xf)];
589+
([Apostrophe, Backslash, AsciiChar::SmallX, hi, lo, Apostrophe], 6)
590+
},
591+
_ => ([Apostrophe, *self, Apostrophe, Null, Null, Null], 3),
594592
};
595593

596-
f.write_char('\'')?;
597-
for byte in &buf[..len as usize] {
598-
f.write_str(byte.as_str())?;
599-
}
600-
f.write_char('\'')
594+
f.write_str(buf[..len].as_str())
601595
}
602596
}

library/core/tests/ascii_char.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use core::ascii::Char;
2+
use core::fmt::Write;
3+
4+
/// Tests Display implementation for ascii::Char.
5+
#[test]
6+
fn test_display() {
7+
let want = (0..128u8).map(|b| b as char).collect::<String>();
8+
let mut got = String::with_capacity(128);
9+
for byte in 0..128 {
10+
write!(&mut got, "{}", Char::from_u8(byte).unwrap()).unwrap();
11+
}
12+
assert_eq!(want, got);
13+
}
14+
15+
/// Tests Debug implementation for ascii::Char.
16+
#[test]
17+
fn test_debug() {
18+
for (chr, want) in [
19+
// Control characters
20+
(Char::Null, r#"'\0'"#),
21+
(Char::StartOfHeading, r#"'\x01'"#),
22+
(Char::StartOfText, r#"'\x02'"#),
23+
(Char::EndOfText, r#"'\x03'"#),
24+
(Char::EndOfTransmission, r#"'\x04'"#),
25+
(Char::Enquiry, r#"'\x05'"#),
26+
(Char::Acknowledge, r#"'\x06'"#),
27+
(Char::Bell, r#"'\x07'"#),
28+
(Char::Backspace, r#"'\x08'"#),
29+
(Char::CharacterTabulation, r#"'\t'"#),
30+
(Char::LineFeed, r#"'\n'"#),
31+
(Char::LineTabulation, r#"'\x0b'"#),
32+
(Char::FormFeed, r#"'\x0c'"#),
33+
(Char::CarriageReturn, r#"'\r'"#),
34+
(Char::ShiftOut, r#"'\x0e'"#),
35+
(Char::ShiftIn, r#"'\x0f'"#),
36+
(Char::DataLinkEscape, r#"'\x10'"#),
37+
(Char::DeviceControlOne, r#"'\x11'"#),
38+
(Char::DeviceControlTwo, r#"'\x12'"#),
39+
(Char::DeviceControlThree, r#"'\x13'"#),
40+
(Char::DeviceControlFour, r#"'\x14'"#),
41+
(Char::NegativeAcknowledge, r#"'\x15'"#),
42+
(Char::SynchronousIdle, r#"'\x16'"#),
43+
(Char::EndOfTransmissionBlock, r#"'\x17'"#),
44+
(Char::Cancel, r#"'\x18'"#),
45+
(Char::EndOfMedium, r#"'\x19'"#),
46+
(Char::Substitute, r#"'\x1a'"#),
47+
(Char::Escape, r#"'\x1b'"#),
48+
(Char::InformationSeparatorFour, r#"'\x1c'"#),
49+
(Char::InformationSeparatorThree, r#"'\x1d'"#),
50+
(Char::InformationSeparatorTwo, r#"'\x1e'"#),
51+
(Char::InformationSeparatorOne, r#"'\x1f'"#),
52+
// U+007F is also a control character
53+
(Char::Delete, r#"'\x7f'"#),
54+
55+
// Characters which need escaping.
56+
(Char::ReverseSolidus, r#"'\\'"#),
57+
(Char::Apostrophe, r#"'\''"#),
58+
59+
// Regular, non-control characters, which don’t need any special
60+
// handling.
61+
(Char::Space, r#"' '"#),
62+
(Char::QuotationMark, r#"'"'"#),
63+
(Char::CapitalM, r#"'M'"#),
64+
(Char::Tilde, r#"'~'"#),
65+
] {
66+
assert_eq!(want, format!("{chr:?}"), "chr: {}", chr as u8);
67+
}
68+
}

library/core/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ mod alloc;
126126
mod any;
127127
mod array;
128128
mod ascii;
129+
mod ascii_char;
129130
mod asserting;
130131
mod async_iter;
131132
mod atomic;

0 commit comments

Comments
 (0)