Skip to content

Commit 742ca0c

Browse files
committed
std: Respect formatting flags for str-like OsStr
Historically many `Display` and `Debug` implementations for `OsStr`-like abstractions have gone through `String::from_utf8_lossy`, but this was updated in #42613 to use an internal `Utf8Lossy` abstraction instead. This had the unfortunate side effect of causing a regression (#43765) in code which relied on these `fmt` trait implementations respecting the various formatting flags specified. This commit opportunistically adds back interpretation of formatting trait flags in the "common case" where where `OsStr`-like "thing" is all valid utf-8 and can delegate to the formatting implementation for `str`. This doesn't entirely solve the regression as non-utf8 paths will format differently than they did before still (in that they will not respect formatting flags), but this should solve the regression for all "real world" use cases of paths and such. The door's also still open for handling these flags in the future! Closes #43765
1 parent f3cf206 commit 742ca0c

File tree

4 files changed

+29
-6
lines changed

4 files changed

+29
-6
lines changed

src/libstd/path.rs

+6
Original file line numberDiff line numberDiff line change
@@ -3953,4 +3953,10 @@ mod tests {
39533953
assert_eq!(path, path_buf);
39543954
assert!(path_buf.into_os_string().capacity() >= 15);
39553955
}
3956+
3957+
#[test]
3958+
fn display_format_flags() {
3959+
assert_eq!(format!("a{:#<5}b", Path::new("").display()), "a#####b");
3960+
assert_eq!(format!("a{:#<5}b", Path::new("a").display()), "aa####b");
3961+
}
39563962
}

src/libstd/sys_common/wtf8.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -452,10 +452,14 @@ impl fmt::Display for Wtf8 {
452452
pos = surrogate_pos + 3;
453453
},
454454
None => {
455-
formatter.write_str(unsafe {
455+
let s = unsafe {
456456
str::from_utf8_unchecked(&wtf8_bytes[pos..])
457-
})?;
458-
return Ok(());
457+
};
458+
if pos == 0 {
459+
return s.fmt(formatter)
460+
} else {
461+
return formatter.write_str(s)
462+
}
459463
}
460464
}
461465
}

src/libstd_unicode/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434

3535
#![feature(core_char_ext)]
3636
#![feature(str_internals)]
37-
#![feature(core_intrinsics)]
3837
#![feature(decode_utf8)]
3938
#![feature(fused)]
4039
#![feature(fn_traits)]

src/libstd_unicode/lossy.rs

+16-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use core::str as core_str;
1212
use core::fmt;
1313
use core::fmt::Write;
1414
use char;
15-
use core::intrinsics;
15+
use core::mem;
1616

1717

1818
/// Lossy UTF-8 string.
@@ -27,7 +27,7 @@ impl Utf8Lossy {
2727
}
2828

2929
pub fn from_bytes(bytes: &[u8]) -> &Utf8Lossy {
30-
unsafe { intrinsics::transmute(bytes) }
30+
unsafe { mem::transmute(bytes) }
3131
}
3232

3333
pub fn chunks(&self) -> Utf8LossyChunksIter {
@@ -153,7 +153,21 @@ impl<'a> Iterator for Utf8LossyChunksIter<'a> {
153153

154154
impl fmt::Display for Utf8Lossy {
155155
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
156+
// If we're the empty string then our iterator won't actually yield
157+
// anything, so perform the formatting manually
158+
if self.bytes.len() == 0 {
159+
return "".fmt(f)
160+
}
161+
156162
for Utf8LossyChunk { valid, broken } in self.chunks() {
163+
// If we successfully decoded the whole chunk as a valid string then
164+
// we can return a direct formatting of the string which will also
165+
// respect various formatting flags if possible.
166+
if valid.len() == self.bytes.len() {
167+
assert!(broken.is_empty());
168+
return valid.fmt(f)
169+
}
170+
157171
f.write_str(valid)?;
158172
if !broken.is_empty() {
159173
f.write_char(char::REPLACEMENT_CHARACTER)?;

0 commit comments

Comments
 (0)