Auto merge of #58051 - SimonSapin:str_escape, r=alexcrichton

Stabilize str::escape_* methods with new return types…

… that implement `Display` and `Iterator<Item=char>`, as proposed in FCP: https://github.com/rust-lang/rust/issues/27791#issuecomment-376864727
This commit is contained in:
bors 2019-02-12 23:30:16 +00:00
commit 0f949c2fcc
14 changed files with 328 additions and 201 deletions

View File

@ -68,7 +68,6 @@
#![warn(intra_doc_link_resolution_failure)]
#![warn(missing_debug_implementations)]
#![cfg_attr(not(test), feature(fn_traits))]
#![cfg_attr(not(test), feature(generator_trait))]
#![cfg_attr(test, feature(test))]
@ -86,6 +85,7 @@
#![feature(dropck_eyepatch)]
#![feature(exact_size_is_empty)]
#![feature(fmt_internals)]
#![feature(fn_traits)]
#![feature(fundamental)]
#![feature(futures_api)]
#![feature(lang_items)]
@ -100,6 +100,7 @@
#![feature(receiver_trait)]
#![feature(specialization)]
#![feature(staged_api)]
#![feature(std_internals)]
#![feature(str_internals)]
#![feature(trusted_len)]
#![feature(try_reserve)]

View File

