]> git.lizzy.rs Git - rust.git/blob - src/libcore/ascii.rs
Rollup merge of #68438 - Aaron1011:fix/tait-non-defining, r=estebank
[rust.git] / src / libcore / ascii.rs
1 //! Operations on ASCII strings and characters.
2 //!
3 //! Most string operations in Rust act on UTF-8 strings. However, at times it
4 //! makes more sense to only consider the ASCII character set for a specific
5 //! operation.
6 //!
7 //! The [`escape_default`] function provides an iterator over the bytes of an
8 //! escaped version of the character given.
9 //!
10 //! [`escape_default`]: fn.escape_default.html
11
12 #![stable(feature = "core_ascii", since = "1.26.0")]
13
14 use crate::fmt;
15 use crate::iter::FusedIterator;
16 use crate::ops::Range;
17 use crate::str::from_utf8_unchecked;
18
19 /// An iterator over the escaped version of a byte.
20 ///
21 /// This `struct` is created by the [`escape_default`] function. See its
22 /// documentation for more.
23 ///
24 /// [`escape_default`]: fn.escape_default.html
25 #[stable(feature = "rust1", since = "1.0.0")]
26 #[derive(Clone)]
27 pub struct EscapeDefault {
28     range: Range<usize>,
29     data: [u8; 4],
30 }
31
32 /// Returns an iterator that produces an escaped version of a `u8`.
33 ///
34 /// The default is chosen with a bias toward producing literals that are
35 /// legal in a variety of languages, including C++11 and similar C-family
36 /// languages. The exact rules are:
37 ///
38 /// * Tab is escaped as `\t`.
39 /// * Carriage return is escaped as `\r`.
40 /// * Line feed is escaped as `\n`.
41 /// * Single quote is escaped as `\'`.
42 /// * Double quote is escaped as `\"`.
43 /// * Backslash is escaped as `\\`.
44 /// * Any character in the 'printable ASCII' range `0x20` .. `0x7e`
45 ///   inclusive is not escaped.
46 /// * Any other chars are given hex escapes of the form '\xNN'.
47 /// * Unicode escapes are never generated by this function.
48 ///
49 /// # Examples
50 ///
51 /// ```
52 /// use std::ascii;
53 ///
54 /// let escaped = ascii::escape_default(b'0').next().unwrap();
55 /// assert_eq!(b'0', escaped);
56 ///
57 /// let mut escaped = ascii::escape_default(b'\t');
58 ///
59 /// assert_eq!(b'\\', escaped.next().unwrap());
60 /// assert_eq!(b't', escaped.next().unwrap());
61 ///
62 /// let mut escaped = ascii::escape_default(b'\r');
63 ///
64 /// assert_eq!(b'\\', escaped.next().unwrap());
65 /// assert_eq!(b'r', escaped.next().unwrap());
66 ///
67 /// let mut escaped = ascii::escape_default(b'\n');
68 ///
69 /// assert_eq!(b'\\', escaped.next().unwrap());
70 /// assert_eq!(b'n', escaped.next().unwrap());
71 ///
72 /// let mut escaped = ascii::escape_default(b'\'');
73 ///
74 /// assert_eq!(b'\\', escaped.next().unwrap());
75 /// assert_eq!(b'\'', escaped.next().unwrap());
76 ///
77 /// let mut escaped = ascii::escape_default(b'"');
78 ///
79 /// assert_eq!(b'\\', escaped.next().unwrap());
80 /// assert_eq!(b'"', escaped.next().unwrap());
81 ///
82 /// let mut escaped = ascii::escape_default(b'\\');
83 ///
84 /// assert_eq!(b'\\', escaped.next().unwrap());
85 /// assert_eq!(b'\\', escaped.next().unwrap());
86 ///
87 /// let mut escaped = ascii::escape_default(b'\x9d');
88 ///
89 /// assert_eq!(b'\\', escaped.next().unwrap());
90 /// assert_eq!(b'x', escaped.next().unwrap());
91 /// assert_eq!(b'9', escaped.next().unwrap());
92 /// assert_eq!(b'd', escaped.next().unwrap());
93 /// ```
94 #[stable(feature = "rust1", since = "1.0.0")]
95 pub fn escape_default(c: u8) -> EscapeDefault {
96     let (data, len) = match c {
97         b'\t' => ([b'\\', b't', 0, 0], 2),
98         b'\r' => ([b'\\', b'r', 0, 0], 2),
99         b'\n' => ([b'\\', b'n', 0, 0], 2),
100         b'\\' => ([b'\\', b'\\', 0, 0], 2),
101         b'\'' => ([b'\\', b'\'', 0, 0], 2),
102         b'"' => ([b'\\', b'"', 0, 0], 2),
103         b'\x20'..=b'\x7e' => ([c, 0, 0, 0], 1),
104         _ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4),
105     };
106
107     return EscapeDefault { range: 0..len, data };
108
109     fn hexify(b: u8) -> u8 {
110         match b {
111             0..=9 => b'0' + b,
112             _ => b'a' + b - 10,
113         }
114     }
115 }
116
117 #[stable(feature = "rust1", since = "1.0.0")]
118 impl Iterator for EscapeDefault {
119     type Item = u8;
120     fn next(&mut self) -> Option<u8> {
121         self.range.next().map(|i| self.data[i])
122     }
123     fn size_hint(&self) -> (usize, Option<usize>) {
124         self.range.size_hint()
125     }
126     fn last(mut self) -> Option<u8> {
127         self.next_back()
128     }
129 }
130 #[stable(feature = "rust1", since = "1.0.0")]
131 impl DoubleEndedIterator for EscapeDefault {
132     fn next_back(&mut self) -> Option<u8> {
133         self.range.next_back().map(|i| self.data[i])
134     }
135 }
136 #[stable(feature = "rust1", since = "1.0.0")]
137 impl ExactSizeIterator for EscapeDefault {}
138 #[stable(feature = "fused", since = "1.26.0")]
139 impl FusedIterator for EscapeDefault {}
140
141 #[stable(feature = "ascii_escape_display", since = "1.39.0")]
142 impl fmt::Display for EscapeDefault {
143     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144         // SAFETY: ok because `escape_default` created only valid utf-8 data
145         f.write_str(unsafe { from_utf8_unchecked(&self.data[self.range.clone()]) })
146     }
147 }
148
149 #[stable(feature = "std_debug", since = "1.16.0")]
150 impl fmt::Debug for EscapeDefault {
151     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152         f.pad("EscapeDefault { .. }")
153     }
154 }