<commit_before>use std::io::prelude::*;
use std::io;
use std::str::FromStr;

use super::utils::CharReader;

type LexReader<R: Read> = CharReader<io::BufReader<R>>;
type LexResult = Result<LexToken, LexError>;

#[derive(Debug, PartialEq, Clone)]
pub enum LexToken {
    OpenBrace, CloseBrace,
    OpenBracket, CloseBracket,
    Comma, Colon,
    Identifier(String),
    StringLit(String),
    IntegerLit(i64),
    FloatLit(f64),
}

#[derive(Debug)]
pub enum LexError {
    IOError(io::Error),
    FloatParseError(<f64 as FromStr>::Err),
    IntegerParseError(<i64 as FromStr>::Err),
    UnrecognisedCharError(char),
}

pub struct Lexer<R: Read> {
    input: LexReader<R>,
    stored_next: Vec<char>,
}

impl<R: Read> Lexer<R> {
    pub fn lex(reader: R) -> Self {
        Lexer {
            input: CharReader::new(io::BufReader::new(reader)),
            stored_next: Vec::new(),
        }
    }

    pub fn pop_next(&mut self) -> Option<char> {
        if let Some(next) = self.stored_next.pop() {
            Some(next)
        } else {
            self.input.next()
        }
    }

    pub fn ret_next(&mut self, returned: char) {
        self.stored_next.push(returned);
    }

    pub fn parse_ident(&mut self) -> Option<LexResult> {
        if let Some(next_char) = self.pop_next() {
            let mut ident = String::new();
            if next_char.is_alphabetic() {
                ident.push(next_char);
            } else {
                self.ret_next(next_char);
                return None;
            }

            while let Some(next_char) = self.pop_next() {
                if next_char.is_alphanumeric() {
                    ident.push(next_char);
                } else if next_char == '_' {
                    ident.push(next_char);
                } else {
                    self.ret_next(next_char);
                    break;
                }
            }

            Some(Ok(LexToken::Identifier(ident)))
        } else {
            None
        }
    }

    pub fn parse_int(&mut self, base: u32) -> Option<LexResult> {
        let mut buffer = String::new();

        while let Some(next_char) = self.pop_next() {
            if next_char.is_digit(base) {
                buffer.push(next_char);
            } else if next_char == '_' {
                continue; // accepted but ignored
            } else {
                self.ret_next(next_char);
                break;
            }
        }

        Some(Ok(LexToken::IntegerLit(i64::from_str_radix(&buffer, base).unwrap())))
    }

    pub fn parse_exponent(&mut self) -> String {
        let mut exponent = String::from("e");
        if let Some(next_char) = self.pop_next() {
            if next_char == '+' || next_char == '-' {
                exponent.push(next_char);
            } else {
                self.ret_next(next_char);
            }
        }

        while let Some(next_char) = self.pop_next() {
            if next_char.is_digit(10) {
                exponent.push(next_char)
            } else {
                self.ret_next(next_char);
                break;
            }
        }

        exponent
    }

    pub fn parse_float_int(&mut self) -> Option<LexResult> {
        let mut sign = '+';
        let mut is_float = false;
        let mut buffer = String::new();
        let mut exponent = String::new();

        if let Some(next_char) = self.pop_next() {
            if next_char == '+' || next_char == '-' {
                sign = next_char;
            } else {
                self.ret_next(next_char);
            }
        }

        while let Some(next_char) = self.pop_next() {
            if next_char == '.' {
                if is_float {
                    // already a float - can't have two periods!
                    self.ret_next(next_char);
                    break;
                } else {
                    is_float = true;
                    buffer.push(next_char);
                }
            } else if next_char.is_digit(10) {
                buffer.push(next_char);
            } else if next_char == '_' {
                continue;  // accepted, but ignored
            } else if next_char == 'e' || next_char == 'E' {
                exponent = self.parse_exponent();
                is_float = true;
                break;
            } else {
                self.ret_next(next_char);
                break;
            }
        }

        if is_float {
            let str_float = buffer + &exponent;
            Some(str_float.parse::<f64>()
                .map(move |flt| {
                    if sign == '+' {
                        LexToken::FloatLit(flt)
                    } else {
                        LexToken::FloatLit(-flt)
                    }
                })
                .map_err(LexError::FloatParseError))
        } else {
            Some(buffer.parse::<i64>()
                .map(move |intgr| {
                    if sign == '+' {
                        LexToken::IntegerLit(intgr)
                    } else {
                        LexToken::IntegerLit(-intgr)
                    }
                })
                .map_err(LexError::IntegerParseError))
        }
    }

    pub fn parse_numeric(&mut self) -> Option<LexResult> {
        if let Some(next_char) = self.pop_next() {
            if let Some(after) = self.pop_next() {
                if next_char == '0' && ['d', 'D'].contains(&after) {
                    self.parse_int(10)
                } else if next_char == '0' && ['x', 'X'].contains(&after)  {
                    self.parse_int(16)
                } else if next_char == '0' && ['o', 'O'].contains(&after) {
                    self.parse_int(8)
                } else if next_char == '0' && ['b', 'B'].contains(&after) {
                    self.parse_int(2)
                } else {
                    self.ret_next(after);      // put back the two characters we popped
                    self.ret_next(next_char);  // off, but in the right order
                    self.parse_float_int()
                }
            } else {
                Some(Ok(LexToken::IntegerLit(next_char.to_digit(10).unwrap() as i64)))
            }
        } else {
            None
        }
    }
}

impl<R: Read> Iterator for Lexer<R> {
    type Item = Result<LexToken, LexError>;

