<commit_before>// Copyright 2013-2014 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// ignore-lexer-test FIXME #15679

//! Operations on ASCII strings and characters

#![feature(macro_rules, globs, default_type_params, old_orphan_check)]
// added old_orphan_check to work around https://github.com/rust-lang/rust/issues/20477

#![unstable = "unsure about placement and naming"]
#![allow(deprecated)]

//use std::kinds::Sized;

use std::fmt;
use std::mem;
use std::borrow::BorrowFrom;
use std::ascii::AsciiExt;

/// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero.
#[derive(Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Copy)]
pub struct Ascii { chr: u8 }

impl Ascii {
    /// Converts an ascii character into a `u8`.
    #[inline]
    #[unstable = "recently renamed"]
    pub fn as_byte(&self) -> u8 {
        self.chr
    }

    /// Converts an ascii character into a `char`.
    #[inline]
    #[unstable = "recently renamed"]
    pub fn as_char(&self) -> char {
        self.chr as char
    }

    /// Convert to lowercase.
    #[inline]
    #[stable]
    pub fn to_lowercase(&self) -> Ascii {
        Ascii{chr: self.chr.to_ascii_lowercase()}
    }

    /// Convert to uppercase.
    #[inline]
    #[stable]
    pub fn to_uppercase(&self) -> Ascii {
        Ascii{chr: self.chr.to_ascii_uppercase()}
    }

    // the following methods are like ctype, and the implementation is inspired by musl

    /// Check if the character is a letter (a-z, A-Z)
    #[inline]
    #[stable]
    pub fn is_alphabetic(&self) -> bool {
        (self.chr >= 0x41 && self.chr <= 0x5A) || (self.chr >= 0x61 && self.chr <= 0x7A)
    }

    /// Check if the character is a number (0-9)
    #[inline]
    #[unstable = "may be renamed"]
    pub fn is_digit(&self) -> bool {
        self.chr >= 0x30 && self.chr <= 0x39
    }

    /// Check if the character is a letter or number
    #[inline]
    #[stable]
    pub fn is_alphanumeric(&self) -> bool {
        self.is_alphabetic() || self.is_digit()
    }

    /// Check if the character is a space or horizontal tab
    #[inline]
    #[experimental = "likely to be removed"]
    pub fn is_blank(&self) -> bool {
        self.chr == b' ' || self.chr == b'\t'
    }

    /// Check if the character is a control character
    #[inline]
    #[stable]
    pub fn is_control(&self) -> bool {
        self.chr < 0x20 || self.chr == 0x7F
    }

    /// Checks if the character is printable (except space)
    #[inline]
    #[experimental = "unsure about naming, or whether this is needed"]
    pub fn is_graph(&self) -> bool {
        (self.chr - 0x21) < 0x5E
    }

    /// Checks if the character is printable (including space)
    #[inline]
    #[unstable = "unsure about naming"]
    pub fn is_print(&self) -> bool {
        (self.chr - 0x20) < 0x5F
    }

    /// Checks if the character is alphabetic and lowercase
    #[inline]
    #[stable]
    pub fn is_lowercase(&self) -> bool {
        (self.chr - b'a') < 26
    }

    /// Checks if the character is alphabetic and uppercase
    #[inline]
    #[stable]
    pub fn is_uppercase(&self) -> bool {
        (self.chr - b'A') < 26
    }

    /// Checks if the character is punctuation
    #[inline]
    #[stable]
    pub fn is_punctuation(&self) -> bool {
        self.is_graph() && !self.is_alphanumeric()
    }

    /// Checks if the character is a valid hex digit
    #[inline]
    #[stable]
    pub fn is_hex(&self) -> bool {
        self.is_digit() || ((self.chr | 32u8) - b'a') < 6
    }
}

impl<'a> fmt::Show for Ascii {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        (self.chr as char).fmt(f)
    }
}

/// Trait for converting into an ascii type.
#[experimental = "may be replaced by generic conversion traits"]
pub trait AsciiCast<T, U = Self> : AsciiExt<U> {
    /// Convert to an ascii type, return Err(()) on non-ASCII input.
    #[inline]
    fn to_ascii(&self) -> Result<T, ()> {
        if self.is_ascii() {
            Ok(unsafe { self.to_ascii_nocheck() })
        } else {
            Err(())
        }
    }

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

#[experimental = "may be replaced by generic conversion traits"]
impl<'a> AsciiCast<&'a[Ascii], Vec<u8>> for [u8] {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> &'a[Ascii] {
        mem::transmute(self)
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl<'a> AsciiCast<&'a [Ascii], String> for str {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> &'a [Ascii] {
        mem::transmute(self)
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl AsciiCast<Ascii> for u8 {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> Ascii {
        Ascii{ chr: *self }
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl AsciiCast<Ascii> for char {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> Ascii {
        Ascii{ chr: *self as u8 }
    }
}

/// Trait for copyless casting to an ascii vector.
#[experimental = "may be replaced by generic conversion traits"]
pub trait OwnedAsciiCast<T: ?Sized, U = Self> : Sized
where T: BorrowFrom<Self> + AsciiExt<U> {
    /// Take ownership and cast to an ascii vector. On non-ASCII input return ownership of data
    /// that was attempted to cast to ascii in `Err(Self)`.
    #[inline]
    fn into_ascii(self) -> Result<Vec<Ascii>, Self> {
        if {
            let borrowed: &T = BorrowFrom::borrow_from(&self);
            borrowed.is_ascii()
        } {
            Ok(unsafe { self.into_ascii_nocheck() })
        } else {
            Err(self)
        }
    }

    /// Take ownership and cast to an ascii vector.
    /// Does not perform validation checks.
    unsafe fn into_ascii_nocheck(self) -> Vec<Ascii>;
}

#[experimental = "may be replaced by generic conversion traits"]
impl OwnedAsciiCast<str> for String {
    #[inline]
    unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
        self.into_bytes().into_ascii_nocheck()
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl OwnedAsciiCast<[u8]> for Vec<u8> {
    #[inline]
    unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
        let v = Vec::from_raw_parts(self.as_ptr() as *mut Ascii,
                                    self.len(),
                                    self.capacity());

        // We forget `self` to avoid freeing it at the end of the scope
        // Otherwise, the returned `Vec` would point to freed memory
        mem::forget(self);
        v
    }
}

/// Trait for converting a type to a string, consuming it in the process.
#[experimental = "may be replaced by generic conversion traits"]
pub trait IntoString {
    /// Consume and convert to a string.
    fn into_string(self) -> String;
}

/// Trait for converting an ascii type to a string. Needed to convert
/// `&[Ascii]` to `&str`.
#[experimental = "may be replaced by generic conversion traits"]
pub trait AsciiStr {
    /// Convert to a string.
    fn as_str<'a>(&'a self) -> &'a str;

    /// Convert to bytes.
    fn as_bytes<'a>(&'a self) -> &'a [u8];
}

#[experimental = "may be replaced by generic conversion traits"]
impl AsciiStr for [Ascii] {
    #[inline]
    fn as_str<'a>(&'a self) -> &'a str {
        unsafe { mem::transmute(self) }
    }

    #[inline]
    fn as_bytes<'a>(&'a self) -> &'a [u8] {
        unsafe { mem::transmute(self) }
    }
}

impl IntoString for Vec<Ascii> {
    #[inline]
    fn into_string(self) -> String {
        unsafe { String::from_utf8_unchecked(self.into_bytes()) }
    }
}

/// Trait to convert to an owned byte vector by consuming self
#[experimental = "may be replaced by generic conversion traits"]
pub trait IntoBytes {
    /// Converts to an owned byte vector by consuming self
    fn into_bytes(self) -> Vec<u8>;
}

#[experimental = "may be replaced by generic conversion traits"]
impl IntoBytes for Vec<Ascii> {
    fn into_bytes(self) -> Vec<u8> {
        unsafe {
            let v = Vec::from_raw_parts(self.as_ptr() as *mut u8,
                                        self.len(),
                                        self.capacity());

            // We forget `self` to avoid freeing it at the end of the scope
            // Otherwise, the returned `Vec` would point to freed memory
            mem::forget(self);
            v
        }
    }
}

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

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

    macro_rules! vec2ascii (
        ($($e:expr),*) => ([$(Ascii{chr:$e}),*].to_vec());
    );

    #[test]
    fn test_ascii() {
        assert_eq!(65u8.to_ascii().unwrap().as_byte(), 65u8);
        assert_eq!(65u8.to_ascii().unwrap().as_char(), 'A');
        assert_eq!('A'.to_ascii().unwrap().as_char(), 'A');
        assert_eq!('A'.to_ascii().unwrap().as_byte(), 65u8);

        assert!('0'.to_ascii().unwrap().is_digit());
        assert!('9'.to_ascii().unwrap().is_digit());
        assert!(!'/'.to_ascii().unwrap().is_digit());
        assert!(!':'.to_ascii().unwrap().is_digit());

        assert!(0x1f_u8.to_ascii().unwrap().is_control());
        assert!(!' '.to_ascii().unwrap().is_control());
        assert!(0x7f_u8.to_ascii().unwrap().is_control());
    }

    #[test]
    fn test_ascii_vec() {
        let test = &[40u8, 32u8, 59u8];
        let b: &[_] = v2ascii!([40, 32, 59]);
        assert_eq!(test.to_ascii().unwrap(), b);
        assert_eq!("( ;".to_ascii().unwrap(), b);
        let v = vec![40u8, 32u8, 59u8];
        assert_eq!(v.as_slice().to_ascii().unwrap(), b);
        assert_eq!("( ;".to_string().as_slice().to_ascii().unwrap(), b);
    }

    #[test]
    fn test_ascii_as_str() {
        let v = v2ascii!([40, 32, 59]);
        assert_eq!(v.as_str(), "( ;");
    }

    #[test]
    fn test_ascii_as_bytes() {
        let v = v2ascii!([40, 32, 59]);
        assert_eq!(v.as_bytes(), b"( ;");
    }

    #[test]
    fn test_ascii_into_string() {
        assert_eq!(vec2ascii![40, 32, 59].into_string(), "( ;".to_string());
        assert_eq!(vec2ascii!(40, 32, 59).into_string(), "( ;".to_string());
    }

    #[test]
    fn test_ascii_to_bytes() {
        assert_eq!(vec2ascii![40, 32, 59].into_bytes(), vec![40u8, 32u8, 59u8]);
    }

    #[test]
    fn test_opt() {
        assert_eq!(65u8.to_ascii(), Ok(Ascii { chr: 65u8 }));
        assert_eq!(255u8.to_ascii(), Err(()));

        assert_eq!('A'.to_ascii(), Ok(Ascii { chr: 65u8 }));
        assert_eq!('λ'.to_ascii(), Err(()));

        assert_eq!("zoä华".to_ascii(), Err(()));

        let test1 = &[127u8, 128u8, 255u8];
        assert_eq!(test1.to_ascii(), Err(()));

        let v = [40u8, 32u8, 59u8];
        let v2: &[_] = v2ascii!(&[40, 32, 59]);
        assert_eq!(v.to_ascii(), Ok(v2));
        let v = [127u8, 128u8, 255u8];
        assert_eq!(v.to_ascii(), Err(()));

        let v = "( ;";
        assert_eq!(v.to_ascii(), Ok(v2));
        assert_eq!("zoä华".to_ascii(), Err(()));

        assert_eq!(vec![40u8, 32u8, 59u8].into_ascii(), Ok(vec2ascii![40, 32, 59]));
        assert_eq!(vec![127u8, 128u8, 255u8].into_ascii(), Err(vec![127u8, 128u8, 255u8]));

        assert_eq!("( ;".to_string().into_ascii(), Ok(vec2ascii![40, 32, 59]));
        assert_eq!("zoä华".to_string().into_ascii(), Err("zoä华".to_string()));
    }

    #[test]
    fn test_to_string() {
        let s = Ascii{ chr: b't' }.to_string();
        assert_eq!(s, "t".to_string());
    }

    #[test]
    fn test_show() {
        let c = Ascii { chr: b't' };
        assert_eq!(format!("{}", c), "t".to_string());
    }
}
<commit_msg>Remove feature gate opt-in, they aren't needed anymore<commit_after>// Copyright 2013-2014 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// ignore-lexer-test FIXME #15679

