diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 60165ed5daebe..309df27e151d2 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -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; diff --git a/src/libstd/str/ascii.rs b/src/libstd/str/ascii.rs index 618d5095777a9..635510b3a78f0 100644 --- a/src/libstd/str/ascii.rs +++ b/src/libstd/str/ascii.rs @@ -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 } @@ -72,6 +73,9 @@ pub trait AsciiCast { /// 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; } @@ -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)] @@ -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)] @@ -110,6 +124,11 @@ impl AsciiCast 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 } } @@ -123,6 +142,11 @@ impl AsciiCast 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 } } @@ -135,26 +159,38 @@ impl AsciiCast 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 } } @@ -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] { @@ -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}),*]); @@ -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()); @@ -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] diff --git a/src/libstd/to_str.rs b/src/libstd/to_str.rs index bfda92d46a284..46e50b6f76e0d 100644 --- a/src/libstd/to_str.rs +++ b/src/libstd/to_str.rs @@ -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 () {