Skip to content

Commit

Permalink
Add display method to OsStr
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
riverbl committed Jan 17, 2024
1 parent 6ae4cfb commit feb0a9b
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 11 deletions.
2 changes: 1 addition & 1 deletion library/alloc/src/string.rs
Expand Up @@ -196,7 +196,7 @@ use crate::vec::Vec;
/// for [`SliceIndex<str>`] for more details on string slicing. For a non-panicking
/// version of string slicing, see [`get`].
///
/// [`OsString`]: ../../std/ffi/struct.OsString.html "ffi::OsString"
/// [`OsString`]: ../../std/ffi/os_str/struct.OsString.html "ffi::OsString"
/// [`SliceIndex<str>`]: core::slice::SliceIndex
/// [`as_bytes()`]: str::as_bytes
/// [`get`]: str::get
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/iter/traits/iterator.rs
Expand Up @@ -514,7 +514,7 @@ pub trait Iterator {
/// ```
///
/// [`once`]: crate::iter::once
/// [`OsStr`]: ../../std/ffi/struct.OsStr.html
/// [`OsStr`]: ../../std/ffi/os_str/struct.OsStr.html
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_do_not_const_check]
Expand Down
3 changes: 2 additions & 1 deletion library/std/src/ffi/mod.rs
Expand Up @@ -181,4 +181,5 @@ pub use core::ffi::c_void;
)]
pub use core::ffi::{VaList, VaListImpl};

mod os_str;
#[unstable(feature = "os_str_display", issue = "120048")]
pub mod os_str;
67 changes: 64 additions & 3 deletions library/std/src/ffi/os_str.rs
@@ -1,3 +1,5 @@
//! The [`OsStr`] and [`OsString`] types and associated utilities.

#[cfg(test)]
mod tests;

Expand Down Expand Up @@ -1173,6 +1175,32 @@ impl OsStr {
pub fn eq_ignore_ascii_case<S: AsRef<OsStr>>(&self, other: S) -> bool {
self.inner.eq_ignore_ascii_case(&other.as_ref().inner)
}

/// Returns an object that implements [`Display`] for safely printing an
/// [`OsStr`] that may contain non-Unicode data. This may perform lossy
/// conversion, depending on the platform. If you would like an
/// implementation which escapes the [`OsStr`] please use [`Debug`]
/// instead.
///
/// [`Display`]: fmt::Display
/// [`Debug`]: fmt::Debug
///
/// # Examples
///
/// ```
/// #![feature(os_str_display)]
/// use std::ffi::OsStr;
///
/// let s = OsStr::new("Hello, world!");
/// println!("{}", s.display());
/// ```
#[unstable(feature = "os_str_display", issue = "120048")]
#[must_use = "this does not display the osstr, \
it returns an object that can be displayed"]
#[inline]
pub fn display(&self) -> Display<'_> {
Display { os_str: self }
}
}

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

impl OsStr {
pub(crate) fn display(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.inner, formatter)
/// Helper struct for safely printing an [`OsStr`] with [`format!`] and `{}`.
///
/// An [`OsStr`] might contain non-Unicode data. This `struct` implements the
/// [`Display`] trait in a way that mitigates that. It is created by the
/// [`display`](OsStr::display) method on [`OsStr`]. This may perform lossy
/// conversion, depending on the platform. If you would like an implementation
/// which escapes the [`OsStr`] please use [`Debug`] instead.
///
/// # Examples
///
/// ```
/// #![feature(os_str_display)]
/// use std::ffi::OsStr;
///
/// let s = OsStr::new("Hello, world!");
/// println!("{}", s.display());
/// ```
///
/// [`Display`]: fmt::Display
/// [`format!`]: crate::format
#[unstable(feature = "os_str_display", issue = "120048")]
pub struct Display<'a> {
os_str: &'a OsStr,
}

#[unstable(feature = "os_str_display", issue = "120048")]
impl fmt::Debug for Display<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.os_str, f)
}
}

#[unstable(feature = "os_str_display", issue = "120048")]
impl fmt::Display for Display<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.os_str.inner, f)
}
}

Expand Down
10 changes: 5 additions & 5 deletions library/std/src/path.rs
Expand Up @@ -84,7 +84,7 @@ use crate::rc::Rc;
use crate::str::FromStr;
use crate::sync::Arc;

use crate::ffi::{OsStr, OsString};
use crate::ffi::{os_str, OsStr, OsString};
use crate::sys;
use crate::sys::path::{is_sep_byte, is_verbatim_sep, parse_prefix, MAIN_SEP_STR};

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

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

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

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

Expand Down

0 comments on commit feb0a9b

Please sign in to comment.