Skip to content

Improved some things in std::ascii #7199

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

Closed
wants to merge 1 commit into from
Closed
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/libstd/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pub use path::Path;
pub use path::PosixPath;
pub use path::WindowsPath;
pub use ptr::RawPtr;
pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr};
pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr, ToBytesConsume};
pub use str::{Str, StrVector, StrSlice, OwnedStr, StrUtil, NullTerminatedStr};
pub use from_str::{FromStr};
pub use to_bytes::IterBytes;
Expand Down
112 changes: 89 additions & 23 deletions src/libstd/str/ascii.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ use cast;
use old_iter::BaseIter;
use iterator::IteratorUtil;
use vec::{CopyableVector, ImmutableVector, OwnedVector};
use to_bytes::IterBytes;

/// Datatype to hold one ascii character. It is 8 bit long.
/// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero.
#[deriving(Clone, Eq)]
pub struct Ascii { priv chr: u8 }

Expand Down Expand Up @@ -72,6 +73,9 @@ pub trait AsciiCast<T> {
/// Convert to an ascii type
fn to_ascii(&self) -> T;

/// Convert to an ascii type, not doing any range asserts
unsafe fn to_ascii_nocheck(&self) -> T;

/// Check if convertible to ascii
fn is_ascii(&self) -> bool;
}
Expand All @@ -80,7 +84,12 @@ impl<'self> AsciiCast<&'self[Ascii]> for &'self [u8] {
#[inline(always)]
fn to_ascii(&self) -> &'self[Ascii] {
assert!(self.is_ascii());
unsafe{ cast::transmute(*self) }
unsafe {self.to_ascii_nocheck()}
}

#[inline(always)]
unsafe fn to_ascii_nocheck(&self) -> &'self[Ascii] {
cast::transmute(*self)
}

#[inline(always)]
Expand All @@ -96,8 +105,13 @@ impl<'self> AsciiCast<&'self[Ascii]> for &'self str {
#[inline(always)]
fn to_ascii(&self) -> &'self[Ascii] {
assert!(self.is_ascii());
let (p,len): (*u8, uint) = unsafe{ cast::transmute(*self) };
unsafe{ cast::transmute((p, len - 1))}
unsafe {self.to_ascii_nocheck()}
}

#[inline(always)]
unsafe fn to_ascii_nocheck(&self) -> &'self[Ascii] {
let (p,len): (*u8, uint) = cast::transmute(*self);
cast::transmute((p, len - 1))
}