    fn next(&mut self) -> Option<Self::Item> {
        let mut option_char = self.pop_next();
        while option_char.is_some() && option_char.unwrap().is_whitespace() {
            option_char = self.pop_next();
        }

        if let Some(next_char) = option_char {
            if next_char == '{' {
                Some(Ok(LexToken::OpenBrace))
            } else if next_char == '}' {
                Some(Ok(LexToken::CloseBrace))
            } else if next_char == '[' {
                Some(Ok(LexToken::OpenBracket))
            } else if next_char == ']' {
                Some(Ok(LexToken::CloseBracket))
            } else if next_char == ',' {
                Some(Ok(LexToken::Comma))
            } else if next_char == ':' {
                Some(Ok(LexToken::Colon))
            } else if next_char.is_alphabetic() {
                self.ret_next(next_char);
                self.parse_ident()
            } else if next_char.is_digit(10) || ['+', '-', '.'].contains(&next_char) {
                self.ret_next(next_char);
                self.parse_numeric()
            } else {
                // TODO: Parsing strings
                None
            }
        } else {
            None
        }
    }
}

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

    #[test]
    fn parse_ident() {
        let mut lexer = Lexer::lex(Cursor::new("ThisIsAnIdent".as_bytes()));
        assert_eq!(lexer.parse_ident().unwrap().unwrap(),
            LexToken::Identifier("ThisIsAnIdent".to_string()));

        let mut lexer = Lexer::lex(Cursor::new("this_is_an_ident".as_bytes()));
        assert_eq!(lexer.parse_ident().unwrap().unwrap(),
            LexToken::Identifier("this_is_an_ident".to_string()));

        let mut lexer = Lexer::lex(Cursor::new("th15_1s_an_1d3n7".as_bytes()));
        assert_eq!(lexer.parse_ident().unwrap().unwrap(),
            LexToken::Identifier("th15_1s_an_1d3n7".to_string()));

        let mut lexer = Lexer::lex(Cursor::new("7h15_1s_an_1d3n7".as_bytes()));
        assert!(lexer.parse_ident().is_none());

        let mut lexer = Lexer::lex(Cursor::new("th15_1s_an_1d3n7".as_bytes()));
        assert_eq!(lexer.parse_ident().unwrap().unwrap(),
            LexToken::Identifier("th15_1s_an_1d3n7".to_string()));
    }

    #[test]
    fn parse_numeric() {
        let mut lexer = Lexer::lex(Cursor::new("12345".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(12345));

        let mut lexer = Lexer::lex(Cursor::new("0".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(0));

        let mut lexer = Lexer::lex(Cursor::new("0d10".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(10));

        let mut lexer = Lexer::lex(Cursor::new("0D10".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(10));

        let mut lexer = Lexer::lex(Cursor::new("0b10".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(2));

        let mut lexer = Lexer::lex(Cursor::new("0B10".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(2));

        let mut lexer = Lexer::lex(Cursor::new("0x10".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(16));

        let mut lexer = Lexer::lex(Cursor::new("0X10".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(16));

        let mut lexer = Lexer::lex(Cursor::new("0o10".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(8));

        let mut lexer = Lexer::lex(Cursor::new("0O10".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(8));

        let mut lexer = Lexer::lex(Cursor::new("0d10e5".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(10));

        let mut lexer = Lexer::lex(Cursor::new("10e5".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::FloatLit(10e5));

        let mut lexer = Lexer::lex(Cursor::new("10.5".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::FloatLit(10.5));

        let mut lexer = Lexer::lex(Cursor::new("105".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(105));

        let mut lexer = Lexer::lex(Cursor::new("1_0__5___".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(105));
    }
}
<commit_msg>Add string lexer<commit_after>use std::io::prelude::*;
use std::io;
use std::char::from_u32;
use std::str::FromStr;

use super::utils::CharReader;

type LexReader<R: Read> = CharReader<io::BufReader<R>>;
type LexResult = Result<LexToken, LexError>;

#[derive(Debug, PartialEq, Clone)]
pub enum LexToken {
    OpenBrace, CloseBrace,
    OpenBracket, CloseBracket,
    Comma, Colon,
    Identifier(String),
    StringLit(String),
    IntegerLit(i64),
    FloatLit(f64),
}

#[derive(Debug)]
pub enum LexError {
    UnclosedStringError,
    InvalidEscape(char),
    InvalidUnicodeEscape(u32),
    IOError(io::Error),
    FloatParseError(<f64 as FromStr>::Err),
    IntegerParseError(<i64 as FromStr>::Err),
    UnrecognisedCharError(char),
}

pub struct Lexer<R: Read> {
    input: LexReader<R>,
    stored_next: Vec<char>,
    errored: bool,
}

impl<R: Read> Lexer<R> {
    pub fn lex(reader: R) -> Self {
        Lexer {
            input: CharReader::new(io::BufReader::new(reader)),
            stored_next: Vec::new(),
            errored: false,
        }
    }

    fn err(&mut self, err: LexError) -> Option<LexResult> {
        self.errored = true;
        Some(Err(err))
    }

    fn pop_next(&mut self) -> Option<char> {
        if let Some(next) = self.stored_next.pop() {
            Some(next)
        } else {
            self.input.next()
        }
    }

    fn ret_next(&mut self, returned: char) {
        self.stored_next.push(returned);
    }

    fn parse_ident(&mut self) -> Option<LexResult> {
        if let Some(next_char) = self.pop_next() {
            let mut ident = String::new();
            if next_char.is_alphabetic() {
                ident.push(next_char);
            } else {
                self.ret_next(next_char);
                return None;
            }

            while let Some(next_char) = self.pop_next() {
                if next_char.is_alphanumeric() {
                    ident.push(next_char);
                } else if next_char == '_' {
                    ident.push(next_char);
                } else {
                    self.ret_next(next_char);
                    break;
                }
            }

            Some(Ok(LexToken::Identifier(ident)))
        } else {
            None
        }
    }

    fn parse_int(&mut self, base: u32) -> Option<LexResult> {
        let mut buffer = String::new();

        while let Some(next_char) = self.pop_next() {
            if next_char.is_digit(base) {
                buffer.push(next_char);
            } else if next_char == '_' {
                continue; // accepted but ignored
            } else {
                self.ret_next(next_char);
                break;
            }
        }

        Some(Ok(LexToken::IntegerLit(i64::from_str_radix(&buffer, base).unwrap())))
    }

    fn parse_exponent(&mut self) -> String {
        let mut exponent = String::from("e");
        if let Some(next_char) = self.pop_next() {
            if next_char == '+' || next_char == '-' {
                exponent.push(next_char);
            } else {
                self.ret_next(next_char);
            }
        }

        while let Some(next_char) = self.pop_next() {
            if next_char.is_digit(10) {
                exponent.push(next_char)
            } else {
                self.ret_next(next_char);
                break;
            }
        }

        exponent
    }

    fn parse_float_int(&mut self) -> Option<LexResult> {
        let mut sign = '+';
        let mut is_float = false;
        let mut buffer = String::new();
        let mut exponent = String::new();

        if let Some(next_char) = self.pop_next() {
            if next_char == '+' || next_char == '-' {
                sign = next_char;
            } else {
                self.ret_next(next_char);
            }
        }

        while let Some(next_char) = self.pop_next() {
            if next_char == '.' {
                if is_float {
                    // already a float - can't have two periods!
                    self.ret_next(next_char);
                    break;
                } else {
                    is_float = true;
                    buffer.push(next_char);
                }
            } else if next_char.is_digit(10) {
                buffer.push(next_char);
            } else if next_char == '_' {
                continue;  // accepted, but ignored
            } else if next_char == 'e' || next_char == 'E' {
                exponent = self.parse_exponent();
                is_float = true;
                break;
            } else {
                self.ret_next(next_char);
                break;
            }
        }

        if is_float {
            let str_float = buffer + &exponent;
            Some(str_float.parse::<f64>()
                .map(move |flt| {
                    if sign == '+' {
                        LexToken::FloatLit(flt)
                    } else {
                        LexToken::FloatLit(-flt)
                    }
                })
                .map_err(LexError::FloatParseError))
        } else {
            Some(buffer.parse::<i64>()
                .map(move |intgr| {
                    if sign == '+' {
                        LexToken::IntegerLit(intgr)
                    } else {
                        LexToken::IntegerLit(-intgr)
                    }
                })
                .map_err(LexError::IntegerParseError))
        }
    }

    fn parse_numeric(&mut self) -> Option<LexResult> {
        if let Some(next_char) = self.pop_next() {
            if let Some(after) = self.pop_next() {
                if next_char == '0' && ['d', 'D'].contains(&after) {
                    self.parse_int(10)
                } else if next_char == '0' && ['x', 'X'].contains(&after)  {
                    self.parse_int(16)
                } else if next_char == '0' && ['o', 'O'].contains(&after) {
                    self.parse_int(8)
                } else if next_char == '0' && ['b', 'B'].contains(&after) {
                    self.parse_int(2)
                } else {
                    self.ret_next(after);      // put back the two characters we popped
                    self.ret_next(next_char);  // off, but in the right order
                    self.parse_float_int()
                }
            } else {
                Some(Ok(LexToken::IntegerLit(next_char.to_digit(10).unwrap() as i64)))
            }
        } else {
            None
        }
    }

    fn parse_string(&mut self) -> Option<LexResult> {
        let mut buffer = String::new();
        let mut quote_closed = false;
        let quote_char = match self.pop_next() {
            Some(c) => c,
            None => { return None; },
        };

        while let Some(next_char) = self.pop_next() {
            if next_char == '\\' {
                // escape next character
                match self.pop_next() {
                    Some('/') => { buffer.push('/'); },
                    Some('n') => { buffer.push('\n'); },
                    Some('r') => { buffer.push('\r'); },
                    Some('t') => { buffer.push('\t'); },
                    Some('\\') => { buffer.push('\\'); },
                    Some('\"') => { buffer.push('\"'); },
                    Some('\'') => { buffer.push('\''); },
                    Some('b') => { buffer.push('\x08'); },
                    Some('f') => { buffer.push('\x0c'); },
                    Some('u') => {
                        let mut uvalue = 0;
                        for _ in 0..4 {
                            if let Some(ch) = self.pop_next() {
                                uvalue = match ch {
                                    '0'...'9' =>
                                        uvalue * 16 + ((ch as u16) - ('0' as u16)),
                                    'a'...'f' =>
                                        uvalue * 16 + (10 + (ch as u16) - ('a' as u16)),
                                    'A'...'F' =>
                                        uvalue * 16 + (10 + (ch as u16) - ('A' as u16)),
                                    _ => {
                                        return self.err(LexError::InvalidUnicodeEscape(uvalue as u32));
                                    },
                                };
                            } else {
                                return self.err(LexError::UnclosedStringError);
                            }
                        }

                        if let Some(next_char) = from_u32(uvalue as u32) {
                            buffer.push(next_char);
                        } else {
                            return self.err(LexError::InvalidUnicodeEscape(uvalue as u32));
                        }
                    },
                    Some(c) => {
                        return self.err(LexError::InvalidEscape(c));
                    },
                    None => {
                        return self.err(LexError::UnclosedStringError);
                    },
                }
            } else if next_char == quote_char {
                quote_closed = true;
                break;
            } else {
                buffer.push(next_char);
            }
        }

        if quote_closed {
            Some(Ok(LexToken::StringLit(buffer)))
        } else {
            self.err(LexError::UnclosedStringError)
        }
    }
}

impl<R: Read> Iterator for Lexer<R> {
    type Item = Result<LexToken, LexError>;

    fn next(&mut self) -> Option<Self::Item> {
        let mut option_char = self.pop_next();
        while option_char.is_some() && option_char.unwrap().is_whitespace() {
            option_char = self.pop_next();
        }

        if let Some(next_char) = option_char {
            if next_char == '{' {
                Some(Ok(LexToken::OpenBrace))
            } else if next_char == '}' {
                Some(Ok(LexToken::CloseBrace))
            } else if next_char == '[' {
                Some(Ok(LexToken::OpenBracket))
            } else if next_char == ']' {
                Some(Ok(LexToken::CloseBracket))
            } else if next_char == ',' {
                Some(Ok(LexToken::Comma))
            } else if next_char == ':' {
                Some(Ok(LexToken::Colon))
            } else if next_char.is_alphabetic() {
                self.ret_next(next_char);
                self.parse_ident()
            } else if next_char.is_digit(10) || ['+', '-', '.'].contains(&next_char) {
                self.ret_next(next_char);
                self.parse_numeric()
            } else if next_char == '\"' || next_char == '\'' {
                self.ret_next(next_char);
                self.parse_string()
            } else {
                // TODO: Error out here
                None
            }
        } else {
            None
        }
    }
}

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

    #[test]
    fn parse_ident() {
        let mut lexer = Lexer::lex(Cursor::new("ThisIsAnIdent".as_bytes()));
        assert_eq!(lexer.parse_ident().unwrap().unwrap(),
            LexToken::Identifier("ThisIsAnIdent".to_string()));

        let mut lexer = Lexer::lex(Cursor::new("this_is_an_ident".as_bytes()));
        assert_eq!(lexer.parse_ident().unwrap().unwrap(),
            LexToken::Identifier("this_is_an_ident".to_string()));

        let mut lexer = Lexer::lex(Cursor::new("th15_1s_an_1d3n7".as_bytes()));
        assert_eq!(lexer.parse_ident().unwrap().unwrap(),
            LexToken::Identifier("th15_1s_an_1d3n7".to_string()));

        let mut lexer = Lexer::lex(Cursor::new("7h15_1s_an_1d3n7".as_bytes()));
        assert!(lexer.parse_ident().is_none());

        let mut lexer = Lexer::lex(Cursor::new("th15_1s_an_1d3n7".as_bytes()));
        assert_eq!(lexer.parse_ident().unwrap().unwrap(),
            LexToken::Identifier("th15_1s_an_1d3n7".to_string()));
    }

    #[test]
    fn parse_numeric() {
        let mut lexer = Lexer::lex(Cursor::new("12345".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(12345));

        let mut lexer = Lexer::lex(Cursor::new("0".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(0));

        let mut lexer = Lexer::lex(Cursor::new("0d10".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(10));

        let mut lexer = Lexer::lex(Cursor::new("0D10".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(10));

        let mut lexer = Lexer::lex(Cursor::new("0b10".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(2));

        let mut lexer = Lexer::lex(Cursor::new("0B10".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(2));

        let mut lexer = Lexer::lex(Cursor::new("0x10".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(16));

        let mut lexer = Lexer::lex(Cursor::new("0X10".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(16));

        let mut lexer = Lexer::lex(Cursor::new("0o10".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(8));

        let mut lexer = Lexer::lex(Cursor::new("0O10".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(8));

        let mut lexer = Lexer::lex(Cursor::new("0d10e5".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(10));

        let mut lexer = Lexer::lex(Cursor::new("10e5".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::FloatLit(10e5));

        let mut lexer = Lexer::lex(Cursor::new("10.5".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::FloatLit(10.5));

        let mut lexer = Lexer::lex(Cursor::new("105".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(105));

        let mut lexer = Lexer::lex(Cursor::new("1_0__5___".as_bytes()));
        assert_eq!(lexer.parse_numeric().unwrap().unwrap(),
            LexToken::IntegerLit(105));
    }

    #[test]
    fn parse_string() {
        let mut lexer = Lexer::lex(Cursor::new("'string'".as_bytes()));
        assert_eq!(lexer.parse_string().unwrap().unwrap(),
            LexToken::StringLit("string".to_string()));

        let mut lexer = Lexer::lex(Cursor::new("\"string\"".as_bytes()));
        assert_eq!(lexer.parse_string().unwrap().unwrap(),
            LexToken::StringLit("string".to_string()));

        let mut lexer = Lexer::lex(Cursor::new("\"s\\ntring\"".as_bytes()));
        assert_eq!(lexer.parse_string().unwrap().unwrap(),
            LexToken::StringLit("s\ntring".to_string()));

        let mut lexer = Lexer::lex(Cursor::new("'stri\\\\ng'".as_bytes()));
        assert_eq!(lexer.parse_string().unwrap().unwrap(),
            LexToken::StringLit("stri\\ng".to_string()));

        let mut lexer = Lexer::lex(Cursor::new("'str\\'ing'".as_bytes()));
        assert_eq!(lexer.parse_string().unwrap().unwrap(),
            LexToken::StringLit("str'ing".to_string()));

        let mut lexer = Lexer::lex(Cursor::new("'string".as_bytes()));
        match lexer.parse_string().unwrap() {
            Ok(_) => panic!("should raise error"),
            Err(LexError::UnclosedStringError) => assert!(true),
            Err(_) => panic!("wrong error raised"),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use book::Book;
use number::Number;
use error::{Error,Result};
use token::Token;
use zipper::Zipper;
use escape::escape_tex;
use resource_handler::ResourceHandler;

use std::iter::Iterator;
use std::fs::File;
use std::borrow::Cow;
use std::io::Read;

use mustache;

/// LaTeX renderer
pub struct LatexRenderer<'a> {
    book: &'a Book,
    current_chapter: Number,
    handler: ResourceHandler<'a>,
}

impl<'a> LatexRenderer<'a> {
    /// Creates new LatexRenderer
    pub fn new(book: &'a Book) -> LatexRenderer<'a> {
        let mut handler = ResourceHandler::new(&book.logger);
        handler.set_images_mapping(true);
        LatexRenderer {
            book: book,
            current_chapter: Number::Default,
            handler: handler,
        }
    }

    /// Render pdf in a file
    pub fn render_pdf(&mut self) -> Result<String> {
        if let Ok(pdf_file) = self.book.options.get_path("output.pdf") {
            let content = try!(self.render_book());
            let mut zipper = try!(Zipper::new(&self.book.options.get_path("temp_dir").unwrap()));
            try!(zipper.write("result.tex", &content.as_bytes(), false));

            // write image files
            for (source, dest) in self.handler.images_mapping() {
                let mut f = try!(File::open(self.book.root.join(source)).map_err(|_| Error::FileNotFound(source.to_owned())));
                let mut content = vec!();
                try!(f.read_to_end(&mut content).map_err(|_| Error::Render("error while reading image file")));
                try!(zipper.write(dest, &content, true));
            }

            zipper.generate_pdf(&self.book.options.get_str("tex.command").unwrap(), "result.tex", &pdf_file)
        } else {
            Err(Error::Render("no output pdf file specified in book config"))
        }
    }

    /// Render latex in a string
    pub fn render_book(&mut self) -> Result<String> {
        let mut content = String::from("");
        for (i, filename) in self.book.filenames.iter().enumerate() {
            self.handler.add_link(filename.clone(), format!("chapter-{}", i));
        }

        // set tex numbering and toc display to book's parameters
        let numbering = self.book.options.get_i32("numbering").unwrap() - 1;
        content.push_str(&format!("\\setcounter{{tocdepth}}{{{}}}
\\setcounter{{secnumdepth}}{{{}}}\n",
                                  numbering, numbering));

        if self.book.options.get_bool("display_toc").unwrap() {
            content.push_str("\\tableofcontents\n");
        }

        let mut i = 0;
        for &(n, ref v) in &self.book.chapters {
            content.push_str(&format!("\\label{{chapter-{}}}", i));
            self.current_chapter = n;
            content.push_str(&self.render_vec(v, true));
            i += 1;
        }

        let tex_lang = String::from(match self.book.options.get_str("lang").unwrap() {
            "en" => "english",
            "fr" => "francais",
            _ => {
                self.book.logger.warning(format!("LaTeX: can't find a tex equivalent for lang '{}', fallbacking on english", self.book.options.get_str("lang").unwrap()));
                "english"
            }
        });

        let template = mustache::compile_str(try!(self.book.get_template("tex.template")).as_ref());
        let mut data = self.book.get_mapbuilder("tex")
            .insert_str("content", content)
            .insert_str("tex_lang", tex_lang);
        if self.book.options.get_bool("tex.short") == Ok(true) {
            data = data.insert_bool("short", true);
        }
        let data = data.build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated LaTeX was not valid utf-8")),
            Ok(res) => Ok(res)
        }
    }

    /// Transform a vector of `Token`s to LaTeX
    fn render_vec(&mut self, tokens: &[Token], escape: bool) -> String {
        let mut res = String::new();

        for token in tokens {
            res.push_str(&self.parse_token(&token, escape));
        }
        res
    }

    fn parse_token(&mut self, token: &Token, escape: bool) -> String {
        match *token {
            Token::Str(ref text) => if escape {escape_tex(text)} else {text.clone()},
            Token::Paragraph(ref vec) => format!("{}\n\n",
                                                 self.render_vec(vec, escape)),
            Token::Header(n, ref vec) => {
                let mut content = String::new();
                if n == 1 && self.current_chapter == Number::Hidden {
                    return String::new();
                }
                if n == 1 {
                    if let Number::Specified(n) = self.current_chapter {
                        content.push_str(r"\setcounter{chapter}{");
                        content.push_str(&format!("{}", n - 1));
                        content.push_str("}\n");
                    }
                }
                match n {
                    1 => content.push_str(r"\chapter"),
                    2 => content.push_str(r"\section"),
                    3 => content.push_str(r"\subsection"),
                    4 => content.push_str(r"\subsubsection"),
                    _ => content.push_str(r"\paragraph"),
                }
                if self.current_chapter == Number::Unnumbered {
                    content.push_str("*");
                }
                content.push_str(r"{");
                content.push_str(&self.render_vec(vec, true));
                content.push_str("}\n");
                content
            },
            Token::Emphasis(ref vec) => format!("\\emph{{{}}}", self.render_vec(vec, escape)),
            Token::Strong(ref vec) => format!("\\textbf{{{}}}", self.render_vec(vec, escape)),
            Token::Code(ref vec) => format!("\\texttt{{{}}}", self.render_vec(vec, escape)),
            Token::BlockQuote(ref vec) => format!("\\begin{{quotation}}\n{}\\end{{quotation}}\n", self.render_vec(vec, escape)),
            Token::CodeBlock(_, ref vec) => format!("\\begin{{spverbatim}}{}\\end{{spverbatim}}\n\\vspace{{1em}}\n", self.render_vec(vec, false)),
            Token::Rule => String::from("\\HRule\n"),
            Token::SoftBreak => String::from(" "),
            Token::HardBreak => String::from("\n"),
            Token::List(ref vec) => format!("\\begin{{itemize}}\n{}\\end{{itemize}}", self.render_vec(vec, escape)),
            Token::OrderedList(_, ref vec) => format!("\\begin{{enumerate}}\n{}\\end{{enumerate}}\n", self.render_vec(vec, escape)),
            Token::Item(ref vec) => format!("\\item {}\n", self.render_vec(vec, escape)),
            Token::Link(ref url, _, ref vec) => {
                let content = self.render_vec(vec, escape);

                if ResourceHandler::is_local(url) {
                    format!("\\hyperref[{}]{{{}}}",
                            self.handler.get_link(url),
                            content)
                }
                else {
                    let url = escape_tex(url);
                    if content == url {
                        format!("\\url{{{}}}", content)
                    } else {
                        if self.book.options.get_bool("tex.links_as_footnotes").unwrap() {
                            format!("\\href{{{}}}{{{}}}\\footnote{{\\url{{{}}}}}", url, content, url)
                        } else {
                            format!("\\href{{{}}}{{{}}}", url, content)
                        }
                    }
                }
            },
            Token::Image(ref url, _, _) => {
                if ResourceHandler::is_local(url) {
                    format!("\\includegraphics{{{}}}", self.handler.map_image(Cow::Borrowed(url)))
                } else {
                    self.book.logger.warning(&format!("LaTeX: image '{}' doesn't seem to be local; ignoring it in Latex output.", url));
                    String::new()
                }
            }
            Token::Footnote(ref vec) => format!("\\footnote{{{}}}", self.render_vec(vec, escape)),
            Token::Table(n, ref vec) => {
                let mut cols = String::new();
                for _ in 0..n {
                    cols.push_str("|c");
                }
                cols.push_str("|");
                format!("\\begin{{center}}
\\begin{{tabular}}{{{}}}
\\hline
{}
\\hline
\\end{{tabular}}
\\end{{center}}\n\n", cols, self.render_vec(vec, escape))
            },
            Token::TableRow(ref vec) | Token::TableHead(ref vec) => {
                let mut res:String = vec.iter().map(|v| {self.parse_token(v, escape)})
                    .collect::<Vec<_>>()
                    .join(" & ");
                res.push_str("\\\\ \n");
                if let Token::TableHead(_) = *token {
                    res.push_str("\\hline\n");
                }
                res
            }
            Token::TableCell(ref vec) => self.render_vec(vec, escape),
        }
    }
}
<commit_msg>Add babel correspondences to more languages codes<commit_after>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use book::Book;
use number::Number;
use error::{Error,Result};
use token::Token;
use zipper::Zipper;
use escape::escape_tex;
use resource_handler::ResourceHandler;

use std::iter::Iterator;
use std::fs::File;
use std::borrow::Cow;
use std::io::Read;

use mustache;

/// LaTeX renderer
pub struct LatexRenderer<'a> {
    book: &'a Book,
    current_chapter: Number,
    handler: ResourceHandler<'a>,
}

impl<'a> LatexRenderer<'a> {
    /// Creates new LatexRenderer
    pub fn new(book: &'a Book) -> LatexRenderer<'a> {
        let mut handler = ResourceHandler::new(&book.logger);
        handler.set_images_mapping(true);
        LatexRenderer {
            book: book,
            current_chapter: Number::Default,
            handler: handler,
        }
    }

    /// Render pdf in a file
    pub fn render_pdf(&mut self) -> Result<String> {
        if let Ok(pdf_file) = self.book.options.get_path("output.pdf") {
            let content = try!(self.render_book());
            let mut zipper = try!(Zipper::new(&self.book.options.get_path("temp_dir").unwrap()));
            try!(zipper.write("result.tex", &content.as_bytes(), false));

            // write image files
            for (source, dest) in self.handler.images_mapping() {
                let mut f = try!(File::open(self.book.root.join(source)).map_err(|_| Error::FileNotFound(source.to_owned())));
                let mut content = vec!();
                try!(f.read_to_end(&mut content).map_err(|_| Error::Render("error while reading image file")));
                try!(zipper.write(dest, &content, true));
            }

            zipper.generate_pdf(&self.book.options.get_str("tex.command").unwrap(), "result.tex", &pdf_file)
        } else {
            Err(Error::Render("no output pdf file specified in book config"))
        }
    }

    /// Render latex in a string
    pub fn render_book(&mut self) -> Result<String> {
        let mut content = String::from("");
        for (i, filename) in self.book.filenames.iter().enumerate() {
            self.handler.add_link(filename.clone(), format!("chapter-{}", i));
        }

        // set tex numbering and toc display to book's parameters
        let numbering = self.book.options.get_i32("numbering").unwrap() - 1;
        content.push_str(&format!("\\setcounter{{tocdepth}}{{{}}}
\\setcounter{{secnumdepth}}{{{}}}\n",
                                  numbering, numbering));

        if self.book.options.get_bool("display_toc").unwrap() {
            content.push_str("\\tableofcontents\n");
        }

        let mut i = 0;
        for &(n, ref v) in &self.book.chapters {
            content.push_str(&format!("\\label{{chapter-{}}}", i));
            self.current_chapter = n;
            content.push_str(&self.render_vec(v, true));
            i += 1;
        }

        let tex_lang = String::from(match self.book.options.get_str("lang").unwrap() {
            "af" => "afrikaans",
            "sq" => "albanian",
            "eu" => "basque",
            "bg" => "bulgarian",
            "ca" => "catalan",
            "hr" => "croatian",
            "cs" => "czech",
            "da" => "danish",
            "nl" => "dutch",
            "en" => "english",
            "eo" => "esperanto",
            "et" => "estonian",
            "fi" => "finnish",
            "fr" => "francais",
            "gl" => "galician",
            "el" => "greek",
            "de" => "ngerman",
            "he" => "hebrew",
            "hu" => "hungarian",
            "it" => "italian",
            "is" => "icelandic",
            "id" => "indonesian",
            "ga" => "irish",
            "la" => "latin",
            "ms" => "malay",
            "nn" => "norsk",
            "pl" => "polish",
            "pt" => "portuguese",
            "ro" => "romanian",
            "ru" => "russian",
            "gd" => "scottish",
            "sr" => "serbian",
            "sk" => "slovak",
            "sl" => "slovene",
            "es" => "spanish",
            "sw" => "swedish",
            "tr" => "turkish",
            "uk" => "ukrainian",
            "cy" => "welsh",

            _ => {
                self.book.logger.warning(format!("LaTeX: can't find a tex equivalent for lang '{}', fallbacking on english", self.book.options.get_str("lang").unwrap()));
                "english"
            }
        });

        let template = mustache::compile_str(try!(self.book.get_template("tex.template")).as_ref());
        let mut data = self.book.get_mapbuilder("tex")
            .insert_str("content", content)
            .insert_str("tex_lang", tex_lang);
        if self.book.options.get_bool("tex.short") == Ok(true) {
            data = data.insert_bool("short", true);
        }
        let data = data.build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated LaTeX was not valid utf-8")),
            Ok(res) => Ok(res)
        }
    }

    /// Transform a vector of `Token`s to LaTeX
    fn render_vec(&mut self, tokens: &[Token], escape: bool) -> String {
        let mut res = String::new();

        for token in tokens {
            res.push_str(&self.parse_token(&token, escape));
        }
        res
    }

    fn parse_token(&mut self, token: &Token, escape: bool) -> String {
        match *token {
            Token::Str(ref text) => if escape {escape_tex(text)} else {text.clone()},
            Token::Paragraph(ref vec) => format!("{}\n\n",
                                                 self.render_vec(vec, escape)),
            Token::Header(n, ref vec) => {
                let mut content = String::new();
                if n == 1 && self.current_chapter == Number::Hidden {
                    return String::new();
                }
                if n == 1 {
                    if let Number::Specified(n) = self.current_chapter {
                        content.push_str(r"\setcounter{chapter}{");
                        content.push_str(&format!("{}", n - 1));
                        content.push_str("}\n");
                    }
                }
                match n {
                    1 => content.push_str(r"\chapter"),
                    2 => content.push_str(r"\section"),
                    3 => content.push_str(r"\subsection"),
                    4 => content.push_str(r"\subsubsection"),
                    _ => content.push_str(r"\paragraph"),
                }
                if self.current_chapter == Number::Unnumbered {
                    content.push_str("*");
                }
                content.push_str(r"{");
                content.push_str(&self.render_vec(vec, true));
                content.push_str("}\n");
                content
            },
            Token::Emphasis(ref vec) => format!("\\emph{{{}}}", self.render_vec(vec, escape)),
            Token::Strong(ref vec) => format!("\\textbf{{{}}}", self.render_vec(vec, escape)),
            Token::Code(ref vec) => format!("\\texttt{{{}}}", self.render_vec(vec, escape)),
            Token::BlockQuote(ref vec) => format!("\\begin{{quotation}}\n{}\\end{{quotation}}\n", self.render_vec(vec, escape)),
            Token::CodeBlock(_, ref vec) => format!("\\begin{{spverbatim}}{}\\end{{spverbatim}}\n\\vspace{{1em}}\n", self.render_vec(vec, false)),
            Token::Rule => String::from("\\HRule\n"),
            Token::SoftBreak => String::from(" "),
            Token::HardBreak => String::from("\n"),
            Token::List(ref vec) => format!("\\begin{{itemize}}\n{}\\end{{itemize}}", self.render_vec(vec, escape)),
            Token::OrderedList(_, ref vec) => format!("\\begin{{enumerate}}\n{}\\end{{enumerate}}\n", self.render_vec(vec, escape)),
            Token::Item(ref vec) => format!("\\item {}\n", self.render_vec(vec, escape)),
            Token::Link(ref url, _, ref vec) => {
                let content = self.render_vec(vec, escape);

                if ResourceHandler::is_local(url) {
                    format!("\\hyperref[{}]{{{}}}",
                            self.handler.get_link(url),
                            content)
                }
                else {
                    let url = escape_tex(url);
                    if content == url {
                        format!("\\url{{{}}}", content)
                    } else {
                        if self.book.options.get_bool("tex.links_as_footnotes").unwrap() {
                            format!("\\href{{{}}}{{{}}}\\footnote{{\\url{{{}}}}}", url, content, url)
                        } else {
                            format!("\\href{{{}}}{{{}}}", url, content)
                        }
                    }
                }
            },
            Token::Image(ref url, _, _) => {
                if ResourceHandler::is_local(url) {
                    format!("\\includegraphics{{{}}}", self.handler.map_image(Cow::Borrowed(url)))
                } else {
                    self.book.logger.warning(&format!("LaTeX: image '{}' doesn't seem to be local; ignoring it in Latex output.", url));
                    String::new()
                }
            }
            Token::Footnote(ref vec) => format!("\\footnote{{{}}}", self.render_vec(vec, escape)),
            Token::Table(n, ref vec) => {
                let mut cols = String::new();
                for _ in 0..n {
                    cols.push_str("|c");
                }
                cols.push_str("|");
                format!("\\begin{{center}}
\\begin{{tabular}}{{{}}}
\\hline
{}
\\hline
\\end{{tabular}}
\\end{{center}}\n\n", cols, self.render_vec(vec, escape))
            },
            Token::TableRow(ref vec) | Token::TableHead(ref vec) => {
                let mut res:String = vec.iter().map(|v| {self.parse_token(v, escape)})
                    .collect::<Vec<_>>()
                    .join(" & ");
                res.push_str("\\\\ \n");
                if let Token::TableHead(_) = *token {
                    res.push_str("\\hline\n");
                }
                res
            }
            Token::TableCell(ref vec) => self.render_vec(vec, escape),
        }
    }
}
<|endoftext|>


<commit_before>use std::os;
use std::fs;
use std::fs::PathExt;
use std::io;
use std::io::{Read,Write};
use std::process;
use std::path;
use std::env;
use std::borrow::ToOwned;
use std::ffi::AsOsStr;

use atomicwrites::{GenericAtomicFile,AtomicFile,AllowOverwrite};

use utils;

macro_rules! main_try {
    ($result: expr, $errmsg: expr) => (
        match $result {
            Ok(m) => m,
            Err(e) => {
                if e.description().len() > 0 {
                    writeln!(&mut io::stderr(), "{}: {}", $errmsg, e).unwrap();
                };
                env::set_exit_status(1);
                return;
            }
        }
    )
}

fn get_pwd() -> path::PathBuf {
    match os::getcwd() {
        Ok(x) => path::PathBuf::new(x.as_os_str()),
        Err(e) => panic!(format!("Failed to get current working directory: {}", e))
    }
}

fn get_envvar(key: &str) -> Option<String> {
    match env::var(key) {
        Ok(x) => Some(x),
        Err(e) => match e {
            env::VarError::NotPresent => None,
            env::VarError::NotUnicode(_) => panic!(format!("{} is not unicode.", key))
        }
    }
}

fn build_index(outfile: &path::Path, dir: &path::Path) -> io::Result<()> {
    if !dir.is_dir() {
        return Err(io::Error::new(
            io::ErrorKind::MismatchedFileTypeForOperation,
            "MATES_DIR must be a directory.",
            None
        ));
    };

    let af: AtomicFile = GenericAtomicFile::new(outfile, AllowOverwrite);
    let mut errors = false;

    try!(af.write(|outf| {
        for entry in try!(fs::read_dir(dir)) {
            let entry = match entry {
                Ok(x) => x,
                Err(e) => {
                    println!("Error while listing directory: {}", e);
                    errors = true;
                    continue;
                }
            };

            let pathbuf = entry.path();

            if !(*pathbuf).is_file() || match pathbuf.extension() {
                Some(x) => x.to_str().unwrap_or("") != ".vcf",
                None => false
            } {
                continue;
            }

            let contact = match utils::Contact::from_file(&pathbuf) {
                Ok(x) => x,
                Err(e) => {
                    println!("Error while reading {}: {}", pathbuf.display(), e);
                    errors = true;
                    continue
                }
            };

            match utils::index_item_from_contact(&contact) {
                Ok(index_string) => {
                    try!(outf.write_all(index_string.as_bytes()));
                },
                Err(e) => {
                    println!("Error while indexing {}: {}", pathbuf.display(), e);
                    errors = true;
                    continue
                }
            };
        };
        Ok(())
    }));

    if errors {
        Err(io::Error::new(
            io::ErrorKind::Other,
            "Several errors happened while generating the index.",
            None
        ))
    } else {
        Ok(())
    }
}

pub fn cli_main() {
    let mut args = env::args();
    let program = args.next().unwrap_or("mates".to_string());

    let help = format!("Usage: {} COMMAND
Commands:
    index:
        Rewrite/create the index.
    mutt-query <query>:
        Search for contact, output is usable for mutt's query_command.
    file-query <query>:
        Search for contact, return just the filename.
    email-query <query>:
        Search for contact, return \"name <email>\".
    add:
        Take mail from stdin, add sender to contacts. Print filename.
    edit <file-or-query>:
        Open contact (given by filepath or search-string) in $MATES_EDITOR. If the file is cleared,
        the contact is removed. As a further convenience it also clears stdin, which is necessary
        for editors and most interactive programs to not act weird when piped to.",
        program);

    let print_help = || {
        println!("{}", help);
    };

    let command = match args.next() {
        Some(x) => x,
        None => {
            print_help();
            env::set_exit_status(1);
            return;
        }
    };

    if command == "--help" || command == "help" || command == "-h" {
        print_help();
        return;
    }

    let config = match Configuration::new() {
        Ok(x) => x,
        Err(e) => {
            println!("Error while reading configuration: {}", e);
            env::set_exit_status(1);
            return;
        }
    };

    match command.as_slice() {
        "index" => {
            println!("Rebuilding index file \"{}\"...", config.index_path.display());
            main_try!(build_index(&config.index_path, &config.vdir_path), "Failed to build index");
        },
        "mutt-query" => {
            let query = args.next().unwrap_or("".to_string());
            main_try!(mutt_query(&config, query.as_slice()), "Failed to execute grep");
        },
        "file-query" => {
            let query = args.next().unwrap_or("".to_string());
            main_try!(file_query(&config, query.as_slice()), "Failed to execute grep");
        },
        "email-query" => {
            let query = args.next().unwrap_or("".to_string());
            main_try!(email_query(&config, query.as_slice()), "Failed to execute grep");
        },
        "add" => {
            let stdin = io::stdin();
            let mut email = String::new();
            main_try!(stdin.lock().read_to_string(&mut email), "Failed to read email");
            let contact = main_try!(utils::add_contact_from_email(
                &config.vdir_path,
                email.as_slice()
            ), "Failed to add contact");
            println!("{}", contact.path.display());

            let mut index_fp = main_try!(
                fs::OpenOptions::new()
                .append(true)
                .write(true)
                .open(&config.index_path),
                "Failed to open index"
            );

            let index_entry = main_try!(utils::index_item_from_contact(&contact), "Failed to generate index");
            main_try!(index_fp.write_all(index_entry.as_bytes()), "Failed to write to index");
        },
        "edit" => {
            let query = args.next().unwrap_or("".to_string());
            main_try!(edit_contact(&config, query.as_slice()), "Failed to edit contact");
        },
        _ => {
            println!("Invalid command: {}", command);
            print_help();
            env::set_exit_status(1);
        }
    };
}

fn edit_contact(config: &Configuration, query: &str) -> io::Result<()> {
    let results = if get_pwd().join(query).is_file() {
        vec![path::PathBuf::new(query)]
    } else {
        try!(utils::file_query(config, query)).into_iter().collect()
    };

    if results.len() < 1 {
        return Err(io::Error::new(
            io::ErrorKind::Other,
            "No such contact.",
            None
        ))
    } else if results.len() > 1 {
        return Err(io::Error::new(
            io::ErrorKind::Other,
            "Ambiguous query.",
            None
        ))
    }

    let fpath = &results[0];
    let mut process = try!(process::Command::new("sh")
        .arg("-c")
        // clear stdin, http://unix.stackexchange.com/a/77593
        .arg(format!("$0 -- \"$1\" < $2").as_slice())
        .arg(config.editor_cmd.as_slice())
        .arg(fpath.as_os_str())
        .arg("/dev/tty")
        .stdin(process::Stdio::inherit())
        .stdout(process::Stdio::inherit())
        .stderr(process::Stdio::inherit())
        .spawn());

    try!(utils::handle_process(&mut process));

    let fcontent = {
        let mut fcontent = String::new();
        let mut file = try!(fs::File::open(fpath));
        try!(file.read_to_string(&mut fcontent));
        fcontent
    };

    if fcontent.as_slice().trim().len() == 0 {
        try!(fs::remove_file(fpath));
        return Err(io::Error::new(
            io::ErrorKind::Other,
            "Contact emptied, file removed.",
            None
        ));
    };

    Ok(())
}

fn mutt_query<'a>(config: &Configuration, query: &str) -> io::Result<()> {
    println!("");  // For some reason mutt requires an empty line
    for item in try!(utils::index_query(config, query)) {
        if item.email.len() > 0 && item.name.len() > 0 {
            println!("{}\t{}", item.email, item.name);
        };
    };
    Ok(())
}

fn file_query<'a>(config: &Configuration, query: &str) -> io::Result<()> {
    for path in try!(utils::file_query(config, query)).iter() {
        println!("{}", path.display());
    };
    Ok(())
}

fn email_query<'a>(config: &Configuration, query: &str) -> io::Result<()> {
    for item in try!(utils::index_query(config, query)) {
        if item.name.len() > 0 && item.email.len() > 0 {
            println!("{} <{}>", item.name, item.email);
        };
    };
    Ok(())
}

pub struct Configuration {
    pub index_path: path::PathBuf,
    pub vdir_path: path::PathBuf,
    pub editor_cmd: String,
    pub grep_cmd: String
}

impl Configuration {
    pub fn new() -> Result<Configuration, String> {
        Ok(Configuration {
            index_path: match get_envvar("MATES_INDEX") {
                Some(x) => path::PathBuf::new(&x),
                None => match get_envvar("HOME") {
                    Some(home) => get_pwd().join(&home).join(".mates_index"),
                    None => return Err("Unable to determine user's home directory.".to_owned())
                }
            },
            vdir_path: match get_envvar("MATES_DIR") {
                Some(x) => path::PathBuf::new(&x),
                None => return Err("MATES_DIR must be set to your vdir path (directory of vcf-files).".to_owned())
            },
            editor_cmd: match get_envvar("MATES_EDITOR") {
                Some(x) => x,
                None => match get_envvar("EDITOR") {
                    Some(x) => x,
                    None => return Err("MATES_EDITOR or EDITOR must be set.".to_owned())
                }
            },
            grep_cmd: match get_envvar("MATES_GREP") {
                Some(x) => x,
                None => "grep -i".to_owned()
            }
        })
    }
}
<commit_msg>Fix bug<commit_after>use std::os;
use std::fs;
use std::fs::PathExt;
use std::io;
use std::io::{Read,Write};
use std::process;
use std::path;
use std::env;
use std::borrow::ToOwned;
use std::ffi::AsOsStr;

use atomicwrites::{GenericAtomicFile,AtomicFile,AllowOverwrite};

use utils;

macro_rules! main_try {
    ($result: expr, $errmsg: expr) => (
        match $result {
            Ok(m) => m,
            Err(e) => {
                if e.description().len() > 0 {
                    writeln!(&mut io::stderr(), "{}: {}", $errmsg, e).unwrap();
                };
                env::set_exit_status(1);
                return;
            }
        }
    )
}

fn get_pwd() -> path::PathBuf {
    match os::getcwd() {
        Ok(x) => path::PathBuf::new(x.as_os_str()),
        Err(e) => panic!(format!("Failed to get current working directory: {}", e))
    }
}

fn get_envvar(key: &str) -> Option<String> {
    match env::var(key) {
        Ok(x) => Some(x),
        Err(e) => match e {
            env::VarError::NotPresent => None,
            env::VarError::NotUnicode(_) => panic!(format!("{} is not unicode.", key))
        }
    }
}

fn build_index(outfile: &path::Path, dir: &path::Path) -> io::Result<()> {
    if !dir.is_dir() {
        return Err(io::Error::new(
            io::ErrorKind::MismatchedFileTypeForOperation,
            "MATES_DIR must be a directory.",
            None
        ));
    };

    let af: AtomicFile = GenericAtomicFile::new(outfile, AllowOverwrite);
    let mut errors = false;

    try!(af.write(|outf| {
        for entry in try!(fs::read_dir(dir)) {
            let entry = match entry {
                Ok(x) => x,
                Err(e) => {
                    println!("Error while listing directory: {}", e);
                    errors = true;
                    continue;
                }
            };

            let pathbuf = entry.path();

            if !(*pathbuf).is_file() || match pathbuf.extension() {
                Some(x) => x.to_str().unwrap_or("") != "vcf",
                None => false
            } {
                continue;
            }

            let contact = match utils::Contact::from_file(&pathbuf) {
                Ok(x) => x,
                Err(e) => {
                    println!("Error while reading {}: {}", pathbuf.display(), e);
                    errors = true;
                    continue
                }
            };

            match utils::index_item_from_contact(&contact) {
                Ok(index_string) => {
                    try!(outf.write_all(index_string.as_bytes()));
                },
                Err(e) => {
                    println!("Error while indexing {}: {}", pathbuf.display(), e);
                    errors = true;
                    continue
                }
            };
        };
        Ok(())
    }));

    if errors {
        Err(io::Error::new(
            io::ErrorKind::Other,
            "Several errors happened while generating the index.",
            None
        ))
    } else {
        Ok(())
    }
}

pub fn cli_main() {
    let mut args = env::args();
    let program = args.next().unwrap_or("mates".to_string());

    let help = format!("Usage: {} COMMAND
Commands:
    index:
        Rewrite/create the index.
    mutt-query <query>:
        Search for contact, output is usable for mutt's query_command.
    file-query <query>:
        Search for contact, return just the filename.
    email-query <query>:
        Search for contact, return \"name <email>\".
    add:
        Take mail from stdin, add sender to contacts. Print filename.
    edit <file-or-query>:
        Open contact (given by filepath or search-string) in $MATES_EDITOR. If the file is cleared,
        the contact is removed. As a further convenience it also clears stdin, which is necessary
        for editors and most interactive programs to not act weird when piped to.",
        program);

    let print_help = || {
        println!("{}", help);
    };

    let command = match args.next() {
        Some(x) => x,
        None => {
            print_help();
            env::set_exit_status(1);
            return;
        }
    };

    if command == "--help" || command == "help" || command == "-h" {
        print_help();
        return;
    }

    let config = match Configuration::new() {
        Ok(x) => x,
        Err(e) => {
            println!("Error while reading configuration: {}", e);
            env::set_exit_status(1);
            return;
        }
    };

    match command.as_slice() {
        "index" => {
            println!("Rebuilding index file \"{}\"...", config.index_path.display());
            main_try!(build_index(&config.index_path, &config.vdir_path), "Failed to build index");
        },
        "mutt-query" => {
            let query = args.next().unwrap_or("".to_string());
            main_try!(mutt_query(&config, query.as_slice()), "Failed to execute grep");
        },
        "file-query" => {
            let query = args.next().unwrap_or("".to_string());
            main_try!(file_query(&config, query.as_slice()), "Failed to execute grep");
        },
        "email-query" => {
            let query = args.next().unwrap_or("".to_string());
            main_try!(email_query(&config, query.as_slice()), "Failed to execute grep");
        },
        "add" => {
            let stdin = io::stdin();
            let mut email = String::new();
            main_try!(stdin.lock().read_to_string(&mut email), "Failed to read email");
            let contact = main_try!(utils::add_contact_from_email(
                &config.vdir_path,
                email.as_slice()
            ), "Failed to add contact");
            println!("{}", contact.path.display());

            let mut index_fp = main_try!(
                fs::OpenOptions::new()
                .append(true)
                .write(true)
                .open(&config.index_path),
                "Failed to open index"
            );

            let index_entry = main_try!(utils::index_item_from_contact(&contact), "Failed to generate index");
            main_try!(index_fp.write_all(index_entry.as_bytes()), "Failed to write to index");
        },
        "edit" => {
            let query = args.next().unwrap_or("".to_string());
            main_try!(edit_contact(&config, query.as_slice()), "Failed to edit contact");
        },
        _ => {
            println!("Invalid command: {}", command);
            print_help();
            env::set_exit_status(1);
        }
    };
}

fn edit_contact(config: &Configuration, query: &str) -> io::Result<()> {
    let results = if get_pwd().join(query).is_file() {
        vec![path::PathBuf::new(query)]
    } else {
        try!(utils::file_query(config, query)).into_iter().collect()
    };

    if results.len() < 1 {
        return Err(io::Error::new(
            io::ErrorKind::Other,
            "No such contact.",
            None
        ))
    } else if results.len() > 1 {
        return Err(io::Error::new(
            io::ErrorKind::Other,
            "Ambiguous query.",
            None
        ))
    }

    let fpath = &results[0];
    let mut process = try!(process::Command::new("sh")
        .arg("-c")
        // clear stdin, http://unix.stackexchange.com/a/77593
        .arg(format!("$0 -- \"$1\" < $2").as_slice())
        .arg(config.editor_cmd.as_slice())
        .arg(fpath.as_os_str())
        .arg("/dev/tty")
        .stdin(process::Stdio::inherit())
        .stdout(process::Stdio::inherit())
        .stderr(process::Stdio::inherit())
        .spawn());

    try!(utils::handle_process(&mut process));

    let fcontent = {
        let mut fcontent = String::new();
        let mut file = try!(fs::File::open(fpath));
        try!(file.read_to_string(&mut fcontent));
        fcontent
    };

    if fcontent.as_slice().trim().len() == 0 {
        try!(fs::remove_file(fpath));
        return Err(io::Error::new(
            io::ErrorKind::Other,
            "Contact emptied, file removed.",
            None
        ));
    };

    Ok(())
}

fn mutt_query<'a>(config: &Configuration, query: &str) -> io::Result<()> {
    println!("");  // For some reason mutt requires an empty line
    for item in try!(utils::index_query(config, query)) {
        if item.email.len() > 0 && item.name.len() > 0 {
            println!("{}\t{}", item.email, item.name);
        };
    };
    Ok(())
}

fn file_query<'a>(config: &Configuration, query: &str) -> io::Result<()> {
    for path in try!(utils::file_query(config, query)).iter() {
        println!("{}", path.display());
    };
    Ok(())
}

fn email_query<'a>(config: &Configuration, query: &str) -> io::Result<()> {
    for item in try!(utils::index_query(config, query)) {
        if item.name.len() > 0 && item.email.len() > 0 {
            println!("{} <{}>", item.name, item.email);
        };
    };
    Ok(())
}

pub struct Configuration {
    pub index_path: path::PathBuf,
    pub vdir_path: path::PathBuf,
    pub editor_cmd: String,
    pub grep_cmd: String
}

impl Configuration {
    pub fn new() -> Result<Configuration, String> {
        Ok(Configuration {
            index_path: match get_envvar("MATES_INDEX") {
                Some(x) => path::PathBuf::new(&x),
                None => match get_envvar("HOME") {
                    Some(home) => get_pwd().join(&home).join(".mates_index"),
                    None => return Err("Unable to determine user's home directory.".to_owned())
                }
            },
            vdir_path: match get_envvar("MATES_DIR") {
                Some(x) => path::PathBuf::new(&x),
                None => return Err("MATES_DIR must be set to your vdir path (directory of vcf-files).".to_owned())
            },
            editor_cmd: match get_envvar("MATES_EDITOR") {
                Some(x) => x,
                None => match get_envvar("EDITOR") {
                    Some(x) => x,
                    None => return Err("MATES_EDITOR or EDITOR must be set.".to_owned())
                }
            },
            grep_cmd: match get_envvar("MATES_GREP") {
                Some(x) => x,
                None => "grep -i".to_owned()
            }
        })
    }
}
<|endoftext|>


<commit_before>#![feature(plugin, collections)]
#![plugin(clippy)]

#[deny(cmp_owned)]
fn main() {
    let x = "oh";

    #[allow(str_to_string)]
    fn with_to_string(x : &str) {
        x != "foo".to_string(); //~ERROR this creates an owned instance
    }
    with_to_string(x);

    x != "foo".to_owned(); //~ERROR this creates an owned instance

    #[allow(deprecated)] // for from_str
    fn old_timey(x : &str) {
        x != String::from_str("foo"); //~ERROR this creates an owned instance
    }
    old_timey(x);

    x != String::from("foo"); //~ERROR this creates an owned instance
}
<commit_msg>removed String::from_str(..) to fix build with 1.4.0-nightly/2015-08-14<commit_after>#![feature(plugin)]
#![plugin(clippy)]

#[deny(cmp_owned)]
fn main() {
    let x = "oh";

    #[allow(str_to_string)]
    fn with_to_string(x : &str) {
        x != "foo".to_string(); //~ERROR this creates an owned instance
    }
    with_to_string(x);

    x != "foo".to_owned(); //~ERROR this creates an owned instance

    // removed String::from_str(..), as it has finally been removed in 1.4.0
    // as of 2015-08-14

    x != String::from("foo"); //~ERROR this creates an owned instance
}
<|endoftext|>


<commit_before>//! Provides audio IO from OS sound devices.

extern crate portaudio;

use std::rc::Rc;

use types::{SAMPLE_RATE, AudioDevice, Sample, Time};

/// Defines the audio format for Portaudio.
static PORTAUDIO_T: portaudio::pa::SampleFormat =
    portaudio::pa::SampleFormat::Float32;

/// Defines the buffer size for Portaudio
static BUFFER_SIZE: usize = 256;

/// The AudioEnginer opens and manages the resources associated with portaudio.
/// It is used open new input/output streams and safely free them.
pub struct AudioEngine {
    marker: Rc<AudioEngineMarker>
}

impl AudioEngine {
    pub fn open() -> Result<AudioEngine, String> {
        match portaudio::pa::initialize() {
            Ok(()) => Ok(AudioEngine { marker: Rc::new(AudioEngineMarker) }),
            Err(e) => Err(portaudio::pa::get_error_text(e))
        }
    }

    pub fn default_input(&self, num_channels: usize) -> AudioIn {
        AudioIn::new(self.marker.clone(), num_channels)
    }

    pub fn default_output(&self, num_channels: usize) -> AudioOut {
        AudioOut::new(self.marker.clone(), num_channels)
    }
}

/// This empty struct is used as a RAII marker for an initialized portaudio
/// connection. It is held in a Rc, and copies are passed to all streams opened
/// with it.
struct AudioEngineMarker;
impl Drop for AudioEngineMarker {
    fn drop(&mut self)
    {
        portaudio::pa::terminate().unwrap();
    }
}

/// Reads audio from the OS's default input device.
pub struct AudioIn {
    #[allow(dead_code)] // the engine is used as an RAII marker
    engine: Rc<AudioEngineMarker>,
    pa_stream: portaudio::pa::Stream<Sample, Sample>,
    num_channels: usize,
    buffer: Vec<Sample>,
    samples_read: usize,
}

impl AudioIn {
    /// Opens an audio input stream reading `num_channels` inputs.
    fn new(engine: Rc<AudioEngineMarker>, num_channels: usize) -> AudioIn {
        // Open a stream in blocking mode
        let mut pa_stream = portaudio::pa::Stream::new();
        pa_stream.open_default(SAMPLE_RATE as f64, BUFFER_SIZE as u32,
                               num_channels as i32, 0i32,
                               PORTAUDIO_T, None).unwrap();
        pa_stream.start().unwrap();

        AudioIn {
            engine: engine,
            pa_stream: pa_stream,
            num_channels: num_channels,
            buffer: Vec::with_capacity(num_channels*BUFFER_SIZE),
            samples_read: BUFFER_SIZE,
        }
    }
}

impl Drop for AudioIn {
    fn drop(&mut self) {
        self.pa_stream.stop().unwrap();
        self.pa_stream.close().unwrap();
    }
}

impl AudioDevice for AudioIn {
    fn num_inputs(&self) -> usize {
        0
    }

    fn num_outputs(&self) -> usize {
        self.num_channels
    }

    fn tick(&mut self, _: Time, _: &[Sample], outputs: &mut[Sample]) {
        if self.samples_read == BUFFER_SIZE {
            let result = self.pa_stream.read(BUFFER_SIZE as u32);
            match result {
                Ok(v) => self.buffer = v.clone(),
                Err(e) => panic!(e)
            }
            self.samples_read = 0;
        }

        for i in (0 .. self.num_channels) {
            outputs[i] = self.buffer[self.samples_read*self.num_channels + i];
        }
        self.samples_read += 1;
    }
}

/// Writes audio to the OS's default output device.
pub struct AudioOut {
    #[allow(dead_code)] // the engine is used as an RAII marker
    engine: Rc<AudioEngineMarker>,
    pa_stream: portaudio::pa::Stream<Sample, Sample>,
    num_channels: usize,
    buffer: Vec<Sample>,
    samples_written: usize,
}

impl AudioOut {
    /// Opens an output stream writing `num_channels` outputs.
    fn new(engine: Rc<AudioEngineMarker>, num_channels: usize) -> AudioOut {
        // Open a stream in blocking mode
        let mut pa_stream = portaudio::pa::Stream::new();
        pa_stream.open_default(SAMPLE_RATE as f64, BUFFER_SIZE as u32,
                               0i32, num_channels as i32,
                               PORTAUDIO_T, None).unwrap();
        pa_stream.start().unwrap();

        AudioOut {
            engine: engine,
            pa_stream: pa_stream,
            num_channels: num_channels,
            buffer: Vec::with_capacity(num_channels*BUFFER_SIZE),
            samples_written: 0,
        }
    }
}

impl Drop for AudioOut {
    fn drop(&mut self) {
        self.pa_stream.stop().unwrap();
        self.pa_stream.close().unwrap();
    }
}

impl AudioDevice for AudioOut {
    fn num_inputs(&self) -> usize {
        self.num_channels
    }

    fn num_outputs(&self) -> usize {
        0
    }

    fn tick(&mut self, _: Time, inputs: &[Sample], _: &mut[Sample]) {
        for s in inputs.iter() {
            let mut clipped = *s;
            if clipped > 1.0 { clipped = 1.0; }
            if clipped < -1.0 { clipped = -1.0; }
            self.buffer.push(clipped)
        }
        self.samples_written += 1;

        if self.samples_written == BUFFER_SIZE {
            self.pa_stream.write(self.buffer.clone(),
                                 BUFFER_SIZE as u32).unwrap();
            self.samples_written = 0;
            self.buffer.clear()
        }
    }
}
<commit_msg>Remove allocation from AudioIn<commit_after>//! Provides audio IO from OS sound devices.

extern crate portaudio;

use std::rc::Rc;

use types::{SAMPLE_RATE, AudioDevice, Sample, Time};

/// Defines the audio format for Portaudio.
static PORTAUDIO_T: portaudio::pa::SampleFormat =
    portaudio::pa::SampleFormat::Float32;

/// Defines the buffer size for Portaudio
static BUFFER_SIZE: usize = 256;

/// The AudioEnginer opens and manages the resources associated with portaudio.
/// It is used open new input/output streams and safely free them.
pub struct AudioEngine {
    marker: Rc<AudioEngineMarker>
}

impl AudioEngine {
    pub fn open() -> Result<AudioEngine, String> {
        match portaudio::pa::initialize() {
            Ok(()) => Ok(AudioEngine { marker: Rc::new(AudioEngineMarker) }),
            Err(e) => Err(portaudio::pa::get_error_text(e))
        }
    }

    pub fn default_input(&self, num_channels: usize) -> AudioIn {
        AudioIn::new(self.marker.clone(), num_channels)
    }

    pub fn default_output(&self, num_channels: usize) -> AudioOut {
        AudioOut::new(self.marker.clone(), num_channels)
    }
}

/// This empty struct is used as a RAII marker for an initialized portaudio
/// connection. It is held in a Rc, and copies are passed to all streams opened
/// with it.
struct AudioEngineMarker;
impl Drop for AudioEngineMarker {
    fn drop(&mut self)
    {
        portaudio::pa::terminate().unwrap();
    }
}

/// Reads audio from the OS's default input device.
pub struct AudioIn {
    #[allow(dead_code)] // the engine is used as an RAII marker
    engine: Rc<AudioEngineMarker>,
    pa_stream: portaudio::pa::Stream<Sample, Sample>,
    num_channels: usize,
    buffer: Vec<Sample>,
    samples_read: usize,
}

impl AudioIn {
    /// Opens an audio input stream reading `num_channels` inputs.
    fn new(engine: Rc<AudioEngineMarker>, num_channels: usize) -> AudioIn {
        // Open a stream in blocking mode
        let mut pa_stream = portaudio::pa::Stream::new();
        pa_stream.open_default(SAMPLE_RATE as f64, BUFFER_SIZE as u32,
                               num_channels as i32, 0i32,
                               PORTAUDIO_T, None).unwrap();
        pa_stream.start().unwrap();

        let buf_size = num_channels*BUFFER_SIZE;
        let mut buffer = Vec::with_capacity(buf_size);
        for _ in 0..buf_size {
            buffer.push(0.0);
        }

        AudioIn {
            engine: engine,
            pa_stream: pa_stream,
            num_channels: num_channels,
            buffer: buffer,
            samples_read: BUFFER_SIZE,
        }
    }
}

impl Drop for AudioIn {
    fn drop(&mut self) {
        self.pa_stream.stop().unwrap();
        self.pa_stream.close().unwrap();
    }
}

impl AudioDevice for AudioIn {
    fn num_inputs(&self) -> usize {
        0
    }

    fn num_outputs(&self) -> usize {
        self.num_channels
    }

    fn tick(&mut self, _: Time, _: &[Sample], outputs: &mut[Sample]) {
        if self.samples_read == BUFFER_SIZE {
            let num_read = self.num_channels * BUFFER_SIZE;
            let result = self.pa_stream.read(num_read as u32).unwrap();
            for (i, &s) in result.iter().enumerate() {
                self.buffer[i] = s;
            }
            self.samples_read = 0;
        }

        for i in (0 .. self.num_channels) {
            outputs[i] = self.buffer[self.samples_read*self.num_channels + i];
        }
        self.samples_read += 1;
    }
}

/// Writes audio to the OS's default output device.
pub struct AudioOut {
    #[allow(dead_code)] // the engine is used as an RAII marker
    engine: Rc<AudioEngineMarker>,
    pa_stream: portaudio::pa::Stream<Sample, Sample>,
    num_channels: usize,
    buffer: Vec<Sample>,
    samples_written: usize,
}

impl AudioOut {
    /// Opens an output stream writing `num_channels` outputs.
    fn new(engine: Rc<AudioEngineMarker>, num_channels: usize) -> AudioOut {
        // Open a stream in blocking mode
        let mut pa_stream = portaudio::pa::Stream::new();
        pa_stream.open_default(SAMPLE_RATE as f64, BUFFER_SIZE as u32,
                               0i32, num_channels as i32,
                               PORTAUDIO_T, None).unwrap();
        pa_stream.start().unwrap();

        AudioOut {
            engine: engine,
            pa_stream: pa_stream,
            num_channels: num_channels,
            buffer: Vec::with_capacity(num_channels*BUFFER_SIZE),
            samples_written: 0,
        }
    }
}

impl Drop for AudioOut {
    fn drop(&mut self) {
        self.pa_stream.stop().unwrap();
        self.pa_stream.close().unwrap();
    }
}

impl AudioDevice for AudioOut {
    fn num_inputs(&self) -> usize {
        self.num_channels
    }

    fn num_outputs(&self) -> usize {
        0
    }

    fn tick(&mut self, _: Time, inputs: &[Sample], _: &mut[Sample]) {
        for s in inputs.iter() {
            let mut clipped = *s;
            if clipped > 1.0 { clipped = 1.0; }
            if clipped < -1.0 { clipped = -1.0; }
            self.buffer.push(clipped)
        }
        self.samples_written += 1;

        if self.samples_written == BUFFER_SIZE {
            self.pa_stream.write(self.buffer.clone(),
                                 BUFFER_SIZE as u32).unwrap();
            self.samples_written = 0;
            self.buffer.clear()
        }
    }
}
<|endoftext|>


<commit_before>//! Iterate over atoms in components.

use coord::Coord;
use system::Residue;

use mdio;

use std::cell::RefCell;
use std::rc::Rc;
use std::slice::Iter;

/// Iteration object which owns the iterator. Used to ensure that it always exists.
///
/// May be unnecessary, should test sometime.
pub struct ConfIter<'a> {
    /// The iterator over residues inside the borrowed configuration.
    iter: mdio::ResidueIter<'a>,
}

impl<'a> ConfIter<'a> {
    /// Create an iteration object from an input configuration which owns the iterator.
    pub fn new(conf: &'a mdio::Conf) -> ConfIter<'a> {
        ConfIter {
            iter: conf.iter_residues(),
        }
    }
}

pub enum ResidueIter<'a> {
    Conf(ConfIter<'a>),
    Component(&'a Residue, Iter<'a, Coord>),
    None,
}

#[derive(Debug, Clone)]
pub enum ResidueIterOut {
    FromConf(Vec<Rc<RefCell<mdio::Atom>>>),
    FromComp(Rc<RefCell<String>>, Vec<(Rc<RefCell<String>>, Coord)>),
}

impl ResidueIterOut {
    /// Return a reference counted pointer to the residue name.
    pub fn get_residue(&self) -> Rc<RefCell<String>> {
        match self {
            &ResidueIterOut::FromConf(ref atoms) => {
                let atom = Rc::clone(&atoms[0]);
                let residue = Rc::clone(&atom.borrow().residue);
                let name = Rc::clone(&residue.borrow().name);

                Rc::clone(&name)
            },
            &ResidueIterOut::FromComp(ref res, _) => Rc::clone(&res),
        }
    }

    /// Return a list of the atoms in the residue. The atom names are pointers.
    pub fn get_atoms(&self) -> Vec<(Rc<RefCell<String>>, Coord)> {
        match self {
            &ResidueIterOut::FromConf(ref atoms) => {
                atoms
                    .iter()
                    .map(|atom| (Rc::clone(&atom.borrow().name), Coord::from(atom.borrow().position)))
                    .collect()
            },
            &ResidueIterOut::FromComp(_, ref atoms) => atoms.clone(),
        }
    }
}

impl<'a> Iterator for ResidueIter<'a> {
    type Item = ResidueIterOut;

    fn next(&mut self) -> Option<Self::Item> {
        match self {
            &mut ResidueIter::None => None,
            &mut ResidueIter::Conf(ref mut conf_iter) => {
                conf_iter.iter
                    .next()
                    .map(|res| res.unwrap())
                    .map(|res| {
                        ResidueIterOut::FromConf(res.into_iter().map(|atom| {
                            Rc::new(RefCell::new(atom))
                        }).collect())
                    })
            },
            &mut ResidueIter::Component(ref res, ref mut iter) => {
                iter.next()
                    .map(|&coord| ResidueIterOut::FromComp(
                        Rc::new(RefCell::new(res.code.clone())),
                        res.atoms
                            .iter()
                            .map(|atom| (
                                Rc::new(RefCell::new(atom.code.clone())),
                                atom.position + coord
                            ))
                            .collect::<Vec<_>>()
                    ))
            },
        }
    }
}
<commit_msg>Reformat code in `iterator.rs`<commit_after>//! Iterate over atoms in components.

use coord::Coord;
use system::Residue;

use mdio;

use std::cell::RefCell;
use std::rc::Rc;
use std::slice::Iter;

/// Iteration object which owns the iterator. Used to ensure that it always exists.
///
/// May be unnecessary, should test sometime.
pub struct ConfIter<'a> {
    /// The iterator over residues inside the borrowed configuration.
    iter: mdio::ResidueIter<'a>,
}

impl<'a> ConfIter<'a> {
    /// Create an iteration object from an input configuration which owns the iterator.
    pub fn new(conf: &'a mdio::Conf) -> ConfIter<'a> {
        ConfIter {
            iter: conf.iter_residues(),
        }
    }
}

pub enum ResidueIter<'a> {
    Conf(ConfIter<'a>),
    Component(&'a Residue, Iter<'a, Coord>),
    None,
}

#[derive(Debug, Clone)]
pub enum ResidueIterOut {
    FromConf(Vec<Rc<RefCell<mdio::Atom>>>),
    FromComp(Rc<RefCell<String>>, Vec<(Rc<RefCell<String>>, Coord)>),
}

impl ResidueIterOut {
    /// Return a reference counted pointer to the residue name.
    pub fn get_residue(&self) -> Rc<RefCell<String>> {
        match self {
            &ResidueIterOut::FromConf(ref atoms) => {
                let atom = Rc::clone(&atoms[0]);
                let residue = Rc::clone(&atom.borrow().residue);
                let name = Rc::clone(&residue.borrow().name);

                Rc::clone(&name)
            }
            &ResidueIterOut::FromComp(ref res, _) => Rc::clone(&res),
        }
    }

    /// Return a list of the atoms in the residue. The atom names are pointers.
    pub fn get_atoms(&self) -> Vec<(Rc<RefCell<String>>, Coord)> {
        match self {
            &ResidueIterOut::FromConf(ref atoms) => atoms
                .iter()
                .map(|atom| {
                    (
                        Rc::clone(&atom.borrow().name),
                        Coord::from(atom.borrow().position),
                    )
                })
                .collect(),
            &ResidueIterOut::FromComp(_, ref atoms) => atoms.clone(),
        }
    }
}

impl<'a> Iterator for ResidueIter<'a> {
    type Item = ResidueIterOut;

    fn next(&mut self) -> Option<Self::Item> {
        match self {
            &mut ResidueIter::None => None,
            &mut ResidueIter::Conf(ref mut conf_iter) => {
                conf_iter.iter.next().map(|res| res.unwrap()).map(|res| {
                    ResidueIterOut::FromConf(
                        res.into_iter()
                            .map(|atom| Rc::new(RefCell::new(atom)))
                            .collect(),
                    )
                })
            }
            &mut ResidueIter::Component(ref res, ref mut iter) => iter.next().map(|&coord| {
                ResidueIterOut::FromComp(
                    Rc::new(RefCell::new(res.code.clone())),
                    res.atoms
                        .iter()
                        .map(|atom| {
                            (
                                Rc::new(RefCell::new(atom.code.clone())),
                                atom.position + coord,
                            )
                        })
                        .collect::<Vec<_>>(),
                )
            }),
        }
    }
}
<|endoftext|>