Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std: Stabilize the ascii module #22024

Merged
merged 2 commits into from
Feb 18, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/librustc/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1761,7 +1761,7 @@ impl LintPass for Stability {
}

fn check_item(&mut self, cx: &Context, item: &ast::Item) {
stability::check_item(cx.tcx, item,
stability::check_item(cx.tcx, item, false,
&mut |id, sp, stab| self.lint(cx, id, sp, stab));
}

Expand Down
33 changes: 31 additions & 2 deletions src/librustc/middle/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
// name `__test`
if item.span == DUMMY_SP && item.ident.as_str() == "__test" { return }

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

/// Helper for discovering nodes to check for stability
pub fn check_item(tcx: &ty::ctxt, item: &ast::Item,
pub fn check_item(tcx: &ty::ctxt, item: &ast::Item, warn_about_defns: bool,
cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
match item.node {
ast::ItemExternCrate(_) => {
Expand All @@ -316,6 +316,35 @@ pub fn check_item(tcx: &ty::ctxt, item: &ast::Item,
let id = ast::DefId { krate: cnum, node: ast::CRATE_NODE_ID };
maybe_do_stability_check(tcx, id, item.span, cb);
}

// For implementations of traits, check the stability of each item
// individually as it's possible to have a stable trait with unstable
// items.
ast::ItemImpl(_, _, _, Some(ref t), _, ref impl_items) => {
let trait_did = tcx.def_map.borrow()[t.ref_id].def_id();
let trait_items = ty::trait_items(tcx, trait_did);

for impl_item in impl_items {
let (ident, span) = match *impl_item {
ast::MethodImplItem(ref method) => {
(match method.node {
ast::MethDecl(ident, _, _, _, _, _, _, _) => ident,
ast::MethMac(..) => unreachable!(),
}, method.span)
}
ast::TypeImplItem(ref typedef) => {
(typedef.ident, typedef.span)
}
};
let item = trait_items.iter().find(|item| {
item.name() == ident.name
}).unwrap();
if warn_about_defns {
maybe_do_stability_check(tcx, item.def_id(), span, cb);
}
}
}

_ => (/* pass */)
}
}
Expand Down
192 changes: 122 additions & 70 deletions src/libstd/ascii.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,12 @@

//! Operations on ASCII strings and characters

#![unstable(feature = "std_misc",
reason = "unsure about placement and naming")]
#![stable(feature = "rust1", since = "1.0.0")]

use iter::IteratorExt;
use ops::FnMut;
use slice::SliceExt;
use str::StrExt;
use string::String;
use vec::Vec;
use prelude::v1::*;

use mem;
use iter::Range;

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

/// Extension methods for ASCII-subset only operations on string slices
#[unstable(feature = "std_misc",
reason = "would prefer to do this in a more general way")]
pub trait AsciiExt<T = Self> {
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsciiExt {
#[stable(feature = "rust1", since = "1.0.0")]
type Owned;

/// Check if within the ASCII range.
#[stable(feature = "rust1", since = "1.0.0")]
fn is_ascii(&self) -> bool;

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

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

/// Check that two strings are an ASCII case-insensitive match.
/// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
/// but without allocating and copying temporary strings.
#[stable(feature = "rust1", since = "1.0.0")]
fn eq_ignore_ascii_case(&self, other: &Self) -> bool;

/// Convert this type to its ASCII upper case equivalent in-place.
///
/// See `to_ascii_uppercase` for more information.
#[unstable(feature = "ascii")]
fn make_ascii_uppercase(&mut self);

/// Convert this type to its ASCII lower case equivalent in-place.
///
/// See `to_ascii_lowercase` for more information.
#[unstable(feature = "ascii")]
fn make_ascii_lowercase(&mut self);
}

#[unstable(feature = "std_misc",
reason = "would prefer to do this in a more general way")]
impl AsciiExt<String> for str {
#[stable(feature = "rust1", since = "1.0.0")]
impl AsciiExt for str {
type Owned = String;

#[inline]
fn is_ascii(&self) -> bool {
self.bytes().all(|b| b.is_ascii())
}

#[inline]
fn to_ascii_uppercase(&self) -> String {
// Vec<u8>::to_ascii_uppercase() preserves the UTF-8 invariant.
unsafe { String::from_utf8_unchecked(self.as_bytes().to_ascii_uppercase()) }
self.to_string().into_ascii_uppercase()
}

#[inline]
fn to_ascii_lowercase(&self) -> String {
// Vec<u8>::to_ascii_lowercase() preserves the UTF-8 invariant.
unsafe { String::from_utf8_unchecked(self.as_bytes().to_ascii_lowercase()) }
self.to_string().into_ascii_lowercase()
}

#[inline]
fn eq_ignore_ascii_case(&self, other: &str) -> bool {
self.as_bytes().eq_ignore_ascii_case(other.as_bytes())
}

fn make_ascii_uppercase(&mut self) {
let me: &mut [u8] = unsafe { mem::transmute(self) };
me.make_ascii_uppercase()
}

fn make_ascii_lowercase(&mut self) {
let me: &mut [u8] = unsafe { mem::transmute(self) };
me.make_ascii_lowercase()
}
}

#[unstable(feature = "std_misc",
Expand All @@ -102,22 +126,22 @@ impl OwnedAsciiExt for String {
}
}

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

