Skip to content

Commit 235f35b

Browse files
committed
std: Stabilize the ascii module
This commit performs a stabilization pass over the `std::ascii` module taking the following actions: * the module name is now stable * `AsciiExt` is now stable after moving its type parameter to an `Owned` associated type * `AsciiExt::is_ascii` is now stable * `AsciiExt::to_ascii_uppercase` is now stable * `AsciiExt::to_ascii_lowercase` is now stable * `AsciiExt::eq_ignore_ascii_case` is now stable * `AsciiExt::make_ascii_uppercase` is added to possibly replace `OwnedAsciiExt::into_ascii_uppercase` (similarly for lowercase variants). * `escape_default` now returns an iterator and is stable * `EscapeDefault` is now stable Trait implementations are now also marked stable. Primarily it is still unstable to *implement* the `AsciiExt` trait due to it containing some unstable methods. [breaking-change]
1 parent 0cf2d00 commit 235f35b

File tree

4 files changed

+132
-78
lines changed

4 files changed

+132
-78
lines changed

src/libstd/ascii.rs

Lines changed: 122 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,12 @@
1212

1313
//! Operations on ASCII strings and characters
1414
15-
#![unstable(feature = "std_misc",
16-
reason = "unsure about placement and naming")]
15+
#![stable(feature = "rust1", since = "1.0.0")]
1716

18-
use iter::IteratorExt;
19-
use ops::FnMut;
20-
use slice::SliceExt;
21-
use str::StrExt;
22-
use string::String;
23-
use vec::Vec;
17+
use prelude::v1::*;
18+
19+
use mem;
20+
use iter::Range;
2421

2522
/// Extension methods for ASCII-subset only operations on owned strings
2623
#[unstable(feature = "std_misc",
@@ -38,52 +35,79 @@ pub trait OwnedAsciiExt {
3835
}
3936

4037
/// Extension methods for ASCII-subset only operations on string slices
41-
#[unstable(feature = "std_misc",
42-
reason = "would prefer to do this in a more general way")]
43-
pub trait AsciiExt<T = Self> {
38+
#[stable(feature = "rust1", since = "1.0.0")]
39+
pub trait AsciiExt {
40+
#[stable(feature = "rust1", since = "1.0.0")]
41+
type Owned;
42+
4443
/// Check if within the ASCII range.
44+
#[stable(feature = "rust1", since = "1.0.0")]
4545
fn is_ascii(&self) -> bool;
4646

4747
/// Makes a copy of the string in ASCII upper case:
4848
/// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
4949
/// but non-ASCII letters are unchanged.
50-
fn to_ascii_uppercase(&self) -> T;
50+
#[stable(feature = "rust1", since = "1.0.0")]
51+
fn to_ascii_uppercase(&self) -> Self::Owned;
5152

5253
/// Makes a copy of the string in ASCII lower case:
5354
/// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
5455
/// but non-ASCII letters are unchanged.
55-
fn to_ascii_lowercase(&self) -> T;
56+
#[stable(feature = "rust1", since = "1.0.0")]
57+
fn to_ascii_lowercase(&self) -> Self::Owned;
5658

5759
/// Check that two strings are an ASCII case-insensitive match.
5860
/// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
5961
/// but without allocating and copying temporary strings.
62+
#[stable(feature = "rust1", since = "1.0.0")]
6063
fn eq_ignore_ascii_case(&self, other: &Self) -> bool;
64+
65+
/// Convert this type to its ASCII upper case equivalent in-place.
66+
///
67+
/// See `to_ascii_uppercase` for more information.
68+
#[unstable(feature = "ascii")]
69+
fn make_ascii_uppercase(&mut self);
70+
71+
/// Convert this type to its ASCII lower case equivalent in-place.
72+
///
73+
/// See `to_ascii_lowercase` for more information.
74+
#[unstable(feature = "ascii")]
75+
fn make_ascii_lowercase(&mut self);
6176
}
6277

63-
#[unstable(feature = "std_misc",
64-
reason = "would prefer to do this in a more general way")]
65-
impl AsciiExt<String> for str {
78+
#[stable(feature = "rust1", since = "1.0.0")]
79+
impl AsciiExt for str {
80+
type Owned = String;
81+
6682
#[inline]
6783
fn is_ascii(&self) -> bool {
6884
self.bytes().all(|b| b.is_ascii())
6985
}
7086

7187
#[inline]
7288
fn to_ascii_uppercase(&self) -> String {
73-
// Vec<u8>::to_ascii_uppercase() preserves the UTF-8 invariant.
74-
unsafe { String::from_utf8_unchecked(self.as_bytes().to_ascii_uppercase()) }
89+
self.to_string().into_ascii_uppercase()
7590
}
7691

7792
#[inline]
7893
fn to_ascii_lowercase(&self) -> String {
79-
// Vec<u8>::to_ascii_lowercase() preserves the UTF-8 invariant.
80-
unsafe { String::from_utf8_unchecked(self.as_bytes().to_ascii_lowercase()) }
94+
self.to_string().into_ascii_lowercase()
8195
}
8296

8397
#[inline]
8498
fn eq_ignore_ascii_case(&self, other: &str) -> bool {
8599
self.as_bytes().eq_ignore_ascii_case(other.as_bytes())
86100
}
101+
102+
fn make_ascii_uppercase(&mut self) {
103+
let me: &mut [u8] = unsafe { mem::transmute(self) };
104+
me.make_ascii_uppercase()
105+
}
106+
107+
fn make_ascii_lowercase(&mut self) {
108+
let me: &mut [u8] = unsafe { mem::transmute(self) };
109+
me.make_ascii_lowercase()
110+
}
87111
}
88112

89113
#[unstable(feature = "std_misc",
@@ -102,22 +126,22 @@ impl OwnedAsciiExt for String {
102126
}
103127
}
104128

