| 1 | #[derive (Copy, Clone)] |
| 2 | pub(crate) struct EscapeOptions { |
| 3 | /// Produce \'. |
| 4 | pub escape_single_quote: bool, |
| 5 | /// Produce \". |
| 6 | pub escape_double_quote: bool, |
| 7 | /// Produce \x escapes for non-ASCII, and use \x rather than \u for ASCII |
| 8 | /// control characters. |
| 9 | pub escape_nonascii: bool, |
| 10 | } |
| 11 | |
| 12 | pub(crate) fn escape_bytes(bytes: &[u8], opt: EscapeOptions) -> String { |
| 13 | let mut repr: String = String::new(); |
| 14 | |
| 15 | if opt.escape_nonascii { |
| 16 | for &byte: u8 in bytes { |
| 17 | escape_single_byte(byte, opt, &mut repr); |
| 18 | } |
| 19 | } else { |
| 20 | let mut chunks: Utf8Chunks<'_> = bytes.utf8_chunks(); |
| 21 | while let Some(chunk: Utf8Chunk<'_>) = chunks.next() { |
| 22 | for ch: char in chunk.valid().chars() { |
| 23 | escape_single_char(ch, opt, &mut repr); |
| 24 | } |
| 25 | for &byte: u8 in chunk.invalid() { |
| 26 | escape_single_byte(byte, opt, &mut repr); |
| 27 | } |
| 28 | } |
| 29 | } |
| 30 | |
| 31 | repr |
| 32 | } |
| 33 | |
| 34 | fn escape_single_byte(byte: u8, opt: EscapeOptions, repr: &mut String) { |
| 35 | if byte == b' \0' { |
| 36 | repr.push_str(string:" \\0" ); |
| 37 | } else if (byte == b' \'' && !opt.escape_single_quote) |
| 38 | || (byte == b'"' && !opt.escape_double_quote) |
| 39 | { |
| 40 | repr.push(ch:byte as char); |
| 41 | } else { |
| 42 | // Escapes \t, \r, \n, \\, \', \", and uses \x## for non-ASCII and |
| 43 | // for ASCII control characters. |
| 44 | repr.extend(iter:byte.escape_ascii().map(char::from)); |
| 45 | } |
| 46 | } |
| 47 | |
| 48 | fn escape_single_char(ch: char, opt: EscapeOptions, repr: &mut String) { |
| 49 | if (ch == ' \'' && !opt.escape_single_quote) || (ch == '"' && !opt.escape_double_quote) { |
| 50 | repr.push(ch); |
| 51 | } else { |
| 52 | // Escapes \0, \t, \r, \n, \\, \', \", and uses \u{...} for |
| 53 | // non-printable characters and for Grapheme_Extend characters, which |
| 54 | // includes things like U+0300 "Combining Grave Accent". |
| 55 | repr.extend(iter:ch.escape_debug()); |
| 56 | } |
| 57 | } |
| 58 | |