Skip to content

Commit 632c7c9

Browse files
committed
Add display method to OsStr
Add `display` method to `OsStr` for lossy display of an `OsStr` which may contain invalid unicode. Invalid Unicode sequences are replaced with `U+FFFD REPLACEMENT CHARACTER`. This change also makes the `std::ffi::os_str` module public.
1 parent 8424f8e commit 632c7c9

File tree

3 files changed

+72
-9
lines changed

3 files changed

+72
-9
lines changed

library/std/src/ffi/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ pub use core::ffi::FromBytesUntilNulError;
162162
pub use core::ffi::{CStr, FromBytesWithNulError};
163163

164164
#[stable(feature = "rust1", since = "1.0.0")]
165+
#[doc(inline)]
165166
pub use self::os_str::{OsStr, OsString};
166167

167168
#[stable(feature = "core_ffi_c", since = "1.64.0")]
@@ -181,4 +182,5 @@ pub use core::ffi::c_void;
181182
)]
182183
pub use core::ffi::{VaList, VaListImpl};
183184

184-
mod os_str;
185+
#[unstable(feature = "os_str_display", issue = "120048")]
186+
pub mod os_str;

library/std/src/ffi/os_str.rs

+64-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! The [`OsStr`] and [`OsString`] types and associated utilities.
2+
13
#[cfg(test)]
24
mod tests;
35

@@ -1173,6 +1175,32 @@ impl OsStr {
11731175
pub fn eq_ignore_ascii_case<S: AsRef<OsStr>>(&self, other: S) -> bool {
11741176
self.inner.eq_ignore_ascii_case(&other.as_ref().inner)
11751177
}
1178+
1179+
/// Returns an object that implements [`Display`] for safely printing an
1180+
/// [`OsStr`] that may contain non-Unicode data. This may perform lossy
1181+
/// conversion, depending on the platform. If you would like an
1182+
/// implementation which escapes the [`OsStr`] please use [`Debug`]
1183+
/// instead.
1184+
///
1185+
/// [`Display`]: fmt::Display
1186+
/// [`Debug`]: fmt::Debug
1187+
///
1188+
/// # Examples
1189+
///
1190+
/// ```
1191+
/// #![feature(os_str_display)]
1192+
/// use std::ffi::OsStr;
1193+
///
1194+
/// let s = OsStr::new("Hello, world!");
1195+
/// println!("{}", s.display());
1196+
/// ```
1197+
#[unstable(feature = "os_str_display", issue = "120048")]
1198+
#[must_use = "this does not display the `OsStr`; \
1199+
it returns an object that can be displayed"]
1200+
#[inline]
1201+
pub fn display(&self) -> Display<'_> {
1202+
Display { os_str: self }
1203+
}
11761204
}
11771205

11781206
#[stable(feature = "box_from_os_str", since = "1.17.0")]
@@ -1467,9 +1495,42 @@ impl fmt::Debug for OsStr {
14671495
}
14681496
}
14691497

1470-
impl OsStr {
1471-
pub(crate) fn display(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1472-
fmt::Display::fmt(&self.inner, formatter)
1498+
/// Helper struct for safely printing an [`OsStr`] with [`format!`] and `{}`.
1499+
///
1500+
/// An [`OsStr`] might contain non-Unicode data. This `struct` implements the
1501+
/// [`Display`] trait in a way that mitigates that. It is created by the
1502+
/// [`display`](OsStr::display) method on [`OsStr`]. This may perform lossy
1503+
/// conversion, depending on the platform. If you would like an implementation
1504+
/// which escapes the [`OsStr`] please use [`Debug`] instead.
1505+
///
1506+
/// # Examples
1507+
///
1508+
/// ```
1509+
/// #![feature(os_str_display)]
1510+
/// use std::ffi::OsStr;
1511+
///
1512+
/// let s = OsStr::new("Hello, world!");
1513+
/// println!("{}", s.display());
1514+
/// ```
1515+
///
1516+
/// [`Display`]: fmt::Display
1517+
/// [`format!`]: crate::format
1518+
#[unstable(feature = "os_str_display", issue = "120048")]
1519+
pub struct Display<'a> {
1520+
os_str: &'a OsStr,
1521+
}
1522+
1523+
#[unstable(feature = "os_str_display", issue = "120048")]
1524+
impl fmt::Debug for Display<'_> {
1525+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1526+
fmt::Debug::fmt(&self.os_str, f)
1527+
}
1528+
}
1529+
1530+
#[unstable(feature = "os_str_display", issue = "120048")]
1531+
impl fmt::Display for Display<'_> {
1532+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1533+
fmt::Display::fmt(&self.os_str.inner, f)
14731534
}
14741535
}
14751536

library/std/src/path.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ use crate::rc::Rc;
8484
use crate::str::FromStr;
8585
use crate::sync::Arc;
8686

87-
use crate::ffi::{OsStr, OsString};
87+
use crate::ffi::{os_str, OsStr, OsString};
8888
use crate::sys;
8989
use crate::sys::path::{is_sep_byte, is_verbatim_sep, parse_prefix, MAIN_SEP_STR};
9090

@@ -2725,7 +2725,7 @@ impl Path {
27252725
it returns an object that can be displayed"]
27262726
#[inline]
27272727
pub fn display(&self) -> Display<'_> {
2728-
Display { path: self }
2728+
Display { inner: self.inner.display() }
27292729
}
27302730

27312731
/// Queries the file system to get information about a file, directory, etc.
@@ -3032,20 +3032,20 @@ impl fmt::Debug for Path {
30323032
/// [`format!`]: crate::format
30333033
#[stable(feature = "rust1", since = "1.0.0")]
30343034
pub struct Display<'a> {
3035-
path: &'a Path,
3035+
inner: os_str::Display<'a>,
30363036
}
30373037

30383038
#[stable(feature = "rust1", since = "1.0.0")]
30393039
impl fmt::Debug for Display<'_> {
30403040
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3041-
fmt::Debug::fmt(&self.path, f)
3041+
fmt::Debug::fmt(&self.inner, f)
30423042
}
30433043
}
30443044

30453045
#[stable(feature = "rust1", since = "1.0.0")]
30463046
impl fmt::Display for Display<'_> {
30473047
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3048-
self.path.inner.display(f)
3048+
fmt::Display::fmt(&self.inner, f)
30493049
}
30503050
}
30513051

0 commit comments

Comments
 (0)