#[inline(always)]
Expand All @@ -110,6 +124,11 @@ impl AsciiCast<Ascii> for u8 {
#[inline(always)]
fn to_ascii(&self) -> Ascii {
assert!(self.is_ascii());
unsafe {self.to_ascii_nocheck()}
}

#[inline(always)]
unsafe fn to_ascii_nocheck(&self) -> Ascii {
Ascii{ chr: *self }
}

Expand All @@ -123,6 +142,11 @@ impl AsciiCast<Ascii> for char {
#[inline(always)]
fn to_ascii(&self) -> Ascii {
assert!(self.is_ascii());
unsafe {self.to_ascii_nocheck()}
}

#[inline(always)]
unsafe fn to_ascii_nocheck(&self) -> Ascii {
Ascii{ chr: *self as u8 }
}

Expand All @@ -135,26 +159,38 @@ impl AsciiCast<Ascii> for char {
/// Trait for copyless casting to an ascii vector.
pub trait OwnedAsciiCast {
/// Take ownership and cast to an ascii vector without trailing zero element.
fn to_ascii_consume(self) -> ~[Ascii];
fn into_ascii(self) -> ~[Ascii];

/// Take ownership and cast to an ascii vector without trailing zero element.
/// Does not perform validation checks.
unsafe fn into_ascii_nocheck(self) -> ~[Ascii];
}

impl OwnedAsciiCast for ~[u8] {
#[inline(always)]
fn to_ascii_consume(self) -> ~[Ascii] {
fn into_ascii(self) -> ~[Ascii] {
assert!(self.is_ascii());
unsafe {cast::transmute(self)}
unsafe {self.into_ascii_nocheck()}
}

#[inline(always)]
unsafe fn into_ascii_nocheck(self) -> ~[Ascii] {
cast::transmute(self)
}
}

impl OwnedAsciiCast for ~str {
#[inline(always)]
fn to_ascii_consume(self) -> ~[Ascii] {
fn into_ascii(self) -> ~[Ascii] {
assert!(self.is_ascii());
let mut s = self;
unsafe {
str::raw::pop_byte(&mut s);
cast::transmute(s)
}
unsafe {self.into_ascii_nocheck()}
}

#[inline(always)]
unsafe fn into_ascii_nocheck(self) -> ~[Ascii] {
let mut r: ~[Ascii] = cast::transmute(self);
r.pop();
r
}
}

Expand All @@ -169,6 +205,8 @@ pub trait AsciiStr {
/// Convert to vector representing a upper cased ascii string.
fn to_upper(&self) -> ~[Ascii];

/// Compares two Ascii strings ignoring case
fn eq_ignore_case(self, other: &[Ascii]) -> bool;
}

impl<'self> AsciiStr for &'self [Ascii] {
Expand All @@ -188,20 +226,45 @@ impl<'self> AsciiStr for &'self [Ascii] {
fn to_upper(&self) -> ~[Ascii] {
self.map(|a| a.to_upper())
}

#[inline(always)]
fn eq_ignore_case(self, other: &[Ascii]) -> bool {
do self.iter().zip(other.iter()).all |(&a, &b)| { a.eq_ignore_case(b) }
}
}

impl ToStrConsume for ~[Ascii] {
#[inline(always)]
fn to_str_consume(self) -> ~str {
fn into_str(self) -> ~str {
let mut cpy = self;
cpy.push(0u8.to_ascii());
unsafe {cast::transmute(cpy)}
}
}

impl IterBytes for Ascii {
#[inline(always)]
fn iter_bytes(&self, _lsb0: bool, f: &fn(buf: &[u8]) -> bool) -> bool {
f([self.to_byte()])
}
}

/// Trait to convert to a owned byte array by consuming self
pub trait ToBytesConsume {
/// Converts to a owned byte array by consuming self
fn into_bytes(self) -> ~[u8];
}

impl ToBytesConsume for ~[Ascii] {
fn into_bytes(self) -> ~[u8] {
unsafe {cast::transmute(self)}
}
}

#[cfg(test)]
mod tests {
use super::*;
use to_bytes::ToBytes;

macro_rules! v2ascii (
( [$($e:expr),*]) => ( [$(Ascii{chr:$e}),*]);
Expand Down Expand Up @@ -245,6 +308,8 @@ mod tests {
assert_eq!("YMCA".to_ascii().to_lower().to_str_ascii(), ~"ymca");
assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().to_str_ascii(), ~"ABCDEFXYZ:.;");

assert!("aBcDeF&?#".to_ascii().eq_ignore_case("AbCdEf&?#".to_ascii()));

assert!("".is_ascii());
assert!("a".is_ascii());
assert!(!"\u2009".is_ascii());
Expand All @@ -253,21 +318,22 @@ mod tests {

#[test]
fn test_owned_ascii_vec() {
// FIXME: #4318 Compiler crashes on moving self
//assert_eq!(~"( ;".to_ascii_consume(), v2ascii!(~[40, 32, 59]));
//assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume(), v2ascii!(~[40, 32, 59]));
//assert_eq!(~"( ;".to_ascii_consume_with_null(), v2ascii!(~[40, 32, 59, 0]));
//assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume_with_null(),
// v2ascii!(~[40, 32, 59, 0]));
assert_eq!((~"( ;").into_ascii(), v2ascii!(~[40, 32, 59]));
assert_eq!((~[40u8, 32u8, 59u8]).into_ascii(), v2ascii!(~[40, 32, 59]));
}

#[test]
fn test_ascii_to_str() { assert_eq!(v2ascii!([40, 32, 59]).to_str_ascii(), ~"( ;"); }

#[test]
fn test_ascii_to_str_consume() {
// FIXME: #4318 Compiler crashes on moving self
//assert_eq!(v2ascii!(~[40, 32, 59]).to_str_consume(), ~"( ;");
fn test_ascii_into_str() {
assert_eq!(v2ascii!(~[40, 32, 59]).into_str(), ~"( ;");
}

#[test]
fn test_ascii_to_bytes() {
assert_eq!(v2ascii!(~[40, 32, 59]).to_bytes(false), ~[40u8, 32u8, 59u8]);
assert_eq!(v2ascii!(~[40, 32, 59]).into_bytes(), ~[40u8, 32u8, 59u8]);
}

#[test] #[should_fail]
Expand Down
2 changes: 1 addition & 1 deletion src/libstd/to_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pub trait ToStr {
/// Trait for converting a type to a string, consuming it in the process.
pub trait ToStrConsume {
/// Cosume and convert to a string.
fn to_str_consume(self) -> ~str;
fn into_str(self) -> ~str;
}

impl ToStr for () {
Expand Down