diff --git a/src/libcore/char.rs b/src/libcore/char.rs index dfcbfd476bc3f..ccce2ad22ddc2 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -185,9 +185,7 @@ impl CharExt for char { '\t' => EscapeDefaultState::Backslash('t'), '\r' => EscapeDefaultState::Backslash('r'), '\n' => EscapeDefaultState::Backslash('n'), - '\\' => EscapeDefaultState::Backslash('\\'), - '\'' => EscapeDefaultState::Backslash('\''), - '"' => EscapeDefaultState::Backslash('"'), + '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), '\x20' ... '\x7e' => EscapeDefaultState::Char(self), _ => EscapeDefaultState::Unicode(self.escape_unicode()) }; @@ -344,6 +342,22 @@ impl Iterator for EscapeUnicode { EscapeUnicodeState::Done => None, } } + + fn size_hint(&self) -> (usize, Option) { + let mut n = 0; + while (self.c as usize) >> (4 * (n + 1)) != 0 { + n += 1; + } + let n = match self.state { + EscapeUnicodeState::Backslash => n + 5, + EscapeUnicodeState::Type => n + 4, + EscapeUnicodeState::LeftBrace => n + 3, + EscapeUnicodeState::Value(offset) => offset + 2, + EscapeUnicodeState::RightBrace => 1, + EscapeUnicodeState::Done => 0, + }; + (n, Some(n)) + } } /// An iterator over the characters that represent a `char`, escaped @@ -377,7 +391,16 @@ impl Iterator for EscapeDefault { Some(c) } EscapeDefaultState::Done => None, - EscapeDefaultState::Unicode(ref mut iter) => iter.next() + EscapeDefaultState::Unicode(ref mut iter) => iter.next(), + } + } + + fn size_hint(&self) -> (usize, Option) { + match self.state { + EscapeDefaultState::Char(_) => (1, Some(1)), + EscapeDefaultState::Backslash(_) => (2, Some(2)), + EscapeDefaultState::Unicode(ref iter) => iter.size_hint(), + EscapeDefaultState::Done => (0, Some(0)), } } } diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index db7e6d3006f3f..e226b5f2ca8fc 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1310,11 +1310,21 @@ impl Display for bool { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for str { fn fmt(&self, f: &mut Formatter) -> Result { - try!(write!(f, "\"")); - for c in self.chars().flat_map(|c| c.escape_default()) { - try!(f.write_char(c)) + try!(f.write_char('"')); + let mut from = 0; + for (i, c) in self.char_indices() { + let esc = c.escape_default(); + // If char needs escaping, flush backlog so far and write, else skip + if esc.size_hint() != (1, Some(1)) { + try!(f.write_str(&self[from..i])); + for c in esc { + try!(f.write_char(c)); + } + from = i + c.len_utf8(); + } } - write!(f, "\"") + try!(f.write_str(&self[from..])); + f.write_char('"') } } @@ -1328,12 +1338,11 @@ impl Display for str { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for char { fn fmt(&self, f: &mut Formatter) -> Result { - use char::CharExt; - try!(write!(f, "'")); + try!(f.write_char('\'')); for c in self.escape_default() { try!(f.write_char(c)) } - write!(f, "'") + f.write_char('\'') } } diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index c8adb6ccc0ab8..2cc033b8a46e1 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -74,6 +74,10 @@ pub fn main() { t!(format!("{:?}", 10_usize), "10"); t!(format!("{:?}", "true"), "\"true\""); t!(format!("{:?}", "foo\nbar"), "\"foo\\nbar\""); + t!(format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"), + r#""foo\n\"bar\"\r\n\'baz\'\t\\qux\\""#); + t!(format!("{:?}", "foo\0bar\x01baz\u{3b1}q\u{75}x"), + r#""foo\u{0}bar\u{1}baz\u{3b1}qux""#); t!(format!("{:o}", 10_usize), "12"); t!(format!("{:x}", 10_usize), "a"); t!(format!("{:X}", 10_usize), "A");