about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichal Nazarewicz <mina86@mina86.com>2024-01-24 16:48:54 +0100
committerMichal Nazarewicz <mina86@mina86.com>2024-08-09 22:50:57 +0200
commit7d1de7f9942e4f91f3fc6dbfd56491caccd02f64 (patch)
tree3838515bc891dfc14b4a24668f544b3eafc63fba
parent19ebdcedf1f5619f8f06c546c7541bb9b54aecda (diff)
downloadrust-7d1de7f9942e4f91f3fc6dbfd56491caccd02f64.tar.gz
rust-7d1de7f9942e4f91f3fc6dbfd56491caccd02f64.zip
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.
-rw-r--r--library/core/src/ascii/ascii_char.rs32
-rw-r--r--library/core/tests/ascii_char.rs28
-rw-r--r--library/core/tests/lib.rs1
3 files changed, 42 insertions, 19 deletions
diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs
index 34a05ac3888..375358dddf5 100644
--- a/library/core/src/ascii/ascii_char.rs
+++ b/library/core/src/ascii/ascii_char.rs
@@ -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 @@ impl fmt::Display for AsciiChar {
 #[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 @@ impl fmt::Debug for AsciiChar {
             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 {
-                    const HEX_DIGITS: [AsciiChar; 16] = *b"0123456789abcdef".as_ascii().unwrap();
+            _ if self.to_u8().is_ascii_control() => {
+                const HEX_DIGITS: [AsciiChar; 16] = *b"0123456789abcdef".as_ascii().unwrap();
 
-                    let hi = HEX_DIGITS[usize::from(byte >> 4)];
-                    let lo = HEX_DIGITS[usize::from(byte & 0xf)];
-                    ([AsciiChar::ReverseSolidus, AsciiChar::SmallX, hi, lo], 4)
-                }
+                let byte = self.to_u8();
+                let hi = HEX_DIGITS[usize::from(byte >> 4)];
+                let lo = HEX_DIGITS[usize::from(byte & 0xf)];
+                ([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())
     }
 }
diff --git a/library/core/tests/ascii_char.rs b/library/core/tests/ascii_char.rs
new file mode 100644
index 00000000000..75b5fd4b9e6
--- /dev/null
+++ b/library/core/tests/ascii_char.rs
@@ -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}");
+    }
+}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 1e336bf96b8..8872b4cbfd5 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -122,6 +122,7 @@ mod alloc;
 mod any;
 mod array;
 mod ascii;
+mod ascii_char;
 mod asserting;
 mod async_iter;
 mod atomic;