Avoid allocations in Debug for os_str

Fixes #38879
This commit is contained in:
Stepan Koltsov 2017-06-12 22:21:53 +03:00
parent ea149b8571
commit ac96fd7787
6 changed files with 117 additions and 35 deletions

View File

@ -9,7 +9,7 @@
// except according to those terms. // except according to those terms.
use borrow::{Borrow, Cow}; use borrow::{Borrow, Cow};
use fmt::{self, Debug}; use fmt;
use mem; use mem;
use ops; use ops;
use cmp; use cmp;
@ -312,8 +312,8 @@ impl Default for OsString {
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl Debug for OsString { impl fmt::Debug for OsString {
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, formatter) fmt::Debug::fmt(&**self, formatter)
} }
} }
@ -669,9 +669,15 @@ impl Hash for OsStr {
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl Debug for OsStr { impl fmt::Debug for OsStr {
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
self.inner.fmt(formatter) fmt::Debug::fmt(&self.inner, formatter)
}
}
impl OsStr {
pub(crate) fn display(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.inner, formatter)
} }
} }

View File

@ -2281,8 +2281,8 @@ impl AsRef<OsStr> for Path {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Debug for Path { impl fmt::Debug for Path {
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
self.inner.fmt(formatter) fmt::Debug::fmt(&self.inner, formatter)
} }
} }
@ -2314,14 +2314,14 @@ pub struct Display<'a> {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<'a> fmt::Debug for Display<'a> { impl<'a> fmt::Debug for Display<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.path.to_string_lossy(), f) fmt::Debug::fmt(&self.path, f)
} }
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<'a> fmt::Display for Display<'a> { impl<'a> fmt::Display for Display<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.path.to_string_lossy(), f) self.path.inner.display(f)
} }
} }

View File

@ -12,10 +12,11 @@
/// a `Vec<u8>`/`[u8]`. /// a `Vec<u8>`/`[u8]`.
use borrow::Cow; use borrow::Cow;
use fmt::{self, Debug}; use fmt;
use str; use str;
use mem; use mem;
use sys_common::{AsInner, IntoInner}; use sys_common::{AsInner, IntoInner};
use std_unicode::lossy::Utf8Lossy;
#[derive(Clone, Hash)] #[derive(Clone, Hash)]
pub struct Buf { pub struct Buf {
@ -26,15 +27,27 @@ pub struct Slice {
pub inner: [u8] pub inner: [u8]
} }
impl Debug for Slice { impl fmt::Debug for Slice {
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
self.to_string_lossy().fmt(formatter) fmt::Debug::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter)
} }
} }
impl Debug for Buf { impl fmt::Display for Slice {
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
self.as_slice().fmt(formatter) fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter)
}
}
impl fmt::Debug for Buf {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self.as_slice(), formatter)
}
}
impl fmt::Display for Buf {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self.as_slice(), formatter)
} }
} }

View File

@ -12,10 +12,11 @@
/// a `Vec<u8>`/`[u8]`. /// a `Vec<u8>`/`[u8]`.
use borrow::Cow; use borrow::Cow;
use fmt::{self, Debug}; use fmt;
use str; use str;
use mem; use mem;
use sys_common::{AsInner, IntoInner}; use sys_common::{AsInner, IntoInner};
use std_unicode::lossy::Utf8Lossy;
#[derive(Clone, Hash)] #[derive(Clone, Hash)]
pub struct Buf { pub struct Buf {
@ -26,15 +27,27 @@ pub struct Slice {
pub inner: [u8] pub inner: [u8]
} }
impl Debug for Slice { impl fmt::Debug for Slice {
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
self.to_string_lossy().fmt(formatter) fmt::Debug::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter)
} }
} }
impl Debug for Buf { impl fmt::Display for Slice {
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
self.as_slice().fmt(formatter) fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter)
}
}
impl fmt::Debug for Buf {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self.as_slice(), formatter)
}
}
impl fmt::Display for Buf {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self.as_slice(), formatter)
} }
} }

View File

