Skip to content

Commit f492095

Browse files
committed
rollup merge of rust-lang#22024: alexcrichton/ascii
* Move the type parameter on the `AsciiExt` trait to an associated type named `Owned`. * Move `ascii::escape_default` to using an iterator. This is a breaking change due to the removal of the type parameter on the `AsciiExt` trait as well as the modifications to the `escape_default` function to returning an iterator. Manual implementations of `AsciiExt` (or `AsciiExt` bounds) should be adjusted to remove the type parameter and using the new `escape_default` should be relatively straightforward. [breaking-change]
2 parents 096b105 + 235f35b commit f492095

File tree

7 files changed

+169
-81
lines changed

7 files changed

+169
-81
lines changed

src/librustc/lint/builtin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1714,7 +1714,7 @@ impl LintPass for Stability {
17141714
}
17151715

17161716
fn check_item(&mut self, cx: &Context, item: &ast::Item) {
1717-
stability::check_item(cx.tcx, item,
1717+
stability::check_item(cx.tcx, item, false,
17181718
&mut |id, sp, stab| self.lint(cx, id, sp, stab));
17191719
}
17201720

src/librustc/middle/stability.rs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
283283
// name `__test`
284284
if item.span == DUMMY_SP && item.ident.as_str() == "__test" { return }
285285

286-
check_item(self.tcx, item,
286+
check_item(self.tcx, item, true,
287287
&mut |id, sp, stab| self.check(id, sp, stab));
288288
visit::walk_item(self, item);
289289
}
@@ -302,7 +302,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
302302
}
303303

304304
/// Helper for discovering nodes to check for stability
305-
pub fn check_item(tcx: &ty::ctxt, item: &ast::Item,
305+
pub fn check_item(tcx: &ty::ctxt, item: &ast::Item, warn_about_defns: bool,
306306
cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
307307
match item.node {
308308
ast::ItemExternCrate(_) => {
@@ -316,6 +316,35 @@ pub fn check_item(tcx: &ty::ctxt, item: &ast::Item,
316316
let id = ast::DefId { krate: cnum, node: ast::CRATE_NODE_ID };
317317
maybe_do_stability_check(tcx, id, item.span, cb);
318318
}
319+
320+
// For implementations of traits, check the stability of each item
321+
// individually as it's possible to have a stable trait with unstable
322+
// items.
323+
ast::ItemImpl(_, _, _, Some(ref t), _, ref impl_items) => {
324+
let trait_did = tcx.def_map.borrow()[t.ref_id].def_id();
325+
let trait_items = ty::trait_items(tcx, trait_did);
326+
327+
for impl_item in impl_items {
328+
let (ident, span) = match *impl_item {
329+
ast::MethodImplItem(ref method) => {
330+
(match method.node {
331+
ast::MethDecl(ident, _, _, _, _, _, _, _) => ident,
332+
ast::MethMac(..) => unreachable!(),
333+
}, method.span)
334+
}
335+
ast::TypeImplItem(ref typedef) => {
336+
(typedef.ident, typedef.span)
337+
}
338+
};
339+
let item = trait_items.iter().find(|item| {
340+
item.name() == ident.name
341+
}).unwrap();
342+
if warn_about_defns {
343+
maybe_do_stability_check(tcx, item.def_id(), span, cb);
344+
}
345+
}
346+
}
347+
319348
_ => (/* pass */)
320349
}
321350
}

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

0 commit comments

Comments
 (0)