From 68efea08fa1cf800b3b76683992ec77a89323d53 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Tue, 26 Jul 2016 01:39:54 +0200 Subject: [PATCH] Restore `char::escape_default` and add `char::escape` instead --- src/libcollections/lib.rs | 1 + src/libcollections/str.rs | 8 ++++++ src/libcollectionstest/str.rs | 16 +++++++++++- src/libcore/char.rs | 38 +++++++++++++++++++++++++++- src/libcore/fmt/mod.rs | 4 +-- src/libcoretest/char.rs | 47 +++++++++++++++++++++++++++++++++-- src/librustc_unicode/char.rs | 37 ++++++++++++++++++++++++++- src/librustc_unicode/lib.rs | 1 + 8 files changed, 145 insertions(+), 7 deletions(-) diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index f027d074cb6..333219bc5e5 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -33,6 +33,7 @@ #![feature(allow_internal_unstable)] #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(char_escape)] #![feature(core_intrinsics)] #![feature(dropck_parametricity)] #![feature(fmt_internals)] diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 55308a46f0a..a63ea9d3ec7 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -1697,6 +1697,14 @@ impl str { return s; } + /// Escapes each char in `s` with `char::escape`. + #[unstable(feature = "str_escape", + reason = "return type may change to be an iterator", + issue = "27791")] + pub fn escape(&self) -> String { + self.chars().flat_map(|c| c.escape()).collect() + } + /// Escapes each char in `s` with `char::escape_default`. #[unstable(feature = "str_escape", reason = "return type may change to be an iterator", diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index 4d85c9d545e..870f8a3a1ec 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -704,7 +704,7 @@ fn test_escape_unicode() { } #[test] -fn test_escape_default() { +fn test_escape() { assert_eq!("abc".escape_default(), "abc"); assert_eq!("a c".escape_default(), "a c"); assert_eq!("éèê".escape_default(), "éèê"); @@ -717,6 +717,20 @@ fn test_escape_default() { assert_eq!("\u{10d4ea}\r".escape_default(), "\\u{10d4ea}\\r"); } +#[test] +fn test_escape_default() { + assert_eq!("abc".escape_default(), "abc"); + assert_eq!("a c".escape_default(), "a c"); + assert_eq!("éèê".escape_default(), "\\u{e9}\\u{e8}\\u{ea}"); + assert_eq!("\r\n\t".escape_default(), "\\r\\n\\t"); + assert_eq!("'\"\\".escape_default(), "\\'\\\"\\\\"); + assert_eq!("\u{7f}\u{ff}".escape_default(), "\\u{7f}\\u{ff}"); + assert_eq!("\u{100}\u{ffff}".escape_default(), "\\u{100}\\u{ffff}"); + assert_eq!("\u{10000}\u{10ffff}".escape_default(), "\\u{10000}\\u{10ffff}"); + assert_eq!("ab\u{200b}".escape_default(), "ab\\u{200b}"); + assert_eq!("\u{10d4ea}\r".escape_default(), "\\u{10d4ea}\\r"); +} + #[test] fn test_total_ord() { assert_eq!("1234".cmp("123"), Greater); diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 0d39217bd72..3e435b47110 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -264,6 +264,8 @@ pub trait CharExt { fn escape_unicode(self) -> EscapeUnicode; #[stable(feature = "core", since = "1.6.0")] fn escape_default(self) -> EscapeDefault; + #[unstable(feature = "char_escape", issue = "0")] + fn escape(self) -> Escape; #[stable(feature = "core", since = "1.6.0")] fn len_utf8(self) -> usize; #[stable(feature = "core", since = "1.6.0")] @@ -316,6 +318,19 @@ impl CharExt for char { #[inline] fn escape_default(self) -> EscapeDefault { + let init_state = match self { + '\t' => EscapeDefaultState::Backslash('t'), + '\r' => EscapeDefaultState::Backslash('r'), + '\n' => EscapeDefaultState::Backslash('n'), + '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), + '\x20' ... '\x7e' => EscapeDefaultState::Char(self), + _ => EscapeDefaultState::Unicode(self.escape_unicode()) + }; + EscapeDefault { state: init_state } + } + + #[inline] + fn escape(self) -> Escape { let init_state = match self { '\t' => EscapeDefaultState::Backslash('t'), '\r' => EscapeDefaultState::Backslash('r'), @@ -324,7 +339,7 @@ impl CharExt for char { c if is_printable(c) => EscapeDefaultState::Char(c), c => EscapeDefaultState::Unicode(c.escape_unicode()), }; - EscapeDefault { state: init_state } + Escape(EscapeDefault { state: init_state }) } #[inline] @@ -601,6 +616,27 @@ impl ExactSizeIterator for EscapeDefault { } } +/// An iterator that yields the literal escape code of a `char`. +/// +/// This `struct` is created by the [`escape()`] method on [`char`]. See its +/// documentation for more. +/// +/// [`escape()`]: ../../std/primitive.char.html#method.escape +/// [`char`]: ../../std/primitive.char.html +#[unstable(feature = "char_escape", issue = "0")] +#[derive(Clone, Debug)] +pub struct Escape(EscapeDefault); + +#[unstable(feature = "char_escape", issue = "0")] +impl Iterator for Escape { + type Item = char; + fn next(&mut self) -> Option { self.0.next() } + fn size_hint(&self) -> (usize, Option) { self.0.size_hint() } +} + +#[unstable(feature = "char_escape", issue = "0")] +impl ExactSizeIterator for Escape { } + /// An iterator over `u8` entries represending the UTF-8 encoding of a `char` /// value. /// diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index e5eb8f21382..3bcdce57af0 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1383,7 +1383,7 @@ impl Debug for str { f.write_char('"')?; let mut from = 0; for (i, c) in self.char_indices() { - let esc = c.escape_default(); + let esc = c.escape(); // If char needs escaping, flush backlog so far and write, else skip if esc.len() != 1 { f.write_str(&self[from..i])?; @@ -1409,7 +1409,7 @@ impl Display for str { impl Debug for char { fn fmt(&self, f: &mut Formatter) -> Result { f.write_char('\'')?; - for c in self.escape_default() { + for c in self.escape() { f.write_char(c)? } f.write_char('\'') diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs index e01f83ed70a..ec757b0b5d3 100644 --- a/src/libcoretest/char.rs +++ b/src/libcoretest/char.rs @@ -124,9 +124,9 @@ fn test_is_digit() { } #[test] -fn test_escape_default() { +fn test_escape() { fn string(c: char) -> String { - c.escape_default().collect() + c.escape().collect() } let s = string('\n'); assert_eq!(s, "\\n"); @@ -166,6 +166,49 @@ fn test_escape_default() { assert_eq!(s, "\\u{100000}"); } +#[test] +fn test_escape_default() { + fn string(c: char) -> String { + c.escape_default().collect() + } + let s = string('\n'); + assert_eq!(s, "\\n"); + let s = string('\r'); + assert_eq!(s, "\\r"); + let s = string('\''); + assert_eq!(s, "\\'"); + let s = string('"'); + assert_eq!(s, "\\\""); + let s = string(' '); + assert_eq!(s, " "); + let s = string('a'); + assert_eq!(s, "a"); + let s = string('~'); + assert_eq!(s, "~"); + let s = string('é'); + assert_eq!(s, "\\u{e9}"); + let s = string('\x00'); + assert_eq!(s, "\\u{0}"); + let s = string('\x1f'); + assert_eq!(s, "\\u{1f}"); + let s = string('\x7f'); + assert_eq!(s, "\\u{7f}"); + let s = string('\u{80}'); + assert_eq!(s, "\\u{80}"); + let s = string('\u{ff}'); + assert_eq!(s, "\\u{ff}"); + let s = string('\u{11b}'); + assert_eq!(s, "\\u{11b}"); + let s = string('\u{1d4b6}'); + assert_eq!(s, "\\u{1d4b6}"); + let s = string('\u{200b}'); // zero width space + assert_eq!(s, "\\u{200b}"); + let s = string('\u{e000}'); // private use 1 + assert_eq!(s, "\\u{e000}"); + let s = string('\u{100000}'); // private use 2 + assert_eq!(s, "\\u{100000}"); +} + #[test] fn test_escape_unicode() { fn string(c: char) -> String { c.escape_unicode().collect() } diff --git a/src/librustc_unicode/char.rs b/src/librustc_unicode/char.rs index 7445ff94eb5..683d5289ab5 100644 --- a/src/librustc_unicode/char.rs +++ b/src/librustc_unicode/char.rs @@ -36,7 +36,7 @@ use tables::{conversions, derived_property, general_category, property}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::char::{MAX, from_digit, from_u32, from_u32_unchecked}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::char::{EncodeUtf16, EncodeUtf8, EscapeDefault, EscapeUnicode}; +pub use core::char::{EncodeUtf16, EncodeUtf8, Escape, EscapeDefault, EscapeUnicode}; // unstable reexports #[unstable(feature = "decode_utf8", issue = "33906")] @@ -267,6 +267,41 @@ impl char { C::escape_unicode(self) } + /// Returns an iterator that yields the literal escape code of a `char`. + /// + /// This will escape the characters similar to the `Debug` implementations + /// of `str` or `char`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// for i in '\n'.escape_default() { + /// println!("{}", i); + /// } + /// ``` + /// + /// This prints: + /// + /// ```text + /// \ + /// n + /// ``` + /// + /// Collecting into a `String`: + /// + /// ``` + /// let quote: String = '\n'.escape_default().collect(); + /// + /// assert_eq!(quote, "\\n"); + /// ``` + #[unstable(feature = "char_escape", issue = "0")] + #[inline] + pub fn escape(self) -> Escape { + C::escape(self) + } + /// Returns an iterator that yields the literal escape code of a `char`. /// /// The default is chosen with a bias toward producing literals that are diff --git a/src/librustc_unicode/lib.rs b/src/librustc_unicode/lib.rs index f91a754ab57..8c91d3b6a92 100644 --- a/src/librustc_unicode/lib.rs +++ b/src/librustc_unicode/lib.rs @@ -32,6 +32,7 @@ #![cfg_attr(not(stage0), deny(warnings))] #![no_std] +#![feature(char_escape)] #![feature(core_char_ext)] #![feature(decode_utf8)] #![feature(lang_items)]