105-
#[unstable(feature = "std_misc",
106-
reason = "would prefer to do this in a more general way")]
107-
impl AsciiExt<Vec<u8>> for [u8] {
129+
#[stable(feature = "rust1", since = "1.0.0")]
130+
impl AsciiExt for [u8] {
131+
type Owned = Vec<u8>;
108132
#[inline]
109133
fn is_ascii(&self) -> bool {
110134
self.iter().all(|b| b.is_ascii())
111135
}
112136

113137
#[inline]
114138
fn to_ascii_uppercase(&self) -> Vec<u8> {
115-
self.iter().map(|b| b.to_ascii_uppercase()).collect()
139+
self.to_vec().into_ascii_uppercase()
116140
}
117141

118142
#[inline]
119143
fn to_ascii_lowercase(&self) -> Vec<u8> {
120-
self.iter().map(|b| b.to_ascii_lowercase()).collect()
144+
self.to_vec().into_ascii_lowercase()
121145
}
122146

123147
#[inline]
@@ -127,55 +151,58 @@ impl AsciiExt<Vec<u8>> for [u8] {
127151
a.eq_ignore_ascii_case(b)
128152
})
129153
}
154+
155+
fn make_ascii_uppercase(&mut self) {
156+
for byte in self {
157+
byte.make_ascii_uppercase();
158+
}
159+
}
160+
161+
fn make_ascii_lowercase(&mut self) {
162+
for byte in self {
163+
byte.make_ascii_lowercase();
164+
}
165+
}
130166
}
131167

132168
#[unstable(feature = "std_misc",
133169
reason = "would prefer to do this in a more general way")]
134170
impl OwnedAsciiExt for Vec<u8> {
135171
#[inline]
136172
fn into_ascii_uppercase(mut self) -> Vec<u8> {
137-
for byte in &mut self {
138-
*byte = byte.to_ascii_uppercase();
139-
}
173+
self.make_ascii_uppercase();
140174
self
141175
}
142176

143177
#[inline]
144178
fn into_ascii_lowercase(mut self) -> Vec<u8> {
145-
for byte in &mut self {
146-
*byte = byte.to_ascii_lowercase();
147-
}
179+
self.make_ascii_lowercase();
148180
self
149181
}
150182
}
151183