//! Operations on ASCII strings and characters

#![unstable = "unsure about placement and naming"]
#![allow(deprecated)]

//use std::kinds::Sized;

use std::fmt;
use std::mem;
use std::borrow::BorrowFrom;
use std::ascii::AsciiExt;

/// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero.
#[derive(Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Copy)]
pub struct Ascii { chr: u8 }

impl Ascii {
    /// Converts an ascii character into a `u8`.
    #[inline]
    #[unstable = "recently renamed"]
    pub fn as_byte(&self) -> u8 {
        self.chr
    }

    /// Converts an ascii character into a `char`.
    #[inline]
    #[unstable = "recently renamed"]
    pub fn as_char(&self) -> char {
        self.chr as char
    }

    /// Convert to lowercase.
    #[inline]
    #[stable]
    pub fn to_lowercase(&self) -> Ascii {
        Ascii{chr: self.chr.to_ascii_lowercase()}
    }

    /// Convert to uppercase.
    #[inline]
    #[stable]
    pub fn to_uppercase(&self) -> Ascii {
        Ascii{chr: self.chr.to_ascii_uppercase()}
    }

    // the following methods are like ctype, and the implementation is inspired by musl

    /// Check if the character is a letter (a-z, A-Z)
    #[inline]
    #[stable]
    pub fn is_alphabetic(&self) -> bool {
        (self.chr >= 0x41 && self.chr <= 0x5A) || (self.chr >= 0x61 && self.chr <= 0x7A)
    }

    /// Check if the character is a number (0-9)
    #[inline]
    #[unstable = "may be renamed"]
    pub fn is_digit(&self) -> bool {
        self.chr >= 0x30 && self.chr <= 0x39
    }

    /// Check if the character is a letter or number
    #[inline]
    #[stable]
    pub fn is_alphanumeric(&self) -> bool {
        self.is_alphabetic() || self.is_digit()
    }

    /// Check if the character is a space or horizontal tab
    #[inline]
    #[experimental = "likely to be removed"]
    pub fn is_blank(&self) -> bool {
        self.chr == b' ' || self.chr == b'\t'
    }

    /// Check if the character is a control character
    #[inline]
    #[stable]
    pub fn is_control(&self) -> bool {
        self.chr < 0x20 || self.chr == 0x7F
    }

    /// Checks if the character is printable (except space)
    #[inline]
    #[experimental = "unsure about naming, or whether this is needed"]
    pub fn is_graph(&self) -> bool {
        (self.chr - 0x21) < 0x5E
    }

    /// Checks if the character is printable (including space)
    #[inline]
    #[unstable = "unsure about naming"]
    pub fn is_print(&self) -> bool {
        (self.chr - 0x20) < 0x5F
    }

    /// Checks if the character is alphabetic and lowercase
    #[inline]
    #[stable]
    pub fn is_lowercase(&self) -> bool {
        (self.chr - b'a') < 26
    }

    /// Checks if the character is alphabetic and uppercase
    #[inline]
    #[stable]
    pub fn is_uppercase(&self) -> bool {
        (self.chr - b'A') < 26
    }

    /// Checks if the character is punctuation
    #[inline]
    #[stable]
    pub fn is_punctuation(&self) -> bool {
        self.is_graph() && !self.is_alphanumeric()
    }

    /// Checks if the character is a valid hex digit
    #[inline]
    #[stable]
    pub fn is_hex(&self) -> bool {
        self.is_digit() || ((self.chr | 32u8) - b'a') < 6
    }
}

impl<'a> fmt::Show for Ascii {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        (self.chr as char).fmt(f)
    }
}

/// Trait for converting into an ascii type.
#[experimental = "may be replaced by generic conversion traits"]
pub trait AsciiCast<T, U = Self> : AsciiExt<U> {
    /// Convert to an ascii type, return Err(()) on non-ASCII input.
    #[inline]
    fn to_ascii(&self) -> Result<T, ()> {
        if self.is_ascii() {
            Ok(unsafe { self.to_ascii_nocheck() })
        } else {
            Err(())
        }
    }

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

#[experimental = "may be replaced by generic conversion traits"]
impl<'a> AsciiCast<&'a[Ascii], Vec<u8>> for [u8] {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> &'a[Ascii] {
        mem::transmute(self)
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl<'a> AsciiCast<&'a [Ascii], String> for str {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> &'a [Ascii] {
        mem::transmute(self)
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl AsciiCast<Ascii> for u8 {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> Ascii {
        Ascii{ chr: *self }
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl AsciiCast<Ascii> for char {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> Ascii {
        Ascii{ chr: *self as u8 }
    }
}

/// Trait for copyless casting to an ascii vector.
#[experimental = "may be replaced by generic conversion traits"]
pub trait OwnedAsciiCast<T: ?Sized, U = Self> : Sized
where T: BorrowFrom<Self> + AsciiExt<U> {
    /// Take ownership and cast to an ascii vector. On non-ASCII input return ownership of data
    /// that was attempted to cast to ascii in `Err(Self)`.
    #[inline]
    fn into_ascii(self) -> Result<Vec<Ascii>, Self> {
        if {
            let borrowed: &T = BorrowFrom::borrow_from(&self);
            borrowed.is_ascii()
        } {
            Ok(unsafe { self.into_ascii_nocheck() })
        } else {
            Err(self)
        }
    }

    /// Take ownership and cast to an ascii vector.
    /// Does not perform validation checks.
    unsafe fn into_ascii_nocheck(self) -> Vec<Ascii>;
}

#[experimental = "may be replaced by generic conversion traits"]
impl OwnedAsciiCast<str> for String {
    #[inline]
    unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
        self.into_bytes().into_ascii_nocheck()
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl OwnedAsciiCast<[u8]> for Vec<u8> {
    #[inline]
    unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
        let v = Vec::from_raw_parts(self.as_ptr() as *mut Ascii,
                                    self.len(),
                                    self.capacity());

        // We forget `self` to avoid freeing it at the end of the scope
        // Otherwise, the returned `Vec` would point to freed memory
        mem::forget(self);
        v
    }
}

/// Trait for converting a type to a string, consuming it in the process.
#[experimental = "may be replaced by generic conversion traits"]
pub trait IntoString {
    /// Consume and convert to a string.
    fn into_string(self) -> String;
}

/// Trait for converting an ascii type to a string. Needed to convert
/// `&[Ascii]` to `&str`.
#[experimental = "may be replaced by generic conversion traits"]
pub trait AsciiStr {
    /// Convert to a string.
    fn as_str<'a>(&'a self) -> &'a str;

    /// Convert to bytes.
    fn as_bytes<'a>(&'a self) -> &'a [u8];
}

#[experimental = "may be replaced by generic conversion traits"]
impl AsciiStr for [Ascii] {
    #[inline]
    fn as_str<'a>(&'a self) -> &'a str {
        unsafe { mem::transmute(self) }
    }

    #[inline]
    fn as_bytes<'a>(&'a self) -> &'a [u8] {
        unsafe { mem::transmute(self) }
    }
}

impl IntoString for Vec<Ascii> {
    #[inline]
    fn into_string(self) -> String {
        unsafe { String::from_utf8_unchecked(self.into_bytes()) }
    }
}

/// Trait to convert to an owned byte vector by consuming self
#[experimental = "may be replaced by generic conversion traits"]
pub trait IntoBytes {
    /// Converts to an owned byte vector by consuming self
    fn into_bytes(self) -> Vec<u8>;
}

#[experimental = "may be replaced by generic conversion traits"]
impl IntoBytes for Vec<Ascii> {
    fn into_bytes(self) -> Vec<u8> {
        unsafe {
            let v = Vec::from_raw_parts(self.as_ptr() as *mut u8,
                                        self.len(),
                                        self.capacity());

            // We forget `self` to avoid freeing it at the end of the scope
            // Otherwise, the returned `Vec` would point to freed memory
            mem::forget(self);
            v
        }
    }
}

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

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

    macro_rules! vec2ascii (
        ($($e:expr),*) => ([$(Ascii{chr:$e}),*].to_vec());
    );

    #[test]
    fn test_ascii() {
        assert_eq!(65u8.to_ascii().unwrap().as_byte(), 65u8);
        assert_eq!(65u8.to_ascii().unwrap().as_char(), 'A');
        assert_eq!('A'.to_ascii().unwrap().as_char(), 'A');
        assert_eq!('A'.to_ascii().unwrap().as_byte(), 65u8);

        assert!('0'.to_ascii().unwrap().is_digit());
        assert!('9'.to_ascii().unwrap().is_digit());
        assert!(!'/'.to_ascii().unwrap().is_digit());
        assert!(!':'.to_ascii().unwrap().is_digit());

        assert!(0x1f_u8.to_ascii().unwrap().is_control());
        assert!(!' '.to_ascii().unwrap().is_control());
        assert!(0x7f_u8.to_ascii().unwrap().is_control());
    }

    #[test]
    fn test_ascii_vec() {
        let test = &[40u8, 32u8, 59u8];
        let b: &[_] = v2ascii!([40, 32, 59]);
        assert_eq!(test.to_ascii().unwrap(), b);
        assert_eq!("( ;".to_ascii().unwrap(), b);
        let v = vec![40u8, 32u8, 59u8];
        assert_eq!(v.as_slice().to_ascii().unwrap(), b);
        assert_eq!("( ;".to_string().as_slice().to_ascii().unwrap(), b);
    }

    #[test]
    fn test_ascii_as_str() {
        let v = v2ascii!([40, 32, 59]);
        assert_eq!(v.as_str(), "( ;");
    }

    #[test]
    fn test_ascii_as_bytes() {
        let v = v2ascii!([40, 32, 59]);
        assert_eq!(v.as_bytes(), b"( ;");
    }

    #[test]
    fn test_ascii_into_string() {
        assert_eq!(vec2ascii![40, 32, 59].into_string(), "( ;".to_string());
        assert_eq!(vec2ascii!(40, 32, 59).into_string(), "( ;".to_string());
    }

    #[test]
    fn test_ascii_to_bytes() {
        assert_eq!(vec2ascii![40, 32, 59].into_bytes(), vec![40u8, 32u8, 59u8]);
    }

    #[test]
    fn test_opt() {
        assert_eq!(65u8.to_ascii(), Ok(Ascii { chr: 65u8 }));
        assert_eq!(255u8.to_ascii(), Err(()));

        assert_eq!('A'.to_ascii(), Ok(Ascii { chr: 65u8 }));
        assert_eq!('λ'.to_ascii(), Err(()));

        assert_eq!("zoä华".to_ascii(), Err(()));

        let test1 = &[127u8, 128u8, 255u8];
        assert_eq!(test1.to_ascii(), Err(()));

        let v = [40u8, 32u8, 59u8];
        let v2: &[_] = v2ascii!(&[40, 32, 59]);
        assert_eq!(v.to_ascii(), Ok(v2));
        let v = [127u8, 128u8, 255u8];
        assert_eq!(v.to_ascii(), Err(()));

        let v = "( ;";
        assert_eq!(v.to_ascii(), Ok(v2));
        assert_eq!("zoä华".to_ascii(), Err(()));

        assert_eq!(vec![40u8, 32u8, 59u8].into_ascii(), Ok(vec2ascii![40, 32, 59]));
        assert_eq!(vec![127u8, 128u8, 255u8].into_ascii(), Err(vec![127u8, 128u8, 255u8]));

        assert_eq!("( ;".to_string().into_ascii(), Ok(vec2ascii![40, 32, 59]));
        assert_eq!("zoä华".to_string().into_ascii(), Err("zoä华".to_string()));
    }

    #[test]
    fn test_to_string() {
        let s = Ascii{ chr: b't' }.to_string();
        assert_eq!(s, "t".to_string());
    }

    #[test]
    fn test_show() {
        let c = Ascii { chr: b't' };
        assert_eq!(format!("{}", c), "t".to_string());
    }
}
<|endoftext|>