@ -29,8 +29,6 @@
#![allow(unused_imports)]
use core::borrow::Borrow;
use core::fmt;
use core::str as core_str;
use core::str::pattern::{Pattern, Searcher, ReverseSearcher, DoubleEndedSearcher};
use core::mem;
use core::ptr;
@ -443,45 +441,6 @@ impl str {
return s;
}
/// Escapes each char in `s` with [`char::escape_debug`].
///
/// Note: only extended grapheme codepoints that begin the string will be
/// escaped.
///
/// [`char::escape_debug`]: primitive.char.html#method.escape_debug
#[unstable(feature = "str_escape",
reason = "return type may change to be an iterator",
issue = "27791")]
pub fn escape_debug(&self) -> String {
let mut string = String::with_capacity(self.len());
let mut chars = self.chars();
if let Some(first) = chars.next() {
string.extend(first.escape_debug_ext(true))
}
string.extend(chars.flat_map(|c| c.escape_debug_ext(false)));
string
}
/// Escapes each char in `s` with [`char::escape_default`].
///
/// [`char::escape_default`]: primitive.char.html#method.escape_default
#[unstable(feature = "str_escape",
reason = "return type may change to be an iterator",
issue = "27791")]
pub fn escape_default(&self) -> String {
self.chars().flat_map(|c| c.escape_default()).collect()
}
/// Escapes each char in `s` with [`char::escape_unicode`].
///
/// [`char::escape_unicode`]: primitive.char.html#method.escape_unicode
#[unstable(feature = "str_escape",
reason = "return type may change to be an iterator",
issue = "27791")]
pub fn escape_unicode(&self) -> String {
self.chars().flat_map(|c| c.escape_unicode()).collect()
}
/// Converts a [`Box<str>`] into a [`String`] without copying or allocating.
///
/// [`String`]: string/struct.String.html
@ -612,3 +571,4 @@ impl str {
pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box<str> {
Box::from_raw(Box::into_raw(v) as *mut str)
}

View File

@ -5,7 +5,6 @@
#![feature(pattern)]
#![feature(repeat_generic_slice)]
#![feature(slice_sort_by_cached_key)]
#![feature(str_escape)]
#![feature(try_reserve)]
#![feature(unboxed_closures)]
#![feature(vecdeque_rotate)]

View File

@ -990,15 +990,15 @@ fn test_split_at_boundscheck() {
#[test]
fn test_escape_unicode() {
assert_eq!("abc".escape_unicode(), "\\u{61}\\u{62}\\u{63}");
assert_eq!("a c".escape_unicode(), "\\u{61}\\u{20}\\u{63}");
assert_eq!("\r\n\t".escape_unicode(), "\\u{d}\\u{a}\\u{9}");
assert_eq!("'\"\\".escape_unicode(), "\\u{27}\\u{22}\\u{5c}");
assert_eq!("\x00\x01\u{fe}\u{ff}".escape_unicode(), "\\u{0}\\u{1}\\u{fe}\\u{ff}");
assert_eq!("\u{100}\u{ffff}".escape_unicode(), "\\u{100}\\u{ffff}");
assert_eq!("\u{10000}\u{10ffff}".escape_unicode(), "\\u{10000}\\u{10ffff}");
assert_eq!("ab\u{fb00}".escape_unicode(), "\\u{61}\\u{62}\\u{fb00}");
assert_eq!("\u{1d4ea}\r".escape_unicode(), "\\u{1d4ea}\\u{d}");
assert_eq!("abc".escape_unicode().to_string(), "\\u{61}\\u{62}\\u{63}");
assert_eq!("a c".escape_unicode().to_string(), "\\u{61}\\u{20}\\u{63}");
assert_eq!("\r\n\t".escape_unicode().to_string(), "\\u{d}\\u{a}\\u{9}");
assert_eq!("'\"\\".escape_unicode().to_string(), "\\u{27}\\u{22}\\u{5c}");
assert_eq!("\x00\x01\u{fe}\u{ff}".escape_unicode().to_string(), "\\u{0}\\u{1}\\u{fe}\\u{ff}");
assert_eq!("\u{100}\u{ffff}".escape_unicode().to_string(), "\\u{100}\\u{ffff}");
assert_eq!("\u{10000}\u{10ffff}".escape_unicode().to_string(), "\\u{10000}\\u{10ffff}");
assert_eq!("ab\u{fb00}".escape_unicode().to_string(), "\\u{61}\\u{62}\\u{fb00}");
assert_eq!("\u{1d4ea}\r".escape_unicode().to_string(), "\\u{1d4ea}\\u{d}");
}
#[test]
@ -1009,31 +1009,32 @@ fn test_escape_debug() {
// they are escaped. However, when the character is unescaped (e.g., for
// printable characters), only a single backslash appears (as the character
// itself appears in the debug string).
assert_eq!("abc".escape_debug(), "abc");
assert_eq!("a c".escape_debug(), "a c");
assert_eq!("éèê".escape_debug(), "éèê");
assert_eq!("\r\n\t".escape_debug(), "\\r\\n\\t");
assert_eq!("'\"\\".escape_debug(), "\\'\\\"\\\\");
assert_eq!("\u{7f}\u{ff}".escape_debug(), "\\u{7f}\u{ff}");
assert_eq!("\u{100}\u{ffff}".escape_debug(), "\u{100}\\u{ffff}");
assert_eq!("\u{10000}\u{10ffff}".escape_debug(), "\u{10000}\\u{10ffff}");
assert_eq!("ab\u{200b}".escape_debug(), "ab\\u{200b}");
assert_eq!("\u{10d4ea}\r".escape_debug(), "\\u{10d4ea}\\r");
assert_eq!("\u{301}a\u{301}\u{e000}".escape_debug(), "\\u{301}a\u{301}\\u{e000}");
assert_eq!("abc".escape_debug().to_string(), "abc");
assert_eq!("a c".escape_debug().to_string(), "a c");
assert_eq!("éèê".escape_debug().to_string(), "éèê");
assert_eq!("\r\n\t".escape_debug().to_string(), "\\r\\n\\t");
assert_eq!("'\"\\".escape_debug().to_string(), "\\'\\\"\\\\");
assert_eq!("\u{7f}\u{ff}".escape_debug().to_string(), "\\u{7f}\u{ff}");
assert_eq!("\u{100}\u{ffff}".escape_debug().to_string(), "\u{100}\\u{ffff}");
assert_eq!("\u{10000}\u{10ffff}".escape_debug().to_string(), "\u{10000}\\u{10ffff}");
assert_eq!("ab\u{200b}".escape_debug().to_string(), "ab\\u{200b}");
assert_eq!("\u{10d4ea}\r".escape_debug().to_string(), "\\u{10d4ea}\\r");
assert_eq!("\u{301}a\u{301}\u{e000}".escape_debug().to_string(),
"\\u{301}a\u{301}\\u{e000}");
}
#[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");
assert_eq!("abc".escape_default().to_string(), "abc");
assert_eq!("a c".escape_default().to_string(), "a c");
assert_eq!("éèê".escape_default().to_string(), "\\u{e9}\\u{e8}\\u{ea}");
assert_eq!("\r\n\t".escape_default().to_string(), "\\r\\n\\t");
assert_eq!("'\"\\".escape_default().to_string(), "\\'\\\"\\\\");
assert_eq!("\u{7f}\u{ff}".escape_default().to_string(), "\\u{7f}\\u{ff}");
assert_eq!("\u{100}\u{ffff}".escape_default().to_string(), "\\u{100}\\u{ffff}");
assert_eq!("\u{10000}\u{10ffff}".escape_default().to_string(), "\\u{10000}\\u{10ffff}");
assert_eq!("ab\u{200b}".escape_default().to_string(), "ab\\u{200b}");
assert_eq!("\u{10d4ea}\r".escape_default().to_string(), "\\u{10d4ea}\\r");
}
#[test]

View File

@ -189,10 +189,8 @@ impl char {
/// An extended version of `escape_debug` that optionally permits escaping
/// Extended Grapheme codepoints. This allows us to format characters like
/// nonspacing marks better when they're at the start of a string.
#[doc(hidden)]
#[unstable(feature = "str_internals", issue = "0")]
#[inline]
pub fn escape_debug_ext(self, escape_grapheme_extended: bool) -> EscapeDebug {
pub(crate) fn escape_debug_ext(self, escape_grapheme_extended: bool) -> EscapeDebug {
let init_state = match self {
'\t' => EscapeDefaultState::Backslash('t'),
'\r' => EscapeDefaultState::Backslash('r'),

View File

@ -75,3 +75,47 @@ macro_rules! forward_ref_op_assign {
}
}
}
/// Create a zero-size type similar to a closure type, but named.
#[unstable(feature = "std_internals", issue = "0")]
macro_rules! impl_fn_for_zst {
($(
$( #[$attr: meta] )*
// FIXME: when libcore is in the 2018 edition, use `?` repetition in
// $( <$( $li : lifetime ),+> )?
struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )* Fn =
|$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty
$body: block;
)+) => {
$(
$( #[$attr] )*
struct $Name;
impl $( <$( $lifetime ),+> )* Fn<($( $ArgTy, )*)> for $Name {
#[inline]
extern "rust-call" fn call(&self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
$body
}
}
impl $( <$( $lifetime ),+> )* FnMut<($( $ArgTy, )*)> for $Name {
#[inline]
extern "rust-call" fn call_mut(
&mut self,
($( $arg, )*): ($( $ArgTy, )*)
) -> $ReturnTy {
Fn::call(&*self, ($( $arg, )*))
}
}
impl $( <$( $lifetime ),+> )* FnOnce<($( $ArgTy, )*)> for $Name {
type Output = $ReturnTy;
#[inline]
extern "rust-call" fn call_once(self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
Fn::call(&self, ($( $arg, )*))
}
}
)+
}
}

View File

@ -95,6 +95,7 @@
#![feature(simd_ffi)]
#![feature(specialization)]
#![feature(staged_api)]
#![feature(std_internals)]
#![feature(stmt_expr_attributes)]
#![feature(unboxed_closures)]
#![feature(unsized_locals)]

View File

@ -8,10 +8,13 @@ use self::pattern::Pattern;
use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher};
use char;
use fmt;
use fmt::{self, Write};
use iter::{Map, Cloned, FusedIterator, TrustedLen, TrustedRandomAccess, Filter};
use iter::{Flatten, FlatMap, Chain};
use slice::{self, SliceIndex, Split as SliceSplit};
use mem;
use ops::Try;
use option;
pub mod pattern;
@ -1345,33 +1348,14 @@ impl FusedIterator for Lines<'_> {}
#[allow(deprecated)]
pub struct LinesAny<'a>(Lines<'a>);
/// A nameable, cloneable fn type
#[derive(Clone)]
struct LinesAnyMap;
impl<'a> Fn<(&'a str,)> for LinesAnyMap {
#[inline]
extern "rust-call" fn call(&self, (line,): (&'a str,)) -> &'a str {
impl_fn_for_zst! {
/// A nameable, cloneable fn type
#[derive(Clone)]
struct LinesAnyMap impl<'a> Fn = |line: &'a str| -> &'a str {
let l = line.len();
if l > 0 && line.as_bytes()[l - 1] == b'\r' { &line[0 .. l - 1] }
else { line }
}
}
impl<'a> FnMut<(&'a str,)> for LinesAnyMap {
#[inline]
extern "rust-call" fn call_mut(&mut self, (line,): (&'a str,)) -> &'a str {
Fn::call(&*self, (line,))
}
}
impl<'a> FnOnce<(&'a str,)> for LinesAnyMap {
type Output = &'a str;
#[inline]
extern "rust-call" fn call_once(self, (line,): (&'a str,)) -> &'a str {
Fn::call(&self, (line,))
}
};
}
#[stable(feature = "rust1", since = "1.0.0")]
@ -2727,7 +2711,7 @@ impl str {
let inner = self
.as_bytes()
.split(IsAsciiWhitespace)
.filter(IsNotEmpty)
.filter(BytesIsNotEmpty)
.map(UnsafeBytesToStr);
SplitAsciiWhitespace { inner }
}
@ -3964,6 +3948,146 @@ impl str {
let me = unsafe { self.as_bytes_mut() };
me.make_ascii_lowercase()
}
/// Return an iterator that escapes each char in `s` with [`char::escape_debug`].
///
/// Note: only extended grapheme codepoints that begin the string will be
/// escaped.
///
/// [`char::escape_debug`]: ../std/primitive.char.html#method.escape_debug
///
/// # Examples
///
/// As an iterator:
///
/// ```
/// for c in "❤\n!".escape_debug() {
/// print!("{}", c);
/// }
/// println!();
/// ```
///
/// Using `println!` directly:
///
/// ```
/// println!("{}", "❤\n!".escape_debug());
/// ```
///
///
/// Both are equivalent to:
///
/// ```
/// println!("❤\\n!");
/// ```
///
/// Using `to_string`:
///
/// ```
/// assert_eq!("❤\n!".escape_debug().to_string(), "❤\\n!");
/// ```
#[stable(feature = "str_escape", since = "1.34.0")]
pub fn escape_debug(&self) -> EscapeDebug {
let mut chars = self.chars();
EscapeDebug {
inner: chars.next()
.map(|first| first.escape_debug_ext(true))
.into_iter()
.flatten()
.chain(chars.flat_map(CharEscapeDebugContinue))
}
}
/// Return an iterator that escapes each char in `s` with [`char::escape_default`].
///
/// [`char::escape_default`]: ../std/primitive.char.html#method.escape_default
///
/// # Examples
///
/// As an iterator:
///
/// ```
/// for c in "❤\n!".escape_default() {
/// print!("{}", c);
/// }
/// println!();
/// ```
///
/// Using `println!` directly:
///
/// ```
/// println!("{}", "❤\n!".escape_default());
/// ```
///
///
/// Both are equivalent to:
///
/// ```
/// println!("\\u{{2764}}\n!");
/// ```
///
/// Using `to_string`:
///
/// ```
/// assert_eq!("❤\n!".escape_default().to_string(), "\\u{2764}\\n!");
/// ```
#[stable(feature = "str_escape", since = "1.34.0")]
pub fn escape_default(&self) -> EscapeDefault {
EscapeDefault { inner: self.chars().flat_map(CharEscapeDefault) }
}
/// Return an iterator that escapes each char in `s` with [`char::escape_unicode`].
///
/// [`char::escape_unicode`]: ../std/primitive.char.html#method.escape_unicode
///
/// # Examples
///
/// As an iterator:
///
/// ```
/// for c in "❤\n!".escape_unicode() {
/// print!("{}", c);
/// }
/// println!();
/// ```
///
/// Using `println!` directly:
///
/// ```
/// println!("{}", "❤\n!".escape_unicode());
/// ```
///
///
/// Both are equivalent to:
///
/// ```
/// println!("\\u{{2764}}\\u{{a}}\\u{{21}}");
/// ```
///
/// Using `to_string`:
///
/// ```
/// assert_eq!("❤\n!".escape_unicode().to_string(), "\\u{2764}\\u{a}\\u{21}");
/// ```
#[stable(feature = "str_escape", since = "1.34.0")]
pub fn escape_unicode(&self) -> EscapeUnicode {
EscapeUnicode { inner: self.chars().flat_map(CharEscapeUnicode) }
}
}
impl_fn_for_zst! {
#[derive(Clone)]
struct CharEscapeDebugContinue impl Fn = |c: char| -> char::EscapeDebug {
c.escape_debug_ext(false)
};
#[derive(Clone)]
struct CharEscapeUnicode impl Fn = |c: char| -> char::EscapeUnicode {
c.escape_unicode()
};
#[derive(Clone)]
struct CharEscapeDefault impl Fn = |c: char| -> char::EscapeDefault {
c.escape_default()
};
}
#[stable(feature = "rust1", since = "1.0.0")]
@ -4011,102 +4135,36 @@ pub struct SplitWhitespace<'a> {
#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
#[derive(Clone, Debug)]
pub struct SplitAsciiWhitespace<'a> {
inner: Map<Filter<SliceSplit<'a, u8, IsAsciiWhitespace>, IsNotEmpty>, UnsafeBytesToStr>,
inner: Map<Filter<SliceSplit<'a, u8, IsAsciiWhitespace>, BytesIsNotEmpty>, UnsafeBytesToStr>,
}
#[derive(Clone)]
struct IsWhitespace;
impl_fn_for_zst! {
#[derive(Clone)]
struct IsWhitespace impl Fn = |c: char| -> bool {
c.is_whitespace()
};
impl FnOnce<(char, )> for IsWhitespace {
type Output = bool;
#[derive(Clone)]
struct IsAsciiWhitespace impl Fn = |byte: &u8| -> bool {
byte.is_ascii_whitespace()
};
#[inline]
extern "rust-call" fn call_once(mut self, arg: (char, )) -> bool {
self.call_mut(arg)
}
#[derive(Clone)]
struct IsNotEmpty impl<'a, 'b> Fn = |s: &'a &'b str| -> bool {
!s.is_empty()
};
#[derive(Clone)]
struct BytesIsNotEmpty impl<'a, 'b> Fn = |s: &'a &'b [u8]| -> bool {
!s.is_empty()
};
#[derive(Clone)]
struct UnsafeBytesToStr impl<'a> Fn = |bytes: &'a [u8]| -> &'a str {
unsafe { from_utf8_unchecked(bytes) }
};
}
impl FnMut<(char, )> for IsWhitespace {
#[inline]
extern "rust-call" fn call_mut(&mut self, arg: (char, )) -> bool {
arg.0.is_whitespace()
}
}
#[derive(Clone)]
struct IsAsciiWhitespace;
impl<'a> FnOnce<(&'a u8, )> for IsAsciiWhitespace {
type Output = bool;
#[inline]
extern "rust-call" fn call_once(mut self, arg: (&u8, )) -> bool {
self.call_mut(arg)
}
}
impl<'a> FnMut<(&'a u8, )> for IsAsciiWhitespace {
#[inline]
extern "rust-call" fn call_mut(&mut self, arg: (&u8, )) -> bool {
arg.0.is_ascii_whitespace()
}
}
#[derive(Clone)]
struct IsNotEmpty;
impl<'a, 'b> FnOnce<(&'a &'b str, )> for IsNotEmpty {
type Output = bool;
#[inline]
extern "rust-call" fn call_once(mut self, arg: (&'a &'b str, )) -> bool {
self.call_mut(arg)
}
}
impl<'a, 'b> FnMut<(&'a &'b str, )> for IsNotEmpty {
#[inline]
extern "rust-call" fn call_mut(&mut self, arg: (&'a &'b str, )) -> bool {
!arg.0.is_empty()
}
}
impl<'a, 'b> FnOnce<(&'a &'b [u8], )> for IsNotEmpty {
type Output = bool;
#[inline]
extern "rust-call" fn call_once(mut self, arg: (&'a &'b [u8], )) -> bool {
self.call_mut(arg)
}
}
impl<'a, 'b> FnMut<(&'a &'b [u8], )> for IsNotEmpty {
#[inline]
extern "rust-call" fn call_mut(&mut self, arg: (&'a &'b [u8], )) -> bool {
!arg.0.is_empty()
}
}
#[derive(Clone)]
struct UnsafeBytesToStr;
impl<'a> FnOnce<(&'a [u8], )> for UnsafeBytesToStr {
type Output = &'a str;
#[inline]
extern "rust-call" fn call_once(mut self, arg: (&'a [u8], )) -> &'a str {
self.call_mut(arg)
}
}
impl<'a> FnMut<(&'a [u8], )> for UnsafeBytesToStr {
#[inline]
extern "rust-call" fn call_mut(&mut self, arg: (&'a [u8], )) -> &'a str {
unsafe { from_utf8_unchecked(arg.0) }
}
}
#[stable(feature = "split_whitespace", since = "1.1.0")]
impl<'a> Iterator for SplitWhitespace<'a> {
type Item = &'a str;
@ -4216,3 +4274,74 @@ impl<'a> Iterator for EncodeUtf16<'a> {
#[stable(feature = "fused", since = "1.26.0")]
impl FusedIterator for EncodeUtf16<'_> {}
/// The return type of [`str::escape_debug`].
///
/// [`str::escape_debug`]: ../../std/primitive.str.html#method.escape_debug
#[stable(feature = "str_escape", since = "1.34.0")]
#[derive(Clone, Debug)]
pub struct EscapeDebug<'a> {
inner: Chain<
Flatten<option::IntoIter<char::EscapeDebug>>,
FlatMap<Chars<'a>, char::EscapeDebug, CharEscapeDebugContinue>
>,
}
/// The return type of [`str::escape_default`].
///
/// [`str::escape_default`]: ../../std/primitive.str.html#method.escape_default
#[stable(feature = "str_escape", since = "1.34.0")]
#[derive(Clone, Debug)]
pub struct EscapeDefault<'a> {
inner: FlatMap<Chars<'a>, char::EscapeDefault, CharEscapeDefault>,
}
/// The return type of [`str::escape_unicode`].
///
/// [`str::escape_unicode`]: ../../std/primitive.str.html#method.escape_unicode
#[stable(feature = "str_escape", since = "1.34.0")]
#[derive(Clone, Debug)]
pub struct EscapeUnicode<'a> {
inner: FlatMap<Chars<'a>, char::EscapeUnicode, CharEscapeUnicode>,
}
macro_rules! escape_types_impls {
($( $Name: ident ),+) => {$(
#[stable(feature = "str_escape", since = "1.34.0")]
impl<'a> fmt::Display for $Name<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.clone().try_for_each(|c| f.write_char(c))
}
}
#[stable(feature = "str_escape", since = "1.34.0")]
impl<'a> Iterator for $Name<'a> {
type Item = char;
#[inline]
fn next(&mut self) -> Option<char> { self.inner.next() }
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
#[inline]
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
{
self.inner.try_fold(init, fold)
}
#[inline]
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.inner.fold(init, fold)
}
}
#[stable(feature = "str_escape", since = "1.34.0")]
impl<'a> FusedIterator for $Name<'a> {}
)+}
}
escape_types_impls!(EscapeDebug, EscapeDefault, EscapeUnicode);