152-
#[unstable(feature = "std_misc",
153-
reason = "would prefer to do this in a more general way")]
184+
#[stable(feature = "rust1", since = "1.0.0")]
154185
impl AsciiExt for u8 {
186+
type Owned = u8;
155187
#[inline]
156-
fn is_ascii(&self) -> bool {
157-
*self & 128 == 0u8
158-
}
159-
188+
fn is_ascii(&self) -> bool { *self & 128 == 0u8 }
160189
#[inline]
161-
fn to_ascii_uppercase(&self) -> u8 {
162-
ASCII_UPPERCASE_MAP[*self as usize]
163-
}
164-
190+
fn to_ascii_uppercase(&self) -> u8 { ASCII_UPPERCASE_MAP[*self as usize] }
165191
#[inline]
166-
fn to_ascii_lowercase(&self) -> u8 {
167-
ASCII_LOWERCASE_MAP[*self as usize]
168-
}
169-
192+
fn to_ascii_lowercase(&self) -> u8 { ASCII_LOWERCASE_MAP[*self as usize] }
170193
#[inline]
171194
fn eq_ignore_ascii_case(&self, other: &u8) -> bool {
172195
self.to_ascii_lowercase() == other.to_ascii_lowercase()
173196
}
197+
#[inline]
198+
fn make_ascii_uppercase(&mut self) { *self = self.to_ascii_uppercase(); }
199+
#[inline]
200+
fn make_ascii_lowercase(&mut self) { *self = self.to_ascii_lowercase(); }
174201
}
175202