<commit_before><commit_msg>Lazily initialize typeinfo queries<commit_after><|endoftext|>


<commit_before><commit_msg>Add div with class and style to the whitelist<commit_after><|endoftext|>


<commit_before><commit_msg>Welp cargo run didnt panic at all; time for printing<commit_after><|endoftext|>


<commit_before>#![feature(asm)]

extern crate rustc_serialize;
extern crate syscall;
extern crate toml;

use std::env;
use std::fs::File;
use std::io::Read;
use std::process::Command;
use std::thread;
use syscall::iopl;

use config::Config;
use pci::{Pci, PciBar, PciClass};

mod config;
mod pci;

fn main() {
    thread::spawn(|| {
        let mut config = Config::default();

        let mut args = env::args().skip(1);
        if let Some(config_path) = args.next() {
            if let Ok(mut config_file) = File::open(&config_path) {
                let mut config_data = String::new();
                if let Ok(_) = config_file.read_to_string(&mut config_data) {
                    config = toml::decode_str(&config_data).unwrap_or(Config::default());
                }
            }
        }

        unsafe { iopl(3).unwrap() };

        println!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV");

        let pci = Pci::new();
        for bus in pci.buses() {
            for dev in bus.devs() {
                for func in dev.funcs() {
                    if let Some(header) = func.header() {
                        print!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X}",
                                bus.num, dev.num, func.num,
                                header.vendor_id, header.device_id,
                                header.class, header.subclass, header.interface, header.revision);

                        let pci_class = PciClass::from(header.class);
                        print!(" {:?}", pci_class);
                        match pci_class {
                            PciClass::Storage => match header.subclass {
                                0x01 => {
                                    print!(" IDE");
                                },
                                0x06 => {
                                    print!(" SATA");
                                },
                                _ => ()
                            },
                            PciClass::SerialBus => match header.subclass {
                                0x03 => match header.interface {
                                    0x00 => {
                                        print!(" UHCI");
                                    },
                                    0x10 => {
                                        print!(" OHCI");
                                    },
                                    0x20 => {
                                        print!(" EHCI");
                                    },
                                    0x30 => {
                                        print!(" XHCI");
                                    },
                                    _ => ()
                                },
                                _ => ()
                            },
                            _ => ()
                        }

                        for i in 0..header.bars.len() {
                            match PciBar::from(header.bars[i]) {
                                PciBar::None => (),
                                PciBar::Memory(address) => print!(" {}={:>08X}", i, address),
                                PciBar::Port(address) => print!(" {}={:>04X}", i, address)
                            }
                        }

                        print!("\n");

                        for driver in config.drivers.iter() {
                            if let Some(class) = driver.class {
                                if class != header.class { continue; }
                            }

                            if let Some(subclass) = driver.subclass {
                                if subclass != header.subclass { continue; }
                            }

                            if let Some(vendor) = driver.vendor {
                                if vendor != header.vendor_id { continue; }
                            }

                            if let Some(device) = driver.device {
                                if device != header.device_id { continue; }
                            }

                            if let Some(ref args) = driver.command {
                                // Enable bus mastering
                                unsafe {
                                    let cmd = pci.read(bus.num, dev.num, func.num, 0x04);
                                    pci.write(bus.num, dev.num, func.num, 0x04, cmd | 4);
                                }

                                let mut args = args.iter();
                                if let Some(program) = args.next() {
                                    let mut command = Command::new(program);
                                    for arg in args {
                                        let bar_arg = |i| -> String {
                                            match PciBar::from(header.bars[i]) {
                                                PciBar::None => String::new(),
                                                PciBar::Memory(address) => format!("{:>08X}", address),
                                                PciBar::Port(address) => format!("{:>04X}", address)
                                            }
                                        };
                                        let arg = match arg.as_str() {
                                            "$BAR0" => bar_arg(0),
                                            "$BAR1" => bar_arg(1),
                                            "$BAR2" => bar_arg(2),
                                            "$BAR3" => bar_arg(3),
                                            "$BAR4" => bar_arg(4),
                                            "$BAR5" => bar_arg(5),
                                            "$IRQ" => format!("{}", header.interrupt_line),
                                            _ => arg.clone()
                                        };
                                        command.arg(&arg);
                                    }

                                    match command.spawn() {
                                        Ok(mut child) => match child.wait() {
                                            Ok(_status) => (), //println!("pcid: waited for {}: {:?}", line, status.code()),
                                            Err(err) => println!("pcid: failed to wait for {:?}: {}", command, err)
                                        },
                                        Err(err) => println!("pcid: failed to execute {:?}: {}", command, err)
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    });
}
<commit_msg>Do not throw pcid into background - this prevents ethernetd from exiting if it tries to open network: too early<commit_after>#![feature(asm)]

extern crate rustc_serialize;
extern crate syscall;
extern crate toml;

use std::env;
use std::fs::File;
use std::io::Read;
use std::process::Command;
use syscall::iopl;

use config::Config;
use pci::{Pci, PciBar, PciClass};

mod config;
mod pci;

fn main() {
    let mut config = Config::default();

    let mut args = env::args().skip(1);
    if let Some(config_path) = args.next() {
        if let Ok(mut config_file) = File::open(&config_path) {
            let mut config_data = String::new();
            if let Ok(_) = config_file.read_to_string(&mut config_data) {
                config = toml::decode_str(&config_data).unwrap_or(Config::default());
            }
        }
    }

    unsafe { iopl(3).unwrap() };

    println!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV");

    let pci = Pci::new();
    for bus in pci.buses() {
        for dev in bus.devs() {
            for func in dev.funcs() {
                if let Some(header) = func.header() {
                    print!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X}",
                            bus.num, dev.num, func.num,
                            header.vendor_id, header.device_id,
                            header.class, header.subclass, header.interface, header.revision);

                    let pci_class = PciClass::from(header.class);
                    print!(" {:?}", pci_class);
                    match pci_class {
                        PciClass::Storage => match header.subclass {
                            0x01 => {
                                print!(" IDE");
                            },
                            0x06 => {
                                print!(" SATA");
                            },
                            _ => ()
                        },
                        PciClass::SerialBus => match header.subclass {
                            0x03 => match header.interface {
                                0x00 => {
                                    print!(" UHCI");
                                },
                                0x10 => {
                                    print!(" OHCI");
                                },
                                0x20 => {
                                    print!(" EHCI");
                                },
                                0x30 => {
                                    print!(" XHCI");
                                },
                                _ => ()
                            },
                            _ => ()
                        },
                        _ => ()
                    }

                    for i in 0..header.bars.len() {
                        match PciBar::from(header.bars[i]) {
                            PciBar::None => (),
                            PciBar::Memory(address) => print!(" {}={:>08X}", i, address),
                            PciBar::Port(address) => print!(" {}={:>04X}", i, address)
                        }
                    }

                    print!("\n");

                    for driver in config.drivers.iter() {
                        if let Some(class) = driver.class {
                            if class != header.class { continue; }
                        }

                        if let Some(subclass) = driver.subclass {
                            if subclass != header.subclass { continue; }
                        }

                        if let Some(vendor) = driver.vendor {
                            if vendor != header.vendor_id { continue; }
                        }

                        if let Some(device) = driver.device {
                            if device != header.device_id { continue; }
                        }

                        if let Some(ref args) = driver.command {
                            // Enable bus mastering
                            unsafe {
                                let cmd = pci.read(bus.num, dev.num, func.num, 0x04);
                                pci.write(bus.num, dev.num, func.num, 0x04, cmd | 4);
                            }

                            let mut args = args.iter();
                            if let Some(program) = args.next() {
                                let mut command = Command::new(program);
                                for arg in args {
                                    let bar_arg = |i| -> String {
                                        match PciBar::from(header.bars[i]) {
                                            PciBar::None => String::new(),
                                            PciBar::Memory(address) => format!("{:>08X}", address),
                                            PciBar::Port(address) => format!("{:>04X}", address)
                                        }
                                    };
                                    let arg = match arg.as_str() {
                                        "$BAR0" => bar_arg(0),
                                        "$BAR1" => bar_arg(1),
                                        "$BAR2" => bar_arg(2),
                                        "$BAR3" => bar_arg(3),
                                        "$BAR4" => bar_arg(4),
                                        "$BAR5" => bar_arg(5),
                                        "$IRQ" => format!("{}", header.interrupt_line),
                                        _ => arg.clone()
                                    };
                                    command.arg(&arg);
                                }

                                match command.spawn() {
                                    Ok(mut child) => match child.wait() {
                                        Ok(_status) => (), //println!("pcid: waited for {}: {:?}", line, status.code()),
                                        Err(err) => println!("pcid: failed to wait for {:?}: {}", command, err)
                                    },
                                    Err(err) => println!("pcid: failed to execute {:?}: {}", command, err)
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) 2015, edef <edef@edef.eu>
// See the LICENSE file included in this distribution.
#![feature(no_std)]
#![feature(asm, core)]
#![no_std]

//! libfringe is a low-level green threading library.
//! It provides only a context-swapping mechanism.

#[macro_use]
extern crate core;

#[cfg(test)]
#[macro_use]
extern crate std;

pub use context::Context;
pub use stack::Stack;

#[cfg(feature = "os")]
pub use os::Stack as OsStack;

mod context;
mod stack;

#[cfg(feature = "os")]
mod os;

mod arch;
mod debug;

#[cfg(not(test))]
mod std { pub use core::*; }
<commit_msg>add #![feature(core_prelude)]<commit_after>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) 2015, edef <edef@edef.eu>
// See the LICENSE file included in this distribution.
#![feature(no_std)]
#![feature(asm, core, core_prelude)]
#![no_std]

//! libfringe is a low-level green threading library.
//! It provides only a context-swapping mechanism.

#[macro_use]
extern crate core;

#[cfg(test)]
#[macro_use]
extern crate std;

pub use context::Context;
pub use stack::Stack;

#[cfg(feature = "os")]
pub use os::Stack as OsStack;

mod context;
mod stack;

#[cfg(feature = "os")]
mod os;

mod arch;
mod debug;

#[cfg(not(test))]
mod std { pub use core::*; }
<|endoftext|>


<commit_before><commit_msg>Simplify the read_unlock path<commit_after><|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![crate_name = "cssparser"]
#![crate_type = "rlib"]

#![cfg_attr(feature = "bench", feature(test))]
#![deny(missing_docs)]

/*!

Implementation of [CSS Syntax Module Level 3](https://drafts.csswg.org/css-syntax/) for Rust.

# Input

Everything is based on `Parser` objects, which borrow a `&str` input.
If you have bytes (from a file, the network, or something)
and want to support character encodings other than UTF-8,
see the `stylesheet_encoding` function,
which can be used together with rust-encoding or encoding-rs.

# Conventions for parsing functions

* Take (at least) a `input: &mut cssparser::Parser` parameter
* Return `Result<_, ()>`
* When returning `Ok(_)`,
  the function must have consume exactly the amount of input that represents the parsed value.
* When returning `Err(())`, any amount of input may have been consumed.

As a consequence, when calling another parsing function, either:

* Any `Err(())` return value must be propagated.
  This happens by definition for tail calls,
  and can otherwise be done with the `try!` macro.
* Or the call must be wrapped in a `Parser::try` call.
  `try` takes a closure that takes a `Parser` and returns a `Result`,
  calls it once,
  and returns itself that same result.
  If the result is `Err`,
  it restores the position inside the input to the one saved before calling the closure.

Examples:

```{rust,ignore}
// 'none' | <image>
fn parse_background_image(context: &ParserContext, input: &mut Parser)
                                    -> Result<Option<Image>, ()> {
    if input.try(|input| input.expect_ident_matching("none")).is_ok() {
        Ok(None)
    } else {
        Image::parse(context, input).map(Some)  // tail call
    }
}
```

```{rust,ignore}
// [ <length> | <percentage> ] [ <length> | <percentage> ]?
fn parse_border_spacing(_context: &ParserContext, input: &mut Parser)
                          -> Result<(LengthOrPercentage, LengthOrPercentage), ()> {
    let first = try!(LengthOrPercentage::parse);
    let second = input.try(LengthOrPercentage::parse).unwrap_or(first);
    (first, second)
}
```

*/

#![recursion_limit="200"]  // For color::parse_color_keyword

#[macro_use] extern crate cssparser_macros;
#[macro_use] extern crate matches;
extern crate phf;
#[cfg(test)] extern crate encoding_rs;
#[cfg(test)] extern crate tempdir;
#[cfg(test)] extern crate rustc_serialize;
#[cfg(feature = "serde")] extern crate serde;
#[cfg(feature = "heapsize")] #[macro_use] extern crate heapsize;

pub use tokenizer::{Token, NumericValue, PercentageValue, SourceLocation};
pub use rules_and_declarations::{parse_important};
pub use rules_and_declarations::{DeclarationParser, DeclarationListParser, parse_one_declaration};
pub use rules_and_declarations::{RuleListParser, parse_one_rule};
pub use rules_and_declarations::{AtRuleType, QualifiedRuleParser, AtRuleParser};
pub use from_bytes::{stylesheet_encoding, EncodingSupport};
pub use color::{RGBA, Color, parse_color_keyword};
pub use nth::parse_nth;
pub use serializer::{ToCss, CssStringWriter, serialize_identifier, serialize_string, TokenSerializationType};
pub use parser::{Parser, Delimiter, Delimiters, SourcePosition};
pub use unicode_range::UnicodeRange;

/// Expands to an expression equivalent to a `match` with string patterns,
/// but matching is case-insensitive in the ASCII range.
///
/// Requirements:
///
/// * The `cssparser_macros` crate must also be imported at the crate root
/// * The patterns must not contain ASCII upper case letters. (They must be already be lower-cased.)
///
/// # Example
///
/// ```rust
/// #[macro_use] extern crate cssparser;
/// #[macro_use] extern crate cssparser_macros;
///
/// # fn main() {}  // Make doctest not wrap everythig in its own main
/// # fn dummy(function_name: &String) { let _ =
/// match_ignore_ascii_case! { &function_name,
///     "rgb" => parse_rgb(..),
///     "rgba" => parse_rgba(..),
///     "hsl" => parse_hsl(..),
///     "hsla" => parse_hsla(..),
///     _ => Err("unknown function")
/// }
/// # ;}
/// # use std::ops::RangeFull;
/// # fn parse_rgb(_: RangeFull) -> Result<(), &'static str> { Err("") }
/// # fn parse_rgba(_: RangeFull) -> Result<(), &'static str> { Err("") }
/// # fn parse_hsl(_: RangeFull) -> Result<(), &'static str> { Err("") }
/// # fn parse_hsla(_: RangeFull) -> Result<(), &'static str> { Err("") }
/// ```
#[macro_export]
macro_rules! match_ignore_ascii_case {
    // parse the last case plus the fallback
    (@inner $value:expr, ($string:expr => $result:expr, _ => $fallback:expr) -> ($($parsed:tt)*) ) => {
        match_ignore_ascii_case!(@inner $value, () -> ($($parsed)* ($string => $result)) $fallback)
    };

    // parse a case (not the last one)
    (@inner $value:expr, ($string:expr => $result:expr, $($rest:tt)*) -> ($($parsed:tt)*) ) => {
        match_ignore_ascii_case!(@inner $value, ($($rest)*) -> ($($parsed)* ($string => $result)))
    };

    // finished parsing
    (@inner $value:expr, () -> ($(($string:expr => $result:expr))*) $fallback:expr ) => {
        {
            #[derive(cssparser__assert_ascii_lowercase)]
            #[cssparser__assert_ascii_lowercase__data($(string = $string),+)]
            #[allow(dead_code)]
            struct Dummy;

            _cssparser_internal__to_lowercase!($value => lowercase, $($string),+);
            match lowercase {
                $(
                    Some($string) => $result,
                )+
                _ => $fallback
            }
        }
    };

    // entry point, start parsing
    ( $value:expr, $($rest:tt)* ) => {
        match_ignore_ascii_case!(@inner $value, ($($rest)*) -> ())
    };
}

/// Define a placeholder type `$Name`
/// with a method `fn get(input: &str) -> Option<&'static $ValueType>`.
///
/// This method uses finds a match for the input string
/// in a [`phf` map](https://github.com/sfackler/rust-phf).
/// Matching is case-insensitive in the ASCII range.
///
/// Requirements:
///
/// * The `phf` and `cssparser_macros` crates must also be imported at the crate root
/// * The values must be given a strings that contain Rust syntax for a constant expression.
///
/// ## Example:
///
/// ```rust
/// extern crate phf;
/// #[macro_use] extern crate cssparser;
/// #[macro_use] extern crate cssparser_macros;
///
/// # fn main() {}  // Make doctest not wrap everythig in its own main
///
/// fn color_rgb(input: &str) -> Option<(u8, u8, u8)> {
///     ascii_case_insensitive_phf_map! {
///         KEYWORDS: Map<(u8, u8, u8)> = {
///             "red" => "(255, 0, 0)",
///             "green" => "(0, 255, 0)",
///             "blue" => "(0, 0, 255)",
///         }
///     }
///     KEYWORDS::get(input).cloned()
/// }
#[macro_export]
macro_rules! ascii_case_insensitive_phf_map {
    ($Name: ident : Map<$ValueType: ty> = {
        $( $key: expr => $value: expr, )*
    }) => {
        #[derive(cssparser__phf_map)]
        #[cssparser__phf_map__kv_pairs(
            $(
                key = $key,
                value = $value
            ),+
        )]
        struct $Name($ValueType);

        impl $Name {
            #[inline]
            fn get(input: &str) -> Option<&'static $ValueType> {
                _cssparser_internal__to_lowercase!(input => lowercase, $($key),+);
                lowercase.and_then(|string| $Name::map().get(string))
            }
        }
    }
}

/// Implementation detail of match_ignore_ascii_case! and ascii_case_insensitive_phf_map! macros.
///
/// **This macro is not part of the public API. It can change or be removed between any versions.**
///
/// * Check at compile-time that none of the `$string`s contain ASCII uppercase letters
/// * Define a local variable named `$output` to the result of calling `_internal__to_lowercase`
///   with a stack-allocated buffer as long as the longest `$string`.
#[macro_export]
#[doc(hidden)]
macro_rules! _cssparser_internal__to_lowercase {
    ($input: expr => $output: ident, $($string: expr),+) => {
        #[derive(cssparser__max_len)]
        #[cssparser__max_len__data($(string = $string),+)]
        #[allow(dead_code)]
        struct Dummy2;

        // mem::uninitialized() is ok because `buffer` is only used in `_internal__to_lowercase`,
        // which initializes with `copy_from_slice` the part of the buffer it uses,
        // before it uses it.
        #[allow(unsafe_code)]
        // MAX_LENGTH is generated by cssparser__max_len
        let mut buffer: [u8; MAX_LENGTH] = unsafe {
            ::std::mem::uninitialized()
        };
        let $output = $crate::_internal__to_lowercase(&mut buffer, $input);
    }
}

/// Implementation detail of match_ignore_ascii_case! and ascii_case_insensitive_phf_map! macros.
///
/// **This function is not part of the public API. It can change or be removed between any verisons.**
///
/// Return `input`, lower-cased, unless larger than `buffer`
/// which is used temporary space for lower-casing a copy of `input` if necessary.
#[doc(hidden)]
#[allow(non_snake_case)]
pub fn _internal__to_lowercase<'a>(buffer: &'a mut [u8], input: &'a str) -> Option<&'a str> {
    if let Some(buffer) = buffer.get_mut(..input.len()) {
        if let Some(first_uppercase) = input.bytes().position(|byte| matches!(byte, b'A'...b'Z')) {
            buffer.copy_from_slice(input.as_bytes());
            std::ascii::AsciiExt::make_ascii_lowercase(&mut buffer[first_uppercase..]);
            // `buffer` was initialized to a copy of `input` (which is &str so well-formed UTF-8)
            // then lowercased (which preserves UTF-8 well-formedness)
            unsafe {
                Some(::std::str::from_utf8_unchecked(buffer))
            }
        } else {
            // Input is already lower-case
            Some(input)
        }
    } else {
        // Input is longer than buffer, which has the length of the longest expected string:
        // none of the expected strings would match.
        None
    }
}

mod rules_and_declarations;

#[cfg(feature = "dummy_match_byte")]
macro_rules! match_byte {
    ($value:expr, $($rest:tt)* ) => {
        match $value {
            $(
                $rest
            )+
        }
    };
}

#[cfg(feature = "dummy_match_byte")]
mod tokenizer;

#[cfg(not(feature = "dummy_match_byte"))]
mod tokenizer {
    include!(concat!(env!("OUT_DIR"), "/tokenizer.rs"));
}
mod parser;
mod from_bytes;
mod color;
mod nth;
mod serializer;
mod unicode_range;

#[cfg(test)]
mod tests;
<commit_msg>match_ignore_ascii_case: extend lifetime of input.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![crate_name = "cssparser"]
#![crate_type = "rlib"]

#![cfg_attr(feature = "bench", feature(test))]
#![deny(missing_docs)]

/*!

Implementation of [CSS Syntax Module Level 3](https://drafts.csswg.org/css-syntax/) for Rust.

# Input

Everything is based on `Parser` objects, which borrow a `&str` input.
If you have bytes (from a file, the network, or something)
and want to support character encodings other than UTF-8,
see the `stylesheet_encoding` function,
which can be used together with rust-encoding or encoding-rs.

# Conventions for parsing functions

* Take (at least) a `input: &mut cssparser::Parser` parameter
* Return `Result<_, ()>`
* When returning `Ok(_)`,
  the function must have consume exactly the amount of input that represents the parsed value.
* When returning `Err(())`, any amount of input may have been consumed.

As a consequence, when calling another parsing function, either:

* Any `Err(())` return value must be propagated.
  This happens by definition for tail calls,
  and can otherwise be done with the `try!` macro.
* Or the call must be wrapped in a `Parser::try` call.
  `try` takes a closure that takes a `Parser` and returns a `Result`,
  calls it once,
  and returns itself that same result.
  If the result is `Err`,
  it restores the position inside the input to the one saved before calling the closure.

Examples:

```{rust,ignore}
// 'none' | <image>
fn parse_background_image(context: &ParserContext, input: &mut Parser)
                                    -> Result<Option<Image>, ()> {
    if input.try(|input| input.expect_ident_matching("none")).is_ok() {
        Ok(None)
    } else {
        Image::parse(context, input).map(Some)  // tail call
    }
}
```

```{rust,ignore}
// [ <length> | <percentage> ] [ <length> | <percentage> ]?
fn parse_border_spacing(_context: &ParserContext, input: &mut Parser)
                          -> Result<(LengthOrPercentage, LengthOrPercentage), ()> {
    let first = try!(LengthOrPercentage::parse);
    let second = input.try(LengthOrPercentage::parse).unwrap_or(first);
    (first, second)
}
```

*/

#![recursion_limit="200"]  // For color::parse_color_keyword

#[macro_use] extern crate cssparser_macros;
#[macro_use] extern crate matches;
extern crate phf;
#[cfg(test)] extern crate encoding_rs;
#[cfg(test)] extern crate tempdir;
#[cfg(test)] extern crate rustc_serialize;
#[cfg(feature = "serde")] extern crate serde;
#[cfg(feature = "heapsize")] #[macro_use] extern crate heapsize;

pub use tokenizer::{Token, NumericValue, PercentageValue, SourceLocation};
pub use rules_and_declarations::{parse_important};
pub use rules_and_declarations::{DeclarationParser, DeclarationListParser, parse_one_declaration};
pub use rules_and_declarations::{RuleListParser, parse_one_rule};
pub use rules_and_declarations::{AtRuleType, QualifiedRuleParser, AtRuleParser};
pub use from_bytes::{stylesheet_encoding, EncodingSupport};
pub use color::{RGBA, Color, parse_color_keyword};
pub use nth::parse_nth;
pub use serializer::{ToCss, CssStringWriter, serialize_identifier, serialize_string, TokenSerializationType};
pub use parser::{Parser, Delimiter, Delimiters, SourcePosition};
pub use unicode_range::UnicodeRange;

/// Expands to an expression equivalent to a `match` with string patterns,
/// but matching is case-insensitive in the ASCII range.
///
/// Requirements:
///
/// * The `cssparser_macros` crate must also be imported at the crate root
/// * The patterns must not contain ASCII upper case letters. (They must be already be lower-cased.)
///
/// # Example
///
/// ```rust
/// #[macro_use] extern crate cssparser;
/// #[macro_use] extern crate cssparser_macros;
///
/// # fn main() {}  // Make doctest not wrap everythig in its own main
/// # fn dummy(function_name: &String) { let _ =
/// match_ignore_ascii_case! { &function_name,
///     "rgb" => parse_rgb(..),
///     "rgba" => parse_rgba(..),
///     "hsl" => parse_hsl(..),
///     "hsla" => parse_hsla(..),
///     _ => Err("unknown function")
/// }
/// # ;}
/// # use std::ops::RangeFull;
/// # fn parse_rgb(_: RangeFull) -> Result<(), &'static str> { Err("") }
/// # fn parse_rgba(_: RangeFull) -> Result<(), &'static str> { Err("") }
/// # fn parse_hsl(_: RangeFull) -> Result<(), &'static str> { Err("") }
/// # fn parse_hsla(_: RangeFull) -> Result<(), &'static str> { Err("") }
/// ```
#[macro_export]
macro_rules! match_ignore_ascii_case {
    // parse the last case plus the fallback
    (@inner $value:expr, ($string:expr => $result:expr, _ => $fallback:expr) -> ($($parsed:tt)*) ) => {
        match_ignore_ascii_case!(@inner $value, () -> ($($parsed)* ($string => $result)) $fallback)
    };

    // parse a case (not the last one)
    (@inner $value:expr, ($string:expr => $result:expr, $($rest:tt)*) -> ($($parsed:tt)*) ) => {
        match_ignore_ascii_case!(@inner $value, ($($rest)*) -> ($($parsed)* ($string => $result)))
    };

    // finished parsing
    (@inner $value:expr, () -> ($(($string:expr => $result:expr))*) $fallback:expr ) => {
        {
            #[derive(cssparser__assert_ascii_lowercase)]
            #[cssparser__assert_ascii_lowercase__data($(string = $string),+)]
            #[allow(dead_code)]
            struct Dummy;

            _cssparser_internal__to_lowercase!($value => lowercase, $($string),+);
            match lowercase {
                $(
                    Some($string) => $result,
                )+
                _ => $fallback
            }
        }
    };

    // entry point, start parsing
    ( $value:expr, $($rest:tt)* ) => {
        match_ignore_ascii_case!(@inner $value, ($($rest)*) -> ())
    };
}

/// Define a placeholder type `$Name`
/// with a method `fn get(input: &str) -> Option<&'static $ValueType>`.
///
/// This method uses finds a match for the input string
/// in a [`phf` map](https://github.com/sfackler/rust-phf).
/// Matching is case-insensitive in the ASCII range.
///
/// Requirements:
///
/// * The `phf` and `cssparser_macros` crates must also be imported at the crate root
/// * The values must be given a strings that contain Rust syntax for a constant expression.
///
/// ## Example:
///
/// ```rust
/// extern crate phf;
/// #[macro_use] extern crate cssparser;
/// #[macro_use] extern crate cssparser_macros;
///
/// # fn main() {}  // Make doctest not wrap everythig in its own main
///
/// fn color_rgb(input: &str) -> Option<(u8, u8, u8)> {
///     ascii_case_insensitive_phf_map! {
///         KEYWORDS: Map<(u8, u8, u8)> = {
///             "red" => "(255, 0, 0)",
///             "green" => "(0, 255, 0)",
///             "blue" => "(0, 0, 255)",
///         }
///     }
///     KEYWORDS::get(input).cloned()
/// }
#[macro_export]
macro_rules! ascii_case_insensitive_phf_map {
    ($Name: ident : Map<$ValueType: ty> = {
        $( $key: expr => $value: expr, )*
    }) => {
        #[derive(cssparser__phf_map)]
        #[cssparser__phf_map__kv_pairs(
            $(
                key = $key,
                value = $value
            ),+
        )]
        struct $Name($ValueType);

        impl $Name {
            #[inline]
            fn get(input: &str) -> Option<&'static $ValueType> {
                _cssparser_internal__to_lowercase!(input => lowercase, $($key),+);
                lowercase.and_then(|string| $Name::map().get(string))
            }
        }
    }
}

/// Implementation detail of match_ignore_ascii_case! and ascii_case_insensitive_phf_map! macros.
///
/// **This macro is not part of the public API. It can change or be removed between any versions.**
///
/// * Check at compile-time that none of the `$string`s contain ASCII uppercase letters
/// * Define a local variable named `$output` to the result of calling `_internal__to_lowercase`
///   with a stack-allocated buffer as long as the longest `$string`.
#[macro_export]
#[doc(hidden)]
macro_rules! _cssparser_internal__to_lowercase {
    ($input: expr => $output: ident, $($string: expr),+) => {
        #[derive(cssparser__max_len)]
        #[cssparser__max_len__data($(string = $string),+)]
        #[allow(dead_code)]
        struct Dummy2;

        // mem::uninitialized() is ok because `buffer` is only used in `_internal__to_lowercase`,
        // which initializes with `copy_from_slice` the part of the buffer it uses,
        // before it uses it.
        #[allow(unsafe_code)]
        // MAX_LENGTH is generated by cssparser__max_len
        let mut buffer: [u8; MAX_LENGTH] = unsafe {
            ::std::mem::uninitialized()
        };
        let input: &str = $input;
        let $output = $crate::_internal__to_lowercase(&mut buffer, input);
    }
}

/// Implementation detail of match_ignore_ascii_case! and ascii_case_insensitive_phf_map! macros.
///
/// **This function is not part of the public API. It can change or be removed between any verisons.**
///
/// Return `input`, lower-cased, unless larger than `buffer`
/// which is used temporary space for lower-casing a copy of `input` if necessary.
#[doc(hidden)]
#[allow(non_snake_case)]
pub fn _internal__to_lowercase<'a>(buffer: &'a mut [u8], input: &'a str) -> Option<&'a str> {
    if let Some(buffer) = buffer.get_mut(..input.len()) {
        if let Some(first_uppercase) = input.bytes().position(|byte| matches!(byte, b'A'...b'Z')) {
            buffer.copy_from_slice(input.as_bytes());
            std::ascii::AsciiExt::make_ascii_lowercase(&mut buffer[first_uppercase..]);
            // `buffer` was initialized to a copy of `input` (which is &str so well-formed UTF-8)
            // then lowercased (which preserves UTF-8 well-formedness)
            unsafe {
                Some(::std::str::from_utf8_unchecked(buffer))
            }
        } else {
            // Input is already lower-case
            Some(input)
        }
    } else {
        // Input is longer than buffer, which has the length of the longest expected string:
        // none of the expected strings would match.
        None
    }
}

mod rules_and_declarations;

#[cfg(feature = "dummy_match_byte")]
macro_rules! match_byte {
    ($value:expr, $($rest:tt)* ) => {
        match $value {
            $(
                $rest
            )+
        }
    };
}

#[cfg(feature = "dummy_match_byte")]
mod tokenizer;

#[cfg(not(feature = "dummy_match_byte"))]
mod tokenizer {
    include!(concat!(env!("OUT_DIR"), "/tokenizer.rs"));
}
mod parser;
mod from_bytes;
mod color;
mod nth;
mod serializer;
mod unicode_range;

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before><commit_msg>added keys() and values() iterators<commit_after><|endoftext|>


<commit_before>#![feature(core)]
#![allow(unused_assignments)]

use std::str;

macro_rules! eof {
    ($buf:expr, $i:expr) => (
        if $buf.len() == $i {
            return Ok(Status::Partial);
        }
    )
}
macro_rules! next {
    ($buf:expr, $i:ident) => ({
        let buf = $buf;
        eof!(buf, $i);
        let ret = unsafe { *$buf.get_unchecked($i) };
        $i += 1;
        ret
    })
}

macro_rules! expect {
    ($buf:ident[$i:ident] == $pat:pat => $ret:expr) => {
        match next!($buf, $i) {
            v@$pat => v,
            _ => return $ret
        }
    }
}

macro_rules! slice {
    ($buf:ident[$from:expr;]) => ({
        slice!($buf[$from; $buf.len()])
    });
    ($buf:ident[$from:expr;$to:expr]) => {
        unsafe {
            use std::mem::transmute;
            use std::raw::Slice;
            transmute(Slice {
                data: $buf.as_ptr().offset($from as isize),
                len: $to - $from
            })
        }
    }
}

/// Determines if byte is a token char.
///
/// > ```notrust
/// > token          = 1*tchar
/// >
/// > tchar          = "!" / "#" / "$" / "%" / "&" / "'" / "*"
/// >                / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
/// >                / DIGIT / ALPHA
/// >                ; any VCHAR, except delimiters
/// > ```
macro_rules! is_token {
    ($b:expr) => ({
        let b = $b;
        b > 0x1F && b < 0x7F
    })
}

macro_rules! parse {
    ($obj:ident.$field:ident = parse_version ($buf:expr)) => ({
        $obj.$field = match try!(parse_version($buf)) {
            Status::Complete(val) => {
                let buf = $buf;
                $buf = slice!(buf[8;]);
                Some(val)
            },
            Status::Partial => return Ok(Status::Partial)
        }
    });
    ($obj:ident.$field:ident = parse_code ($buf:expr)) => ({
        $obj.$field = match try!(parse_code($buf)) {
            Status::Complete(val) => {
                let buf = $buf;
                $buf = slice!(buf[3;]);
                Some(val)
            },
            Status::Partial => return Ok(Status::Partial)
        }
    });
    ($obj:ident.$field:ident = $action:ident ($buf:expr)) => ({
        $obj.$field = match try!($action($buf)) {
            Status::Complete(val) => {
                let buf = $buf;
                $buf = slice!(buf[val.len();]);
                Some(val)
            },
            Status::Partial => return Ok(Status::Partial)
        }
    })
}

macro_rules! newline {
    ($buf:ident) => ({
        let mut i = 0;
        eof!($buf, i);
        match next!($buf, i) {
            b'\r' => {
                expect!($buf[i] == b'\n' => Ok(Status::Partial));
                let buf = $buf;
                $buf = slice!(buf[2;]);
            },
            b'\n' => {
                let buf = $buf;
                $buf = slice!(buf[1;]);
            },
            _ => return Err(Error::NewLine)
        }
    })
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Error {
    HeaderName,
    HeaderValue,
    NewLine,
    Status,
    Token,
    TooManyHeaders,
    Version
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Status<T> {
    Complete(T),
    Partial
}

impl<T> Status<T> {
    #[inline]
    pub fn is_complete(&self) -> bool {
        match *self {
            Status::Complete(..) => true,
            Status::Partial => false
        }
    }

    #[inline]
    pub fn is_partial(&self) -> bool {
        match *self {
            Status::Complete(..) => false,
            Status::Partial => true
        }
    }

    #[inline]
    pub fn unwrap(self) -> T {
        match self {
            Status::Complete(t) => t,
            Status::Partial => panic!("Tried to unwrap Status::Partial")
        }
    }
}

pub struct Request<'a> {
    pub method: Option<&'a str>,
    pub path: Option<&'a str>,
    pub version: Option<u8>,
    pub headers: &'a mut [Header<'a>]
}

impl<'a> Request<'a> {
    #[inline]
    pub fn new(headers: &'a mut [Header<'a>]) -> Request<'a> {
        Request {
            method: None,
            path: None,
            version: None,
            headers: headers,
        }
    }

    pub fn parse(&mut self, mut buf: &'a [u8]) -> Result<Status<usize>, Error> {
        let orig_len = buf.len();
        parse!(self.method = parse_token(buf));
        buf = slice!(buf[1;]);
        parse!(self.path = parse_token(buf));
        buf = slice!(buf[1;]);
        parse!(self.version = parse_version(buf));
        newline!(buf);

        let len = orig_len - buf.len();
        let headers_len = match try!(parse_headers(self.headers, buf)) {
            Status::Complete(len) => len,
            Status::Partial => return Ok(Status::Partial)
        };

        Ok(Status::Complete(len + headers_len))
    }
}

pub struct Response<'a> {
    pub version: Option<u8>,
    pub code: Option<u16>,
    pub reason: Option<&'a str>,
    pub headers: &'a mut [Header<'a>]
}

impl<'a> Response<'a> {
    #[inline]
    pub fn new(headers: &'a mut [Header<'a>]) -> Response<'a> {
        Response {
            version: None,
            code: None,
            reason: None,
            headers: headers,
        }
    }

    pub fn parse(&mut self, mut buf: &'a [u8]) -> Result<Status<usize>, Error> {
        let orig_len = buf.len();

        parse!(self.version = parse_version(buf));
        buf = slice!(buf[1;]);
        parse!(self.code = parse_code(buf));
        buf = slice!(buf[1;]);
        parse!(self.reason = parse_token(buf));
        newline!(buf);

        let len = orig_len - buf.len();
        let headers_len = match try!(parse_headers(self.headers, buf)) {
            Status::Complete(len) => len,
            Status::Partial => return Ok(Status::Partial)
        };
        Ok(Status::Complete(len + headers_len))
    }
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Header<'a> {
    pub name: &'a str,
    pub value: &'a [u8],
}

#[inline]
fn parse_version(buf: &[u8]) -> Result<Status<u8>, Error> {
    let mut i = 0;

    expect!(buf[i] == b'H' => Err(Error::Version));
    expect!(buf[i] == b'T' => Err(Error::Version));
    expect!(buf[i] == b'T' => Err(Error::Version));
    expect!(buf[i] == b'P' => Err(Error::Version));
    expect!(buf[i] == b'/' => Err(Error::Version));
    expect!(buf[i] == b'1' => Err(Error::Version));
    expect!(buf[i] == b'.' => Err(Error::Version));
    match next!(buf, i) {
        b'0' => Ok(Status::Complete(0)),
        b'1' => Ok(Status::Complete(1)),
        _ => Err(Error::Version)
    }
}

#[inline]
fn parse_token(buf: &[u8]) -> Result<Status<&str>, Error> {
    let mut i: usize = 0;
    loop {
        let b = next!(buf, i);
        if b == b' ' || b == b'\r' || b == b'\n' {
            return Ok(Status::Complete(unsafe {
                // all bytes up till `i` must have been `is_token`.
                str::from_utf8_unchecked(&buf[..i - 1])
            }));
        } else if !is_token!(b) {
            return Err(Error::Token);
        }
    }
}

#[inline]
fn parse_code(buf: &[u8]) -> Result<Status<u16>, Error> {
    let mut i = 0;
    let hundreds = expect!(buf[i] == b'0'...b'9' => Err(Error::Status));
    let tens = expect!(buf[i] == b'0'...b'9' => Err(Error::Status));
    let ones = expect!(buf[i] == b'0'...b'9' => Err(Error::Status));

    Ok(Status::Complete((hundreds - b'0') as u16 * 100 +
                        (tens - b'0') as u16 * 10 +
                        (ones - b'0') as u16))
}

#[inline]
fn parse_headers<'a>(headers: &mut [Header<'a>], buf: &'a [u8]) -> Result<Status<usize>, Error> {
    let mut i: usize = 0;
    let mut last_i: usize = 0;
    'headers: for header in headers {
        // a newline here means the head is over!
        eof!(buf, i);
        let b = unsafe { *buf.get_unchecked(i) };
        if b == b'\r' {
            i += 1;
            expect!(buf[i] == b'\n' => Err(Error::NewLine));
            return Ok(Status::Complete(i));
        } else if b == b'\n' {
            i += 1;
            return Ok(Status::Complete(i));
        }

        last_i = i;
        // parse header name until colon
        loop {
            let b = next!(buf, i);
            if b == b':' {
                header.name = unsafe {
                    str::from_utf8_unchecked(slice!(buf[last_i;i - 1]))
                };
                break;
            } else if !is_token!(b) {
                return Err(Error::HeaderName);
            }
        }

        // eat white space between colon and value
        loop {
            let b = next!(buf, i);
            if !(b == b' ' || b == b'\t') {
                i -= 1;
                last_i = i;
                break;
            }
        }

        // parse value till EOL

        macro_rules! check {
            () => ({
                let b = unsafe { *buf.get_unchecked(i) };
                i += 1;
                if !is_token!(b) {
                    if (b < 0o40 && b != 0o11) || b == 0o177 {
                        if b == b'\r' {
                            expect!(buf[i] == b'\n' => Err(Error::HeaderValue));
                            header.value = slice!(buf[last_i;i - 2]);
                            continue 'headers;
                        } else if b == b'\n' {
                            header.value = slice!(buf[last_i;i - 1]);
                            continue 'headers;
                        } else {
                            return Err(Error::HeaderValue);
                        }
                    }
                }
            })
        }
        while buf.len() - i >= 8 {
            check!();
            check!();
            check!();
            check!();
            check!();
            check!();
            check!();
            check!();
        }
        loop {
            let b = next!(buf, i);
            if !is_token!(b) {
                if (b < 0o40 && b != 0o11) || b == 0o177 {
                    if b == b'\r' {
                        expect!(buf[i] == b'\n' => Err(Error::HeaderValue));
                        header.value = slice!(buf[last_i;i - 2]);
                        break;
                    } else if b == b'\n' {
                        header.value = slice!(buf[last_i;i - 1]);
                        break;
                    } else {
                        return Err(Error::HeaderValue);
                    }
                }
            }
        }
    }

    Err(Error::TooManyHeaders)
}

#[cfg(test)]
mod tests {
    use super::{Request, Response, Header, Status};

    macro_rules! req {
        ($name:ident, $buf:expr, $closure:expr) => (
            req! {$name, $buf, Ok(Status::Complete($buf.len())), $closure }
        );
        ($name:ident, $buf:expr, $len:expr, $closure:expr) => (
        #[test]
        fn $name() {
            let mut headers = [Header{ name: "", value: &[] }; 16];
            let mut req = Request::new(&mut headers[..]);
            let closure: Box<Fn(Request)> = Box::new($closure);
            let status = req.parse(unsafe { ::std::mem::transmute($buf) });
            assert_eq!(status, $len);
            closure(req);
        }
        )
    }

    req! {
        test_request_simple,
        "GET / HTTP/1.1\r\n\r\n",
        |req| {
            assert_eq!(req.method.unwrap(), "GET");
            assert_eq!(req.path.unwrap(), "/");
            assert_eq!(req.version.unwrap(), 1);
        }
    }

    req! {
        test_request_headers,
        "GET / HTTP/1.1\r\nHost: foo.com\r\nCookie: \r\n\r\n",
        |req| {
            assert_eq!(req.method.unwrap(), "GET");
            assert_eq!(req.path.unwrap(), "/");
            assert_eq!(req.version.unwrap(), 1);
            assert_eq!(req.headers[0].name, "Host");
            assert_eq!(req.headers[0].value, b"foo.com");
            assert_eq!(req.headers[1].name, "Cookie");
            assert_eq!(req.headers[1].value, b"");
        }
    }

    req! {
        test_request_multibyte,
        b"GET / HTTP/1.1\r\nHost: foo.com\r\nUser-Agent: \xe3\x81\xb2\xe3/1.0\r\n\r\n",
        |req| {
            assert_eq!(req.method.unwrap(), "GET");
            assert_eq!(req.path.unwrap(), "/");
            assert_eq!(req.version.unwrap(), 1);
            assert_eq!(req.headers[0].name, "Host");
            assert_eq!(req.headers[0].value, b"foo.com");
            assert_eq!(req.headers[1].name, "User-Agent");
            assert_eq!(req.headers[1].value, b"\xe3\x81\xb2\xe3/1.0");
        }
    }

    req! {
        test_request_partial,
        "GET / HTTP/1.1\r\n\r", Ok(Status::Partial),
        |_req| {}
    }

    macro_rules! res {
        ($name:ident, $buf:expr, $closure:expr) => (
            res! {$name, $buf, Ok(Status::Complete($buf.len())), $closure }
        );
        ($name:ident, $buf:expr, $len:expr, $closure:expr) => (
        #[test]
        fn $name() {
            let mut headers = [Header{ name: "", value: &[] }; 16];
            let mut res = Response::new(&mut headers[..]);
            let closure: Box<Fn(Response)> = Box::new($closure);
            let status = res.parse(unsafe { ::std::mem::transmute($buf.as_bytes()) });
            assert_eq!(status, $len);
            closure(res);
        }
        )
    }

    res! {
        test_response_simple,
        "HTTP/1.1 200 OK\r\n\r\n",
        |res| {
            assert_eq!(res.version.unwrap(), 1);
            assert_eq!(res.code.unwrap(), 200);
            assert_eq!(res.reason.unwrap(), "OK");
        }
    }
}
<commit_msg>tests and performance<commit_after>#![feature(core)]
#![allow(unused_assignments)]

use std::str;

macro_rules! eof {
    ($buf:expr, $i:expr) => (
        if $buf.len() == $i {
            return Ok(Status::Partial);
        }
    )
}
macro_rules! next {
    ($buf:expr, $i:ident) => ({
        let buf = $buf;
        eof!(buf, $i);
        let ret = unsafe { *$buf.get_unchecked($i) };
        $i += 1;
        ret
    })
}

macro_rules! expect {
    ($buf:ident[$i:ident] == $pat:pat => $ret:expr) => {
        match next!($buf, $i) {
            v@$pat => v,
            _ => return $ret
        }
    }
}

macro_rules! slice {
    ($buf:ident[$from:expr;]) => ({
        slice!($buf[$from; $buf.len()])
    });
    ($buf:ident[$from:expr;$to:expr]) => {
        unsafe {
            use std::mem::transmute;
            use std::raw::Slice;
            transmute(Slice {
                data: $buf.as_ptr().offset($from as isize),
                len: $to - $from
            })
        }
    }
}

/// Determines if byte is a token char.
///
/// > ```notrust
/// > token          = 1*tchar
/// >
/// > tchar          = "!" / "#" / "$" / "%" / "&" / "'" / "*"
/// >                / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
/// >                / DIGIT / ALPHA
/// >                ; any VCHAR, except delimiters
/// > ```
macro_rules! is_token {
    ($b:expr) => ({
        let b = $b;
        b > 0x1F && b < 0x7F
    })
}

macro_rules! parse {
    ($obj:ident.$field:ident = parse_version ($buf:expr)) => ({
        $obj.$field = match try!(parse_version($buf)) {
            Status::Complete(val) => {
                let buf = $buf;
                $buf = slice!(buf[8;]);
                Some(val)
            },
            Status::Partial => return Ok(Status::Partial)
        }
    });
    ($obj:ident.$field:ident = parse_code ($buf:expr)) => ({
        $obj.$field = match try!(parse_code($buf)) {
            Status::Complete(val) => {
                let buf = $buf;
                $buf = slice!(buf[3;]);
                Some(val)
            },
            Status::Partial => return Ok(Status::Partial)
        }
    });
    ($obj:ident.$field:ident = $action:ident ($buf:expr)) => ({
        $obj.$field = match try!($action($buf)) {
            Status::Complete(val) => {
                let buf = $buf;
                $buf = slice!(buf[val.len();]);
                Some(val)
            },
            Status::Partial => return Ok(Status::Partial)
        }
    })
}

macro_rules! newline {
    ($buf:ident) => ({
        let mut i = 0;
        eof!($buf, i);
        match next!($buf, i) {
            b'\r' => {
                expect!($buf[i] == b'\n' => Ok(Status::Partial));
                let buf = $buf;
                $buf = slice!(buf[2;]);
            },
            b'\n' => {
                let buf = $buf;
                $buf = slice!(buf[1;]);
            },
            _ => return Err(Error::NewLine)
        }
    })
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Error {
    HeaderName,
    HeaderValue,
    NewLine,
    Status,
    Token,
    TooManyHeaders,
    Version
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Status<T> {
    Complete(T),
    Partial
}

impl<T> Status<T> {
    #[inline]
    pub fn is_complete(&self) -> bool {
        match *self {
            Status::Complete(..) => true,
            Status::Partial => false
        }
    }

    #[inline]
    pub fn is_partial(&self) -> bool {
        match *self {
            Status::Complete(..) => false,
            Status::Partial => true
        }
    }

    #[inline]
    pub fn unwrap(self) -> T {
        match self {
            Status::Complete(t) => t,
            Status::Partial => panic!("Tried to unwrap Status::Partial")
        }
    }
}

pub struct Request<'a> {
    pub method: Option<&'a str>,
    pub path: Option<&'a str>,
    pub version: Option<u8>,
    pub headers: &'a mut [Header<'a>]
}

impl<'a> Request<'a> {
    #[inline]
    pub fn new(headers: &'a mut [Header<'a>]) -> Request<'a> {
        Request {
            method: None,
            path: None,
            version: None,
            headers: headers,
        }
    }

    pub fn parse(&mut self, mut buf: &'a [u8]) -> Result<Status<usize>, Error> {
        let orig_len = buf.len();
        parse!(self.method = parse_token(buf));
        buf = slice!(buf[1;]);
        parse!(self.path = parse_token(buf));
        buf = slice!(buf[1;]);
        parse!(self.version = parse_version(buf));
        newline!(buf);

        let len = orig_len - buf.len();
        let headers_len = match try!(parse_headers(self.headers, buf)) {
            Status::Complete(len) => len,
            Status::Partial => return Ok(Status::Partial)
        };

        Ok(Status::Complete(len + headers_len))
    }
}

pub struct Response<'a> {
    pub version: Option<u8>,
    pub code: Option<u16>,
    pub reason: Option<&'a str>,
    pub headers: &'a mut [Header<'a>]
}

impl<'a> Response<'a> {
    #[inline]
    pub fn new(headers: &'a mut [Header<'a>]) -> Response<'a> {
        Response {
            version: None,
            code: None,
            reason: None,
            headers: headers,
        }
    }

    pub fn parse(&mut self, mut buf: &'a [u8]) -> Result<Status<usize>, Error> {
        let orig_len = buf.len();

        parse!(self.version = parse_version(buf));
        buf = slice!(buf[1;]);
        parse!(self.code = parse_code(buf));
        buf = slice!(buf[1;]);
        parse!(self.reason = parse_token(buf));
        newline!(buf);

        let len = orig_len - buf.len();
        let headers_len = match try!(parse_headers(self.headers, buf)) {
            Status::Complete(len) => len,
            Status::Partial => return Ok(Status::Partial)
        };
        Ok(Status::Complete(len + headers_len))
    }
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Header<'a> {
    pub name: &'a str,
    pub value: &'a [u8],
}

#[inline]
fn parse_version(buf: &[u8]) -> Result<Status<u8>, Error> {
    let mut i = 0;

    expect!(buf[i] == b'H' => Err(Error::Version));
    expect!(buf[i] == b'T' => Err(Error::Version));
    expect!(buf[i] == b'T' => Err(Error::Version));
    expect!(buf[i] == b'P' => Err(Error::Version));
    expect!(buf[i] == b'/' => Err(Error::Version));
    expect!(buf[i] == b'1' => Err(Error::Version));
    expect!(buf[i] == b'.' => Err(Error::Version));
    match next!(buf, i) {
        b'0' => Ok(Status::Complete(0)),
        b'1' => Ok(Status::Complete(1)),
        _ => Err(Error::Version)
    }
}

#[inline]
fn parse_token(buf: &[u8]) -> Result<Status<&str>, Error> {
    let mut i: usize = 0;
    loop {
        let b = next!(buf, i);
        if b == b' ' || b == b'\r' || b == b'\n' {
            return Ok(Status::Complete(unsafe {
                // all bytes up till `i` must have been `is_token`.
                str::from_utf8_unchecked(&buf[..i - 1])
            }));
        } else if !is_token!(b) {
            return Err(Error::Token);
        }
    }
}

#[inline]
fn parse_code(buf: &[u8]) -> Result<Status<u16>, Error> {
    let mut i = 0;
    let hundreds = expect!(buf[i] == b'0'...b'9' => Err(Error::Status));
    let tens = expect!(buf[i] == b'0'...b'9' => Err(Error::Status));
    let ones = expect!(buf[i] == b'0'...b'9' => Err(Error::Status));

    Ok(Status::Complete((hundreds - b'0') as u16 * 100 +
                        (tens - b'0') as u16 * 10 +
                        (ones - b'0') as u16))
}

#[inline]
fn parse_headers<'a>(headers: &mut [Header<'a>], buf: &'a [u8]) -> Result<Status<usize>, Error> {
    let mut i: usize = 0;
    let mut last_i: usize = 0;
    'headers: for header in headers {
        // a newline here means the head is over!
        eof!(buf, i);
        let b = unsafe { *buf.get_unchecked(i) };
        if b == b'\r' {
            i += 1;
            expect!(buf[i] == b'\n' => Err(Error::NewLine));
            return Ok(Status::Complete(i));
        } else if b == b'\n' {
            i += 1;
            return Ok(Status::Complete(i));
        }

        last_i = i;
        // parse header name until colon
        loop {
            let b = next!(buf, i);
            if b == b':' {
                header.name = unsafe {
                    str::from_utf8_unchecked(slice!(buf[last_i;i - 1]))
                };
                break;
            } else if !is_token!(b) {
                return Err(Error::HeaderName);
            }
        }

        // eat white space between colon and value
        loop {
            let b = next!(buf, i);
            if !(b == b' ' || b == b'\t') {
                i -= 1;
                last_i = i;
                break;
            }
        }

        // parse value till EOL

        macro_rules! check {
            () => ({
                let b = unsafe { *buf.get_unchecked(i) };
                i += 1;
                if !is_token!(b) {
                    if (b < 0o40 && b != 0o11) || b == 0o177 {
                        if b == b'\r' {
                            expect!(buf[i] == b'\n' => Err(Error::HeaderValue));
                            header.value = slice!(buf[last_i;i - 2]);
                            continue 'headers;
                        } else if b == b'\n' {
                            header.value = slice!(buf[last_i;i - 1]);
                            continue 'headers;
                        } else {
                            return Err(Error::HeaderValue);
                        }
                    }
                }
            })
        }
        while buf.len() - i >= 8 {
            check!();
            check!();
            check!();
            check!();
            check!();
            check!();
            check!();
            check!();
        }
        loop {
            let b = next!(buf, i);
            if !is_token!(b) {
                if (b < 0o40 && b != 0o11) || b == 0o177 {
                    if b == b'\r' {
                        expect!(buf[i] == b'\n' => Err(Error::HeaderValue));
                        header.value = slice!(buf[last_i;i - 2]);
                        break;
                    } else if b == b'\n' {
                        header.value = slice!(buf[last_i;i - 1]);
                        break;
                    } else {
                        return Err(Error::HeaderValue);
                    }
                }
            }
        }
    }

    Err(Error::TooManyHeaders)
}

#[cfg(test)]
mod tests {
    use super::{Request, Response, Header, Status};

    macro_rules! req {
        ($name:ident, $buf:expr, $closure:expr) => (
            req! {$name, $buf, Ok(Status::Complete($buf.len())), $closure }
        );
        ($name:ident, $buf:expr, $len:expr, $closure:expr) => (
        #[test]
        fn $name() {
            let mut headers = [Header{ name: "", value: &[] }; 16];
            let mut req = Request::new(&mut headers[..]);
            let closure: Box<Fn(Request)> = Box::new($closure);
            let status = req.parse(unsafe { ::std::mem::transmute($buf) });
            assert_eq!(status, $len);
            closure(req);
        }
        )
    }

    req! {
        test_request_simple,
        "GET / HTTP/1.1\r\n\r\n",
        |req| {
            assert_eq!(req.method.unwrap(), "GET");
            assert_eq!(req.path.unwrap(), "/");
            assert_eq!(req.version.unwrap(), 1);
        }
    }

    req! {
        test_request_headers,
        "GET / HTTP/1.1\r\nHost: foo.com\r\nCookie: \r\n\r\n",
        |req| {
            assert_eq!(req.method.unwrap(), "GET");
            assert_eq!(req.path.unwrap(), "/");
            assert_eq!(req.version.unwrap(), 1);
            assert_eq!(req.headers[0].name, "Host");
            assert_eq!(req.headers[0].value, b"foo.com");
            assert_eq!(req.headers[1].name, "Cookie");
            assert_eq!(req.headers[1].value, b"");
        }
    }

    req! {
        test_request_multibyte,
        b"GET / HTTP/1.1\r\nHost: foo.com\r\nUser-Agent: \xe3\x81\xb2\xe3/1.0\r\n\r\n",
        |req| {
            assert_eq!(req.method.unwrap(), "GET");
            assert_eq!(req.path.unwrap(), "/");
            assert_eq!(req.version.unwrap(), 1);
            assert_eq!(req.headers[0].name, "Host");
            assert_eq!(req.headers[0].value, b"foo.com");
            assert_eq!(req.headers[1].name, "User-Agent");
            assert_eq!(req.headers[1].value, b"\xe3\x81\xb2\xe3/1.0");
        }
    }

    req! {
        test_request_partial,
        "GET / HTTP/1.1\r\n\r", Ok(Status::Partial),
        |_req| {}
    }

    req! {
        test_request_newlines,
        "GET / HTTP/1.1\n\n",
        |_| {}
    }

    macro_rules! res {
        ($name:ident, $buf:expr, $closure:expr) => (
            res! {$name, $buf, Ok(Status::Complete($buf.len())), $closure }
        );
        ($name:ident, $buf:expr, $len:expr, $closure:expr) => (
        #[test]
        fn $name() {
            let mut headers = [Header{ name: "", value: &[] }; 16];
            let mut res = Response::new(&mut headers[..]);
            let closure: Box<Fn(Response)> = Box::new($closure);
            let status = res.parse(unsafe { ::std::mem::transmute($buf.as_bytes()) });
            assert_eq!(status, $len);
            closure(res);
        }
        )
    }

    res! {
        test_response_simple,
        "HTTP/1.1 200 OK\r\n\r\n",
        |res| {
            assert_eq!(res.version.unwrap(), 1);
            assert_eq!(res.code.unwrap(), 200);
            assert_eq!(res.reason.unwrap(), "OK");
        }
    }
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate json;

mod request;
mod response;

pub use request::Request;
pub use response::Response;

pub type Result = hyper::Result<Response>;
pub type Error = hyper::error::Error;

pub fn get(url: &str) -> Result {
    Request::default().get(url)
}

pub fn post(url: &str) -> Result {
    Request::default().post(url)
}

pub fn put(url: &str) -> Result {
    Request::default().put(url)
}

pub fn head(url: &str) -> Result {
    Request::default().head(url)
}

pub fn delete(url: &str) -> Result {
    Request::default().delete(url)
}
<commit_msg>Prepare for upcoming public Codes enum<commit_after>extern crate hyper;
extern crate json;

mod request;
mod response;

pub use request::Request;
pub use response::Response;
pub use response::Codes;

pub type Result = hyper::Result<Response>;
pub type Error = hyper::error::Error;

pub fn get(url: &str) -> Result {
    Request::default().get(url)
}

pub fn post(url: &str) -> Result {
    Request::default().post(url)
}

pub fn put(url: &str) -> Result {
    Request::default().put(url)
}

pub fn head(url: &str) -> Result {
    Request::default().head(url)
}

pub fn delete(url: &str) -> Result {
    Request::default().delete(url)
}
<|endoftext|>


<commit_before>//! A simple `io::stdout` and `io::stderr` writing `Logger` implementation from the
//! `log` crate, using the `ansi_term` crate for colors and configured at runtime,
//! or at compile time with simple function calls. Designed for simple CLIs.
//!
//! This library only comes with 3 public ways to initialize the global logger.
//! Ensure you call one of these exactly once early in your rust program as shown
//! in one of the examples below.
//!
//! ## Example
//! The standard example with `clap` as the arg parser.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate clap;
//! extern crate loggerv;
//!
//! use clap::{Arg, App};
//!
//! fn main() {
//!     let args = App::new("app")
//!                    .arg(Arg::with_name("v")
//!                             .short("v")
//!                             .multiple(true)
//!                             .help("Sets the level of verbosity"))
//!                    .get_matches();
//!
//!     loggerv::init_with_verbosity(args.occurrences_of("v")).unwrap();
//!
//!     error!("this is always printed");
//!     warn!("this too, and it's printed to stderr");
//!     info!("this is optional");  // for ./app -v or higher
//!     debug!("this is optional"); // for ./app -vv or higher
//!     trace!("this is optional"); // for ./app -vvv
//! }
//! ```
//!
//! But obviously use whatever argument parsing methods you prefer.
//!
//! ## Example
//! For a compile time switch, all you really need is `log` (for the macros)
//! and `loggerv` for how to print what's being sent to the macros.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! use log::LogLevel;
//!
//! fn main() {
//!     loggerv::init_with_level(LogLevel::Info).unwrap();
//!     debug!("this is a debug {}", "message");
//!     error!("this is printed by default");
//! }
//! ```
//!
//! # Example
//! If you don't really care at all you could just use the plain `init_quiet` function
//! to only show warnings and errors:
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! fn main() {
//!     loggerv::init_quiet().unwrap();
//!     info!("hidden");
//!     error!("this is printed by default");
//! }
//! ```
//!
//!
//! See the documentation for the log crate for more information about its API.
//!

#[cfg(test)]
#[macro_use]
extern crate log;

#[cfg(not(test))]
extern crate log;

extern crate atty;
extern crate ansi_term;

use log::{Log, LogLevel, LogMetadata, LogRecord, SetLoggerError};
use std::io::{self, Write};
use ansi_term::Colour;

struct VLogger {
    log_level: LogLevel,
    colors: bool,
}

impl VLogger {
    fn new(log_level: LogLevel) -> VLogger {
        let colors = atty::is(atty::Stream::Stdout) && atty::is(atty::Stream::Stderr);
        VLogger { log_level, colors }
    }
}

fn level_style(l: LogLevel) -> Colour {
    match l {
        LogLevel::Error => Colour::Fixed(9), // bright red
        LogLevel::Warn => Colour::Fixed(11), // bright yellow
        LogLevel::Info => Colour::Fixed(10), // bright green
        LogLevel::Debug => Colour::Fixed(7), // light grey
        LogLevel::Trace => Colour::Fixed(8), // grey
    }
}

impl Log for VLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.log_level
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let level = record.level();
            let tag = if self.colors {
                level_style(level).paint(format!("{} [{}]", level, record.location().module_path())).to_string()
            } else {
                format!("{} [{}]", level, record.location().module_path())
            };
            if level <= LogLevel::Warn {
                let _ = writeln!(&mut io::stderr(), "{}: {}", tag, record.args());
            } else {
                println!("{}: {}", tag, record.args());
            }
        }
    }
}

/// Initialize loggerv with a maximal log level.
///
/// See the main loggerv documentation page for an example.
pub fn init_with_level(log_level: LogLevel) -> Result<(), SetLoggerError> {
    log::set_logger(|max_log_level| {
        max_log_level.set(log_level.to_log_level_filter());
        Box::new(VLogger::new(log_level))
    })
}

/// Initialize loggerv with a verbosity level.
///
/// Intended to be used with an arg parser counting the amount of -v flags.
/// See the main loggerv documentation page for an example.
pub fn init_with_verbosity(verbosity: u64) -> Result<(), SetLoggerError> {
    init_with_level(match verbosity {
        0 => LogLevel::Warn,  // default
        1 => LogLevel::Info,  // -v
        2 => LogLevel::Debug, // -vv
        _ => LogLevel::Trace, // -vvv and above
    })
}

/// Initializes loggerv with only warnings and errors.
///
/// See the main loggerv documentation page for an example.
pub fn init_quiet() -> Result<(), SetLoggerError> {
    init_with_level(LogLevel::Warn)
}

#[cfg(test)]
mod tests {
    use init_with_verbosity;

    #[test]
    fn init_and_macros() {
        let l = init_with_verbosity(3);
        assert_eq!(l.is_ok(), true);
        error!("error log");
        warn!("warn log");
        info!("info log");
        debug!("debug log");
        trace!("trace log");
    }
}
<commit_msg>Add separator field to VLogger struct<commit_after>//! A simple `io::stdout` and `io::stderr` writing `Logger` implementation from the
//! `log` crate, using the `ansi_term` crate for colors and configured at runtime,
//! or at compile time with simple function calls. Designed for simple CLIs.
//!
//! This library only comes with 3 public ways to initialize the global logger.
//! Ensure you call one of these exactly once early in your rust program as shown
//! in one of the examples below.
//!
//! ## Example
//! The standard example with `clap` as the arg parser.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate clap;
//! extern crate loggerv;
//!
//! use clap::{Arg, App};
//!
//! fn main() {
//!     let args = App::new("app")
//!                    .arg(Arg::with_name("v")
//!                             .short("v")
//!                             .multiple(true)
//!                             .help("Sets the level of verbosity"))
//!                    .get_matches();
//!
//!     loggerv::init_with_verbosity(args.occurrences_of("v")).unwrap();
//!
//!     error!("this is always printed");
//!     warn!("this too, and it's printed to stderr");
//!     info!("this is optional");  // for ./app -v or higher
//!     debug!("this is optional"); // for ./app -vv or higher
//!     trace!("this is optional"); // for ./app -vvv
//! }
//! ```
//!
//! But obviously use whatever argument parsing methods you prefer.
//!
//! ## Example
//! For a compile time switch, all you really need is `log` (for the macros)
//! and `loggerv` for how to print what's being sent to the macros.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! use log::LogLevel;
//!
//! fn main() {
//!     loggerv::init_with_level(LogLevel::Info).unwrap();
//!     debug!("this is a debug {}", "message");
//!     error!("this is printed by default");
//! }
//! ```
//!
//! # Example
//! If you don't really care at all you could just use the plain `init_quiet` function
//! to only show warnings and errors:
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! fn main() {
//!     loggerv::init_quiet().unwrap();
//!     info!("hidden");
//!     error!("this is printed by default");
//! }
//! ```
//!
//!
//! See the documentation for the log crate for more information about its API.
//!

#[cfg(test)]
#[macro_use]
extern crate log;

#[cfg(not(test))]
extern crate log;

extern crate atty;
extern crate ansi_term;

use log::{Log, LogLevel, LogMetadata, LogRecord, SetLoggerError};
use std::io::{self, Write};
use ansi_term::Colour;

pub const DEFAULT_SEPARATOR: &str = ": ";

fn level_style(l: LogLevel) -> Colour {
    match l {
        LogLevel::Error => Colour::Fixed(9), // bright red
        LogLevel::Warn => Colour::Fixed(11), // bright yellow
        LogLevel::Info => Colour::Fixed(10), // bright green
        LogLevel::Debug => Colour::Fixed(7), // light grey
        LogLevel::Trace => Colour::Fixed(8), // grey
    }
}

struct VLogger {
    log_level: LogLevel,
    colors: bool,
    separator: String,
}

impl VLogger {
    fn new(log_level: LogLevel) -> VLogger {
        let colors = atty::is(atty::Stream::Stdout) && atty::is(atty::Stream::Stderr);
        VLogger {
            log_level,
            colors ,
            separator: String::from(DEFAULT_SEPARATOR),
        }
    }
}

impl Log for VLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.log_level
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let level = record.level();
            let tag = if self.colors {
                level_style(level).paint(format!("{} [{}]", level, record.location().module_path())).to_string()
            } else {
                format!("{} [{}]", level, record.location().module_path())
            };
            if level <= LogLevel::Warn {
                let _ = writeln!(&mut io::stderr(), "{}{}{}", tag, self.separator, record.args());
            } else {
                println!("{}{}{}", tag, self.separator, record.args());
            }
        }
    }
}

/// Initialize loggerv with a maximal log level.
///
/// See the main loggerv documentation page for an example.
pub fn init_with_level(log_level: LogLevel) -> Result<(), SetLoggerError> {
    log::set_logger(|max_log_level| {
        max_log_level.set(log_level.to_log_level_filter());
        Box::new(VLogger::new(log_level))
    })
}

/// Initialize loggerv with a verbosity level.
///
/// Intended to be used with an arg parser counting the amount of -v flags.
/// See the main loggerv documentation page for an example.
pub fn init_with_verbosity(verbosity: u64) -> Result<(), SetLoggerError> {
    init_with_level(match verbosity {
        0 => LogLevel::Warn,  // default
        1 => LogLevel::Info,  // -v
        2 => LogLevel::Debug, // -vv
        _ => LogLevel::Trace, // -vvv and above
    })
}

/// Initializes loggerv with only warnings and errors.
///
/// See the main loggerv documentation page for an example.
pub fn init_quiet() -> Result<(), SetLoggerError> {
    init_with_level(LogLevel::Warn)
}

#[cfg(test)]
mod tests {
    use init_with_verbosity;

    #[test]
    fn init_and_macros() {
        let l = init_with_verbosity(3);
        assert_eq!(l.is_ok(), true);
        error!("error log");
        warn!("warn log");
        info!("info log");
        debug!("debug log");
        trace!("trace log");
    }
}
<|endoftext|>