Skip to content

Commit a3a7203

Browse files
committed
Auto merge of #46798 - Diggsey:debug-osstr, r=dtolnay
Add lossless debug implementation for unix OsStrs Fixes #22766 Invalid utf8 byte sequences are replaced with `\xFF` style escape codes, while valid utf8 goes through the normal `Debug` implementation. This is necessarily different from the windows Debug implementation, which uses `\u{xxxx}` style escape sequences for unpaired surrogates, but both implementations are consistent in that they are both lossless, and display invalid sequences in the way most similar to existing language syntax. r? @dtolnay
2 parents dc39c31 + 8fac7d9 commit a3a7203

File tree

5 files changed

+63
-3
lines changed

5 files changed

+63
-3
lines changed

Diff for: src/libstd/sys/redox/os_str.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use mem;
1818
use rc::Rc;
1919
use sync::Arc;
2020
use sys_common::{AsInner, IntoInner};
21+
use sys_common::bytestring::debug_fmt_bytestring;
2122
use std_unicode::lossy::Utf8Lossy;
2223

2324
#[derive(Clone, Hash)]
@@ -31,7 +32,7 @@ pub struct Slice {
3132

3233
impl fmt::Debug for Slice {
3334
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
34-
fmt::Debug::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter)
35+
debug_fmt_bytestring(&self.inner, formatter)
3536
}
3637
}
3738

Diff for: src/libstd/sys/unix/os_str.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use mem;
1818
use rc::Rc;
1919
use sync::Arc;
2020
use sys_common::{AsInner, IntoInner};
21+
use sys_common::bytestring::debug_fmt_bytestring;
2122
use std_unicode::lossy::Utf8Lossy;
2223

2324
#[derive(Clone, Hash)]
@@ -31,7 +32,7 @@ pub struct Slice {
3132

3233
impl fmt::Debug for Slice {
3334
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
34-
fmt::Debug::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter)
35+
debug_fmt_bytestring(&self.inner, formatter)
3536
}
3637
}
3738

Diff for: src/libstd/sys/wasm/os_str.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use mem;
1818
use rc::Rc;
1919
use sync::Arc;
2020
use sys_common::{AsInner, IntoInner};
21+
use sys_common::bytestring::debug_fmt_bytestring;
2122
use std_unicode::lossy::Utf8Lossy;
2223

2324
#[derive(Clone, Hash)]
@@ -31,7 +32,7 @@ pub struct Slice {
3132

3233
impl fmt::Debug for Slice {
3334
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
34-
fmt::Debug::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter)
35+
debug_fmt_bytestring(&self.inner, formatter)
3536
}
3637
}
3738

Diff for: src/libstd/sys_common/bytestring.rs

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![allow(dead_code)]
12+
13+
use fmt::{Formatter, Result, Write};
14+
use std_unicode::lossy::{Utf8Lossy, Utf8LossyChunk};
15+
16+
pub fn debug_fmt_bytestring(slice: &[u8], f: &mut Formatter) -> Result {
17+
// Writes out a valid unicode string with the correct escape sequences
18+
fn write_str_escaped(f: &mut Formatter, s: &str) -> Result {
19+
for c in s.chars().flat_map(|c| c.escape_debug()) {
20+
f.write_char(c)?
21+
}
22+
Ok(())
23+
}
24+
25+
f.write_str("\"")?;
26+
for Utf8LossyChunk { valid, broken } in Utf8Lossy::from_bytes(slice).chunks() {
27+
write_str_escaped(f, valid)?;
28+
for b in broken {
29+
write!(f, "\\x{:02X}", b)?;
30+
}
31+
}
32+
f.write_str("\"")
33+
}
34+
35+
#[cfg(test)]
36+
mod tests {
37+
use super::*;
38+
use fmt::{Formatter, Result, Debug};
39+
40+
#[test]
41+
fn smoke() {
42+
struct Helper<'a>(&'a [u8]);
43+
44+
impl<'a> Debug for Helper<'a> {
45+
fn fmt(&self, f: &mut Formatter) -> Result {
46+
debug_fmt_bytestring(self.0, f)
47+
}
48+
}
49+
50+
let input = b"\xF0hello,\tworld";
51+
let expected = r#""\xF0hello,\tworld""#;
52+
let output = format!("{:?}", Helper(input));
53+
54+
assert!(output == expected);
55+
}
56+
}

Diff for: src/libstd/sys_common/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub mod thread_info;
4343
pub mod thread_local;
4444
pub mod util;
4545
pub mod wtf8;
46+
pub mod bytestring;
4647

4748
cfg_if! {
4849
if #[cfg(any(target_os = "redox", target_os = "l4re"))] {

0 commit comments

Comments
 (0)