176-
#[unstable(feature = "std_misc",
177-
reason = "would prefer to do this in a more general way")]
203+
#[stable(feature = "rust1", since = "1.0.0")]
178204
impl AsciiExt for char {
205+
type Owned = char;
179206
#[inline]
180207
fn is_ascii(&self) -> bool {
181208
*self as u32 <= 0x7F
@@ -203,6 +230,19 @@ impl AsciiExt for char {
203230
fn eq_ignore_ascii_case(&self, other: &char) -> bool {
204231
self.to_ascii_lowercase() == other.to_ascii_lowercase()
205232
}
233+
234+
#[inline]
235+
fn make_ascii_uppercase(&mut self) { *self = self.to_ascii_uppercase(); }
236+
#[inline]
237+
fn make_ascii_lowercase(&mut self) { *self = self.to_ascii_lowercase(); }
238+
}
239+
240+
/// An iterator over the escaped version of a byte, constructed via
241+
/// `std::ascii::escape_default`.
242+
#[stable(feature = "rust1", since = "1.0.0")]
243+
pub struct EscapeDefault {
244+
range: Range<usize>,
245+
data: [u8; 4],
206246
}
207247

208248
/// Returns a 'default' ASCII and C++11-like literal escape of a `u8`
@@ -214,34 +254,46 @@ impl AsciiExt for char {
214254
/// - Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively.
215255
/// - Single-quote, double-quote and backslash chars are backslash-escaped.
216256
/// - Any other chars in the range [0x20,0x7e] are not escaped.
217-
/// - Any other chars are given hex escapes.
257+
/// - Any other chars are given hex escapes of the form '\xNN'.
218258
/// - Unicode escapes are never generated by this function.
219-
#[unstable(feature = "std_misc",
220-
reason = "needs to be updated to use an iterator")]
221-
pub fn escape_default<F>(c: u8, mut f: F) where
222-
F: FnMut(u8),
223-
{
224-
match c {
225-
b'\t' => { f(b'\\'); f(b't'); }
226-
b'\r' => { f(b'\\'); f(b'r'); }
227-
b'\n' => { f(b'\\'); f(b'n'); }
228-
b'\\' => { f(b'\\'); f(b'\\'); }
229-
b'\'' => { f(b'\\'); f(b'\''); }
230-
b'"' => { f(b'\\'); f(b'"'); }
231-
b'\x20' ... b'\x7e' => { f(c); }
232-
_ => {
233-
f(b'\\');
234-
f(b'x');
235-
for &offset in &[4u, 0u] {
236-
match ((c as i32) >> offset) & 0xf {
237-
i @ 0 ... 9 => f(b'0' + (i as u8)),
238-
i => f(b'a' + (i as u8 - 10)),
239-
}
240-
}
259+
#[stable(feature = "rust1", since = "1.0.0")]
260+
pub fn escape_default(c: u8) -> EscapeDefault {
261+
let (data, len) = match c {
262+
b'\t' => ([b'\\', b't', 0, 0], 2),
263+
b'\r' => ([b'\\', b'r', 0, 0], 2),
264+
b'\n' => ([b'\\', b'n', 0, 0], 2),
265+
b'\\' => ([b'\\', b'\\', 0, 0], 2),
266+
b'\'' => ([b'\\', b'\'', 0, 0], 2),
267+
b'"' => ([b'\\', b'"', 0, 0], 2),
268+
b'\x20' ... b'\x7e' => ([c, 0, 0, 0], 1),
269+
_ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4),
270+
};
271+
272+
return EscapeDefault { range: range(0, len), data: data };
273+
274+
fn hexify(b: u8) -> u8 {
275+
match b {
276+
0 ... 9 => b'0' + b,
277+
_ => b'a' + b - 10,
241278
}
242279
}
243280
}
244281

282+
#[stable(feature = "rust1", since = "1.0.0")]
283+
impl Iterator for EscapeDefault {
284+
type Item = u8;
285+
fn next(&mut self) -> Option<u8> { self.range.next().map(|i| self.data[i]) }
286+
fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
287+
}
288+
#[stable(feature = "rust1", since = "1.0.0")]
289+
impl DoubleEndedIterator for EscapeDefault {
290+
fn next_back(&mut self) -> Option<u8> {
291+
self.range.next_back().map(|i| self.data[i])
292+
}
293+
}
294+
#[stable(feature = "rust1", since = "1.0.0")]
295+
impl ExactSizeIterator for EscapeDefault {}
296+
245297
static ASCII_LOWERCASE_MAP: [u8; 256] = [
246298
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
247299
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,

src/libstd/sys/common/wtf8.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -817,7 +817,9 @@ impl<'a, S: Writer + Hasher> Hash<S> for Wtf8 {
817817
}
818818
}
819819

820-
impl AsciiExt<Wtf8Buf> for Wtf8 {
820+
impl AsciiExt for Wtf8 {
821+
type Owned = Wtf8Buf;
822+
821823
fn is_ascii(&self) -> bool {
822824
self.bytes.is_ascii()
823825
}
@@ -830,6 +832,9 @@ impl AsciiExt<Wtf8Buf> for Wtf8 {
830832
fn eq_ignore_ascii_case(&self, other: &Wtf8) -> bool {
831833
self.bytes.eq_ignore_ascii_case(&other.bytes)
832834
}
835+
836+
fn make_ascii_uppercase(&mut self) { self.bytes.make_ascii_uppercase() }
837+
fn make_ascii_lowercase(&mut self) { self.bytes.make_ascii_lowercase() }
833838
}
834839

835840
#[cfg(test)]

src/libsyntax/print/pprust.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2761,15 +2761,13 @@ impl<'a> State<'a> {
27612761
ast::LitStr(ref st, style) => self.print_string(&st, style),
27622762
ast::LitByte(byte) => {
27632763
let mut res = String::from_str("b'");
2764-
ascii::escape_default(byte, |c| res.push(c as char));
2764+
res.extend(ascii::escape_default(byte).map(|c| c as char));
27652765
res.push('\'');
27662766
word(&mut self.s, &res[])
27672767
}
27682768
ast::LitChar(ch) => {
27692769
let mut res = String::from_str("'");
2770-
for c in ch.escape_default() {
2771-
res.push(c);
2772-
}
2770+
res.extend(ch.escape_default());
27732771
res.push('\'');
27742772
word(&mut self.s, &res[])
27752773
}
@@ -2809,8 +2807,8 @@ impl<'a> State<'a> {
28092807
ast::LitBinary(ref v) => {
28102808
let mut escaped: String = String::new();
28112809
for &ch in &**v {
2812-
ascii::escape_default(ch as u8,
2813-
|ch| escaped.push(ch as char));
2810+
escaped.extend(ascii::escape_default(ch as u8)
2811+
.map(|c| c as char));
28142812
}
28152813
word(&mut self.s, &format!("b\"{}\"", escaped)[])
28162814
}

src/libterm/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@
5858
#![feature(path)]
5959
#![feature(rustc_private)]
6060
#![feature(staged_api)]
61-
#![feature(std_misc)]
6261
#![feature(unicode)]
6362
#![feature(env)]
6463
#![cfg_attr(windows, feature(libc))]

0 commit comments

Comments
 (0)