@ -12,7 +12,7 @@
/// wrapper around the "WTF-8" encoding; see the `wtf8` module for more. /// wrapper around the "WTF-8" encoding; see the `wtf8` module for more.
use borrow::Cow; use borrow::Cow;
use fmt::{self, Debug}; use fmt;
use sys_common::wtf8::{Wtf8, Wtf8Buf}; use sys_common::wtf8::{Wtf8, Wtf8Buf};
use mem; use mem;
use sys_common::{AsInner, IntoInner}; use sys_common::{AsInner, IntoInner};
@ -34,9 +34,15 @@ impl AsInner<Wtf8> for Buf {
} }
} }
impl Debug for Buf { impl fmt::Debug for Buf {
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
self.as_slice().fmt(formatter) fmt::Debug::fmt(self.as_slice(), formatter)
}
}
impl fmt::Display for Buf {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self.as_slice(), formatter)
} }
} }
@ -44,9 +50,15 @@ pub struct Slice {
pub inner: Wtf8 pub inner: Wtf8
} }
impl Debug for Slice { impl fmt::Debug for Slice {
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
self.inner.fmt(formatter) fmt::Debug::fmt(&self.inner, formatter)
}
}
impl fmt::Display for Slice {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.inner, formatter)
} }
} }

View File

@ -39,7 +39,7 @@ use slice;
use str; use str;
use sys_common::AsInner; use sys_common::AsInner;
const UTF8_REPLACEMENT_CHARACTER: &'static [u8] = b"\xEF\xBF\xBD"; const UTF8_REPLACEMENT_CHARACTER: &'static str = "\u{FFFD}";
/// A Unicode code point: from U+0000 to U+10FFFF. /// A Unicode code point: from U+0000 to U+10FFFF.
/// ///
@ -339,7 +339,7 @@ impl Wtf8Buf {
Some((surrogate_pos, _)) => { Some((surrogate_pos, _)) => {
pos = surrogate_pos + 3; pos = surrogate_pos + 3;
self.bytes[surrogate_pos..pos] self.bytes[surrogate_pos..pos]
.copy_from_slice(UTF8_REPLACEMENT_CHARACTER); .copy_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes());
}, },
None => return unsafe { String::from_utf8_unchecked(self.bytes) } None => return unsafe { String::from_utf8_unchecked(self.bytes) }
} }
@ -438,6 +438,30 @@ impl fmt::Debug for Wtf8 {
} }
} }
impl fmt::Display for Wtf8 {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
let wtf8_bytes = &self.bytes;
let mut pos = 0;
loop {
match self.next_surrogate(pos) {
Some((surrogate_pos, _)) => {
formatter.write_str(unsafe {
str::from_utf8_unchecked(&wtf8_bytes[pos .. surrogate_pos])
})?;
formatter.write_str(UTF8_REPLACEMENT_CHARACTER)?;
pos = surrogate_pos + 3;
},
None => {
formatter.write_str(unsafe {
str::from_utf8_unchecked(&wtf8_bytes[pos..])
})?;
return Ok(());
}
}
}
}
}
impl Wtf8 { impl Wtf8 {
/// Creates a WTF-8 slice from a UTF-8 `&str` slice. /// Creates a WTF-8 slice from a UTF-8 `&str` slice.
/// ///
@ -516,13 +540,13 @@ impl Wtf8 {
let wtf8_bytes = &self.bytes; let wtf8_bytes = &self.bytes;
let mut utf8_bytes = Vec::with_capacity(self.len()); let mut utf8_bytes = Vec::with_capacity(self.len());
utf8_bytes.extend_from_slice(&wtf8_bytes[..surrogate_pos]); utf8_bytes.extend_from_slice(&wtf8_bytes[..surrogate_pos]);
utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER); utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes());
let mut pos = surrogate_pos + 3; let mut pos = surrogate_pos + 3;
loop { loop {
match self.next_surrogate(pos) { match self.next_surrogate(pos) {
Some((surrogate_pos, _)) => { Some((surrogate_pos, _)) => {
utf8_bytes.extend_from_slice(&wtf8_bytes[pos .. surrogate_pos]); utf8_bytes.extend_from_slice(&wtf8_bytes[pos .. surrogate_pos]);
utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER); utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes());
pos = surrogate_pos + 3; pos = surrogate_pos + 3;
}, },
None => { None => {
@ -1200,6 +1224,20 @@ mod tests {
assert_eq!(string.to_string_lossy(), expected); assert_eq!(string.to_string_lossy(), expected);
} }
#[test]
fn wtf8_display() {
fn d(b: &[u8]) -> String {
format!("{}", &unsafe { Wtf8::from_bytes_unchecked(b) })
}
assert_eq!("", d("".as_bytes()));
assert_eq!("aé 💩", d("aé 💩".as_bytes()));
let mut string = Wtf8Buf::from_str("aé 💩");
string.push(CodePoint::from_u32(0xD800).unwrap());
assert_eq!("aé 💩<>", d(string.as_inner()));
}
#[test] #[test]
fn wtf8_encode_wide() { fn wtf8_encode_wide() {
let mut string = Wtf8Buf::from_str(""); let mut string = Wtf8Buf::from_str("");