diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index d5b19470e318b..b2eac4547ff64 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -716,6 +716,15 @@ impl fmt::Debug for CString { } } +/// Delegates to the [`CStr`] implementation of [`fmt::Display`], +/// showing invalid UTF-8 as the Unicode replacement character. +#[stable(feature = "cstr_display", since = "CURRENT_RUSTC_VERSION")] +impl fmt::Display for CString { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.as_c_str(), f) + } +} + #[stable(feature = "cstring_into", since = "1.7.0")] impl From for Vec { /// Converts a [`CString`] into a [Vec]<[u8]>. diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 85e87445a1b43..85c48ccdb89ac 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -168,6 +168,15 @@ impl fmt::Debug for CStr { } } +/// Behaves as if `self` were first lossily converted to a `str`, with +/// invalid UTF-8 presented as the Unicode replacement character: �. +#[stable(feature = "cstr_display", since = "CURRENT_RUSTC_VERSION")] +impl fmt::Display for CStr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(crate::bstr::ByteStr::from_bytes(self.to_bytes()), f) + } +} + #[stable(feature = "cstr_default", since = "1.10.0")] impl Default for &CStr { #[inline] diff --git a/library/coretests/tests/ffi/cstr.rs b/library/coretests/tests/ffi/cstr.rs index 0d85b22c585a1..b9f3d65dc02cd 100644 --- a/library/coretests/tests/ffi/cstr.rs +++ b/library/coretests/tests/ffi/cstr.rs @@ -19,3 +19,9 @@ fn debug() { let s = c"abc\x01\x02\n\xE2\x80\xA6\xFF"; assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#); } + +#[test] +fn display() { + let s = c"\xf0\x28\x8c\xbc"; + assert_eq!(format!("{s}"), "�(��"); +}