Skip to content

Commit

Permalink
auto merge of rust-lang#10828 : SimonSapin/rust/ascii_opt, r=pcwalton
Browse files Browse the repository at this point in the history
… instead of failing.

Make them default methods on the trait, and also make .to_ascii() a default method while we’re at it.
  • Loading branch information
bors committed Jan 2, 2014
2 parents 0df9b85 + f8cc9a9 commit 2e98a93
Showing 1 changed file with 70 additions and 36 deletions.
106 changes: 70 additions & 36 deletions src/libstd/ascii.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@

use to_str::{ToStr,IntoStr};
use str;
use str::Str;
use str::StrSlice;
use str::OwnedStr;
use container::Container;
use cast;
use iter::Iterator;
use vec::{ImmutableVector, MutableVector};
use vec::{ImmutableVector, MutableVector, Vector};
use to_bytes::IterBytes;
use option::{Some, None};
use option::{Option, Some, None};

/// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero.
#[deriving(Clone, Eq, Ord, TotalOrd, TotalEq)]
Expand Down Expand Up @@ -135,8 +136,22 @@ impl ToStr for Ascii {

/// Trait for converting into an ascii type.
pub trait AsciiCast<T> {
/// Convert to an ascii type
fn to_ascii(&self) -> T;
/// Convert to an ascii type, fail on non-ASCII input.
#[inline]
fn to_ascii(&self) -> T {
assert!(self.is_ascii());
unsafe {self.to_ascii_nocheck()}
}

/// Convert to an ascii type, return None on non-ASCII input.
#[inline]
fn to_ascii_opt(&self) -> Option<T> {
if self.is_ascii() {
Some(unsafe { self.to_ascii_nocheck() })
} else {
None
}
}

/// Convert to an ascii type, not doing any range asserts
unsafe fn to_ascii_nocheck(&self) -> T;
Expand All @@ -146,12 +161,6 @@ pub trait AsciiCast<T> {
}

impl<'a> AsciiCast<&'a[Ascii]> for &'a [u8] {
#[inline]
fn to_ascii(&self) -> &'a[Ascii] {
assert!(self.is_ascii());
unsafe {self.to_ascii_nocheck()}
}

#[inline]
unsafe fn to_ascii_nocheck(&self) -> &'a[Ascii] {
cast::transmute(*self)
Expand All @@ -167,12 +176,6 @@ impl<'a> AsciiCast<&'a[Ascii]> for &'a [u8] {
}

impl<'a> AsciiCast<&'a [Ascii]> for &'a str {
#[inline]
fn to_ascii(&self) -> &'a [Ascii] {
assert!(self.is_ascii());
unsafe { self.to_ascii_nocheck() }
}

#[inline]
unsafe fn to_ascii_nocheck(&self) -> &'a [Ascii] {
cast::transmute(*self)
Expand All @@ -185,12 +188,6 @@ impl<'a> AsciiCast<&'a [Ascii]> for &'a str {
}

impl AsciiCast<Ascii> for u8 {
#[inline]
fn to_ascii(&self) -> Ascii {
assert!(self.is_ascii());
unsafe {self.to_ascii_nocheck()}
}

#[inline]
unsafe fn to_ascii_nocheck(&self) -> Ascii {
Ascii{ chr: *self }
Expand All @@ -203,12 +200,6 @@ impl AsciiCast<Ascii> for u8 {
}

impl AsciiCast<Ascii> for char {
#[inline]
fn to_ascii(&self) -> Ascii {
assert!(self.is_ascii());
unsafe {self.to_ascii_nocheck()}
}

#[inline]
unsafe fn to_ascii_nocheck(&self) -> Ascii {
Ascii{ chr: *self as u8 }
Expand All @@ -222,8 +213,25 @@ impl AsciiCast<Ascii> for char {

/// Trait for copyless casting to an ascii vector.
pub trait OwnedAsciiCast {
/// Take ownership and cast to an ascii vector.
fn into_ascii(self) -> ~[Ascii];
/// Check if convertible to ascii
fn is_ascii(&self) -> bool;

/// Take ownership and cast to an ascii vector. Fail on non-ASCII input.
#[inline]
fn into_ascii(self) -> ~[Ascii] {
assert!(self.is_ascii());
unsafe {self.into_ascii_nocheck()}
}

/// Take ownership and cast to an ascii vector. Return None on non-ASCII input.
#[inline]
fn into_ascii_opt(self) -> Option<~[Ascii]> {
if self.is_ascii() {
Some(unsafe { self.into_ascii_nocheck() })
} else {
None
}
}

/// Take ownership and cast to an ascii vector.
/// Does not perform validation checks.
Expand All @@ -232,9 +240,8 @@ pub trait OwnedAsciiCast {

impl OwnedAsciiCast for ~[u8] {
#[inline]
fn into_ascii(self) -> ~[Ascii] {
assert!(self.is_ascii());
unsafe {self.into_ascii_nocheck()}
fn is_ascii(&self) -> bool {
self.as_slice().is_ascii()
}

#[inline]
Expand All @@ -245,9 +252,8 @@ impl OwnedAsciiCast for ~[u8] {

impl OwnedAsciiCast for ~str {
#[inline]
fn into_ascii(self) -> ~[Ascii] {
assert!(self.is_ascii());
unsafe {self.into_ascii_nocheck()}
fn is_ascii(&self) -> bool {
self.as_slice().is_ascii()
}

#[inline]
Expand Down Expand Up @@ -475,9 +481,11 @@ mod tests {
use super::*;
use str::from_char;
use char::from_u32;
use option::{Some, None};

macro_rules! v2ascii (
( [$($e:expr),*]) => ( [$(Ascii{chr:$e}),*]);
(&[$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
(~[$($e:expr),*]) => (~[$(Ascii{chr:$e}),*]);
)

Expand Down Expand Up @@ -569,6 +577,32 @@ mod tests {
#[test] #[should_fail]
fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }

fn test_opt() {
assert_eq!(65u8.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
assert_eq!(255u8.to_ascii_opt(), None);

assert_eq!('A'.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
assert_eq!('λ'.to_ascii_opt(), None);

assert_eq!("zoä华".to_ascii_opt(), None);

assert_eq!((&[127u8, 128u8, 255u8]).to_ascii_opt(), None);

let v = [40u8, 32u8, 59u8];
assert_eq!(v.to_ascii_opt(), Some(v2ascii!(&[40, 32, 59])));
let v = [127u8, 128u8, 255u8];
assert_eq!(v.to_ascii_opt(), None);

assert_eq!("( ;".to_ascii_opt(), Some(v2ascii!(&[40, 32, 59])));
assert_eq!("zoä华".to_ascii_opt(), None);

assert_eq!((~[40u8, 32u8, 59u8]).into_ascii_opt(), Some(v2ascii!(~[40, 32, 59])));
assert_eq!((~[127u8, 128u8, 255u8]).into_ascii_opt(), None);

assert_eq!((~"( ;").into_ascii_opt(), Some(v2ascii!(~[40, 32, 59])));
assert_eq!((~"zoä华").into_ascii_opt(), None);
}

#[test]
fn test_to_ascii_upper() {
assert_eq!("url()URL()uRl()ürl".to_ascii_upper(), ~"URL()URL()URL()üRL");
Expand Down

0 comments on commit 2e98a93

Please sign in to comment.