View File

@ -277,7 +277,6 @@
#![deny(rust_2018_idioms)]
#![feature(nll)]
#![feature(str_escape)]
use LabelText::*;
@ -538,7 +537,7 @@ impl<'a> LabelText<'a> {
EscStr(s) => s,
LabelStr(s) => {
if s.contains('\\') {
(&*s).escape_default().into()
(&*s).escape_default().to_string().into()
} else {
s
}

View File

@ -634,7 +634,7 @@ impl LitKind {
match *self {
LitKind::Str(string, ast::StrStyle::Cooked) => {
let escaped = string.as_str().escape_default();
let escaped = string.as_str().escape_default().to_string();
Token::Literal(token::Lit::Str_(Symbol::intern(&escaped)), None)
}
LitKind::Str(string, ast::StrStyle::Raw(n)) => {

View File

@ -15,7 +15,6 @@
#![feature(rustc_attrs)]
#![feature(rustc_diagnostic_macros)]
#![feature(slice_sort_by_cached_key)]
#![feature(str_escape)]
#![feature(step_trait)]
#![feature(try_trait)]
#![feature(unicode_internals)]

View File

@ -606,7 +606,7 @@ pub trait PrintState<'a> {
match lit.node {
ast::LitKind::Str(st, style) => self.print_string(&st.as_str(), style),
ast::LitKind::Err(st) => {
let st = st.as_str().escape_debug();
let st = st.as_str().escape_debug().to_string();
let mut res = String::with_capacity(st.len() + 2);
res.push('\'');
res.push_str(&st);

View File

@ -10,7 +10,6 @@
#![feature(proc_macro_span)]
#![feature(decl_macro)]
#![feature(nll)]
#![feature(str_escape)]
#![feature(rustc_diagnostic_macros)]
#![recursion_limit="256"]

View File

@ -2,9 +2,6 @@
// pretty-expanded FIXME #23616
#![allow(warnings)]
#![feature(iter_empty)]
#![feature(iter_once)]
#![feature(str_escape)]
use std::iter::{empty, once, repeat};