#[inline]
fn to_ascii_uppercase(&self) -> Vec<u8> {
self.iter().map(|b| b.to_ascii_uppercase()).collect()
self.to_vec().into_ascii_uppercase()
}

#[inline]
fn to_ascii_lowercase(&self) -> Vec<u8> {
self.iter().map(|b| b.to_ascii_lowercase()).collect()
self.to_vec().into_ascii_lowercase()
}

#[inline]
Expand All @@ -127,55 +151,58 @@ impl AsciiExt<Vec<u8>> for [u8] {
a.eq_ignore_ascii_case(b)
})
}

fn make_ascii_uppercase(&mut self) {
for byte in self {
byte.make_ascii_uppercase();
}
}

fn make_ascii_lowercase(&mut self) {
for byte in self {
byte.make_ascii_lowercase();
}
}
}

#[unstable(feature = "std_misc",
reason = "would prefer to do this in a more general way")]
impl OwnedAsciiExt for Vec<u8> {
#[inline]
fn into_ascii_uppercase(mut self) -> Vec<u8> {
for byte in &mut self {
*byte = byte.to_ascii_uppercase();
}
self.make_ascii_uppercase();
self
}

#[inline]
fn into_ascii_lowercase(mut self) -> Vec<u8> {
for byte in &mut self {
*byte = byte.to_ascii_lowercase();
}
self.make_ascii_lowercase();
self
}
}

#[unstable(feature = "std_misc",
reason = "would prefer to do this in a more general way")]
#[stable(feature = "rust1", since = "1.0.0")]
impl AsciiExt for u8 {
type Owned = u8;
#[inline]
fn is_ascii(&self) -> bool {
*self & 128 == 0u8
}

fn is_ascii(&self) -> bool { *self & 128 == 0u8 }
#[inline]
fn to_ascii_uppercase(&self) -> u8 {
ASCII_UPPERCASE_MAP[*self as usize]
}

fn to_ascii_uppercase(&self) -> u8 { ASCII_UPPERCASE_MAP[*self as usize] }
#[inline]
fn to_ascii_lowercase(&self) -> u8 {
ASCII_LOWERCASE_MAP[*self as usize]
}

fn to_ascii_lowercase(&self) -> u8 { ASCII_LOWERCASE_MAP[*self as usize] }
#[inline]
fn eq_ignore_ascii_case(&self, other: &u8) -> bool {
self.to_ascii_lowercase() == other.to_ascii_lowercase()
}
#[inline]
fn make_ascii_uppercase(&mut self) { *self = self.to_ascii_uppercase(); }
#[inline]
fn make_ascii_lowercase(&mut self) { *self = self.to_ascii_lowercase(); }
}

