Skip to content

Commit

Permalink
Merge pull request #17 from tormol/into_ascii
Browse files Browse the repository at this point in the history
Add traits IntoAscii* to replace (Owned)AsciiCast
  • Loading branch information
Thomas Bahn committed May 9, 2016
2 parents 082c577 + a6c80f7 commit c351e7e
Show file tree
Hide file tree
Showing 5 changed files with 359 additions and 23 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ before_script:
script:
- |
travis-cargo build &&
travis-cargo test &&
travis-cargo --skip 1.1.0 test &&
travis-cargo --only stable doc
after_success:
Expand Down
96 changes: 88 additions & 8 deletions src/ascii.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::mem::transmute;
use std::fmt;
#[cfg(feature="unstable")]
use std::error::Error;
use std::ascii::AsciiExt;

use AsciiCast;
Expand Down Expand Up @@ -279,7 +279,7 @@ pub enum Ascii {
}

impl Ascii {
/// Constructs an Ascii character from a `char`.
/// Constructs an ASCII character from a `u8`, `char` or other character type.
///
/// # Failure
///
Expand All @@ -292,11 +292,13 @@ impl Ascii {
/// assert_eq!(a.as_char(), 'g');
/// ```
#[inline]
pub fn from(ch: char) -> Result<Ascii, ()> {
unsafe{if ch as u32 <= 0x7F {
return Ok(ch.to_ascii_nocheck());
}}
Err(())
pub fn from<C:IntoAscii>(ch: C) -> Result<Self, ()> {
ch.into_ascii().map_err(|_| () )
}

/// Constructs an ASCII character from a `char` or `u8` without any checks.
pub unsafe fn from_unchecked<C:IntoAscii>(ch: C) -> Self {
ch.into_ascii_unchecked()
}

/// Constructs an Ascii character from a `u8`.
Expand Down Expand Up @@ -530,10 +532,79 @@ impl<'a> AsciiCast<'a> for char {
}
}


/// Error returned by `IntoAscii`.
#[derive(PartialEq)]
pub struct IntoAsciiError(());

const ERRORMSG_CHAR: &'static str = "not an ASCII character";

impl fmt::Debug for IntoAsciiError {
fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
write!(fmtr, "{}", ERRORMSG_CHAR)
}
}

impl fmt::Display for IntoAsciiError {
fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
write!(fmtr, "{}", ERRORMSG_CHAR)
}
}

impl Error for IntoAsciiError {
fn description(&self) -> &'static str {
ERRORMSG_CHAR
}
}


/// Convert `char`, `u8` and other character types to `Ascii`.
pub trait IntoAscii : AsciiExt {
/// Convert to `Ascii` without checking that it is an ASCII character.
unsafe fn into_ascii_unchecked(self) -> Ascii;
/// Convert to `Ascii`.
fn into_ascii(self) -> Result<Ascii,IntoAsciiError>;
}

#[cfg(feature = "unstable")]
impl IntoAscii for Ascii {
fn into_ascii(self) -> Result<Ascii,IntoAsciiError> {
Ok(self)
}
unsafe fn into_ascii_unchecked(self) -> Ascii {
self
}
}

impl IntoAscii for u8 {
fn into_ascii(self) -> Result<Ascii,IntoAsciiError> {
unsafe{if self <= 0x7F {
return Ok(self.into_ascii_unchecked());
}}
Err(IntoAsciiError(()))
}
unsafe fn into_ascii_unchecked(self) -> Ascii {
transmute(self)
}
}

impl IntoAscii for char {
fn into_ascii(self) -> Result<Ascii,IntoAsciiError> {
unsafe{if self as u32 <= 0x7F {
return Ok(self.into_ascii_unchecked());
}}
Err(IntoAsciiError(()))
}
unsafe fn into_ascii_unchecked(self) -> Ascii {
(self as u8).into_ascii_unchecked()
}
}


#[cfg(test)]
mod tests {
use AsciiCast;
use super::Ascii;
use super::{Ascii,IntoAscii,IntoAsciiError};

#[test]
fn to_ascii() {
Expand All @@ -544,6 +615,15 @@ mod tests {
assert_eq!('λ'.to_ascii(), Err(()));
}

#[test]
fn into_ascii() {
fn generic<C:IntoAscii>(c: C) -> Result<Ascii,IntoAsciiError> {
c.into_ascii()
}
assert_eq!(generic('A'), Ok(Ascii::A));
assert_eq!(generic(b'A'), Ok(Ascii::A));
}

#[test]
fn as_byte() {
assert_eq!(65u8.to_ascii().unwrap().as_byte(), 65u8);
Expand Down
Loading

0 comments on commit c351e7e

Please sign in to comment.