1/*!
2Provides convenience routines for escaping raw bytes.
34Since this crate tends to deal with `&[u8]` everywhere and the default
5`Debug` implementation just shows decimal integers, it makes debugging those
6representations quite difficult. This module provides types that show `&[u8]`
7as if it were a string, with invalid UTF-8 escaped into its byte-by-byte hex
8representation.
9*/
1011use crate::util::utf8;
1213/// Provides a convenient `Debug` implementation for a `u8`.
14///
15/// The `Debug` impl treats the byte as an ASCII, and emits a human readable
16/// representation of it. If the byte isn't ASCII, then it's emitted as a hex
17/// escape sequence.
18#[derive(#[automatically_derived]
impl ::core::clone::Clone for DebugByte {
#[inline]
fn clone(&self) -> DebugByte {
let _: ::core::clone::AssertParamIsClone<u8>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for DebugByte { }Copy)]
19pub struct DebugByte(pub u8);
2021impl core::fmt::Debugfor DebugByte {
22fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
23// Special case ASCII space. It's too hard to read otherwise, so
24 // put quotes around it. I sometimes wonder whether just '\x20' would
25 // be better...
26if self.0 == b' ' {
27return f.write_fmt(format_args!("\' \'"))write!(f, "' '");
28 }
29// 10 bytes is enough to cover any output from ascii::escape_default.
30let mut bytes = [0u8; 10];
31let mut len = 0;
32for (i, mut b) in core::ascii::escape_default(self.0).enumerate() {
33// capitalize \xab to \xAB
34if i >= 2 && b'a' <= b && b <= b'f' {
35 b -= 32;
36 }
37 bytes[len] = b;
38 len += 1;
39 }
40f.write_fmt(format_args!("{0}", core::str::from_utf8(&bytes[..len]).unwrap()))write!(f, "{}", core::str::from_utf8(&bytes[..len]).unwrap())41 }
42}
4344/// Provides a convenient `Debug` implementation for `&[u8]`.
45///
46/// This generally works best when the bytes are presumed to be mostly UTF-8,
47/// but will work for anything. For any bytes that aren't UTF-8, they are
48/// emitted as hex escape sequences.
49pub struct DebugHaystack<'a>(pub &'a [u8]);
5051impl<'a> core::fmt::Debugfor DebugHaystack<'a> {
52fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
53f.write_fmt(format_args!("\""))write!(f, "\"")?;
54// This is a sad re-implementation of a similar impl found in bstr.
55let mut bytes = self.0;
56while let Some(result) = utf8::decode(bytes) {
57let ch = match result {
58Ok(ch) => ch,
59Err(byte) => {
60f.write_fmt(format_args!("\\x{0:02x}", byte))write!(f, r"\x{byte:02x}")?;
61 bytes = &bytes[1..];
62continue;
63 }
64 };
65 bytes = &bytes[ch.len_utf8()..];
66match ch {
67'\0' => f.write_fmt(format_args!("\\0"))write!(f, "\\0")?,
68// ASCII control characters except \0, \n, \r, \t
69'\x01'..='\x08'
70| '\x0b'
71| '\x0c'
72| '\x0e'..='\x19'
73| '\x7f' => {
74f.write_fmt(format_args!("\\x{0:02x}", u32::from(ch)))write!(f, "\\x{:02x}", u32::from(ch))?;
75 }
76'\n' | '\r' | '\t' | _ => {
77f.write_fmt(format_args!("{0}", ch.escape_debug()))write!(f, "{}", ch.escape_debug())?;
78 }
79 }
80 }
81f.write_fmt(format_args!("\""))write!(f, "\"")?;
82Ok(())
83 }
84}