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.
This commit is contained in:
Michal Nazarewicz 2024-01-24 16:48:54 +01:00
parent 19ebdcedf1
commit 7d1de7f994
3 changed files with 42 additions and 19 deletions

View File

@ -3,7 +3,7 @@
//! suggestions from rustc if you get anything slightly wrong in here, and overall
//! helps with clarity as we're also referring to `char` intentionally in here.
use crate::fmt::{self, Write};
use crate::fmt;
use crate::mem::transmute;
/// One of the 128 Unicode characters from U+0000 through U+007F,
@ -583,9 +583,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[unstable(feature = "ascii_char", issue = "110998")]
impl fmt::Debug for AsciiChar {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[inline]
fn backslash(a: AsciiChar) -> ([AsciiChar; 4], u8) {
([AsciiChar::ReverseSolidus, a, AsciiChar::Null, AsciiChar::Null], 2)
use AsciiChar::{Apostrophe, Null, ReverseSolidus as Backslash};
fn backslash(a: AsciiChar) -> ([AsciiChar; 6], usize) {
([Apostrophe, Backslash, a, Apostrophe, Null, Null], 4)
}
let (buf, len) = match self {
@ -595,24 +596,17 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
AsciiChar::LineFeed => backslash(AsciiChar::SmallN),
AsciiChar::ReverseSolidus => backslash(AsciiChar::ReverseSolidus),
AsciiChar::Apostrophe => backslash(AsciiChar::Apostrophe),
_ => {
let byte = self.to_u8();
if !byte.is_ascii_control() {
([*self, AsciiChar::Null, AsciiChar::Null, AsciiChar::Null], 1)
} else {
_ if self.to_u8().is_ascii_control() => {
const HEX_DIGITS: [AsciiChar; 16] = *b"0123456789abcdef".as_ascii().unwrap();
let byte = self.to_u8();
let hi = HEX_DIGITS[usize::from(byte >> 4)];
let lo = HEX_DIGITS[usize::from(byte & 0xf)];
([AsciiChar::ReverseSolidus, AsciiChar::SmallX, hi, lo], 4)
}
([Apostrophe, Backslash, AsciiChar::SmallX, hi, lo, Apostrophe], 6)
}
_ => ([Apostrophe, *self, Apostrophe, Null, Null, Null], 3),
};
f.write_char('\'')?;
for byte in &buf[..len as usize] {
f.write_str(byte.as_str())?;
}
f.write_char('\'')
f.write_str(buf[..len].as_str())
}
}

View File

@ -0,0 +1,28 @@
use core::ascii::Char;
use core::fmt::Write;
/// Tests Display implementation for ascii::Char.
#[test]
fn test_display() {
let want = (0..128u8).map(|b| b as char).collect::<String>();
let mut got = String::with_capacity(128);
for byte in 0..128 {
write!(&mut got, "{}", Char::from_u8(byte).unwrap()).unwrap();
}
assert_eq!(want, got);
}
/// Tests Debug implementation for ascii::Char.
#[test]
fn test_debug_control() {
for byte in 0..128u8 {
let mut want = format!("{:?}", byte as char);
// `char` uses `'\u{#}'` representation where ascii::char uses `'\x##'`.
// Transform former into the latter.
if let Some(rest) = want.strip_prefix("'\\u{") {
want = format!("'\\x{:0>2}'", rest.strip_suffix("}'").unwrap());
}
let chr = core::ascii::Char::from_u8(byte).unwrap();
assert_eq!(want, format!("{chr:?}"), "byte: {byte}");
}
}

View File

@ -122,6 +122,7 @@
mod any;
mod array;
mod ascii;
mod ascii_char;
mod asserting;
mod async_iter;
mod atomic;