about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <dylan.dpc@gmail.com>2021-03-30 00:32:20 +0200
committerGitHub <noreply@github.com>2021-03-30 00:32:20 +0200
commit68964d1fc24888b04be492c3f3ba0dae7d6219da (patch)
tree019e77de1d81bd17996e557758ef3ab334a77689
parent2843baaeb6e20c494b3b938b4d4024ead7bbdd1b (diff)
parentc20ba9cdae257c70c934e2c9dc1a77c1798d8113 (diff)
downloadrust-68964d1fc24888b04be492c3f3ba0dae7d6219da.tar.gz
rust-68964d1fc24888b04be492c3f3ba0dae7d6219da.zip
Rollup merge of #83130 - clarfonthey:escape, r=m-ou-se
escape_ascii take 2

The previous PR, #73111 was closed for inactivity; since I've had trouble in the past reopening closed PRs, I'm just making a new one.

I'm still running the tests locally but figured I'd open the PR in the meantime. Will fix whatever errors show up so we don't have to wait again for this.

r? ``@m-ou-se``
-rw-r--r--library/core/src/num/mod.rs26
-rw-r--r--library/core/src/slice/ascii.rs92
-rw-r--r--library/core/src/slice/mod.rs3
3 files changed, 121 insertions, 0 deletions
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index f0bd976ba83..6032dc9a2d3 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -2,6 +2,7 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+use crate::ascii;
 use crate::intrinsics;
 use crate::mem;
 use crate::str::FromStr;
@@ -661,6 +662,31 @@ impl u8 {
     pub const fn is_ascii_control(&self) -> bool {
         matches!(*self, b'\0'..=b'\x1F' | b'\x7F')
     }
+
+    /// Returns an iterator that produces an escaped version of a `u8`,
+    /// treating it as an ASCII character.
+    ///
+    /// The behavior is identical to [`ascii::escape_default`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(inherent_ascii_escape)]
+    ///
+    /// assert_eq!("0", b'0'.escape_ascii().to_string());
+    /// assert_eq!("\\t", b'\t'.escape_ascii().to_string());
+    /// assert_eq!("\\r", b'\r'.escape_ascii().to_string());
+    /// assert_eq!("\\n", b'\n'.escape_ascii().to_string());
+    /// assert_eq!("\\'", b'\''.escape_ascii().to_string());
+    /// assert_eq!("\\\"", b'"'.escape_ascii().to_string());
+    /// assert_eq!("\\\\", b'\\'.escape_ascii().to_string());
+    /// assert_eq!("\\x9d", b'\x9d'.escape_ascii().to_string());
+    /// ```
+    #[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+    #[inline]
+    pub fn escape_ascii(&self) -> ascii::EscapeDefault {
+        ascii::escape_default(*self)
+    }
 }
 
 #[lang = "u16"]
diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs
index 009ef9e0a9c..22fa08b9795 100644
--- a/library/core/src/slice/ascii.rs
+++ b/library/core/src/slice/ascii.rs
@@ -1,7 +1,10 @@
 //! Operations on ASCII `[u8]`.
 
+use crate::ascii;
+use crate::fmt::{self, Write};
 use crate::iter;
 use crate::mem;
+use crate::ops;
 
 #[lang = "slice_u8"]
 #[cfg(not(test))]
@@ -56,6 +59,95 @@ impl [u8] {
             byte.make_ascii_lowercase();
         }
     }
+
+    /// Returns an iterator that produces an escaped version of this slice,
+    /// treating it as an ASCII string.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(inherent_ascii_escape)]
+    ///
+    /// let s = b"0\t\r\n'\"\\\x9d";
+    /// let escaped = s.escape_ascii().to_string();
+    /// assert_eq!(escaped, "0\\t\\r\\n\\'\\\"\\\\\\x9d");
+    /// ```
+    #[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+    pub fn escape_ascii(&self) -> EscapeAscii<'_> {
+        EscapeAscii { inner: self.iter().flat_map(EscapeByte) }
+    }
+}
+
+impl_fn_for_zst! {
+    #[derive(Clone)]
+    struct EscapeByte impl Fn = |byte: &u8| -> ascii::EscapeDefault {
+        ascii::escape_default(*byte)
+    };
+}
+
+/// An iterator over the escaped version of a byte slice.
+///
+/// This `struct` is created by the [`slice::escape_ascii`] method. See its
+/// documentation for more information.
+#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[derive(Clone)]
+pub struct EscapeAscii<'a> {
+    inner: iter::FlatMap<super::Iter<'a, u8>, ascii::EscapeDefault, EscapeByte>,
+}
+
+#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+impl<'a> iter::Iterator for EscapeAscii<'a> {
+    type Item = u8;
+    #[inline]
+    fn next(&mut self) -> Option<u8> {
+        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
+        Fold: FnMut(Acc, Self::Item) -> R,
+        R: ops::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)
+    }
+    #[inline]
+    fn last(mut self) -> Option<u8> {
+        self.next_back()
+    }
+}
+
+#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+impl<'a> iter::DoubleEndedIterator for EscapeAscii<'a> {
+    fn next_back(&mut self) -> Option<u8> {
+        self.inner.next_back()
+    }
+}
+#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+impl<'a> iter::ExactSizeIterator for EscapeAscii<'a> {}
+#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+impl<'a> iter::FusedIterator for EscapeAscii<'a> {}
+#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+impl<'a> fmt::Display for EscapeAscii<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.clone().try_for_each(|b| f.write_char(b as char))
+    }
+}
+#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+impl<'a> fmt::Debug for EscapeAscii<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.pad("EscapeAscii { .. }")
+    }
 }
 
 /// Returns `true` if any byte in the word `v` is nonascii (>= 128). Snarfed
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index d7a28c8d08f..59fad8c813c 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -81,6 +81,9 @@ pub use index::SliceIndex;
 #[unstable(feature = "slice_range", issue = "76393")]
 pub use index::range;
 
+#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+pub use ascii::EscapeAscii;
+
 #[lang = "slice"]
 #[cfg(not(test))]
 impl<T> [T] {