Restore char::escape_default and add char::escape instead

This commit is contained in:
Tobias Bucher 2016-07-26 01:39:54 +02:00
parent 0685900fbd
commit 68efea08fa
8 changed files with 145 additions and 7 deletions

View File

@ -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)]

View File

@ -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",

View File

@ -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);

View File

@ -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<char> { self.0.next() }
fn size_hint(&self) -> (usize, Option<usize>) { 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.
///

View File

@ -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('\'')

View File

@ -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() }

View File

@ -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

View File

@ -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)]