From 03fc15876fb7e6cbe932f84f368e696413bfe203 Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Sun, 2 Feb 2020 12:12:05 -0800 Subject: [PATCH] Add ExtSlice::escape_debug_into Add a method to the `ExtSlice` trait that supports writing the `BStr` escaped representation into a `fmt::Write`. This enables extracting the escaped `String` into a buffer without going through `fmt::Debug`. The written `String` does not contain the surrounding quotes present in the `fmt::Debug` implementation. Fixes GH-34. --- src/ext_slice.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/ext_slice.rs b/src/ext_slice.rs index ce83ab7..6ee2ad9 100644 --- a/src/ext_slice.rs +++ b/src/ext_slice.rs @@ -3,6 +3,8 @@ use std::borrow::Cow; #[cfg(feature = "std")] use std::ffi::OsStr; #[cfg(feature = "std")] +use std::fmt; +#[cfg(feature = "std")] use std::path::Path; use core::cmp; @@ -429,6 +431,43 @@ pub trait ByteSlice: Sealed { } } + /// Write a UTF-8 debug representation of a potentially UTF-8 invalid + /// sequence. + /// + /// This method encodes a bytes slice into a UTF-8 valid representation by + /// writing invalid sequences as `\xXX` escape codes. + /// + /// This method uses `char::escape_debug` which means UTF-8 valid characters + /// like `\n` and `\t` are also escaped. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let mut message = String::from("cannot load such file -- "); + /// let filename = b"utf8-invalid-name-\xFF"; + /// filename.escape_debug_into(&mut message).unwrap(); + /// assert_eq!(r"cannot load such file -- utf8-invalid-name-\xFF", message); + /// ``` + #[cfg(feature = "std")] + #[inline] + fn escape_debug_into(&self, f: &mut T) -> fmt::Result { + let buf = self.as_bstr(); + for (start, end, ch) in buf.char_indices() { + if ch == '\u{FFFD}' { + for byte in buf[start..end].as_bytes() { + write!(f, r"\x{:X}", byte)?; + } + } else { + write!(f, "{}", ch.escape_debug())?; + } + } + Ok(()) + } + /// Create an OS string slice from this byte string. /// /// On Unix, this always succeeds and is zero cost. On non-Unix systems,