1 | /*! |
2 | Provides convenience routines for escaping raw bytes. |
3 | |
4 | This was copied from `regex-automata` with a few light edits. |
5 | */ |
6 | |
7 | use super::utf8; |
8 | |
9 | /// Provides a convenient `Debug` implementation for a `u8`. |
10 | /// |
11 | /// The `Debug` impl treats the byte as an ASCII, and emits a human |
12 | /// readable representation of it. If the byte isn't ASCII, then it's |
13 | /// emitted as a hex escape sequence. |
14 | #[derive (Clone, Copy)] |
15 | pub(crate) struct Byte(pub u8); |
16 | |
17 | impl core::fmt::Display for Byte { |
18 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { |
19 | if self.0 == b' ' { |
20 | return write!(f, " " ); |
21 | } |
22 | // 10 bytes is enough for any output from ascii::escape_default. |
23 | let mut bytes: [u8; 10] = [0u8; 10]; |
24 | let mut len: usize = 0; |
25 | for (i: usize, mut b: u8) in core::ascii::escape_default(self.0).enumerate() { |
26 | // capitalize \xab to \xAB |
27 | if i >= 2 && b'a' <= b && b <= b'f' { |
28 | b -= 32; |
29 | } |
30 | bytes[len] = b; |
31 | len += 1; |
32 | } |
33 | write!(f, " {}" , core::str::from_utf8(&bytes[..len]).unwrap()) |
34 | } |
35 | } |
36 | |
37 | impl core::fmt::Debug for Byte { |
38 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { |
39 | write!(f, " \"" )?; |
40 | core::fmt::Display::fmt(self, f)?; |
41 | write!(f, " \"" )?; |
42 | Ok(()) |
43 | } |
44 | } |
45 | |
46 | /// Provides a convenient `Debug` implementation for `&[u8]`. |
47 | /// |
48 | /// This generally works best when the bytes are presumed to be mostly |
49 | /// UTF-8, but will work for anything. For any bytes that aren't UTF-8, |
50 | /// they are emitted as hex escape sequences. |
51 | #[derive (Clone, Copy)] |
52 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
53 | |
54 | impl<'a> core::fmt::Display for Bytes<'a> { |
55 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { |
56 | // This is a sad re-implementation of a similar impl found in bstr. |
57 | let mut bytes = self.0; |
58 | while let Some(result) = utf8::decode(bytes) { |
59 | let ch = match result { |
60 | Ok(ch) => ch, |
61 | Err(byte) => { |
62 | write!(f, r"\x{:02x}" , byte)?; |
63 | bytes = &bytes[1..]; |
64 | continue; |
65 | } |
66 | }; |
67 | bytes = &bytes[ch.len_utf8()..]; |
68 | match ch { |
69 | ' \0' => write!(f, " \\0" )?, |
70 | ' \x01' ..=' \x7f' => { |
71 | write!(f, " {}" , (ch as u8).escape_ascii())?; |
72 | } |
73 | _ => write!(f, " {}" , ch.escape_debug())?, |
74 | } |
75 | } |
76 | Ok(()) |
77 | } |
78 | } |
79 | |
80 | impl<'a> core::fmt::Debug for Bytes<'a> { |
81 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { |
82 | write!(f, " \"" )?; |
83 | core::fmt::Display::fmt(self, f)?; |
84 | write!(f, " \"" )?; |
85 | Ok(()) |
86 | } |
87 | } |
88 | |