#[unstable(feature = "std_misc",
reason = "would prefer to do this in a more general way")]
#[stable(feature = "rust1", since = "1.0.0")]
impl AsciiExt for char {
type Owned = char;
#[inline]
fn is_ascii(&self) -> bool {
*self as u32 <= 0x7F
Expand Down Expand Up @@ -203,6 +230,19 @@ impl AsciiExt for char {
fn eq_ignore_ascii_case(&self, other: &char) -> bool {
self.to_ascii_lowercase() == other.to_ascii_lowercase()
}

#[inline]
fn make_ascii_uppercase(&mut self) { *self = self.to_ascii_uppercase(); }
#[inline]
fn make_ascii_lowercase(&mut self) { *self = self.to_ascii_lowercase(); }
}

/// An iterator over the escaped version of a byte, constructed via
/// `std::ascii::escape_default`.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct EscapeDefault {
range: Range<usize>,
data: [u8; 4],
}

/// Returns a 'default' ASCII and C++11-like literal escape of a `u8`
Expand All @@ -214,34 +254,46 @@ impl AsciiExt for char {
/// - Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively.
/// - Single-quote, double-quote and backslash chars are backslash-escaped.
/// - Any other chars in the range [0x20,0x7e] are not escaped.
/// - Any other chars are given hex escapes.
/// - Any other chars are given hex escapes of the form '\xNN'.
/// - Unicode escapes are never generated by this function.
#[unstable(feature = "std_misc",
reason = "needs to be updated to use an iterator")]
pub fn escape_default<F>(c: u8, mut f: F) where
F: FnMut(u8),
{
match c {
b'\t' => { f(b'\\'); f(b't'); }
b'\r' => { f(b'\\'); f(b'r'); }
b'\n' => { f(b'\\'); f(b'n'); }
b'\\' => { f(b'\\'); f(b'\\'); }
b'\'' => { f(b'\\'); f(b'\''); }
b'"' => { f(b'\\'); f(b'"'); }
b'\x20' ... b'\x7e' => { f(c); }
_ => {
f(b'\\');
f(b'x');
for &offset in &[4u, 0u] {
match ((c as i32) >> offset) & 0xf {
i @ 0 ... 9 => f(b'0' + (i as u8)),
i => f(b'a' + (i as u8 - 10)),
}
}
#[stable(feature = "rust1", since = "1.0.0")]
pub fn escape_default(c: u8) -> EscapeDefault {
let (data, len) = match c {
b'\t' => ([b'\\', b't', 0, 0], 2),
b'\r' => ([b'\\', b'r', 0, 0], 2),
b'\n' => ([b'\\', b'n', 0, 0], 2),
b'\\' => ([b'\\', b'\\', 0, 0], 2),
b'\'' => ([b'\\', b'\'', 0, 0], 2),
b'"' => ([b'\\', b'"', 0, 0], 2),
b'\x20' ... b'\x7e' => ([c, 0, 0, 0], 1),
_ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4),
};

return EscapeDefault { range: range(0, len), data: data };

fn hexify(b: u8) -> u8 {
match b {
0 ... 9 => b'0' + b,
_ => b'a' + b - 10,
}
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Iterator for EscapeDefault {
type Item = u8;
fn next(&mut self) -> Option<u8> { self.range.next().map(|i| self.data[i]) }
fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl DoubleEndedIterator for EscapeDefault {
fn next_back(&mut self) -> Option<u8> {
self.range.next_back().map(|i| self.data[i])
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl ExactSizeIterator for EscapeDefault {}

static ASCII_LOWERCASE_MAP: [u8; 256] = [
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
Expand Down
7 changes: 6 additions & 1 deletion src/libstd/sys/common/wtf8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -817,7 +817,9 @@ impl<'a, S: Writer + Hasher> Hash<S> for Wtf8 {
}
}

impl AsciiExt<Wtf8Buf> for Wtf8 {
impl AsciiExt for Wtf8 {
type Owned = Wtf8Buf;

fn is_ascii(&self) -> bool {
self.bytes.is_ascii()
}
Expand All @@ -830,6 +832,9 @@ impl AsciiExt<Wtf8Buf> for Wtf8 {
fn eq_ignore_ascii_case(&self, other: &Wtf8) -> bool {
self.bytes.eq_ignore_ascii_case(&other.bytes)
}

fn make_ascii_uppercase(&mut self) { self.bytes.make_ascii_uppercase() }
fn make_ascii_lowercase(&mut self) { self.bytes.make_ascii_lowercase() }
}

#[cfg(test)]
Expand Down
Loading