-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Write escaped string into a buffer #34
Comments
This looks reasonableish, yes. I'd like to see its API cleaned up a bit. Namely:
Thanks for the good idea! |
Thanks. I’ll work on a PR tonight. |
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.
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`.
Apologies of leading you down the wrong path here, but as noted in #37, I think we should add APIs that mirror std for this as closely as possible. In particular, we should be able to have an This is harder to implement, but I think looking at std should give some inspiration. Note that there is an important difference between bstr and std here. std has an |
I'm sharing this because I believe that it's a step towards @BurntSushi 's proposed solution (just needs mapping from enum DebugItem<'a> {
NullByte,
Escaped(core::char::EscapeDebug),
HexedChar(char),
HexedBytes(&'a [u8]),
}
impl<'a> std::fmt::Display for DebugItem<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DebugItem::NullByte => write!(f, "\\0"),
DebugItem::Escaped(escaped) => write!(f, "{}", escaped),
DebugItem::HexedBytes(bytes) => {
for &b in bytes.as_bytes() {
write!(f, r"\x{:02X}", b)?;
}
Ok(())
},
DebugItem::HexedChar(ch) => write!(f, "\\x{:02x}", *ch as u32),
}
}
}
fn iter_debug_items<'a>(debug_str: &'a BStr) -> impl Iterator<Item = DebugItem<'a>> {
debug_str.char_indices()
.map(|(s, e, ch)| {
match ch {
'\0' => DebugItem::NullByte,
'\u{FFFD}' => {
let bytes = debug_str[s..e].as_bytes();
if bytes == b"\xEF\xBF\xBD" {
DebugItem::Escaped(ch.escape_debug())
} else {
DebugItem::HexedBytes(bytes)
}
}
// ASCII control characters except \0, \n, \r, \t
'\x01'..='\x08'
| '\x0b'
| '\x0c'
| '\x0e'..='\x19'
| '\x7f' => {
DebugItem::HexedChar(ch)
}
'\n' | '\r' | '\t' | _ => {
DebugItem::Escaped(ch.escape_debug())
}
}
})
}
impl fmt::Debug for BStr {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "\"")?;
for item in iter_debug_items(self) {
write!(f, "{}", item)?;
}
write!(f, "\"")?;
Ok(())
}
} |
Hi @BurntSushi,
I'm using
bstr
for turning aVec<u8>
-like structure into debug strings and error messages. Specifically, I'm working on a Ruby implementation. In RubyString
is aVec<u8>
with a default UTF-8 encoding with no guarantees that the bytes are actually valid UTF-8.bstr
is the means by which I interpret these byte vectors as UTF-8 the best I can.The
fmt::Debug
implementation on&BStr
is very close to what I'd like, but I cannot use it because it wraps the escaped string in quotes. I need control of the output since these strings are being but into error messages.I've put together this function for writing the escaped representation to an arbitrary
fmt::Write
(cribbing heavily form thefmt::Debug
impl on&BStr
).Here's an example usage:
I'm trying to generate a message like this:
Is this patch something you would consider upstreaming?
The text was updated successfully, but these errors were encountered: