<commit_before>/// Literal kind.
///
/// E.g. `"foo"`, `42`, `12.34` or `bool`
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Lit {
    /// A string literal (`"foo"`)
    Str(String, StrStyle),
    /// A byte string (`b"foo"`)
    ByteStr(Vec<u8>, StrStyle),
    /// A byte char (`b'f'`)
    Byte(u8),
    /// A character literal (`'a'`)
    Char(char),
    /// An integer literal (`1`)
    Int(u64, IntTy),
    /// A float literal (`1f64` or `1E10f64` or `1.0E10`)
    Float(String, FloatTy),
    /// A boolean literal
    Bool(bool),
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum StrStyle {
    /// A regular string, like `"foo"`
    Cooked,
    /// A raw string, like `r##"foo"##`
    ///
    /// The uint is the number of `#` symbols used
    Raw(usize),
}

impl From<String> for Lit {
    fn from(input: String) -> Lit {
        Lit::Str(input, StrStyle::Cooked)
    }
}

impl<'a> From<&'a str> for Lit {
    fn from(input: &str) -> Lit {
        Lit::Str(input.into(), StrStyle::Cooked)
    }
}

impl From<Vec<u8>> for Lit {
    fn from(input: Vec<u8>) -> Lit {
        Lit::ByteStr(input, StrStyle::Cooked)
    }
}

impl<'a> From<&'a [u8]> for Lit {
    fn from(input: &[u8]) -> Lit {
        Lit::ByteStr(input.into(), StrStyle::Cooked)
    }
}

impl From<char> for Lit {
    fn from(input: char) -> Lit {
        Lit::Char(input)
    }
}

impl From<bool> for Lit {
    fn from(input: bool) -> Lit {
        Lit::Bool(input)
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum IntTy {
    Isize,
    I8,
    I16,
    I32,
    I64,
    Usize,
    U8,
    U16,
    U32,
    U64,
    Unsuffixed,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum FloatTy {
    F32,
    F64,
    Unsuffixed,
}

macro_rules! impl_from_for_lit {
    (Int, [$($rust_type:ty => $syn_type:expr),+]) => {
        $(
            impl From<$rust_type> for Lit {
                fn from(input: $rust_type) -> Lit {
                    Lit::Int(input as u64, $syn_type)
                }
            }
        )+
    };
    (Float, [$($rust_type:ty => $syn_type:expr),+]) => {
        $(
            impl From<$rust_type> for Lit {
                fn from(input: $rust_type) -> Lit {
                    Lit::Float(format!("{}", input), $syn_type)
                }
            }
        )+
    };
}

impl_from_for_lit! {Int, [
    isize => IntTy::Isize,
    i8 => IntTy::I8,
    i16 => IntTy::I16,
    i32 => IntTy::I32,
    i64 => IntTy::I64,
    usize => IntTy::Usize,
    u8 => IntTy::U8,
    u16 => IntTy::U16,
    u32 => IntTy::U32,
    u64 => IntTy::U64
]}

impl_from_for_lit! {Float, [
    f32 => FloatTy::F32,
    f64 => FloatTy::F64
]}

#[cfg(feature = "parsing")]
#[derive(Debug, Clone)]
pub struct StrLit {
    value: String,
    style: StrStyle,
}

#[cfg(feature = "parsing")]
#[derive(Debug, Clone)]
pub struct ByteStrLit {
    value: Vec<u8>,
    style: StrStyle,
}

#[cfg(feature = "parsing")]
#[derive(Debug, Clone)]
pub struct IntLit {
    value: u64,
    suffix: IntTy,
}

#[cfg(feature = "parsing")]
#[derive(Debug, Clone)]
pub struct FloatLit {
    value: String,
    suffix: FloatTy,
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use escape::{cooked_byte, cooked_byte_string, cooked_char, cooked_string, raw_string};
    use synom::space::skip_whitespace;
    use synom::IResult;
    use unicode_xid::UnicodeXID;

    named!(pub lit -> Lit, alt!(
        string => { |StrLit { value, style }| Lit::Str(value, style) }
        |
        byte_string => { |ByteStrLit { value, style }| Lit::ByteStr(value, style) }
        |
        byte => { |b| Lit::Byte(b) }
        |
        character => { |ch| Lit::Char(ch) }
        |
        float => { |FloatLit { value, suffix }| Lit::Float(value, suffix) } // must be before int
        |
        int => { |IntLit { value, suffix }| Lit::Int(value, suffix) }
        |
        boolean => { |value| Lit::Bool(value) }
    ));

    named!(pub string -> StrLit, alt!(
        quoted_string => { |s| StrLit { value: s, style: StrStyle::Cooked } }
        |
        preceded!(
            punct!("r"),
            raw_string
        ) => { |(s, n)| StrLit { value: s, style: StrStyle::Raw(n) }}
    ));

    named!(pub quoted_string -> String, delimited!(
        punct!("\""),
        cooked_string,
        tag!("\"")
    ));

    named!(pub byte_string -> ByteStrLit, alt!(
        delimited!(
            punct!("b\""),
            cooked_byte_string,
            tag!("\"")
        ) => { |vec| ByteStrLit { value: vec, style: StrStyle::Cooked } }
        |
        preceded!(
            punct!("br"),
            raw_string
        ) => { |(s, n): (String, _)| ByteStrLit { value: s.into_bytes(), style: StrStyle::Raw(n) } }
    ));

    named!(pub byte -> u8, do_parse!(
        punct!("b") >>
        tag!("'") >>
        b: cooked_byte >>
        tag!("'") >>
        (b)
    ));

    named!(pub character -> char, do_parse!(
        punct!("'") >>
        ch: cooked_char >>
        tag!("'") >>
        (ch)
    ));

    named!(pub float -> FloatLit, do_parse!(
        value: float_string >>
        suffix: alt!(
            tag!("f32") => { |_| FloatTy::F32 }
            |
            tag!("f64") => { |_| FloatTy::F64 }
            |
            epsilon!() => { |_| FloatTy::Unsuffixed }
        ) >>
        (FloatLit { value: value, suffix: suffix })
    ));

    named!(pub int -> IntLit, do_parse!(
        value: digits >>
        suffix: alt!(
            tag!("isize") => { |_| IntTy::Isize }
            |
            tag!("i8") => { |_| IntTy::I8 }
            |
            tag!("i16") => { |_| IntTy::I16 }
            |
            tag!("i32") => { |_| IntTy::I32 }
            |
            tag!("i64") => { |_| IntTy::I64 }
            |
            tag!("usize") => { |_| IntTy::Usize }
            |
            tag!("u8") => { |_| IntTy::U8 }
            |
            tag!("u16") => { |_| IntTy::U16 }
            |
            tag!("u32") => { |_| IntTy::U32 }
            |
            tag!("u64") => { |_| IntTy::U64 }
            |
            epsilon!() => { |_| IntTy::Unsuffixed }
        ) >>
        (IntLit { value: value, suffix: suffix })
    ));

    named!(pub boolean -> bool, alt!(
        keyword!("true") => { |_| true }
        |
        keyword!("false") => { |_| false }
    ));

    fn float_string(mut input: &str) -> IResult<&str, String> {
        input = skip_whitespace(input);

        let mut chars = input.chars().peekable();
        match chars.next() {
            Some(ch) if ch >= '0' && ch <= '9' => {}
            _ => return IResult::Error,
        }

        let mut len = 1;
        let mut has_dot = false;
        let mut has_exp = false;
        while let Some(&ch) = chars.peek() {
            match ch {
                '0'...'9' | '_' => {
                    chars.next();
                    len += 1;
                }
                '.' => {
                    if has_dot {
                        break;
                    }
                    chars.next();
                    if chars.peek()
                        .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
                        .unwrap_or(false) {
                        return IResult::Error;
                    }
                    len += 1;
                    has_dot = true;
                }
                'e' | 'E' => {
                    chars.next();
                    len += 1;
                    has_exp = true;
                    break;
                }
                _ => break,
            }
        }

        let rest = &input[len..];
        if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
            return IResult::Error;
        }

        if has_exp {
            let mut has_exp_value = false;
            while let Some(&ch) = chars.peek() {
                match ch {
                    '+' | '-' => {
                        if has_exp_value {
                            break;
                        }
                        chars.next();
                        len += 1;
                    }
                    '0'...'9' => {
                        chars.next();
                        len += 1;
                        has_exp_value = true;
                    }
                    '_' => {
                        chars.next();
                        len += 1;
                    }
                    _ => break,
                }
            }
            if !has_exp_value {
                return IResult::Error;
            }
        }

        IResult::Done(&input[len..], input[..len].replace("_", ""))
    }

    pub fn digits(mut input: &str) -> IResult<&str, u64> {
        input = skip_whitespace(input);

        let base = if input.starts_with("0x") {
            input = &input[2..];
            16
        } else if input.starts_with("0o") {
            input = &input[2..];
            8
        } else if input.starts_with("0b") {
            input = &input[2..];
            2
        } else {
            10
        };

        let mut value = 0u64;
        let mut len = 0;
        let mut empty = true;
        for b in input.bytes() {
            let digit = match b {
                b'0'...b'9' => (b - b'0') as u64,
                b'a'...b'f' => 10 + (b - b'a') as u64,
                b'A'...b'F' => 10 + (b - b'A') as u64,
                b'_' => {
                    if empty && base == 10 {
                        return IResult::Error;
                    }
                    len += 1;
                    continue;
                }
                _ => break,
            };
            if digit >= base {
                return IResult::Error;
            }
            value = match value.checked_mul(base) {
                Some(value) => value,
                None => return IResult::Error,
            };
            value = match value.checked_add(digit) {
                Some(value) => value,
                None => return IResult::Error,
            };
            len += 1;
            empty = false;
        }
        if empty {
            IResult::Error
        } else {
            IResult::Done(&input[len..], value)
        }
    }
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use quote::{Tokens, ToTokens};
    use std::{ascii, iter};
    use std::fmt::{self, Display};
    use std::str;

    impl ToTokens for Lit {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                Lit::Str(ref s, StrStyle::Cooked) => s.to_tokens(tokens),
                Lit::Str(ref s, StrStyle::Raw(n)) => {
                    tokens.append(&format!("r{delim}\"{string}\"{delim}",
                        delim = iter::repeat("#").take(n).collect::<String>(),
                        string = s));
                }
                Lit::ByteStr(ref v, StrStyle::Cooked) => {
                    let mut escaped = "b\"".to_string();
                    for &ch in v.iter() {
                        match ch {
                            0 => escaped.push_str(r"\0"),
                            b'\'' => escaped.push('\''),
                            _ => escaped.extend(ascii::escape_default(ch).map(|c| c as char)),
                        }
                    }
                    escaped.push('"');
                    tokens.append(&escaped);
                }
                Lit::ByteStr(ref vec, StrStyle::Raw(n)) => {
                    tokens.append(&format!("br{delim}\"{string}\"{delim}",
                        delim = iter::repeat("#").take(n).collect::<String>(),
                        string = str::from_utf8(vec).unwrap()));
                }
                Lit::Byte(b) => {
                    match b {
                        0 => tokens.append(r"b'\0'"),
                        b'\"' => tokens.append("b'\"'"),
                        _ => {
                            let mut escaped = "b'".to_string();
                            escaped.extend(ascii::escape_default(b).map(|c| c as char));
                            escaped.push('\'');
                            tokens.append(&escaped);
                        }
                    }
                }
                Lit::Char(ch) => ch.to_tokens(tokens),
                Lit::Int(value, ty) => tokens.append(&format!("{}{}", value, ty)),
                Lit::Float(ref value, ty) => tokens.append(&format!("{}{}", value, ty)),
                Lit::Bool(true) => tokens.append("true"),
                Lit::Bool(false) => tokens.append("false"),
            }
        }
    }

    impl Display for IntTy {
        fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
            match *self {
                IntTy::Isize => formatter.write_str("isize"),
                IntTy::I8 => formatter.write_str("i8"),
                IntTy::I16 => formatter.write_str("i16"),
                IntTy::I32 => formatter.write_str("i32"),
                IntTy::I64 => formatter.write_str("i64"),
                IntTy::Usize => formatter.write_str("usize"),
                IntTy::U8 => formatter.write_str("u8"),
                IntTy::U16 => formatter.write_str("u16"),
                IntTy::U32 => formatter.write_str("u32"),
                IntTy::U64 => formatter.write_str("u64"),
                IntTy::Unsuffixed => Ok(()),
            }
        }
    }

    impl Display for FloatTy {
        fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
            match *self {
                FloatTy::F32 => formatter.write_str("f32"),
                FloatTy::F64 => formatter.write_str("f64"),
                FloatTy::Unsuffixed => Ok(()),
            }
        }
    }
}
<commit_msg>Make StrLit, ByteStrLit, IntLit etc. have public fields, fixes #88<commit_after>/// Literal kind.
///
/// E.g. `"foo"`, `42`, `12.34` or `bool`
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Lit {
    /// A string literal (`"foo"`)
    Str(String, StrStyle),
    /// A byte string (`b"foo"`)
    ByteStr(Vec<u8>, StrStyle),
    /// A byte char (`b'f'`)
    Byte(u8),
    /// A character literal (`'a'`)
    Char(char),
    /// An integer literal (`1`)
    Int(u64, IntTy),
    /// A float literal (`1f64` or `1E10f64` or `1.0E10`)
    Float(String, FloatTy),
    /// A boolean literal
    Bool(bool),
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum StrStyle {
    /// A regular string, like `"foo"`
    Cooked,
    /// A raw string, like `r##"foo"##`
    ///
    /// The uint is the number of `#` symbols used
    Raw(usize),
}

impl From<String> for Lit {
    fn from(input: String) -> Lit {
        Lit::Str(input, StrStyle::Cooked)
    }
}

impl<'a> From<&'a str> for Lit {
    fn from(input: &str) -> Lit {
        Lit::Str(input.into(), StrStyle::Cooked)
    }
}

impl From<Vec<u8>> for Lit {
    fn from(input: Vec<u8>) -> Lit {
        Lit::ByteStr(input, StrStyle::Cooked)
    }
}

impl<'a> From<&'a [u8]> for Lit {
    fn from(input: &[u8]) -> Lit {
        Lit::ByteStr(input.into(), StrStyle::Cooked)
    }
}

impl From<char> for Lit {
    fn from(input: char) -> Lit {
        Lit::Char(input)
    }
}

impl From<bool> for Lit {
    fn from(input: bool) -> Lit {
        Lit::Bool(input)
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum IntTy {
    Isize,
    I8,
    I16,
    I32,
    I64,
    Usize,
    U8,
    U16,
    U32,
    U64,
    Unsuffixed,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum FloatTy {
    F32,
    F64,
    Unsuffixed,
}

macro_rules! impl_from_for_lit {
    (Int, [$($rust_type:ty => $syn_type:expr),+]) => {
        $(
            impl From<$rust_type> for Lit {
                fn from(input: $rust_type) -> Lit {
                    Lit::Int(input as u64, $syn_type)
                }
            }
        )+
    };
    (Float, [$($rust_type:ty => $syn_type:expr),+]) => {
        $(
            impl From<$rust_type> for Lit {
                fn from(input: $rust_type) -> Lit {
                    Lit::Float(format!("{}", input), $syn_type)
                }
            }
        )+
    };
}

impl_from_for_lit! {Int, [
    isize => IntTy::Isize,
    i8 => IntTy::I8,
    i16 => IntTy::I16,
    i32 => IntTy::I32,
    i64 => IntTy::I64,
    usize => IntTy::Usize,
    u8 => IntTy::U8,
    u16 => IntTy::U16,
    u32 => IntTy::U32,
    u64 => IntTy::U64
]}

impl_from_for_lit! {Float, [
    f32 => FloatTy::F32,
    f64 => FloatTy::F64
]}

#[cfg(feature = "parsing")]
#[derive(Debug, Clone)]
pub struct StrLit {
    pub value: String,
    pub style: StrStyle,
}

#[cfg(feature = "parsing")]
#[derive(Debug, Clone)]
pub struct ByteStrLit {
    pub value: Vec<u8>,
    pub style: StrStyle,
}

#[cfg(feature = "parsing")]
#[derive(Debug, Clone)]
pub struct IntLit {
    pub value: u64,
    pub suffix: IntTy,
}

#[cfg(feature = "parsing")]
#[derive(Debug, Clone)]
pub struct FloatLit {
    pub value: String,
    pub suffix: FloatTy,
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use escape::{cooked_byte, cooked_byte_string, cooked_char, cooked_string, raw_string};
    use synom::space::skip_whitespace;
    use synom::IResult;
    use unicode_xid::UnicodeXID;

    named!(pub lit -> Lit, alt!(
        string => { |StrLit { value, style }| Lit::Str(value, style) }
        |
        byte_string => { |ByteStrLit { value, style }| Lit::ByteStr(value, style) }
        |
        byte => { |b| Lit::Byte(b) }
        |
        character => { |ch| Lit::Char(ch) }
        |
        float => { |FloatLit { value, suffix }| Lit::Float(value, suffix) } // must be before int
        |
        int => { |IntLit { value, suffix }| Lit::Int(value, suffix) }
        |
        boolean => { |value| Lit::Bool(value) }
    ));

    named!(pub string -> StrLit, alt!(
        quoted_string => { |s| StrLit { value: s, style: StrStyle::Cooked } }
        |
        preceded!(
            punct!("r"),
            raw_string
        ) => { |(s, n)| StrLit { value: s, style: StrStyle::Raw(n) }}
    ));

    named!(pub quoted_string -> String, delimited!(
        punct!("\""),
        cooked_string,
        tag!("\"")
    ));

    named!(pub byte_string -> ByteStrLit, alt!(
        delimited!(
            punct!("b\""),
            cooked_byte_string,
            tag!("\"")
        ) => { |vec| ByteStrLit { value: vec, style: StrStyle::Cooked } }
        |
        preceded!(
            punct!("br"),
            raw_string
        ) => { |(s, n): (String, _)| ByteStrLit { value: s.into_bytes(), style: StrStyle::Raw(n) } }
    ));

    named!(pub byte -> u8, do_parse!(
        punct!("b") >>
        tag!("'") >>
        b: cooked_byte >>
        tag!("'") >>
        (b)
    ));

    named!(pub character -> char, do_parse!(
        punct!("'") >>
        ch: cooked_char >>
        tag!("'") >>
        (ch)
    ));

    named!(pub float -> FloatLit, do_parse!(
        value: float_string >>
        suffix: alt!(
            tag!("f32") => { |_| FloatTy::F32 }
            |
            tag!("f64") => { |_| FloatTy::F64 }
            |
            epsilon!() => { |_| FloatTy::Unsuffixed }
        ) >>
        (FloatLit { value: value, suffix: suffix })
    ));

    named!(pub int -> IntLit, do_parse!(
        value: digits >>
        suffix: alt!(
            tag!("isize") => { |_| IntTy::Isize }
            |
            tag!("i8") => { |_| IntTy::I8 }
            |
            tag!("i16") => { |_| IntTy::I16 }
            |
            tag!("i32") => { |_| IntTy::I32 }
            |
            tag!("i64") => { |_| IntTy::I64 }
            |
            tag!("usize") => { |_| IntTy::Usize }
            |
            tag!("u8") => { |_| IntTy::U8 }
            |
            tag!("u16") => { |_| IntTy::U16 }
            |
            tag!("u32") => { |_| IntTy::U32 }
            |
            tag!("u64") => { |_| IntTy::U64 }
            |
            epsilon!() => { |_| IntTy::Unsuffixed }
        ) >>
        (IntLit { value: value, suffix: suffix })
    ));

    named!(pub boolean -> bool, alt!(
        keyword!("true") => { |_| true }
        |
        keyword!("false") => { |_| false }
    ));

    fn float_string(mut input: &str) -> IResult<&str, String> {
        input = skip_whitespace(input);

        let mut chars = input.chars().peekable();
        match chars.next() {
            Some(ch) if ch >= '0' && ch <= '9' => {}
            _ => return IResult::Error,
        }

        let mut len = 1;
        let mut has_dot = false;
        let mut has_exp = false;
        while let Some(&ch) = chars.peek() {
            match ch {
                '0'...'9' | '_' => {
                    chars.next();
                    len += 1;
                }
                '.' => {
                    if has_dot {
                        break;
                    }
                    chars.next();
                    if chars.peek()
                        .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
                        .unwrap_or(false) {
                        return IResult::Error;
                    }
                    len += 1;
                    has_dot = true;
                }
                'e' | 'E' => {
                    chars.next();
                    len += 1;
                    has_exp = true;
                    break;
                }
                _ => break,
            }
        }

        let rest = &input[len..];
        if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
            return IResult::Error;
        }

        if has_exp {
            let mut has_exp_value = false;
            while let Some(&ch) = chars.peek() {
                match ch {
                    '+' | '-' => {
                        if has_exp_value {
                            break;
                        }
                        chars.next();
                        len += 1;
                    }
                    '0'...'9' => {
                        chars.next();
                        len += 1;
                        has_exp_value = true;
                    }
                    '_' => {
                        chars.next();
                        len += 1;
                    }
                    _ => break,
                }
            }
            if !has_exp_value {
                return IResult::Error;
            }
        }

        IResult::Done(&input[len..], input[..len].replace("_", ""))
    }

    pub fn digits(mut input: &str) -> IResult<&str, u64> {
        input = skip_whitespace(input);

        let base = if input.starts_with("0x") {
            input = &input[2..];
            16
        } else if input.starts_with("0o") {
            input = &input[2..];
            8
        } else if input.starts_with("0b") {
            input = &input[2..];
            2
        } else {
            10
        };

        let mut value = 0u64;
        let mut len = 0;
        let mut empty = true;
        for b in input.bytes() {
            let digit = match b {
                b'0'...b'9' => (b - b'0') as u64,
                b'a'...b'f' => 10 + (b - b'a') as u64,
                b'A'...b'F' => 10 + (b - b'A') as u64,
                b'_' => {
                    if empty && base == 10 {
                        return IResult::Error;
                    }
                    len += 1;
                    continue;
                }
                _ => break,
            };
            if digit >= base {
                return IResult::Error;
            }
            value = match value.checked_mul(base) {
                Some(value) => value,
                None => return IResult::Error,
            };
            value = match value.checked_add(digit) {
                Some(value) => value,
                None => return IResult::Error,
            };
            len += 1;
            empty = false;
        }
        if empty {
            IResult::Error
        } else {
            IResult::Done(&input[len..], value)
        }
    }
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use quote::{Tokens, ToTokens};
    use std::{ascii, iter};
    use std::fmt::{self, Display};
    use std::str;

    impl ToTokens for Lit {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                Lit::Str(ref s, StrStyle::Cooked) => s.to_tokens(tokens),
                Lit::Str(ref s, StrStyle::Raw(n)) => {
                    tokens.append(&format!("r{delim}\"{string}\"{delim}",
                        delim = iter::repeat("#").take(n).collect::<String>(),
                        string = s));
                }
                Lit::ByteStr(ref v, StrStyle::Cooked) => {
                    let mut escaped = "b\"".to_string();
                    for &ch in v.iter() {
                        match ch {
                            0 => escaped.push_str(r"\0"),
                            b'\'' => escaped.push('\''),
                            _ => escaped.extend(ascii::escape_default(ch).map(|c| c as char)),
                        }
                    }
                    escaped.push('"');
                    tokens.append(&escaped);
                }
                Lit::ByteStr(ref vec, StrStyle::Raw(n)) => {
                    tokens.append(&format!("br{delim}\"{string}\"{delim}",
                        delim = iter::repeat("#").take(n).collect::<String>(),
                        string = str::from_utf8(vec).unwrap()));
                }
                Lit::Byte(b) => {
                    match b {
                        0 => tokens.append(r"b'\0'"),
                        b'\"' => tokens.append("b'\"'"),
                        _ => {
                            let mut escaped = "b'".to_string();
                            escaped.extend(ascii::escape_default(b).map(|c| c as char));
                            escaped.push('\'');
                            tokens.append(&escaped);
                        }
                    }
                }
                Lit::Char(ch) => ch.to_tokens(tokens),
                Lit::Int(value, ty) => tokens.append(&format!("{}{}", value, ty)),
                Lit::Float(ref value, ty) => tokens.append(&format!("{}{}", value, ty)),
                Lit::Bool(true) => tokens.append("true"),
                Lit::Bool(false) => tokens.append("false"),
            }
        }
    }

    impl Display for IntTy {
        fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
            match *self {
                IntTy::Isize => formatter.write_str("isize"),
                IntTy::I8 => formatter.write_str("i8"),
                IntTy::I16 => formatter.write_str("i16"),
                IntTy::I32 => formatter.write_str("i32"),
                IntTy::I64 => formatter.write_str("i64"),
                IntTy::Usize => formatter.write_str("usize"),
                IntTy::U8 => formatter.write_str("u8"),
                IntTy::U16 => formatter.write_str("u16"),
                IntTy::U32 => formatter.write_str("u32"),
                IntTy::U64 => formatter.write_str("u64"),
                IntTy::Unsuffixed => Ok(()),
            }
        }
    }

    impl Display for FloatTy {
        fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
            match *self {
                FloatTy::F32 => formatter.write_str("f32"),
                FloatTy::F64 => formatter.write_str("f64"),
                FloatTy::Unsuffixed => Ok(()),
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::io::net::tcp::{TcpListener, TcpAcceptor, TcpStream};
use std::io::{ChanReader, ChanWriter, util, stdio};
use std::io::{Listener, Acceptor, File, BufferedReader, BufferedStream};
use std::os;
use std::str;
use std::task;

use curl::http;

// A "bomb" so when the test task exists we know when to shut down
// the server and fail if the subtask failed.
pub struct Bomb {
    accept: TcpAcceptor,
    rx: Receiver<()>,
    iorx: ChanReader,
}

impl Drop for Bomb {
    fn drop(&mut self) {
        self.accept.close_accept().unwrap();
        let res = self.rx.recv_opt();
        let stderr = self.iorx.read_to_string().unwrap();
        match res {
            Err(..) if !task::failing() => {
                fail!("server subtask failed: {}", stderr)
            }
            _ => {
                if stderr.len() > 0 {
                    println!("server subtask failed: {}", stderr)
                }
            }
        }
    }
}

pub fn proxy() -> (String, Bomb) {
    let me = task::name().unwrap();
    let record = os::getenv("RECORD").is_some();

    let mut l = TcpListener::bind("127.0.0.1", 0).unwrap();
    let ret = format!("http://{}", l.socket_name().unwrap());
    let mut a = l.listen().unwrap();
    let (tx, rx) = channel();

    let data = Path::new(file!()).dir_path().join("http-data")
                                 .join(me.as_slice().replace("::", "_"));
    let file = if record {File::create(&data)} else {File::open(&data)};
    let a2 = a.clone();

    let (iotx, iorx) = channel();
    let (iotx, iorx) = (ChanWriter::new(iotx), ChanReader::new(iorx));

    spawn(proc() {
        stdio::set_stderr(box iotx.clone());
        stdio::set_stdout(box iotx);
        let mut file = Some(file);
        let mut data = None;
        for socket in a.incoming() {
            let socket = match socket { Ok(s) => s, Err(..) => break };

            if data.is_none() {
                data = Some(BufferedStream::new(file.take().unwrap().unwrap()));
            }

            if record {
                record_http(socket, data.as_mut().unwrap());
            } else {
                replay_http(socket, data.as_mut().unwrap());
            }
        }
        match data {
            Some(ref mut f) => assert!(f.read_line().is_err()),
            None => {}
        }
        tx.send(());
    });

    (ret, Bomb { accept: a2, rx: rx, iorx: iorx })
}

fn record_http(mut socket: TcpStream, data: &mut BufferedStream<File>) {
    let (tx, rx) = channel();
    let (tx, mut rx) = (ChanWriter::new(tx), ChanReader::new(rx));
    let http_response = send(util::TeeReader::new(&mut socket as &mut Reader, tx));
    let request = rx.read_to_end().unwrap();

    let (tx, rx) = channel();
    let (tx, mut rx) = (ChanWriter::new(tx), ChanReader::new(rx));
    let socket = box socket as Box<Writer + 'static>;
    let tx = box tx as Box<Writer + 'static>;
    respond(http_response, util::MultiWriter::new(vec![socket, tx]));
    let response = rx.read_to_end().unwrap();

    (write!(data, "===REQUEST {}\n{}\n===RESPONSE {}\n{}\n",
            request.len(),
            str::from_utf8(request.as_slice()).unwrap(),
            response.len(),
            str::from_utf8(response.as_slice()).unwrap())).unwrap();

    fn send<R: Reader>(rdr: R) -> http::Response {
        let mut socket = BufferedReader::new(rdr);
        let method;
        let url;
        let mut headers = HashMap::new();
        {
            let mut lines = socket.lines();
            let line = lines.next().unwrap().unwrap();
            let mut parts = line.as_slice().split(' ');
            method = parts.next().unwrap().to_string();
            url = parts.next().unwrap().replace("http://", "https://");

            for line in lines {
                let line = line.unwrap();
                if line.len() < 3 { break }
                let mut parts = line.as_slice().splitn(1, ':');
                headers.insert(parts.next().unwrap().to_string(),
                               parts.next().unwrap().slice_from(1).to_string());
            }
        }

        let mut handle = http::handle();
        let mut req = match method.as_slice() {
            "PUT" => handle.put(url, &mut socket),
            "POST" => handle.post(url, &mut socket),
            "DELETE" => handle.delete(url),
            "GET" => handle.get(url),
            _ => fail!("unknown method: {}", method),
        };
        for (k, v) in headers.iter() {
            let v = v.as_slice().trim();
            match k.as_slice() {
                "Content-Length" => req = req.content_length(from_str(v).unwrap()),
                "Content-Type" => req = req.content_type(v),
                "Transfer-Encoding" => {}
                k => req = req.header(k, v),
            }
        }
        req.exec().unwrap()
    }

    fn respond<W: Writer>(response: http::Response, mut socket: W) {
        socket.write_str(format!("HTTP/1.1 {}\r\n",
                                 response.get_code()).as_slice())
              .unwrap();
        for (k, v) in response.get_headers().iter() {
            if k.as_slice() == "transfer-encoding" { continue }
            for v in v.iter() {
                socket.write(k.as_bytes()).unwrap();
                socket.write(b": ").unwrap();
                socket.write(v.as_bytes()).unwrap();
                socket.write(b"\r\n").unwrap();
            }
        }
        socket.write(b"\r\n").unwrap();
        socket.write(response.get_body()).unwrap();
    }
}

fn replay_http(socket: TcpStream, data: &mut BufferedStream<File>) {
    let mut writer = socket.clone();
    let mut socket = BufferedReader::new(socket);

    let request = data.read_line().unwrap();
    let mut request = request.as_slice().split(' ');
    assert_eq!(request.next().unwrap().as_slice(), "===REQUEST");
    let request_size: uint = from_str(request.next().unwrap().trim()).unwrap();

    let expected = data.read_exact(request_size).unwrap();
    let mut expected_lines = expected.as_slice().split(|b| *b == b'\n')
                                     .map(|s| str::from_utf8(s).unwrap())
                                     .map(|s| format!("{}\n", s));
    let mut actual_lines = socket.lines().map(|s| s.unwrap());

    // validate the headers
    let mut expected: HashSet<String> = expected_lines.by_ref()
                                                      .take_while(|l| l.len() > 2)
                                                      .collect();
    let mut found = HashSet::new();
    println!("expecting: {}", expected);
    for line in actual_lines.by_ref().take_while(|l| l.len() > 2) {
        println!("received: {}", line.as_slice().trim());
        if !found.insert(line.clone()) { continue }
        if expected.remove(&line) { continue }
        if line.as_slice().starts_with("Date:") { continue }
        if line.as_slice().starts_with("Authorization:") { continue }
        fail!("unexpected header: {}", line);
    }
    for line in expected.iter() {
        if line.as_slice().starts_with("Date:") { continue }
        if line.as_slice().starts_with("Authorization:") { continue }
        fail!("didn't receive header: {}", line);
    }

    // TODO: validate the body

    data.read_line().unwrap();
    let response = data.read_line().unwrap();
    let mut response = response.as_slice().split(' ');
    assert_eq!(response.next().unwrap().as_slice(), "===RESPONSE");
    let response_size: uint = from_str(response.next().unwrap().trim()).unwrap();
    let response = data.read_exact(response_size).unwrap();
    let mut lines = response.as_slice().split(|b| *b == b'\n')
                            .map(|s| str::from_utf8(s).unwrap());
    for line in lines {
        if line.starts_with("Date:") { continue }
        writer.write_str(line).unwrap();
        writer.write(b"\r\n").unwrap();
    }
    data.read_line().unwrap();
}
<commit_msg>Only record missing tests<commit_after>use std::collections::{HashMap, HashSet};
use std::io::net::tcp::{TcpListener, TcpAcceptor, TcpStream};
use std::io::{ChanReader, ChanWriter, util, stdio};
use std::io::{Listener, Acceptor, File, BufferedReader, BufferedStream};
use std::os;
use std::str;
use std::task;

use curl::http;

// A "bomb" so when the test task exists we know when to shut down
// the server and fail if the subtask failed.
pub struct Bomb {
    accept: TcpAcceptor,
    rx: Receiver<()>,
    iorx: ChanReader,
}

impl Drop for Bomb {
    fn drop(&mut self) {
        self.accept.close_accept().unwrap();
        let res = self.rx.recv_opt();
        let stderr = self.iorx.read_to_string().unwrap();
        match res {
            Err(..) if !task::failing() => {
                fail!("server subtask failed: {}", stderr)
            }
            _ => {
                if stderr.len() > 0 {
                    println!("server subtask failed: {}", stderr)
                }
            }
        }
    }
}

pub fn proxy() -> (String, Bomb) {
    let me = task::name().unwrap();
    let record = os::getenv("RECORD").is_some();

    let mut l = TcpListener::bind("127.0.0.1", 0).unwrap();
    let ret = format!("http://{}", l.socket_name().unwrap());
    let mut a = l.listen().unwrap();
    let (tx, rx) = channel();

    let data = Path::new(file!()).dir_path().join("http-data")
                                 .join(me.as_slice().replace("::", "_"));
    let record = record && !data.exists();
    let file = if record {File::create(&data)} else {File::open(&data)};
    let a2 = a.clone();

    let (iotx, iorx) = channel();
    let (iotx, iorx) = (ChanWriter::new(iotx), ChanReader::new(iorx));

    spawn(proc() {
        stdio::set_stderr(box iotx.clone());
        stdio::set_stdout(box iotx);
        let mut file = Some(file);
        let mut data = None;
        for socket in a.incoming() {
            let socket = match socket { Ok(s) => s, Err(..) => break };

            if data.is_none() {
                data = Some(BufferedStream::new(file.take().unwrap().unwrap()));
            }

            if record {
                record_http(socket, data.as_mut().unwrap());
            } else {
                replay_http(socket, data.as_mut().unwrap());
            }
        }
        match data {
            Some(ref mut f) => assert!(f.read_line().is_err()),
            None => {}
        }
        tx.send(());
    });

    (ret, Bomb { accept: a2, rx: rx, iorx: iorx })
}

fn record_http(mut socket: TcpStream, data: &mut BufferedStream<File>) {
    let (tx, rx) = channel();
    let (tx, mut rx) = (ChanWriter::new(tx), ChanReader::new(rx));
    let http_response = send(util::TeeReader::new(&mut socket as &mut Reader, tx));
    let request = rx.read_to_end().unwrap();

    let (tx, rx) = channel();
    let (tx, mut rx) = (ChanWriter::new(tx), ChanReader::new(rx));
    let socket = box socket as Box<Writer + 'static>;
    let tx = box tx as Box<Writer + 'static>;
    respond(http_response, util::MultiWriter::new(vec![socket, tx]));
    let response = rx.read_to_end().unwrap();

    (write!(data, "===REQUEST {}\n{}\n===RESPONSE {}\n{}\n",
            request.len(),
            str::from_utf8(request.as_slice()).unwrap(),
            response.len(),
            str::from_utf8(response.as_slice()).unwrap())).unwrap();

    fn send<R: Reader>(rdr: R) -> http::Response {
        let mut socket = BufferedReader::new(rdr);
        let method;
        let url;
        let mut headers = HashMap::new();
        {
            let mut lines = socket.lines();
            let line = lines.next().unwrap().unwrap();
            let mut parts = line.as_slice().split(' ');
            method = parts.next().unwrap().to_string();
            url = parts.next().unwrap().replace("http://", "https://");

            for line in lines {
                let line = line.unwrap();
                if line.len() < 3 { break }
                let mut parts = line.as_slice().splitn(1, ':');
                headers.insert(parts.next().unwrap().to_string(),
                               parts.next().unwrap().slice_from(1).to_string());
            }
        }

        let mut handle = http::handle();
        let mut req = match method.as_slice() {
            "PUT" => handle.put(url, &mut socket),
            "POST" => handle.post(url, &mut socket),
            "DELETE" => handle.delete(url),
            "GET" => handle.get(url),
            _ => fail!("unknown method: {}", method),
        };
        for (k, v) in headers.iter() {
            let v = v.as_slice().trim();
            match k.as_slice() {
                "Content-Length" => req = req.content_length(from_str(v).unwrap()),
                "Content-Type" => req = req.content_type(v),
                "Transfer-Encoding" => {}
                k => req = req.header(k, v),
            }
        }
        req.exec().unwrap()
    }

    fn respond<W: Writer>(response: http::Response, mut socket: W) {
        socket.write_str(format!("HTTP/1.1 {}\r\n",
                                 response.get_code()).as_slice())
              .unwrap();
        for (k, v) in response.get_headers().iter() {
            if k.as_slice() == "transfer-encoding" { continue }
            for v in v.iter() {
                socket.write(k.as_bytes()).unwrap();
                socket.write(b": ").unwrap();
                socket.write(v.as_bytes()).unwrap();
                socket.write(b"\r\n").unwrap();
            }
        }
        socket.write(b"\r\n").unwrap();
        socket.write(response.get_body()).unwrap();
    }
}

fn replay_http(socket: TcpStream, data: &mut BufferedStream<File>) {
    let mut writer = socket.clone();
    let mut socket = BufferedReader::new(socket);

    let request = data.read_line().unwrap();
    let mut request = request.as_slice().split(' ');
    assert_eq!(request.next().unwrap().as_slice(), "===REQUEST");
    let request_size: uint = from_str(request.next().unwrap().trim()).unwrap();

    let expected = data.read_exact(request_size).unwrap();
    let mut expected_lines = expected.as_slice().split(|b| *b == b'\n')
                                     .map(|s| str::from_utf8(s).unwrap())
                                     .map(|s| format!("{}\n", s));
    let mut actual_lines = socket.lines().map(|s| s.unwrap());

    // validate the headers
    let mut expected: HashSet<String> = expected_lines.by_ref()
                                                      .take_while(|l| l.len() > 2)
                                                      .collect();
    let mut found = HashSet::new();
    println!("expecting: {}", expected);
    for line in actual_lines.by_ref().take_while(|l| l.len() > 2) {
        println!("received: {}", line.as_slice().trim());
        if !found.insert(line.clone()) { continue }
        if expected.remove(&line) { continue }
        if line.as_slice().starts_with("Date:") { continue }
        if line.as_slice().starts_with("Authorization:") { continue }
        fail!("unexpected header: {}", line);
    }
    for line in expected.iter() {
        if line.as_slice().starts_with("Date:") { continue }
        if line.as_slice().starts_with("Authorization:") { continue }
        fail!("didn't receive header: {}", line);
    }

    // TODO: validate the body

    data.read_line().unwrap();
    let response = data.read_line().unwrap();
    let mut response = response.as_slice().split(' ');
    assert_eq!(response.next().unwrap().as_slice(), "===RESPONSE");
    let response_size: uint = from_str(response.next().unwrap().trim()).unwrap();
    let response = data.read_exact(response_size).unwrap();
    let mut lines = response.as_slice().split(|b| *b == b'\n')
                            .map(|s| str::from_utf8(s).unwrap());
    for line in lines {
        if line.starts_with("Date:") { continue }
        writer.write_str(line).unwrap();
        writer.write(b"\r\n").unwrap();
    }
    data.read_line().unwrap();
}
<|endoftext|>


<commit_before>///
/// Represents the address of a node relative to another node
///
pub enum TreeAddress {
    /// Selects this node
    Here,

    /// Selects a child of this node by index, then selects a new address from there
    ChildAtIndex(usize, Box<TreeAddress>),

    /// Selects a child of this node by tag name, then selects a new address from there
    ChildWithTag(String, Box<TreeAddress>),

    /// Selects a child of this node by looking up the 'nth' child with the specified tag, then selects a new address from there
    ChildWithIndexedTag(String, usize, Box<TreeAddress>)
}
<commit_msg>Implement TreeNodeIndex for TreeAddress<commit_after>use std::rc::*;

use super::treenode::*;

///
/// Represents the address of a node relative to another node
///
pub enum TreeAddress {
    /// Selects this node
    Here,

    /// Selects a child of this node by index, then selects a new address from there
    ChildAtIndex(usize, Box<TreeAddress>),

    /// Selects a child of this node by tag name, then selects a new address from there
    ChildWithTag(String, Box<TreeAddress>),

    /// Selects a child of this node by looking up the 'nth' child with the specified tag, then selects a new address from there
    ChildWithIndexedTag(String, usize, Box<TreeAddress>)
}

impl TreeNodeIndex for TreeAddress {
    fn lookup_index(&self, parent_node: &Rc<TreeNode>) -> Option<Rc<TreeNode>> {
        match *self {
            TreeAddress::Here => Some(parent_node.to_owned()),

            TreeAddress::ChildAtIndex(ref pos, ref next) => {
                (*pos).lookup_index(parent_node).and_then(|new_parent| {
                    (*next).lookup_index(&new_parent)
                })
            },

            TreeAddress::ChildWithTag(ref name, ref next) => {
                (&**name).lookup_index(parent_node).and_then(|new_parent| {
                    (*next).lookup_index(&new_parent)
                })
            },

            TreeAddress::ChildWithIndexedTag(ref name, ref pos, ref next) => {
                let mut current = parent_node.get_child_ref();
                let mut remaining = *pos;

                loop {
                    match current.to_owned() {
                        Some(ref current_ref) => {
                            if current_ref.get_tag() == name {
                                if remaining == 0 {
                                    return (*next).lookup_index(current_ref);
                                }

                                remaining = remaining-1;
                            }

                            current = current_ref.get_sibling_ref();
                        },

                        None => {
                            return None;
                        }
                    }
                }
            }
        }
    }
}

#[cfg(test)]
mod treeaddress_test {
    #[macro_use]
    use super::super::super::tree::*;

    #[test]
    fn lookup_here() {
        let someTree = tree!("Here", "There", "Everywhere");

        assert!(someTree.get_child_ref_at(TreeAddress::Here).unwrap().get_tag() == "Here");
    }

    #[test]
    fn lookup_child() {
        let someTree = tree!("Here", "There", "Everywhere");

        assert!(someTree.get_child_ref_at(TreeAddress::ChildAtIndex(0, Box::new(TreeAddress::Here))).unwrap().get_tag() == "There");
        assert!(someTree.get_child_ref_at(TreeAddress::ChildAtIndex(1, Box::new(TreeAddress::Here))).unwrap().get_tag() == "Everywhere");
    }

    #[test]
    fn lookup_tag() {
        let someTree = tree!("Here", "There", "Everywhere");

        assert!(someTree.get_child_ref_at(TreeAddress::ChildWithTag("There".to_string(), Box::new(TreeAddress::Here))).unwrap().get_tag() == "There");
        assert!(someTree.get_child_ref_at(TreeAddress::ChildWithTag("Everywhere".to_string(), Box::new(TreeAddress::Here))).unwrap().get_tag() == "Everywhere");
    }

    #[test]
    fn lookup_indexed_tag() {
        let someTree = tree!("Here", ("Tag", "First"), ("Tag", "Second"));

        assert!(someTree.get_child_ref_at(TreeAddress::ChildWithIndexedTag("Tag".to_string(), 0, Box::new(TreeAddress::Here))).unwrap().get_value().to_str("") == "First");
        assert!(someTree.get_child_ref_at(TreeAddress::ChildWithIndexedTag("Tag".to_string(), 1, Box::new(TreeAddress::Here))).unwrap().get_value().to_str("") == "Second");
    }

    #[test]
    fn lookup_grandchild() {
        let someTree = tree!("Here", tree!("There", "Everywhere"));

        assert!(someTree.get_child_ref_at(TreeAddress::ChildWithTag("There".to_string(), Box::new(TreeAddress::ChildAtIndex(0, Box::new(TreeAddress::Here))))).unwrap().get_tag() == "Everywhere");
    }
}
<|endoftext|>


<commit_before>//! Define matrix traits for performing linear algebra operations.

use eigenvalues::{self, Eigen, SymEigen};
use solve_linear::{SolveLinear, SymmetricSolveLinear};
use least_squares::{LeastSquares, LeastSquaresSolution};
use super::error::*;
use super::scalar::LinxalScalar;
use impl_prelude::*;
use factorization::{QR, QRFactors, LU, LUFactors, Cholesky};
use svd::{SVD, SVDSolution};
use properties::{self, default_tol};

/// Enum for specifying the rank of the input matrix for least-squares problems.
pub enum LeastSquaresType {
    /// data matrix is degenerate (less than full rank)
    Degenerate,

    /// / data matrix is overdetermined (of full rank)
    Full,
}

/// All-encompassing matrix trait, supporting all of the linear
/// algebra operations defined for any `LinxalScalar`.
pub trait LinxalMatrix<F: LinxalScalar> {
    /// Compute the eigenvalues of a matrix.
    fn eigenvalues(&self,
                   compute_left: bool,
                   compute_right: bool)
                   -> Result<<F as Eigen>::Solution, EigenError>;

    /// Compute the eigenvalues of a symmetric matrix
    fn symmetric_eigenvalues(&self,
                             uplo: Symmetric,
                             with_vectors: bool)
                             -> Result<eigenvalues::Solution<F, F::RealPart>, EigenError>;

    /// Solve a single system of linear equations.
    fn solve_linear<D1: Data<Elem = F>>(&self,
                                        b: &ArrayBase<D1, Ix1>)
                                        -> Result<Array<F, Ix1>, SolveError>;

    /// Solve a single system of linear equations with a symmetrix coefficient matrix.
    fn solve_symmetric_linear<D1: Data<Elem = F>>(&self,
                                                  b: &ArrayBase<D1, Ix1>,
                                                  uplo: Symmetric)
                                                  -> Result<Array<F, Ix1>, SolveError>;

    /// Solve a system of linear equations with multiple RHS vectors.
    fn solve_multi_linear<D1: Data<Elem = F>>(&self,
                                              b: &ArrayBase<D1, Ix2>)
                                              -> Result<Array<F, Ix2>, SolveError>;

    /// Solve a system of linear equations with a symmetrix
    /// coefficient matrix for multiple RHS vectors.
    ///
    /// Each column of `b` is a RHS vector to be solved for.
    fn solve_symmetric_multi_linear<D1: Data<Elem = F>>(&self,
                                                        b: &ArrayBase<D1, Ix2>,
                                                        uplo: Symmetric)
                                                        -> Result<Array<F, Ix2>, SolveError>;

    /// Compute the least squares solution for a single RHS.
    fn least_squares<D1, PT>(&self,
                             b: &ArrayBase<D1, Ix1>,
                             problem_type: PT)
                             -> Result<LeastSquaresSolution<F, Ix1>, LeastSquaresError>
        where D1: Data<Elem = F>,
              PT: Into<Option<LeastSquaresType>>;

    /// Compute the least squares solution for a multiple RHS.
    fn multi_least_squares<D1, PT>(&self,
                                   b: &ArrayBase<D1, Ix2>,
                                   problem_type: PT)
                                   -> Result<LeastSquaresSolution<F, Ix2>, LeastSquaresError>
        where D1: Data<Elem = F>,
              PT: Into<Option<LeastSquaresType>>;

    /// Return the QR factorization of the matrix.
    ///
    /// See [QR::compute]().
    fn qr(&self) -> Result<QRFactors<F>, QRError>;

    /// Return the LU factorization of the matrix.
    ///
    /// See [LU::compute]()
    fn lu(&self) -> Result<LUFactors<F>, LUError>;

    /// Return the cholesky factorization of the matrix, via the
    /// upper- or lower-triangular matrix defining it.
    fn cholesky(&self, uplo: Symmetric) -> Result<Array<F, Ix2>, CholeskyError>;

    /// Return the singular value decomposition of the matrix.
    fn svd(&self, compute_u: bool, compute_vt: bool) -> Result<SVDSolution<F>, SVDError>;

    //*** property methods ***//
    /// Returns true iff the matrix is square.
    fn is_square(&self) -> bool;

    /// Returns true iff the matrix is the identity matrix, within an
    /// optional tolerance.
    fn is_identity<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool;

    /// Returns true iff the matrix is diagnoal, within a certain
    /// tolerance.
    fn is_diagonal<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool;

    /// Returns true iff the matrix is symmetric (or Hermitian, in the
    /// complex case), within an optional tolerance.
    fn is_symmetric<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool;

    /// Returns true iff the matrix is unitary, within an optional
    /// tolerance.
    fn is_unitary<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool;

    /// Returns true iff the matrix is triangular or trapezoidal, with
    /// size specified by `uplo`.
    fn is_triangular<T: Into<Option<F::RealPart>>>(&self, uplo: Symmetric, tolerance: T) -> bool;

}

impl<F: LinxalScalar, D: Data<Elem = F>> LinxalMatrix<F> for ArrayBase<D, Ix2> {
    fn eigenvalues(&self,
                   compute_left: bool,
                   compute_right: bool)
                   -> Result<<F as Eigen>::Solution, EigenError> {
        Eigen::compute(self, compute_left, compute_right)
    }

    fn symmetric_eigenvalues(&self,
                             uplo: Symmetric,
                             with_vectors: bool)
                             -> Result<eigenvalues::Solution<F, F::RealPart>, EigenError> {
        SymEigen::compute(self, uplo, with_vectors)
    }

    fn solve_linear<D1: Data<Elem = F>>(&self,
                                        b: &ArrayBase<D1, Ix1>)
                                        -> Result<Array<F, Ix1>, SolveError> {
        SolveLinear::compute(self, b)
    }

    fn solve_symmetric_linear<D1: Data<Elem = F>>(&self,
                                                  b: &ArrayBase<D1, Ix1>,
                                                  uplo: Symmetric)
                                                  -> Result<Array<F, Ix1>, SolveError> {
        SymmetricSolveLinear::compute(self, uplo, b)
    }

    fn solve_multi_linear<D1: Data<Elem = F>>(&self,
                                              b: &ArrayBase<D1, Ix2>)
                                              -> Result<Array<F, Ix2>, SolveError> {
        SolveLinear::compute_multi(self, b)
    }

    fn solve_symmetric_multi_linear<D1: Data<Elem = F>>(&self,
                                                        b: &ArrayBase<D1, Ix2>,
                                                        uplo: Symmetric)
                                                        -> Result<Array<F, Ix2>, SolveError> {
        SymmetricSolveLinear::compute_multi(self, uplo, b)
    }

    fn least_squares<D1, PT>(&self,
                             b: &ArrayBase<D1, Ix1>,
                             _problem_type: PT)
                             -> Result<LeastSquaresSolution<F, Ix1>, LeastSquaresError>
        where D1: Data<Elem = F>,
              PT: Into<Option<LeastSquaresType>>
    {
        LeastSquares::compute(self, b)
    }

    fn multi_least_squares<D1, PT>(&self,
                                   b: &ArrayBase<D1, Ix2>,
                                   problem_type: PT)
                                   -> Result<LeastSquaresSolution<F, Ix2>, LeastSquaresError>
        where D1: Data<Elem = F>,
              PT: Into<Option<LeastSquaresType>>
    {

        match problem_type.into() {
            Some(LeastSquaresType::Degenerate) => LeastSquares::compute_multi_degenerate(self, b),
            Some(LeastSquaresType::Full) => LeastSquares::compute_multi_full(self, b),
            None => LeastSquares::compute_multi(self, b),
        }
    }

    fn qr(&self) -> Result<QRFactors<F>, QRError> {
        QR::compute(self)
    }

    fn lu(&self) -> Result<LUFactors<F>, LUError> {
        LU::compute(self)
    }

    fn cholesky(&self, uplo: Symmetric) -> Result<Array<F, Ix2>, CholeskyError> {
        Cholesky::compute(self, uplo)
    }

    fn svd(&self, compute_u: bool, compute_vt: bool) -> Result<SVDSolution<F>, SVDError> {
        SVD::compute(self, compute_u, compute_vt)
    }

    fn is_square(&self) -> bool {
        match self.dim() {
            (a, b) => a == b
        }
    }

    fn is_diagonal<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool {
        let tol: F::RealPart = tolerance.into().unwrap_or(default_tol(self)).into();
        properties::is_diagonal_tol(self, tol)
    }

    fn is_symmetric<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool {
        let tol: F::RealPart = tolerance.into().unwrap_or(default_tol(self)).into();
        properties::is_symmetric_tol(self, tol)
    }

    fn is_identity<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool {
        let tol: F::RealPart = tolerance.into().unwrap_or(default_tol(self)).into();
        properties::is_identity_tol(self, tol)
    }

    fn is_unitary<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool {
        let tol: F::RealPart = tolerance.into().unwrap_or(default_tol(self)).into();
        properties::is_unitary_tol(self, tol)
    }

    fn is_triangular<T: Into<Option<F::RealPart>>>(&self, uplo: Symmetric, tolerance: T) -> bool {
        let tol: F::RealPart = tolerance.into().unwrap_or(default_tol(self)).into();
        properties::is_triangular_tol(self, uplo, tol)
    }

}
<commit_msg>add inversion routine to LinxalMatrix<commit_after>//! Define matrix traits for performing linear algebra operations.

use eigenvalues::{self, Eigen, SymEigen};
use solve_linear::{SolveLinear, SymmetricSolveLinear};
use least_squares::{LeastSquares, LeastSquaresSolution};
use super::error::*;
use super::scalar::LinxalScalar;
use impl_prelude::*;
use factorization::{QR, QRFactors, LU, LUFactors, Cholesky};
use svd::{SVD, SVDSolution};
use properties::{self, default_tol};

/// Enum for specifying the rank of the input matrix for least-squares problems.
pub enum LeastSquaresType {
    /// data matrix is degenerate (less than full rank)
    Degenerate,

    /// / data matrix is overdetermined (of full rank)
    Full,
}

/// All-encompassing matrix trait, supporting all of the linear
/// algebra operations defined for any `LinxalScalar`.
pub trait LinxalMatrix<F: LinxalScalar> {
    /// Compute the eigenvalues of a matrix.
    fn eigenvalues(&self,
                   compute_left: bool,
                   compute_right: bool)
                   -> Result<<F as Eigen>::Solution, EigenError>;

    /// Compute the eigenvalues of a symmetric matrix
    fn symmetric_eigenvalues(&self,
                             uplo: Symmetric,
                             with_vectors: bool)
                             -> Result<eigenvalues::Solution<F, F::RealPart>, EigenError>;

    /// Solve a single system of linear equations.
    fn solve_linear<D1: Data<Elem = F>>(&self,
                                        b: &ArrayBase<D1, Ix1>)
                                        -> Result<Array<F, Ix1>, SolveError>;

    /// Solve a single system of linear equations with a symmetrix coefficient matrix.
    fn solve_symmetric_linear<D1: Data<Elem = F>>(&self,
                                                  b: &ArrayBase<D1, Ix1>,
                                                  uplo: Symmetric)
                                                  -> Result<Array<F, Ix1>, SolveError>;

    /// Solve a system of linear equations with multiple RHS vectors.
    fn solve_multi_linear<D1: Data<Elem = F>>(&self,
                                              b: &ArrayBase<D1, Ix2>)
                                              -> Result<Array<F, Ix2>, SolveError>;

    /// Solve a system of linear equations with a symmetrix
    /// coefficient matrix for multiple RHS vectors.
    ///
    /// Each column of `b` is a RHS vector to be solved for.
    fn solve_symmetric_multi_linear<D1: Data<Elem = F>>(&self,
                                                        b: &ArrayBase<D1, Ix2>,
                                                        uplo: Symmetric)
                                                        -> Result<Array<F, Ix2>, SolveError>;

    /// Compute the least squares solution for a single RHS.
    fn least_squares<D1, PT>(&self,
                             b: &ArrayBase<D1, Ix1>,
                             problem_type: PT)
                             -> Result<LeastSquaresSolution<F, Ix1>, LeastSquaresError>
        where D1: Data<Elem = F>,
              PT: Into<Option<LeastSquaresType>>;

    /// Compute the least squares solution for a multiple RHS.
    fn multi_least_squares<D1, PT>(&self,
                                   b: &ArrayBase<D1, Ix2>,
                                   problem_type: PT)
                                   -> Result<LeastSquaresSolution<F, Ix2>, LeastSquaresError>
        where D1: Data<Elem = F>,
              PT: Into<Option<LeastSquaresType>>;

    /// Return the QR factorization of the matrix.
    ///
    /// See [QR::compute]().
    fn qr(&self) -> Result<QRFactors<F>, QRError>;

    /// Return the LU factorization of the matrix.
    ///
    /// See [LU::compute]()
    fn lu(&self) -> Result<LUFactors<F>, LUError>;

    /// Return the cholesky factorization of the matrix, via the
    /// upper- or lower-triangular matrix defining it.
    fn cholesky(&self, uplo: Symmetric) -> Result<Array<F, Ix2>, CholeskyError>;

    /// Return the singular value decomposition of the matrix.
    fn svd(&self, compute_u: bool, compute_vt: bool) -> Result<SVDSolution<F>, SVDError>;

    /// Return the inverse of the matrix, if it has one.
    fn inverse(&self) -> Result<Array<F, Ix2>, Error>;

    //*** property methods ***//
    /// Returns true iff the matrix is square.
    fn is_square(&self) -> bool;

    /// Returns true iff the matrix is the identity matrix, within an
    /// optional tolerance.
    fn is_identity<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool;

    /// Returns true iff the matrix is diagnoal, within a certain
    /// tolerance.
    fn is_diagonal<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool;

    /// Returns true iff the matrix is symmetric (or Hermitian, in the
    /// complex case), within an optional tolerance.
    fn is_symmetric<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool;

    /// Returns true iff the matrix is unitary, within an optional
    /// tolerance.
    fn is_unitary<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool;

    /// Returns true iff the matrix is triangular or trapezoidal, with
    /// size specified by `uplo`.
    fn is_triangular<T: Into<Option<F::RealPart>>>(&self, uplo: Symmetric, tolerance: T) -> bool;

}

impl<F: LinxalScalar, D: Data<Elem = F>> LinxalMatrix<F> for ArrayBase<D, Ix2> {
    fn eigenvalues(&self,
                   compute_left: bool,
                   compute_right: bool)
                   -> Result<<F as Eigen>::Solution, EigenError> {
        Eigen::compute(self, compute_left, compute_right)
    }

    fn symmetric_eigenvalues(&self,
                             uplo: Symmetric,
                             with_vectors: bool)
                             -> Result<eigenvalues::Solution<F, F::RealPart>, EigenError> {
        SymEigen::compute(self, uplo, with_vectors)
    }

    fn solve_linear<D1: Data<Elem = F>>(&self,
                                        b: &ArrayBase<D1, Ix1>)
                                        -> Result<Array<F, Ix1>, SolveError> {
        SolveLinear::compute(self, b)
    }

    fn solve_symmetric_linear<D1: Data<Elem = F>>(&self,
                                                  b: &ArrayBase<D1, Ix1>,
                                                  uplo: Symmetric)
                                                  -> Result<Array<F, Ix1>, SolveError> {
        SymmetricSolveLinear::compute(self, uplo, b)
    }

    fn solve_multi_linear<D1: Data<Elem = F>>(&self,
                                              b: &ArrayBase<D1, Ix2>)
                                              -> Result<Array<F, Ix2>, SolveError> {
        SolveLinear::compute_multi(self, b)
    }

    fn solve_symmetric_multi_linear<D1: Data<Elem = F>>(&self,
                                                        b: &ArrayBase<D1, Ix2>,
                                                        uplo: Symmetric)
                                                        -> Result<Array<F, Ix2>, SolveError> {
        SymmetricSolveLinear::compute_multi(self, uplo, b)
    }

    fn least_squares<D1, PT>(&self,
                             b: &ArrayBase<D1, Ix1>,
                             _problem_type: PT)
                             -> Result<LeastSquaresSolution<F, Ix1>, LeastSquaresError>
        where D1: Data<Elem = F>,
              PT: Into<Option<LeastSquaresType>>
    {
        LeastSquares::compute(self, b)
    }

    fn multi_least_squares<D1, PT>(&self,
                                   b: &ArrayBase<D1, Ix2>,
                                   problem_type: PT)
                                   -> Result<LeastSquaresSolution<F, Ix2>, LeastSquaresError>
        where D1: Data<Elem = F>,
              PT: Into<Option<LeastSquaresType>>
    {

        match problem_type.into() {
            Some(LeastSquaresType::Degenerate) => LeastSquares::compute_multi_degenerate(self, b),
            Some(LeastSquaresType::Full) => LeastSquares::compute_multi_full(self, b),
            None => LeastSquares::compute_multi(self, b),
        }
    }

    fn qr(&self) -> Result<QRFactors<F>, QRError> {
        QR::compute(self)
    }

    fn lu(&self) -> Result<LUFactors<F>, LUError> {
        LU::compute(self)
    }

    fn cholesky(&self, uplo: Symmetric) -> Result<Array<F, Ix2>, CholeskyError> {
        Cholesky::compute(self, uplo)
    }

    fn svd(&self, compute_u: bool, compute_vt: bool) -> Result<SVDSolution<F>, SVDError> {
        SVD::compute(self, compute_u, compute_vt)
    }

    fn inverse(&self) -> Result<Array<F, Ix2>, Error> {
        match LU::compute(self) {
            Ok(factors) => factors.inverse_into().map_err(|x| x.into()),
            Err(lu_error) => Err(lu_error.into())
        }
    }

    fn is_square(&self) -> bool {
        match self.dim() {
            (a, b) => a == b
        }
    }

    fn is_diagonal<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool {
        let tol: F::RealPart = tolerance.into().unwrap_or(default_tol(self)).into();
        properties::is_diagonal_tol(self, tol)
    }

    fn is_symmetric<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool {
        let tol: F::RealPart = tolerance.into().unwrap_or(default_tol(self)).into();
        properties::is_symmetric_tol(self, tol)
    }

    fn is_identity<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool {
        let tol: F::RealPart = tolerance.into().unwrap_or(default_tol(self)).into();
        properties::is_identity_tol(self, tol)
    }

    fn is_unitary<T: Into<Option<F::RealPart>>>(&self, tolerance: T) -> bool {
        let tol: F::RealPart = tolerance.into().unwrap_or(default_tol(self)).into();
        properties::is_unitary_tol(self, tol)
    }

    fn is_triangular<T: Into<Option<F::RealPart>>>(&self, uplo: Symmetric, tolerance: T) -> bool {
        let tol: F::RealPart = tolerance.into().unwrap_or(default_tol(self)).into();
        properties::is_triangular_tol(self, uplo, tol)
    }

}
<|endoftext|>


<commit_before>/*
 * Built-in method definitions for scheme
 *
 * Done:
 * +, -, *, / (works on lists of numbers)
 * =, >, <, >=, <= (works on list of numbers)
 * not (works on single argument)
 * list (works on any arguments)
 * list?, null?, symbol? (works on single argument)
 * cons, car, cdr, append
 *
 * Coming:
 * equal?, eq?
 *
 *    {'+':op.add, '-':op.sub, '*':op.mul, '/':op.div, 'not':op.not_,
       '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq,
       'equal?':op.eq, 'eq?':op.is_, 'length':len, 'cons':lambda x,y:[x]+y,
       'car':lambda x:x[0],'cdr':lambda x:x[1:], 'append':op.add,
       'list':lambda *x:list(x), 'list?': lambda x:isa(x,list),
       'null?':lambda x:x==[], 'symbol?':lambda x: isa(x, Symbol)})
 *
 */

macro_rules! math_function {
    ($function:ident $identity:expr) => {
        pub fn $function( args:~[Expression], _:@Environment) -> Expression {
            match args.len() {
                0 => $identity,
                1 => vec::foldl($identity, args, |x, y| {x.$function(y)}),
                _ => vec::foldl(args.head(), args.tail(), |x, y| {x.$function(y)})
            }
        }
    }
}

math_function!(add Int(0))
math_function!(sub Int(0))
math_function!(mul Int(1))
math_function!(div Int(1))

pub fn equals( args:~[Expression], _:@Environment) -> Expression {
    for args.tail().each() |&expr| {
        if expr != args.head() {
            return Bool(false);
        }
    }
    return Bool(true);
}

pub fn not( args:~[Expression], _:@Environment) -> Expression {
    if args.len() > 1 {
        fail fmt!("Built-in function 'not' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    return Bool(!args[0].to_bool());
}

pub fn car( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'car' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => list.head(),
        _ => fail fmt!("Built-in function 'car' requires a list argument. It was called with %s", args[0].to_str())
    }
}

pub fn cdr( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'cdr' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => List(list.tail()),
        _ => fail fmt!("Built-in function 'cdr' requires a list argument. It was called with %s", args[0].to_str())
    }
}

pub fn cons( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 2 {
        fail fmt!("Built-in function 'cons' takes two arguments. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[1] {
        List(list) => List( ~[args[0]] + list ),
        x => List( ~[args[0]] + ~[x] )
    }
}

pub fn append( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 2 {
        fail fmt!("Built-in function 'append' takes two arguments. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list1) => {
            match copy args[1] {
                List(list) => List( list1 + list ),
                x => List( list1 + ~[x] )
            }
        }
        _ => fail fmt!("Built-in function 'append' requires a list as the first arguments. It was called with %s", List(args).to_str())
    }
}

pub fn length( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'length' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => Int(list.len() as int),
        _ => fail fmt!("Built-in function 'append' requires a list argument. It was called with %s", List(args).to_str())
    }
}

pub fn equal_( args:~[Expression], _:@Environment ) -> Expression {
    if args.len() != 2 {
        fail fmt!("Built-in function 'equal?' takes two arguments. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    Bool(args[0] == args[1])
}

pub fn symbol_( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'symbol?' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match args[0] {
        Symbol(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn list_( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'list?' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match args[0] {
        List(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn null_( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'null?' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => Bool(list.len() == 0),
        _ => Bool(false)
    }
}

pub fn list( args:~[Expression], _:@Environment) -> Expression {
    List(args)
}

pub fn builtins() -> ~[(~str,~fn(~[Expression], @Environment) -> Expression)] {
    ~[ (~"+", add), (~"-", sub), (~"*", mul), (~"/", div),
       (~"=", equals), (~"not", not),
       (~"car", car), (~"cdr", cdr),
       (~"cons", cons), (~"append", append),
       (~"list", list), (~"length", length),
       (~"equal?", equal_),
       (~"symbol?", symbol_),
       (~"list?", list_),
       (~"null?", null_)
    ]
}
<commit_msg>Mark equal? as done in comment<commit_after>/*
 * Built-in method definitions for scheme
 *
 * Done:
 * +, -, *, / (works on lists of numbers)
 * =, >, <, >=, <= (works on list of numbers)
 * not (works on single argument)
 * list (works on any arguments)
 * list?, null?, symbol? (works on single argument)
 * cons, car, cdr, append
 * equal?
 *
 * Coming:
 * eq?
 *
 *    {'+':op.add, '-':op.sub, '*':op.mul, '/':op.div, 'not':op.not_,
       '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq,
       'equal?':op.eq, 'eq?':op.is_, 'length':len, 'cons':lambda x,y:[x]+y,
       'car':lambda x:x[0],'cdr':lambda x:x[1:], 'append':op.add,
       'list':lambda *x:list(x), 'list?': lambda x:isa(x,list),
       'null?':lambda x:x==[], 'symbol?':lambda x: isa(x, Symbol)})
 *
 */

macro_rules! math_function {
    ($function:ident $identity:expr) => {
        pub fn $function( args:~[Expression], _:@Environment) -> Expression {
            match args.len() {
                0 => $identity,
                1 => vec::foldl($identity, args, |x, y| {x.$function(y)}),
                _ => vec::foldl(args.head(), args.tail(), |x, y| {x.$function(y)})
            }
        }
    }
}

math_function!(add Int(0))
math_function!(sub Int(0))
math_function!(mul Int(1))
math_function!(div Int(1))

pub fn equals( args:~[Expression], _:@Environment) -> Expression {
    for args.tail().each() |&expr| {
        if expr != args.head() {
            return Bool(false);
        }
    }
    return Bool(true);
}

pub fn not( args:~[Expression], _:@Environment) -> Expression {
    if args.len() > 1 {
        fail fmt!("Built-in function 'not' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    return Bool(!args[0].to_bool());
}

pub fn car( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'car' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => list.head(),
        _ => fail fmt!("Built-in function 'car' requires a list argument. It was called with %s", args[0].to_str())
    }
}

pub fn cdr( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'cdr' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => List(list.tail()),
        _ => fail fmt!("Built-in function 'cdr' requires a list argument. It was called with %s", args[0].to_str())
    }
}

pub fn cons( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 2 {
        fail fmt!("Built-in function 'cons' takes two arguments. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[1] {
        List(list) => List( ~[args[0]] + list ),
        x => List( ~[args[0]] + ~[x] )
    }
}

pub fn append( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 2 {
        fail fmt!("Built-in function 'append' takes two arguments. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list1) => {
            match copy args[1] {
                List(list) => List( list1 + list ),
                x => List( list1 + ~[x] )
            }
        }
        _ => fail fmt!("Built-in function 'append' requires a list as the first arguments. It was called with %s", List(args).to_str())
    }
}

pub fn length( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'length' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => Int(list.len() as int),
        _ => fail fmt!("Built-in function 'append' requires a list argument. It was called with %s", List(args).to_str())
    }
}

pub fn equal_( args:~[Expression], _:@Environment ) -> Expression {
    if args.len() != 2 {
        fail fmt!("Built-in function 'equal?' takes two arguments. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    Bool(args[0] == args[1])
}

pub fn symbol_( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'symbol?' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match args[0] {
        Symbol(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn list_( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'list?' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match args[0] {
        List(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn null_( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'null?' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => Bool(list.len() == 0),
        _ => Bool(false)
    }
}

pub fn list( args:~[Expression], _:@Environment) -> Expression {
    List(args)
}

pub fn builtins() -> ~[(~str,~fn(~[Expression], @Environment) -> Expression)] {
    ~[ (~"+", add), (~"-", sub), (~"*", mul), (~"/", div),
       (~"=", equals), (~"not", not),
       (~"car", car), (~"cdr", cdr),
       (~"cons", cons), (~"append", append),
       (~"list", list), (~"length", length),
       (~"equal?", equal_),
       (~"symbol?", symbol_),
       (~"list?", list_),
       (~"null?", null_)
    ]
}
<|endoftext|>


<commit_before>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use prometheus::{Counter, CounterVec, Histogram, HistogramVec};

lazy_static! {
    pub static ref SEND_SNAP_HISTOGRAM: Histogram =
        register_histogram!(
            "tikv_server_send_snapshot_duration_seconds",
            "Bucketed histogram of server send snapshots duration"
        ).unwrap();

    pub static ref SNAP_TASK_COUNTER: CounterVec =
        register_counter_vec!(
            "tikv_server_snapshot_task_total",
            "Total number of snapshot task",
            &["type"]
        ).unwrap();

    pub static ref GRPC_MSG_HISTOGRAM_VEC: HistogramVec =
        register_histogram_vec!(
            "tikv_grpc_msg_duration_seconds",
            "Bucketed histogram of grpc server messages",
            &["type"]
        ).unwrap();

    pub static ref GRPC_MSG_FAIL_COUNTER: CounterVec =
        register_counter_vec!(
            "tikv_grpc_msg_fail_total",
            "Total number of handle grpc message failure",
            &["type"]
        ).unwrap();

    pub static ref RAFT_MESSAGE_RECV_COUNTER: Counter =
        register_counter!(
            "tikv_server_raft_message_recv_total",
            "Total number of raft messages received"
        ).unwrap();

    pub static ref RESOLVE_STORE_COUNTER: CounterVec =
        register_counter_vec!(
            "tikv_server_resolve_store_total",
            "Total number of resolving store",
            &["type"]
        ).unwrap();

    pub static ref REPORT_FAILURE_MSG_COUNTER: CounterVec =
        register_counter_vec!(
            "tikv_server_report_failure_msg_total",
            "Total number of reporting failure messages",
            &["type", "store_id"]
        ).unwrap();
}
<commit_msg>grpc: adjust metrics. (#2488)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use prometheus::*;

lazy_static! {
    pub static ref SEND_SNAP_HISTOGRAM: Histogram =
        register_histogram!(
            "tikv_server_send_snapshot_duration_seconds",
            "Bucketed histogram of server send snapshots duration"
        ).unwrap();

    pub static ref SNAP_TASK_COUNTER: CounterVec =
        register_counter_vec!(
            "tikv_server_snapshot_task_total",
            "Total number of snapshot task",
            &["type"]
        ).unwrap();

    pub static ref GRPC_MSG_HISTOGRAM_VEC: HistogramVec =
        register_histogram_vec!(
            "tikv_grpc_msg_duration_seconds",
            "Bucketed histogram of grpc server messages",
            &["type"],
            exponential_buckets(0.0005, 2.0, 20).unwrap()
        ).unwrap();

    pub static ref GRPC_MSG_FAIL_COUNTER: CounterVec =
        register_counter_vec!(
            "tikv_grpc_msg_fail_total",
            "Total number of handle grpc message failure",
            &["type"]
        ).unwrap();

    pub static ref RAFT_MESSAGE_RECV_COUNTER: Counter =
        register_counter!(
            "tikv_server_raft_message_recv_total",
            "Total number of raft messages received"
        ).unwrap();

    pub static ref RESOLVE_STORE_COUNTER: CounterVec =
        register_counter_vec!(
            "tikv_server_resolve_store_total",
            "Total number of resolving store",
            &["type"]
        ).unwrap();

    pub static ref REPORT_FAILURE_MSG_COUNTER: CounterVec =
        register_counter_vec!(
            "tikv_server_report_failure_msg_total",
            "Total number of reporting failure messages",
            &["type", "store_id"]
        ).unwrap();
}
<|endoftext|>