From 61ffee738d505328fae14ac7c53bc388c69c5938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20L=C3=B6bel?= Date: Sat, 20 Apr 2013 19:39:15 +0200 Subject: [PATCH] Added Ascii type --- src/libcore/prelude.rs | 7 +- src/libcore/str.rs | 17 ++- src/libcore/str/ascii.rs | 216 +++++++++++++++++++++++++++++++++++++++ src/libcore/to_str.rs | 6 ++ 4 files changed, 243 insertions(+), 3 deletions(-) create mode 100644 src/libcore/str/ascii.rs diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index 822fb2e476b..84793694582 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -40,9 +40,14 @@ pub use path::Path; pub use path::PosixPath; pub use path::WindowsPath; pub use ptr::Ptr; +// NOTE: Remove markers after snapshot +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] +pub use str::{Ascii, AsciiCast, OwnedAsciiCast, ToStrAscii}; pub use str::{StrSlice, OwnedStr}; pub use to_bytes::IterBytes; -pub use to_str::ToStr; +pub use to_str::{ToStr, ToStrConsume}; pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps}; pub use vec::{CopyableVector, ImmutableVector}; pub use vec::{ImmutableEqVector, ImmutableCopyableVector}; diff --git a/src/libcore/str.rs b/src/libcore/str.rs index 2296fea0454..11301c9f1db 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -17,6 +17,12 @@ * some heavy-duty uses, try std::rope. */ +// NOTE: Remove markers after snapshot +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] +pub use self::ascii::{Ascii, AsciiCast, OwnedAsciiCast, ToStrAscii}; + use at_vec; use cast; use char; @@ -34,6 +40,13 @@ use to_str::ToStr; #[cfg(notest)] use cmp::{Eq, Ord, Equiv, TotalEq}; +// NOTE: Remove markers after snapshot +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] +#[path = "str/ascii.rs"] +mod ascii; + /* Section: Creating a string */ @@ -3347,7 +3360,7 @@ mod tests { #[test] fn test_shift_byte() { let mut s = ~"ABC"; - let b = raw::shift_byte(&mut s); + let b = unsafe{raw::shift_byte(&mut s)}; assert!((s == ~"BC")); assert!((b == 65u8)); } @@ -3355,7 +3368,7 @@ mod tests { #[test] fn test_pop_byte() { let mut s = ~"ABC"; - let b = raw::pop_byte(&mut s); + let b = unsafe{raw::pop_byte(&mut s)}; assert!((s == ~"AB")); assert!((b == 67u8)); } diff --git a/src/libcore/str/ascii.rs b/src/libcore/str/ascii.rs new file mode 100644 index 00000000000..1e882daeef9 --- /dev/null +++ b/src/libcore/str/ascii.rs @@ -0,0 +1,216 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use to_str::{ToStr,ToStrConsume}; +use str; +use cast; + +#[cfg(test)] +pub struct Ascii { priv chr: u8 } + +/// Datatype to hold one ascii character. It is 8 bit long. +#[cfg(notest)] +#[deriving(Clone, Eq, Ord)] +pub struct Ascii { priv chr: u8 } + +pub impl Ascii { + /// Converts a ascii character into a `u8`. + fn to_byte(self) -> u8 { + self.chr + } + + /// Converts a ascii character into a `char`. + fn to_char(self) -> char { + self.chr as char + } +} + +impl ToStr for Ascii { + fn to_str(&self) -> ~str { str::from_bytes(['\'' as u8, self.chr, '\'' as u8]) } +} + +/// Trait for converting into an ascii type. +pub trait AsciiCast { + /// Convert to an ascii type + fn to_ascii(&self) -> T; + + /// Check if convertible to ascii + fn is_ascii(&self) -> bool; +} + +impl<'self> AsciiCast<&'self[Ascii]> for &'self [u8] { + fn to_ascii(&self) -> &'self[Ascii] { + assert!(self.is_ascii()); + + unsafe{ cast::transmute(*self) } + } + + fn is_ascii(&self) -> bool { + for self.each |b| { + if !b.is_ascii() { return false; } + } + true + } +} + +impl<'self> AsciiCast<&'self[Ascii]> for &'self str { + 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))} + } + + fn is_ascii(&self) -> bool { + for self.each |b| { + if !b.is_ascii() { return false; } + } + true + } +} + +impl AsciiCast for u8 { + fn to_ascii(&self) -> Ascii { + assert!(self.is_ascii()); + Ascii{ chr: *self } + } + + fn is_ascii(&self) -> bool { + *self & 128 == 0u8 + } +} + +impl AsciiCast for char { + fn to_ascii(&self) -> Ascii { + assert!(self.is_ascii()); + Ascii{ chr: *self as u8 } + } + + fn is_ascii(&self) -> bool { + *self - ('\x7F' & *self) == '\x00' + } +} + +/// 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]; +} + +impl OwnedAsciiCast for ~[u8] { + fn to_ascii_consume(self) -> ~[Ascii] { + assert!(self.is_ascii()); + + unsafe {cast::transmute(self)} + } +} + +impl OwnedAsciiCast for ~str { + fn to_ascii_consume(self) -> ~[Ascii] { + let mut s = self; + unsafe { + str::raw::pop_byte(&mut s); + cast::transmute(s) + } + } +} + +/// Trait for converting an ascii type to a string. Needed to convert `&[Ascii]` to `~str` +pub trait ToStrAscii { + /// Convert to a string. + fn to_str_ascii(&self) -> ~str; +} + +impl<'self> ToStrAscii for &'self [Ascii] { + fn to_str_ascii(&self) -> ~str { + let mut cpy = self.to_owned(); + cpy.push(0u8.to_ascii()); + unsafe {cast::transmute(cpy)} + } +} + +impl ToStrConsume for ~[Ascii] { + fn to_str_consume(self) -> ~str { + let mut cpy = self; + cpy.push(0u8.to_ascii()); + unsafe {cast::transmute(cpy)} + } +} + +// NOTE: Remove stage0 marker after snapshot +#[cfg(and(test, not(stage0)))] +mod tests { + use super::*; + use to_str::{ToStr,ToStrConsume}; + use str; + use cast; + + macro_rules! v2ascii ( + ( [$($e:expr),*]) => ( [$(Ascii{chr:$e}),*]); + (~[$($e:expr),*]) => (~[$(Ascii{chr:$e}),*]); + ) + + #[test] + fn test_ascii() { + assert_eq!(65u8.to_ascii().to_byte(), 65u8); + assert_eq!(65u8.to_ascii().to_char(), 'A'); + assert_eq!('A'.to_ascii().to_char(), 'A'); + assert_eq!('A'.to_ascii().to_byte(), 65u8); + } + + #[test] + fn test_ascii_vec() { + assert_eq!((&[40u8, 32u8, 59u8]).to_ascii(), v2ascii!([40, 32, 59])); + assert_eq!("( ;".to_ascii(), v2ascii!([40, 32, 59])); + // FIXME: #5475 borrowchk error, owned vectors do not live long enough + // if chained-from directly + let v = ~[40u8, 32u8, 59u8]; assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59])); + let v = ~"( ;"; assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59])); + } + + #[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])); + } + + #[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(), ~"( ;"); + } + + #[test] #[should_fail] + fn test_ascii_vec_fail_u8_slice() { (&[127u8, 128u8, 255u8]).to_ascii(); } + + #[test] #[should_fail] + fn test_ascii_vec_fail_str_slice() { "zoä华".to_ascii(); } + + #[test] #[should_fail] + fn test_ascii_fail_u8_slice() { 255u8.to_ascii(); } + + #[test] #[should_fail] + fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); } +} + + + + + + + + diff --git a/src/libcore/to_str.rs b/src/libcore/to_str.rs index 980d4b445d0..7f8e6915add 100644 --- a/src/libcore/to_str.rs +++ b/src/libcore/to_str.rs @@ -20,6 +20,12 @@ pub trait ToStr { fn to_str(&self) -> ~str; } +/// 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; +} + impl ToStr for bool { #[inline(always)] fn to_str(&self) -> ~str { ::bool::to_str(*self) }