Skip to content

Commit

Permalink
Add ExtSlice::escape_debug_into
Browse files Browse the repository at this point in the history
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 BurntSushiGH-34.

This change reimplements `fmt::Debug` for `BStr` with
`ExtSlice::escape_debug_into`.
  • Loading branch information
lopopolo committed Feb 17, 2020
1 parent f8a6c70 commit c266d44
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 10 deletions.
40 changes: 40 additions & 0 deletions src/ext_slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::ffi::OsStr;
use std::path::Path;

use core::cmp;
use core::fmt;
use core::ops;
use core::ptr;
use core::slice;
Expand Down Expand Up @@ -429,6 +430,45 @@ pub trait ByteSlice: Sealed {
}
}

/// Write a UTF-8 debug representation of this byte slice into the given
/// writer.
///
/// This method encodes a bytes slice into a UTF-8 valid representation by
/// writing invalid sequences as `\xXX` escape codes.
///
/// This method also escapes UTF-8 valid characters like `\n` and `\t`.
///
/// # 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);
/// ```
///
/// # Errors
///
/// This method only returns an error when the given writer returns an
/// error.
#[inline]
fn escape_debug_into<W: fmt::Write>(&self, mut f: W) -> fmt::Result {
for (start, end, ch) in self.char_indices() {
if ch == '\u{FFFD}' {
for byte in &self.as_bytes()[start..end] {
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,
Expand Down
12 changes: 2 additions & 10 deletions src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,17 +326,9 @@ mod bstr {

impl fmt::Debug for BStr {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, mut f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "\"")?;
for (s, e, ch) in self.char_indices() {
if ch == '\u{FFFD}' {
for &b in self[s..e].as_bytes() {
write!(f, r"\x{:X}", b)?;
}
} else {
write!(f, "{}", ch.escape_debug())?;
}
}
self.escape_debug_into(&mut f)?;
write!(f, "\"")?;
Ok(())
}
Expand Down

0 comments on commit c266d44

Please sign in to comment.