<commit_before>use std::io::{Read, Chars, CharsError};
use std::borrow::Cow;
use std::fmt;
use std::char;

use num::Num;

use error::{ParserError, ParserErrorKind, StreamError};

/// Token types
#[derive(PartialEq)]
pub enum Token {
    /// `(`
    OpenParen,
    /// `)`
    CloseParen,
    /// `[`
    OpenBracket,
    /// `]`
    CloseBracket,
    /// `#(`
    OpenVectorParen,
    /// `#vu8(`
    OpenBytesParen,
    /// `.`
    Dot,
    /// `'`
    Quote,
    /// `\``
    QuasiQuote,
    /// `,`
    Comma,
    /// `,@`
    UnquoteSplicing,
    Identifier(Cow<'static, str>),
    /// `#t`
    True,
    /// `#f`
    False,
    /// `#\<String>`
    Character(String),
    String(String),
    Numeric(String),
    /// End of character stream
    EOF
}

impl fmt::Debug for Token {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Token::OpenParen => write!(f, "OpenParen"),
            Token::OpenVectorParen => write!(f, "OpenVectorParen"),
            Token::OpenBytesParen => write!(f, "OpenBytesParen"),
            Token::CloseParen => write!(f, "CloseParen"),
            Token::OpenBracket => write!(f, "OpenBracket"),
            Token::CloseBracket => write!(f, "CloseBracket"),
            Token::Dot => write!(f, "Dot"),
            Token::Quote => write!(f, "Quote"),
            Token::QuasiQuote => write!(f, "QuasiQuote"),
            Token::Comma => write!(f, "Comma"),
            Token::UnquoteSplicing => write!(f, "UnquoteSplicing"),
            Token::Identifier(ref name) => write!(f, "Identifier({})", name),
            Token::True => write!(f, "#t"),
            Token::False => write!(f, "#f"),
            Token::Character(ref name) => write!(f, "#\\{}", name),
            Token::Numeric(ref rep) => rep.fmt(f),
            Token::String(ref rep) => write!(f, "{:?}", rep),
            Token::EOF => write!(f, "EOF"),
        }
    }
}

/// TokenWrapper provides positional information to each token
pub struct TokenWrapper {
    pub line: usize,
    pub column: usize,
    pub token: Token
}

fn wrap(line: usize, column: usize, t: Token) -> TokenWrapper {
    TokenWrapper {
        line: line,
        column: column,
        token: t
    }
}

fn is_whitespace(c: char) -> bool {
    match c {
        '\t' | '\n' | '\x0b' | '\x0c' | '\r' | ' ' => true,
        _ => false
    }
}

fn is_initial(c: char) -> bool {
    match c {
        'a'...'z' | 'A'...'Z' | '!' | '$' | '%' | '&' | '*' | '/' | ':' | '<' | '=' | '>' | '?' | '^' | '_' | '~' => true,
        _ => false
    }
}

fn is_subsequent(c: char) -> bool {
    if is_initial(c) {
        true
    } else {
        match c {
            '0'...'9' | '+' | '-' | '.' | '@' => true,
            _ => false
        }
    }
}

fn is_delim(c: char) -> bool {
    match c {
        '(' | ')' | '[' | ']' | '"' | ';' => true,
        _ => c.is_whitespace()
    }
}

/// Lexer transforms character stream into a token stream
pub struct Lexer<R> {
    line: usize,
    column: usize,
    stream: Chars<R>,
    lookahead_buf: Option<char>,
}

macro_rules! try_consume {
    ($this:ident) => (
        match $this.consume() {
            Some(Ok(c)) => c,
            Some(Err(e)) => return Err($this.make_error(ParserErrorKind::UnderlyingError(StreamError(e)))),
            None => return Err($this.make_error(ParserErrorKind::UnexpectedEOF))
        }
    )
}

impl <R: Read + Sized> Lexer<R> {
    /// Creates new Lexer from io::Buffer
    pub fn new(stream: R) -> Lexer<R> {
        Lexer {
            line: 1,
            column: 1,
            stream: stream.chars(),
            lookahead_buf: None,
        }
    }

    pub fn lex_token(&mut self) -> Result<TokenWrapper, ParserError> {
        try!(self.consume_whitespace());

        let line = self.line;
        let col = self.column;

        let token = try!(self.lex());

        try!(self.consume_whitespace());

        Ok(wrap(line, col, token))
    }

    /// return next token
    fn lex(&mut self) -> Result<Token, ParserError> {
        let c = match try!(self.consume_eof()) {
            Some(c) => c,
            None => return Ok(Token::EOF)
        };

        let end_of_token = try!(self.is_end_of_token());

        if is_initial(c) {
            let mut init = String::new();
            init.push(c);
            self.lex_ident(init).map(|s| Token::Identifier(Cow::Owned(s)))
        } else if c == '+' {
            if end_of_token {
                Ok(Token::Identifier(Cow::Borrowed("+")))
            } else {
                self.lex_numeric("+".to_string()).map(Token::Numeric)
            }
        } else if c == '-' {
            if end_of_token {
                Ok(Token::Identifier(Cow::Borrowed("-")))
            } else {
                match try!(self.lookahead()) {
                    Some('>') => self.lex_ident("-".to_string()).map(|s| Token::Identifier(Cow::Owned(s))),
                    Some(_) => self.lex_numeric("-".to_string()).map(Token::Numeric),
                    None => Ok(Token::Identifier(Cow::Borrowed("-")))
                }
            }
        } else if c == ',' {
            match try!(self.lookahead()) {
                Some('@') => {
                    self.consume().expect("lookahead buffer error");
                    Ok(Token::UnquoteSplicing)
                },
                _ => Ok(Token::Comma)
            }
        } else if c == '(' {
            Ok(Token::OpenParen)
        } else if c == ')' {
            Ok(Token::CloseParen)
        } else if c == '[' {
            Ok(Token::OpenBracket)
        } else if c == ']' {
            Ok(Token::CloseBracket)
        } else if c == '.' {
            if end_of_token {
                Ok(Token::Dot)
            } else {
                let rest_prefix = try!(self.read_while(|c| !is_delim(c)));
                if rest_prefix == ".." {
                    Ok(Token::Identifier(Cow::Borrowed("...")))
                } else {
                    Err(self.make_error(ParserErrorKind::InvalidToken(format!("{}{}", c, rest_prefix))))
                }
            }
        } else if c == '\'' {
            Ok(Token::Quote)
        } else if c == '`' {
            Ok(Token::QuasiQuote)
        } else if c == '#' {
            let c0 = try!(self.consume());
            match c0 {
                't' | 'T' => Ok(Token::True),
                'f' | 'F' => Ok(Token::False),
                'b' | 'B' | 'o' | 'O' | 'd' | 'D' | 'x' | 'X' | 'i' | 'I' | 'e' | 'E' => {
                    let s = format!("{}{}", c, c0);
                    self.lex_numeric(s).map(Token::Numeric)
                },
                'v' | 'u' => {
                    let rest_prefix = try!(self.read_while(|c| !is_delim(c)));
                    let delim = try!(self.consume());
                    let prefix = format!("{}{}{}", c0, rest_prefix, delim);
                    match prefix.as_ref() {
                        "vu8(" | "u8(" =>
                            Ok(Token::OpenBytesParen),
                        _ =>
                            Err(self.make_error(ParserErrorKind::InvalidToken(prefix)))
                    }
                },
                '\\' => self.lex_char().map(Token::Character),
                '(' => Ok(Token::OpenVectorParen),
                _ => Err(self.make_error(ParserErrorKind::InvalidToken(format!("#{}", c))))
            }
        } else if c == '"' {
            self.lex_string().map(Token::String)
        } else if c.is_numeric() {
            let s = format!("{}", c);
            self.lex_numeric(s).map(Token::Numeric)
        } else {
            Err(self.make_error(ParserErrorKind::InvalidCharacter(c)))
        }
    }

    fn is_end_of_token(&mut self) -> Result<bool, ParserError> {
        match try!(self.lookahead()) {
            Some(c) => Ok(is_whitespace(c) || is_delim(c)),
            None => Ok(true)
        }
    }

    fn lex_ident(&mut self, initial: String) -> Result<String, ParserError> {
        let mut s = initial;
        let sub = try!(self.read_while(is_subsequent));
        s.push_str(sub.as_ref());
        return Ok(s);
    }

    fn lex_char(&mut self) -> Result<String, ParserError> {
        let c = try!(self.consume());
        let mut s = String::new();
        s.push(c);
        let sub = try!(self.read_while(|c| c.is_alphanumeric()));
        s.push_str(sub.as_ref());
        return Ok(s);
    }

    fn lex_string(&mut self) -> Result<String, ParserError> {
        let mut s = String::new();
        loop {
            match try!(self.consume()) {
                '"' => return Ok(s),
                '\\' => match try!(self.consume()) {
                    'a' => s.push('\x07'),
                    'b' => s.push('\x08'),
                    't' => s.push('\t'),
                    'n' => s.push('\n'),
                    'v' => s.push('\x0b'),
                    'f' => s.push('\x0c'),
                    'r' => s.push('\r'),
                    '"' => s.push('"'),
                    '\\' => s.push('\\'),
                    'x' => {
                        let hex_str = try!(self.read_while(|c| c != ';'));
                        if try!(self.consume()) != ';' {
                            panic!("read_while error");
                        }
                        if hex_str.len() == 0 {
                            return Err(self.make_error(ParserErrorKind::InvalidStringEscape(hex_str)))
                        }
                        let code = match Num::from_str_radix(hex_str.as_ref(), 16) {
                            Ok(n) => n,
                            Err(_) => return Err(self.make_error(ParserErrorKind::InvalidStringEscape(hex_str)))
                        };
                        match char::from_u32(code) {
                            Some(c) => s.push(c),
                            None => return Err(self.make_error(ParserErrorKind::InvalidUnicodeRange(code)))
                        }
                    },
                    c =>
                        if c.is_whitespace() {
                            try!(self.read_while(|c| c != '\n' && c.is_whitespace()));
                            if c != '\n' {
                                if let '\n' = try!(self.consume()) {
                                    try!(self.read_while(|c| c != '\n' && c.is_whitespace()));
                                } else {
                                    return Err(self.make_error(ParserErrorKind::InvalidStringLiteral))
                                }
                            }
                        } else {
                            return Err(self.make_error(ParserErrorKind::InvalidStringEscape(format!("{}", c))))
                        }
                },
                c => s.push(c),
            }
        }
    }

    fn lex_numeric(&mut self, init: String) -> Result<String, ParserError> {
        let mut s = init;
        let sub = try!(self.read_while(|c| !is_delim(c)));
        s.push_str(sub.as_ref());
        return Ok(s);
    }

    fn make_error(&self, kind: ParserErrorKind) -> ParserError {
        ParserError {
            line: self.line,
            column: self.column,
            kind: kind
        }
    }

    fn lookahead(&mut self) -> Result<Option<char>, CharsError> {
        match self.lookahead_buf {
            Some(c) => Ok(Some(c)),
            None => {
                match self.stream.next() {
                    Some(Ok(ch)) => {
                        self.lookahead_buf = Some(ch);
                        Ok(Some(ch))
                    },
                    Some(Err(e)) => {
                        Err(e)
                    },
                    None => {
                        Ok(None)
                    }
                }
            }
        }
    }

    fn advance(&mut self, c: char) {
        if c == '\n' {
            self.line += 1;
            self.column = 1;
        } else {
            self.column += 1;
        }
    }

    fn read_while<F>(&mut self, f: F) -> Result<String, ParserError> where
        F: Fn(char) -> bool
    {
        let mut s = match self.lookahead_buf {
            None => String::new(),
            Some(c) => if f(c) {
                self.lookahead_buf = None;
                self.advance(c);
                let mut s = String::new();
                s.push(c);
                s
            } else {
                return Ok(String::new());
            }
        };

        loop {
            match self.stream.next() {
                Some(Ok(c)) => if f(c) {
                    self.advance(c);
                    s.push(c);
                } else {
                    self.lookahead_buf = Some(c);
                    return Ok(s);
                },
                Some(Err(e)) =>
                    return Err(self.make_error(ParserErrorKind::UnderlyingError(StreamError(e)))),
                None => return Ok(s)
            }
        }
    }

    fn consume_eof(&mut self) -> Result<Option<char>, CharsError> {
        let c = match self.lookahead_buf {
            Some(c) => {
                self.lookahead_buf = None;
                Some(Ok(c))
            },
            None => self.stream.next()
        };

        match c {
            Some(Ok(ch)) => {
                self.advance(ch);
                Ok(Some(ch))
            },
            Some(Err(e)) => Err(e),
            None => Ok(None)
        }
    }

    fn consume(&mut self) -> Result<char, ParserError> {
        match try!(self.consume_eof()) {
            Some(c) => Ok(c),
            None => return Err(self.make_error(ParserErrorKind::UnexpectedEOF))
        }
    }

    fn consume_whitespace(&mut self) -> Result<bool, ParserError> {
        let mut consumed = false;
        loop {
            let whitespace = try!(self.read_while(is_whitespace));
            consumed = consumed || whitespace.len() > 0;
            if let Some(';') = try!(self.lookahead()) {
                consumed = true;
                try!(self.read_while(|c| c != '\n'));
                if self.lookahead_buf.is_some() {
                    self.lookahead_buf = None;
                }
            } else {
                return Ok(consumed);
            }
        }
    }
}
<commit_msg># is a delimiter<commit_after>use std::io::{Read, Chars, CharsError};
use std::borrow::Cow;
use std::fmt;
use std::char;

use num::Num;

use error::{ParserError, ParserErrorKind, StreamError};

/// Token types
#[derive(PartialEq)]
pub enum Token {
    /// `(`
    OpenParen,
    /// `)`
    CloseParen,
    /// `[`
    OpenBracket,
    /// `]`
    CloseBracket,
    /// `#(`
    OpenVectorParen,
    /// `#vu8(`
    OpenBytesParen,
    /// `.`
    Dot,
    /// `'`
    Quote,
    /// `\``
    QuasiQuote,
    /// `,`
    Comma,
    /// `,@`
    UnquoteSplicing,
    Identifier(Cow<'static, str>),
    /// `#t`
    True,
    /// `#f`
    False,
    /// `#\<String>`
    Character(String),
    String(String),
    Numeric(String),
    /// End of character stream
    EOF
}

impl fmt::Debug for Token {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Token::OpenParen => write!(f, "OpenParen"),
            Token::OpenVectorParen => write!(f, "OpenVectorParen"),
            Token::OpenBytesParen => write!(f, "OpenBytesParen"),
            Token::CloseParen => write!(f, "CloseParen"),
            Token::OpenBracket => write!(f, "OpenBracket"),
            Token::CloseBracket => write!(f, "CloseBracket"),
            Token::Dot => write!(f, "Dot"),
            Token::Quote => write!(f, "Quote"),
            Token::QuasiQuote => write!(f, "QuasiQuote"),
            Token::Comma => write!(f, "Comma"),
            Token::UnquoteSplicing => write!(f, "UnquoteSplicing"),
            Token::Identifier(ref name) => write!(f, "Identifier({})", name),
            Token::True => write!(f, "#t"),
            Token::False => write!(f, "#f"),
            Token::Character(ref name) => write!(f, "#\\{}", name),
            Token::Numeric(ref rep) => rep.fmt(f),
            Token::String(ref rep) => write!(f, "{:?}", rep),
            Token::EOF => write!(f, "EOF"),
        }
    }
}

/// TokenWrapper provides positional information to each token
pub struct TokenWrapper {
    pub line: usize,
    pub column: usize,
    pub token: Token
}

fn wrap(line: usize, column: usize, t: Token) -> TokenWrapper {
    TokenWrapper {
        line: line,
        column: column,
        token: t
    }
}

fn is_whitespace(c: char) -> bool {
    match c {
        '\t' | '\n' | '\x0b' | '\x0c' | '\r' | ' ' => true,
        _ => false
    }
}

fn is_initial(c: char) -> bool {
    match c {
        'a'...'z' | 'A'...'Z' | '!' | '$' | '%' | '&' | '*' | '/' | ':' | '<' | '=' | '>' | '?' | '^' | '_' | '~' => true,
        _ => false
    }
}

fn is_subsequent(c: char) -> bool {
    if is_initial(c) {
        true
    } else {
        match c {
            '0'...'9' | '+' | '-' | '.' | '@' => true,
            _ => false
        }
    }
}

fn is_delim(c: char) -> bool {
    match c {
        '(' | ')' | '[' | ']' | '"' | ';' | '#' => true,
        _ => c.is_whitespace()
    }
}

/// Lexer transforms character stream into a token stream
pub struct Lexer<R> {
    line: usize,
    column: usize,
    stream: Chars<R>,
    lookahead_buf: Option<char>,
}

macro_rules! try_consume {
    ($this:ident) => (
        match $this.consume() {
            Some(Ok(c)) => c,
            Some(Err(e)) => return Err($this.make_error(ParserErrorKind::UnderlyingError(StreamError(e)))),
            None => return Err($this.make_error(ParserErrorKind::UnexpectedEOF))
        }
    )
}

impl <R: Read + Sized> Lexer<R> {
    /// Creates new Lexer from io::Buffer
    pub fn new(stream: R) -> Lexer<R> {
        Lexer {
            line: 1,
            column: 1,
            stream: stream.chars(),
            lookahead_buf: None,
        }
    }

    pub fn lex_token(&mut self) -> Result<TokenWrapper, ParserError> {
        try!(self.consume_whitespace());

        let line = self.line;
        let col = self.column;

        let token = try!(self.lex());

        try!(self.consume_whitespace());

        Ok(wrap(line, col, token))
    }

    /// return next token
    fn lex(&mut self) -> Result<Token, ParserError> {
        let c = match try!(self.consume_eof()) {
            Some(c) => c,
            None => return Ok(Token::EOF)
        };

        let end_of_token = try!(self.is_end_of_token());

        if is_initial(c) {
            let mut init = String::new();
            init.push(c);
            self.lex_ident(init).map(|s| Token::Identifier(Cow::Owned(s)))
        } else if c == '+' {
            if end_of_token {
                Ok(Token::Identifier(Cow::Borrowed("+")))
            } else {
                self.lex_numeric("+".to_string()).map(Token::Numeric)
            }
        } else if c == '-' {
            if end_of_token {
                Ok(Token::Identifier(Cow::Borrowed("-")))
            } else {
                match try!(self.lookahead()) {
                    Some('>') => self.lex_ident("-".to_string()).map(|s| Token::Identifier(Cow::Owned(s))),
                    Some(_) => self.lex_numeric("-".to_string()).map(Token::Numeric),
                    None => Ok(Token::Identifier(Cow::Borrowed("-")))
                }
            }
        } else if c == ',' {
            match try!(self.lookahead()) {
                Some('@') => {
                    self.consume().expect("lookahead buffer error");
                    Ok(Token::UnquoteSplicing)
                },
                _ => Ok(Token::Comma)
            }
        } else if c == '(' {
            Ok(Token::OpenParen)
        } else if c == ')' {
            Ok(Token::CloseParen)
        } else if c == '[' {
            Ok(Token::OpenBracket)
        } else if c == ']' {
            Ok(Token::CloseBracket)
        } else if c == '.' {
            if end_of_token {
                Ok(Token::Dot)
            } else {
                let rest_prefix = try!(self.read_while(|c| !is_delim(c)));
                if rest_prefix == ".." {
                    Ok(Token::Identifier(Cow::Borrowed("...")))
                } else {
                    Err(self.make_error(ParserErrorKind::InvalidToken(format!("{}{}", c, rest_prefix))))
                }
            }
        } else if c == '\'' {
            Ok(Token::Quote)
        } else if c == '`' {
            Ok(Token::QuasiQuote)
        } else if c == '#' {
            let c0 = try!(self.consume());
            match c0 {
                't' | 'T' => Ok(Token::True),
                'f' | 'F' => Ok(Token::False),
                'b' | 'B' | 'o' | 'O' | 'd' | 'D' | 'x' | 'X' | 'i' | 'I' | 'e' | 'E' => {
                    let s = format!("{}{}", c, c0);
                    self.lex_numeric(s).map(Token::Numeric)
                },
                'v' | 'u' => {
                    let rest_prefix = try!(self.read_while(|c| !is_delim(c)));
                    let delim = try!(self.consume());
                    let prefix = format!("{}{}{}", c0, rest_prefix, delim);
                    match prefix.as_ref() {
                        "vu8(" | "u8(" =>
                            Ok(Token::OpenBytesParen),
                        _ =>
                            Err(self.make_error(ParserErrorKind::InvalidToken(prefix)))
                    }
                },
                '\\' => self.lex_char().map(Token::Character),
                '(' => Ok(Token::OpenVectorParen),
                _ => Err(self.make_error(ParserErrorKind::InvalidToken(format!("#{}", c))))
            }
        } else if c == '"' {
            self.lex_string().map(Token::String)
        } else if c.is_numeric() {
            let s = format!("{}", c);
            self.lex_numeric(s).map(Token::Numeric)
        } else {
            Err(self.make_error(ParserErrorKind::InvalidCharacter(c)))
        }
    }

    fn is_end_of_token(&mut self) -> Result<bool, ParserError> {
        match try!(self.lookahead()) {
            Some(c) => Ok(is_whitespace(c) || is_delim(c)),
            None => Ok(true)
        }
    }

    fn lex_ident(&mut self, initial: String) -> Result<String, ParserError> {
        let mut s = initial;
        let sub = try!(self.read_while(is_subsequent));
        s.push_str(sub.as_ref());
        return Ok(s);
    }

    fn lex_char(&mut self) -> Result<String, ParserError> {
        let c = try!(self.consume());
        let mut s = String::new();
        s.push(c);
        let sub = try!(self.read_while(|c| c.is_alphanumeric()));
        s.push_str(sub.as_ref());
        return Ok(s);
    }

    fn lex_string(&mut self) -> Result<String, ParserError> {
        let mut s = String::new();
        loop {
            match try!(self.consume()) {
                '"' => return Ok(s),
                '\\' => match try!(self.consume()) {
                    'a' => s.push('\x07'),
                    'b' => s.push('\x08'),
                    't' => s.push('\t'),
                    'n' => s.push('\n'),
                    'v' => s.push('\x0b'),
                    'f' => s.push('\x0c'),
                    'r' => s.push('\r'),
                    '"' => s.push('"'),
                    '\\' => s.push('\\'),
                    'x' => {
                        let hex_str = try!(self.read_while(|c| c != ';'));
                        if try!(self.consume()) != ';' {
                            panic!("read_while error");
                        }
                        if hex_str.len() == 0 {
                            return Err(self.make_error(ParserErrorKind::InvalidStringEscape(hex_str)))
                        }
                        let code = match Num::from_str_radix(hex_str.as_ref(), 16) {
                            Ok(n) => n,
                            Err(_) => return Err(self.make_error(ParserErrorKind::InvalidStringEscape(hex_str)))
                        };
                        match char::from_u32(code) {
                            Some(c) => s.push(c),
                            None => return Err(self.make_error(ParserErrorKind::InvalidUnicodeRange(code)))
                        }
                    },
                    c =>
                        if c.is_whitespace() {
                            try!(self.read_while(|c| c != '\n' && c.is_whitespace()));
                            if c != '\n' {
                                if let '\n' = try!(self.consume()) {
                                    try!(self.read_while(|c| c != '\n' && c.is_whitespace()));
                                } else {
                                    return Err(self.make_error(ParserErrorKind::InvalidStringLiteral))
                                }
                            }
                        } else {
                            return Err(self.make_error(ParserErrorKind::InvalidStringEscape(format!("{}", c))))
                        }
                },
                c => s.push(c),
            }
        }
    }

    fn lex_numeric(&mut self, init: String) -> Result<String, ParserError> {
        let mut s = init;
        let sub = try!(self.read_while(|c| !is_delim(c)));
        s.push_str(sub.as_ref());
        return Ok(s);
    }

    fn make_error(&self, kind: ParserErrorKind) -> ParserError {
        ParserError {
            line: self.line,
            column: self.column,
            kind: kind
        }
    }

    fn lookahead(&mut self) -> Result<Option<char>, CharsError> {
        match self.lookahead_buf {
            Some(c) => Ok(Some(c)),
            None => {
                match self.stream.next() {
                    Some(Ok(ch)) => {
                        self.lookahead_buf = Some(ch);
                        Ok(Some(ch))
                    },
                    Some(Err(e)) => {
                        Err(e)
                    },
                    None => {
                        Ok(None)
                    }
                }
            }
        }
    }

    fn advance(&mut self, c: char) {
        if c == '\n' {
            self.line += 1;
            self.column = 1;
        } else {
            self.column += 1;
        }
    }

    fn read_while<F>(&mut self, f: F) -> Result<String, ParserError> where
        F: Fn(char) -> bool
    {
        let mut s = match self.lookahead_buf {
            None => String::new(),
            Some(c) => if f(c) {
                self.lookahead_buf = None;
                self.advance(c);
                let mut s = String::new();
                s.push(c);
                s
            } else {
                return Ok(String::new());
            }
        };

        loop {
            match self.stream.next() {
                Some(Ok(c)) => if f(c) {
                    self.advance(c);
                    s.push(c);
                } else {
                    self.lookahead_buf = Some(c);
                    return Ok(s);
                },
                Some(Err(e)) =>
                    return Err(self.make_error(ParserErrorKind::UnderlyingError(StreamError(e)))),
                None => return Ok(s)
            }
        }
    }

    fn consume_eof(&mut self) -> Result<Option<char>, CharsError> {
        let c = match self.lookahead_buf {
            Some(c) => {
                self.lookahead_buf = None;
                Some(Ok(c))
            },
            None => self.stream.next()
        };

        match c {
            Some(Ok(ch)) => {
                self.advance(ch);
                Ok(Some(ch))
            },
            Some(Err(e)) => Err(e),
            None => Ok(None)
        }
    }

    fn consume(&mut self) -> Result<char, ParserError> {
        match try!(self.consume_eof()) {
            Some(c) => Ok(c),
            None => return Err(self.make_error(ParserErrorKind::UnexpectedEOF))
        }
    }

    fn consume_whitespace(&mut self) -> Result<bool, ParserError> {
        let mut consumed = false;
        loop {
            let whitespace = try!(self.read_while(is_whitespace));
            consumed = consumed || whitespace.len() > 0;
            if let Some(';') = try!(self.lookahead()) {
                consumed = true;
                try!(self.read_while(|c| c != '\n'));
                if self.lookahead_buf.is_some() {
                    self.lookahead_buf = None;
                }
            } else {
                return Ok(consumed);
            }
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(not(target_os = "linux"))]
use std::io::ErrorKind;
use std::io::{self, Error};
use std::sync::atomic::{AtomicBool, Ordering};

/// An active AX.25 network interface, e.g. "ax0"
pub(crate) struct NetDev {
    pub name: String,
    pub ifindex: i32,
}

/// An open socket for sending and receiving AX.25 frames
pub(crate) struct Ax25RawSocket {
    #[cfg(target_os = "linux")]
    fd: i32,
    is_shutdown: AtomicBool,
}

impl Ax25RawSocket {
    /// Create a new socket for sending and receiving raw AX.25 frames. This requires root or CAP_NET_ADMIN.
    pub(crate) fn new() -> io::Result<Ax25RawSocket> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_new()
        }
        #[cfg(not(target_os = "linux"))]
        {
            Err(Error::new(ErrorKind::NotFound, "only supported on linux"))
        }
    }

    /// Find all AX.25 interfaces on the system
    pub(crate) fn list_ax25_interfaces(&self) -> io::Result<Vec<NetDev>> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_list_ax25_interfaces(self)
        }
        #[cfg(not(target_os = "linux"))]
        {
            Ok(Vec::new())
        }
    }

    /// Send a frame to a particular interface, specified by its index
    #[allow(unused_variables)]
    pub(crate) fn send_frame(&self, frame: &[u8], ifindex: i32) -> io::Result<()> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_send_frame(self, frame, ifindex)
        }
        #[cfg(not(target_os = "linux"))]
        {
            Err(Error::new(
                ErrorKind::NotConnected,
                "only supported on linux",
            ))
        }
    }

    /// Block to receive an incoming AX.25 frame from any interface
    #[allow(unused_variables)]
    pub(crate) fn receive_frame(&self, ifindex: i32) -> io::Result<Vec<u8>> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_receive_frame(self, ifindex)
        }
        #[cfg(not(target_os = "linux"))]
        {
            Err(Error::new(
                ErrorKind::NotConnected,
                "only supported on linux",
            ))
        }
    }

    /// Shutdown the socket.
    pub(crate) fn shutdown(&self) {
        if !self.is_shutdown.load(Ordering::SeqCst) {
            self.is_shutdown.store(true, Ordering::SeqCst);
            #[cfg(target_os = "linux")]
            {
                let _ = sys::socket_close(self);
            }
        }
    }
}

impl Drop for Ax25RawSocket {
    fn drop(&mut self) {
        self.shutdown();
    }
}

/// Keeps all the linux interface-specific code in one place
#[cfg(target_os = "linux")]
mod sys {
    use super::*;
    use libc::{
        c_char, c_int, c_ulong, c_void, close, recvfrom, sendto, sockaddr_ll, socket, socklen_t,
        AF_AX25, AF_PACKET, SOCK_RAW,
    };
    use std::fs::File;
    use std::io::{BufRead, BufReader};
    use std::mem;

    const ETH_P_AX25: u16 = 0x0002; // from if_ether.h for SOCK_RAW
    const SIOCGIFHWADDR: c_ulong = 0x8927; // from sockios.h in the linux kernel
    const SIOCGIFINDEX: c_ulong = 0x8933;

    pub(crate) fn socket_new() -> io::Result<Ax25RawSocket> {
        match unsafe { socket(AF_PACKET, SOCK_RAW, ETH_P_AX25.to_be() as i32) } {
            -1 => Err(Error::last_os_error()),
            fd => Ok(Ax25RawSocket {
                fd,
                is_shutdown: AtomicBool::new(false),
            }),
        }
    }

    pub(crate) fn socket_close(socket: &Ax25RawSocket) -> io::Result<()> {
        match unsafe { close(socket.fd) } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    pub(crate) fn socket_list_ax25_interfaces(socket: &Ax25RawSocket) -> io::Result<Vec<NetDev>> {
        let dev_file = File::open("/proc/net/dev")?;
        let mut devices: Vec<NetDev> = Vec::new();
        let reader = BufReader::new(dev_file);
        let lines = reader.lines();
        for l in lines.skip(2) {
            if let Ok(line) = l {
                let device_name = line.trim().split(':').next().unwrap();
                if let Some(net_dev) = get_ax25_netdev(&device_name, socket.fd) {
                    devices.push(net_dev);
                }
            }
        }
        Ok(devices)
    }

    pub(crate) fn socket_send_frame(
        socket: &Ax25RawSocket,
        frame: &[u8],
        ifindex: i32,
    ) -> io::Result<()> {
        // The Linux interface demands a single null byte prefix on the actual packet
        let mut prefixed_frame: Vec<u8> = Vec::with_capacity(frame.len() + 1);
        prefixed_frame.push(0);
        prefixed_frame.extend(frame.iter().cloned());

        let sa = sockaddr_ll {
            sll_family: AF_PACKET as u16,
            sll_protocol: ETH_P_AX25.to_be(),
            sll_ifindex: ifindex,
            sll_hatype: 0,
            sll_pkttype: 0,
            sll_halen: 0,
            sll_addr: [0; 8],
        };

        match unsafe {
            let sa_ptr = &sa as *const libc::sockaddr_ll as *const libc::sockaddr;
            sendto(
                socket.fd,
                prefixed_frame.as_ptr() as *const c_void,
                prefixed_frame.len(),
                0,
                sa_ptr,
                mem::size_of_val(&sa) as socklen_t,
            )
        } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    pub(crate) fn socket_receive_frame(
        socket: &Ax25RawSocket,
        ifindex: i32,
    ) -> io::Result<Vec<u8>> {
        let mut buf: [u8; 1024] = [0; 1024];
        let mut addr_struct: sockaddr_ll = unsafe { mem::zeroed() };
        let mut len: usize;
        loop {
            unsafe {
                let sa_ptr = &mut addr_struct as *mut libc::sockaddr_ll as *mut libc::sockaddr;
                let mut sa_in_sz: socklen_t = mem::size_of::<sockaddr_ll>() as socklen_t;
                len = match recvfrom(
                    socket.fd,
                    buf.as_mut_ptr() as *mut c_void,
                    buf.len(),
                    0,
                    sa_ptr,
                    &mut sa_in_sz,
                ) {
                    -1 => return Err(Error::last_os_error()),
                    len => len as usize,
                };
                // We actually get packets from all interfaces when receiving this way
                // Only report ones from the interface we're interested in
                if addr_struct.sll_ifindex == ifindex {
                    break;
                }
            }
        }
        let valid_buf = &buf[0..len];

        // In practice AF_PACKET gives us one leading one null byte
        // These are unhelpful so we will skip all leading null bytes
        let filtered: Vec<u8> = valid_buf.iter().skip_while(|&c| *c == 0).cloned().collect();
        Ok(filtered)
    }

    fn get_ax25_netdev(name: &str, fd: i32) -> Option<NetDev> {
        let mut req = ifreq::default();
        let if_name = name.to_owned();
        for (d, s) in req.ifr_name.iter_mut().zip(if_name.as_bytes()) {
            *d = *s as c_char;
        }

        if unsafe { ioctl(fd, SIOCGIFHWADDR, &mut req) } == -1 {
            return None;
        }
        if req.data.address_family() as i32 != AF_AX25 {
            return None;
        }
        let hw_addr = match req.data.ax25_address() {
            Some(addr) => addr,
            None => return None,
        };

        if unsafe { ioctl(fd, SIOCGIFINDEX, &mut req) } == -1 {
            return None;
        }
        let ifindex = req.data.ifindex();

        Some(NetDev {
            name: hw_addr,
            ifindex,
        })
    }

    extern "C" {
        fn ioctl(fd: c_int, request: c_ulong, ifreq: *mut ifreq) -> c_int;
    }

    #[repr(C)]
    struct ifreq {
        ifr_name: [c_char; 16],
        data: ifreq_union,
    }

    impl Default for ifreq {
        fn default() -> ifreq {
            ifreq {
                ifr_name: [0; 16],
                data: ifreq_union::default(),
            }
        }
    }

    #[repr(C)]
    struct ifreq_union {
        data: [u8; 24],
    }

    impl Default for ifreq_union {
        fn default() -> ifreq_union {
            ifreq_union { data: [0; 24] }
        }
    }

    impl ifreq_union {
        fn ifindex(&self) -> c_int {
            c_int::from_be(
                ((self.data[0] as c_int) << 24)
                    + ((self.data[1] as c_int) << 16)
                    + ((self.data[2] as c_int) << 8)
                    + (self.data[3] as c_int),
            )
        }

        fn address_family(&self) -> u16 {
            u16::from_be(((self.data[0] as u16) << 8) + (self.data[1] as u16))
        }

        fn ax25_address(&self) -> Option<String> {
            let mut addr_utf8: Vec<u8> = self.data[2..8]
                .iter()
                .rev()
                .map(|&c| c >> 1)
                .skip_while(|&c| c == 0)
                .collect::<Vec<u8>>();
            addr_utf8.reverse();
            let ssid = (self.data[8] >> 1) & 0x0f;
            if let Ok(addr) = String::from_utf8(addr_utf8) {
                return Some(format!("{}-{}", addr, ssid));
            }
            None
        }
    }
}
<commit_msg>Fix lints in linux-specific code<commit_after>#[cfg(not(target_os = "linux"))]
use std::io::ErrorKind;
use std::io::{self, Error};
use std::sync::atomic::{AtomicBool, Ordering};

/// An active AX.25 network interface, e.g. "ax0"
pub(crate) struct NetDev {
    pub name: String,
    pub ifindex: i32,
}

/// An open socket for sending and receiving AX.25 frames
pub(crate) struct Ax25RawSocket {
    #[cfg(target_os = "linux")]
    fd: i32,
    is_shutdown: AtomicBool,
}

impl Ax25RawSocket {
    /// Create a new socket for sending and receiving raw AX.25 frames. This requires root or CAP_NET_ADMIN.
    pub(crate) fn new() -> io::Result<Ax25RawSocket> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_new()
        }
        #[cfg(not(target_os = "linux"))]
        {
            Err(Error::new(ErrorKind::NotFound, "only supported on linux"))
        }
    }

    /// Find all AX.25 interfaces on the system
    pub(crate) fn list_ax25_interfaces(&self) -> io::Result<Vec<NetDev>> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_list_ax25_interfaces(self)
        }
        #[cfg(not(target_os = "linux"))]
        {
            Ok(Vec::new())
        }
    }

    /// Send a frame to a particular interface, specified by its index
    #[allow(unused_variables)]
    pub(crate) fn send_frame(&self, frame: &[u8], ifindex: i32) -> io::Result<()> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_send_frame(self, frame, ifindex)
        }
        #[cfg(not(target_os = "linux"))]
        {
            Err(Error::new(
                ErrorKind::NotConnected,
                "only supported on linux",
            ))
        }
    }

    /// Block to receive an incoming AX.25 frame from any interface
    #[allow(unused_variables)]
    pub(crate) fn receive_frame(&self, ifindex: i32) -> io::Result<Vec<u8>> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_receive_frame(self, ifindex)
        }
        #[cfg(not(target_os = "linux"))]
        {
            Err(Error::new(
                ErrorKind::NotConnected,
                "only supported on linux",
            ))
        }
    }

    /// Shutdown the socket.
    pub(crate) fn shutdown(&self) {
        if !self.is_shutdown.load(Ordering::SeqCst) {
            self.is_shutdown.store(true, Ordering::SeqCst);
            #[cfg(target_os = "linux")]
            {
                let _ = sys::socket_close(self);
            }
        }
    }
}

impl Drop for Ax25RawSocket {
    fn drop(&mut self) {
        self.shutdown();
    }
}

/// Keeps all the linux interface-specific code in one place
#[cfg(target_os = "linux")]
mod sys {
    use super::*;
    use libc::{
        c_char, c_int, c_ulong, c_void, close, recvfrom, sendto, sockaddr_ll, socket, socklen_t,
        AF_AX25, AF_PACKET, SOCK_RAW,
    };
    use std::fs::File;
    use std::io::{BufRead, BufReader};
    use std::mem;

    const ETH_P_AX25: u16 = 0x0002; // from if_ether.h for SOCK_RAW
    const SIOCGIFHWADDR: c_ulong = 0x8927; // from sockios.h in the linux kernel
    const SIOCGIFINDEX: c_ulong = 0x8933;

    pub(crate) fn socket_new() -> io::Result<Ax25RawSocket> {
        match unsafe { socket(AF_PACKET, SOCK_RAW, ETH_P_AX25.to_be() as i32) } {
            -1 => Err(Error::last_os_error()),
            fd => Ok(Ax25RawSocket {
                fd,
                is_shutdown: AtomicBool::new(false),
            }),
        }
    }

    pub(crate) fn socket_close(socket: &Ax25RawSocket) -> io::Result<()> {
        match unsafe { close(socket.fd) } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    pub(crate) fn socket_list_ax25_interfaces(socket: &Ax25RawSocket) -> io::Result<Vec<NetDev>> {
        let dev_file = File::open("/proc/net/dev")?;
        let mut devices: Vec<NetDev> = Vec::new();
        let reader = BufReader::new(dev_file);
        let lines = reader.lines();
        for l in lines.skip(2).flatten() {
            let device_name = l.trim().split(':').next().unwrap();
            if let Some(net_dev) = get_ax25_netdev(device_name, socket.fd) {
                devices.push(net_dev);
            }
        }
        Ok(devices)
    }

    pub(crate) fn socket_send_frame(
        socket: &Ax25RawSocket,
        frame: &[u8],
        ifindex: i32,
    ) -> io::Result<()> {
        // The Linux interface demands a single null byte prefix on the actual packet
        let mut prefixed_frame: Vec<u8> = Vec::with_capacity(frame.len() + 1);
        prefixed_frame.push(0);
        prefixed_frame.extend(frame.iter().cloned());

        let sa = sockaddr_ll {
            sll_family: AF_PACKET as u16,
            sll_protocol: ETH_P_AX25.to_be(),
            sll_ifindex: ifindex,
            sll_hatype: 0,
            sll_pkttype: 0,
            sll_halen: 0,
            sll_addr: [0; 8],
        };

        match unsafe {
            let sa_ptr = &sa as *const libc::sockaddr_ll as *const libc::sockaddr;
            sendto(
                socket.fd,
                prefixed_frame.as_ptr() as *const c_void,
                prefixed_frame.len(),
                0,
                sa_ptr,
                mem::size_of_val(&sa) as socklen_t,
            )
        } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    pub(crate) fn socket_receive_frame(
        socket: &Ax25RawSocket,
        ifindex: i32,
    ) -> io::Result<Vec<u8>> {
        let mut buf: [u8; 1024] = [0; 1024];
        let mut addr_struct: sockaddr_ll = unsafe { mem::zeroed() };
        let mut len: usize;
        loop {
            unsafe {
                let sa_ptr = &mut addr_struct as *mut libc::sockaddr_ll as *mut libc::sockaddr;
                let mut sa_in_sz: socklen_t = mem::size_of::<sockaddr_ll>() as socklen_t;
                len = match recvfrom(
                    socket.fd,
                    buf.as_mut_ptr() as *mut c_void,
                    buf.len(),
                    0,
                    sa_ptr,
                    &mut sa_in_sz,
                ) {
                    -1 => return Err(Error::last_os_error()),
                    len => len as usize,
                };
                // We actually get packets from all interfaces when receiving this way
                // Only report ones from the interface we're interested in
                if addr_struct.sll_ifindex == ifindex {
                    break;
                }
            }
        }
        let valid_buf = &buf[0..len];

        // In practice AF_PACKET gives us one leading one null byte
        // These are unhelpful so we will skip all leading null bytes
        let filtered: Vec<u8> = valid_buf.iter().skip_while(|&c| *c == 0).cloned().collect();
        Ok(filtered)
    }

    fn get_ax25_netdev(name: &str, fd: i32) -> Option<NetDev> {
        let mut req = ifreq::default();
        let if_name = name.to_owned();
        for (d, s) in req.ifr_name.iter_mut().zip(if_name.as_bytes()) {
            *d = *s as c_char;
        }

        if unsafe { ioctl(fd, SIOCGIFHWADDR, &mut req) } == -1 {
            return None;
        }
        if req.data.address_family() as i32 != AF_AX25 {
            return None;
        }
        let hw_addr = match req.data.ax25_address() {
            Some(addr) => addr,
            None => return None,
        };

        if unsafe { ioctl(fd, SIOCGIFINDEX, &mut req) } == -1 {
            return None;
        }
        let ifindex = req.data.ifindex();

        Some(NetDev {
            name: hw_addr,
            ifindex,
        })
    }

    extern "C" {
        fn ioctl(fd: c_int, request: c_ulong, ifreq: *mut ifreq) -> c_int;
    }

    #[derive(Default)]
    #[repr(C)]
    struct ifreq {
        ifr_name: [c_char; 16],
        data: ifreq_union,
    }

    #[derive(Default)]
    #[repr(C)]
    struct ifreq_union {
        data: [u8; 24],
    }

    impl ifreq_union {
        fn ifindex(&self) -> c_int {
            c_int::from_be(
                ((self.data[0] as c_int) << 24)
                    + ((self.data[1] as c_int) << 16)
                    + ((self.data[2] as c_int) << 8)
                    + (self.data[3] as c_int),
            )
        }

        fn address_family(&self) -> u16 {
            u16::from_be(((self.data[0] as u16) << 8) + (self.data[1] as u16))
        }

        fn ax25_address(&self) -> Option<String> {
            let mut addr_utf8: Vec<u8> = self.data[2..8]
                .iter()
                .rev()
                .map(|&c| c >> 1)
                .skip_while(|&c| c == 0)
                .collect::<Vec<u8>>();
            addr_utf8.reverse();
            let ssid = (self.data[8] >> 1) & 0x0f;
            if let Ok(addr) = String::from_utf8(addr_utf8) {
                return Some(format!("{}-{}", addr, ssid));
            }
            None
        }
    }
}
<|endoftext|>


<commit_before>use postgres::{Connection, SslMode};
use postgres::error::ConnectError;
use std::collections::BTreeMap;
use std::env;
use rustc_serialize::json::{ToJson, Json};
use uuid::Uuid;
use std::fmt;

static DEFAULT_DATABASE_URL: &'static str = "postgres://kumabook@localhost/pink_spider_development_master";

use youtube;
use soundcloud;

#[derive(Debug, Clone)]
pub enum Provider {
    YouTube,
    SoundCloud,
    Raw
}
impl PartialEq for Provider {
    fn eq(&self, p: &Provider) -> bool {
        match *self {
            Provider::YouTube    => match *p { Provider::YouTube    => true, _ => false },
            Provider::SoundCloud => match *p { Provider::SoundCloud => true, _ => false },
            Provider::Raw        => match *p { Provider::Raw        => true, _ => false }
        }
    }
}
impl Provider {
    fn to_string(&self) -> String {
        match *self {
            Provider::YouTube    => "YouTube".to_string(),
            Provider::SoundCloud => "SoundCloud".to_string(),
            Provider::Raw        => "Raw".to_string(),
        }
    }
    fn new(str: String) -> Provider {
        match str.as_ref() {
            "YouTube"    => Provider::YouTube,
            "SoundCloud" => Provider::SoundCloud,
            _            => Provider::Raw,
        }
    }
}

impl fmt::Display for Provider {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({})", self.to_string())
    }
}

#[derive(Debug, Clone)]
pub struct Track {
    pub id:         Uuid,
    pub provider:   Provider,
    pub title:      String,
    pub url:        String,
    pub identifier: String
}

impl PartialEq for Track {
    fn eq(&self, t: &Track) -> bool {
        return self.identifier == t.identifier && self.provider == t.provider
    }
}

impl ToJson for Track {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("id".to_string(),         self.id.to_string().to_json());
        d.insert("provider".to_string(),   self.provider.to_string().to_json());
        d.insert("identifier".to_string(), self.identifier.to_json());
        d.insert("title".to_string(),      self.title.to_json());
        d.insert("url".to_string(),        self.url.to_json());
        Json::Object(d)
    }
}

impl fmt::Display for Track {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{}", self.provider, self.identifier)
    }
}

impl Track {
    pub fn from_yt_playlist_item(item: &youtube::PlaylistItem) -> Track {
        let identifier = (*item).snippet.resourceId["videoId"].to_string();
        Track {
                    id: Uuid::new_v4(),
              provider: Provider::YouTube,
                 title: (*item).snippet.title.to_string(),
                   url: format!("https://www.youtube.com/watch/?v={}", identifier),
            identifier: identifier
        }
    }
    pub fn from_sc_track(track: &soundcloud::Track) -> Track {
        Track {
                    id: Uuid::new_v4(),
              provider: Provider::SoundCloud,
                 title: (*track).title.to_string(),
                   url: (*track).permalink_url.to_string(),
            identifier: (*track).id.to_string()
        }
    }
    pub fn find_by_id(id: i32) -> Option<Track> {
        let conn = conn().unwrap();
        let stmt = conn.prepare("SELECT id, provider, title, url, identifier
                                 FROM tracks WHERE id = $1").unwrap();
        for row in stmt.query(&[&id]).unwrap().iter() {
            let track = Track {
                      id: row.get(0),
                provider: Provider::new(row.get(1)),
                   title: row.get(2),
                     url: row.get(3),
              identifier: row.get(4)
            };
            return Some(track);
        }
        return None
    }

    pub fn find_by(provider: &Provider, identifier: &str) -> Option<Track> {
        let conn = conn().unwrap();
        let stmt = conn.prepare("SELECT id,  provider, title, url, identifier
                                 FROM tracks WHERE provider = $1
                                 AND identifier = $2").unwrap();
        for row in stmt.query(&[&(*provider).to_string(), &identifier]).unwrap().iter() {
            let track = Track {
                      id: row.get(0),
                provider: Provider::new(row.get(1)),
                   title: row.get(2),
                     url: row.get(3),
              identifier: row.get(4)
            };
            return Some(track);
        }
        return None
    }

    pub fn find_by_entry_id(entry_id: Uuid) -> Vec<Track> {
        let mut tracks = Vec::new();
        let conn = conn().unwrap();
        println!(" entry_id {}", entry_id);
        let stmt = conn.prepare("SELECT t.id,
                                        t.provider,
                                        t.title,
                                        t.url,
                                        t.identifier
                                 FROM tracks t LEFT JOIN track_entries te
                                 ON t.id = te.track_id
                                 WHERE te.entry_id = $1").unwrap();
        for row in stmt.query(&[&entry_id]).unwrap().iter() {
            tracks.push(Track {
                      id: row.get(0),
                provider: Provider::new(row.get(1)),
                   title: row.get(2),
                     url: row.get(3),
              identifier: row.get(4)
            });
        }
        return tracks
    }

    pub fn find_all() -> Vec<Track> {
        let mut tracks = Vec::new();
        let conn = conn().unwrap();
        let stmt = conn.prepare("SELECT id, provider, title, url, identifier FROM track").unwrap();
        for row in stmt.query(&[]).unwrap().iter() {
            let track = Track {
                      id: row.get(0),
                provider: Provider::new(row.get(1)),
                   title: row.get(2),
                     url: row.get(3),
              identifier: row.get(4)
            };
            tracks.push(track);
        }
        return tracks
    }

    pub fn create(provider: Provider, title: String, url: String, identifier: String) -> Option<Track> {
        let conn = conn().unwrap();
        let stmt = conn.prepare("INSERT INTO tracks (provider, title, url, identifier)
                                 VALUES ($1, $2, $3, $4) RETURNING id").unwrap();
        for row in stmt.query(&[&provider.to_string(), &title, &url, &identifier]).unwrap().iter() {
            let track = Track {
                        id: row.get(0),
                  provider: provider,
                     title: title,
                       url: url,
                identifier: identifier
            };
            return Some(track);
        }
        return None
    }

    pub fn find_or_create(provider: Provider, title: String, url: String, identifier: String) -> Option<Track> {
        return match Track::find_by(&provider, &identifier) {
            Some(track) => Some(track),
            None        => Track::create(provider, title, url, identifier)
        }
    }

    pub fn save(&self) -> bool {
        let conn = conn().unwrap();
        let stmt = conn.prepare("UPDATE track SET title=$1, url=$2 WHERE id = $3").unwrap();
        let result = stmt.query(&[&self.title, &self.url, &self.id.to_string()]);
        match result {
            Ok(_)  => return true,
            Err(_) => return false
        }
    }
}

pub struct Playlist {
    pub title:  String,
    pub tracks: Vec<Track>,
}

#[derive(Debug)]
pub struct Entry {
    pub id:  Uuid,
    pub url: String,
    pub tracks: Vec<Track>,
}

impl ToJson for Entry {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("id".to_string(),  self.id.to_string().to_json());
        d.insert("url".to_string(), self.url.to_json());
        let ref tracks = self.tracks;
        let mut t = Vec::new();
        for ref x in tracks.iter() {
            t.push(x.to_json());
        }
        d.insert("tracks".to_string(), Json::Array(t));
        Json::Object(d)
    }
}

impl Entry {
    pub fn find_by_id(id: String) -> Option<Entry> {
        let conn = conn().unwrap();
        let stmt = conn.prepare("SELECT id, url FROM entries WHERE id = $1").unwrap();
        for row in stmt.query(&[&id]).unwrap().iter() {
            return Some(Entry {
                    id: row.get(0),
                   url: row.get(1),
                tracks: Track::find_by_entry_id(row.get(0))
            });
        }
        return None
    }

    pub fn find_by_url(url: &str) -> Option<Entry> {
        let conn = conn().unwrap();
        let stmt = conn.prepare("SELECT id, url FROM entries WHERE url = $1").unwrap();
        for row in stmt.query(&[&url]).unwrap().iter() {
            return Some(Entry {
                    id: row.get(0),
                   url: row.get(1),
                tracks: Track::find_by_entry_id(row.get(0))
            });
        }
        return None
    }

    pub fn find_all() -> Vec<Entry> {
        let conn = conn().unwrap();
        let stmt = conn.prepare("SELECT id, url FROM entries").unwrap();
        let mut entries = Vec::new();
        for row in stmt.query(&[]).unwrap().iter() {
            entries.push(Entry {
                    id: row.get(0),
                   url: row.get(1),
                tracks: Track::find_by_entry_id(row.get(0))
            })
        }
        return entries
    }

    pub fn find_or_create_by_url(url: String) -> Option<Entry> {
        return match Entry::find_by_url(&url) {
            Some(entry) => Some(entry),
            None        => Entry::create_by_url(url)
        }
    }

    pub fn create_by_url(url: String) -> Option<Entry> {
        let conn = conn().unwrap();
        let stmt = conn.prepare("INSERT INTO entries (url) VALUES ($1) RETURNING id").unwrap();
        for row in stmt.query(&[&url]).unwrap().iter() {
            let entry = Entry {
                      id: row.get(0),
                     url: url,
                  tracks: Vec::new()
            };
            return Some(entry);
        }
        return None
    }

    pub fn add_track(&mut self, track: Track) {
        let conn = conn().unwrap();
        let stmt = conn.prepare("INSERT INTO track_entries (track_id, entry_id)
                                 VALUES ($1, $2)").unwrap();
        stmt.query(&[&track.id, &self.id]).unwrap();
        self.tracks.push(track);
    }

    pub fn save(&self) -> bool {
        return true
    }
}

pub fn conn() -> Result<Connection, ConnectError> {
    let opt_url = env::var("DATABASE_URL");
    match opt_url {
        Ok(url) =>
            Connection::connect(url.trim(), SslMode::None),
        Err(_)  =>
            Connection::connect(DEFAULT_DATABASE_URL, SslMode::None)
    }
}
<commit_msg>Remove println<commit_after>use postgres::{Connection, SslMode};
use postgres::error::ConnectError;
use std::collections::BTreeMap;
use std::env;
use rustc_serialize::json::{ToJson, Json};
use uuid::Uuid;
use std::fmt;

static DEFAULT_DATABASE_URL: &'static str = "postgres://kumabook@localhost/pink_spider_development_master";

use youtube;
use soundcloud;

#[derive(Debug, Clone)]
pub enum Provider {
    YouTube,
    SoundCloud,
    Raw
}
impl PartialEq for Provider {
    fn eq(&self, p: &Provider) -> bool {
        match *self {
            Provider::YouTube    => match *p { Provider::YouTube    => true, _ => false },
            Provider::SoundCloud => match *p { Provider::SoundCloud => true, _ => false },
            Provider::Raw        => match *p { Provider::Raw        => true, _ => false }
        }
    }
}
impl Provider {
    fn to_string(&self) -> String {
        match *self {
            Provider::YouTube    => "YouTube".to_string(),
            Provider::SoundCloud => "SoundCloud".to_string(),
            Provider::Raw        => "Raw".to_string(),
        }
    }
    fn new(str: String) -> Provider {
        match str.as_ref() {
            "YouTube"    => Provider::YouTube,
            "SoundCloud" => Provider::SoundCloud,
            _            => Provider::Raw,
        }
    }
}

impl fmt::Display for Provider {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({})", self.to_string())
    }
}

#[derive(Debug, Clone)]
pub struct Track {
    pub id:         Uuid,
    pub provider:   Provider,
    pub title:      String,
    pub url:        String,
    pub identifier: String
}

impl PartialEq for Track {
    fn eq(&self, t: &Track) -> bool {
        return self.identifier == t.identifier && self.provider == t.provider
    }
}

impl ToJson for Track {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("id".to_string(),         self.id.to_string().to_json());
        d.insert("provider".to_string(),   self.provider.to_string().to_json());
        d.insert("identifier".to_string(), self.identifier.to_json());
        d.insert("title".to_string(),      self.title.to_json());
        d.insert("url".to_string(),        self.url.to_json());
        Json::Object(d)
    }
}

impl fmt::Display for Track {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{}", self.provider, self.identifier)
    }
}

impl Track {
    pub fn from_yt_playlist_item(item: &youtube::PlaylistItem) -> Track {
        let identifier = (*item).snippet.resourceId["videoId"].to_string();
        Track {
                    id: Uuid::new_v4(),
              provider: Provider::YouTube,
                 title: (*item).snippet.title.to_string(),
                   url: format!("https://www.youtube.com/watch/?v={}", identifier),
            identifier: identifier
        }
    }
    pub fn from_sc_track(track: &soundcloud::Track) -> Track {
        Track {
                    id: Uuid::new_v4(),
              provider: Provider::SoundCloud,
                 title: (*track).title.to_string(),
                   url: (*track).permalink_url.to_string(),
            identifier: (*track).id.to_string()
        }
    }
    pub fn find_by_id(id: i32) -> Option<Track> {
        let conn = conn().unwrap();
        let stmt = conn.prepare("SELECT id, provider, title, url, identifier
                                 FROM tracks WHERE id = $1").unwrap();
        for row in stmt.query(&[&id]).unwrap().iter() {
            let track = Track {
                      id: row.get(0),
                provider: Provider::new(row.get(1)),
                   title: row.get(2),
                     url: row.get(3),
              identifier: row.get(4)
            };
            return Some(track);
        }
        return None
    }

    pub fn find_by(provider: &Provider, identifier: &str) -> Option<Track> {
        let conn = conn().unwrap();
        let stmt = conn.prepare("SELECT id,  provider, title, url, identifier
                                 FROM tracks WHERE provider = $1
                                 AND identifier = $2").unwrap();
        for row in stmt.query(&[&(*provider).to_string(), &identifier]).unwrap().iter() {
            let track = Track {
                      id: row.get(0),
                provider: Provider::new(row.get(1)),
                   title: row.get(2),
                     url: row.get(3),
              identifier: row.get(4)
            };
            return Some(track);
        }
        return None
    }

    pub fn find_by_entry_id(entry_id: Uuid) -> Vec<Track> {
        let mut tracks = Vec::new();
        let conn = conn().unwrap();
        let stmt = conn.prepare("SELECT t.id,
                                        t.provider,
                                        t.title,
                                        t.url,
                                        t.identifier
                                 FROM tracks t LEFT JOIN track_entries te
                                 ON t.id = te.track_id
                                 WHERE te.entry_id = $1").unwrap();
        for row in stmt.query(&[&entry_id]).unwrap().iter() {
            tracks.push(Track {
                      id: row.get(0),
                provider: Provider::new(row.get(1)),
                   title: row.get(2),
                     url: row.get(3),
              identifier: row.get(4)
            });
        }
        return tracks
    }

    pub fn find_all() -> Vec<Track> {
        let mut tracks = Vec::new();
        let conn = conn().unwrap();
        let stmt = conn.prepare("SELECT id, provider, title, url, identifier FROM track").unwrap();
        for row in stmt.query(&[]).unwrap().iter() {
            let track = Track {
                      id: row.get(0),
                provider: Provider::new(row.get(1)),
                   title: row.get(2),
                     url: row.get(3),
              identifier: row.get(4)
            };
            tracks.push(track);
        }
        return tracks
    }

    pub fn create(provider: Provider, title: String, url: String, identifier: String) -> Option<Track> {
        let conn = conn().unwrap();
        let stmt = conn.prepare("INSERT INTO tracks (provider, title, url, identifier)
                                 VALUES ($1, $2, $3, $4) RETURNING id").unwrap();
        for row in stmt.query(&[&provider.to_string(), &title, &url, &identifier]).unwrap().iter() {
            let track = Track {
                        id: row.get(0),
                  provider: provider,
                     title: title,
                       url: url,
                identifier: identifier
            };
            return Some(track);
        }
        return None
    }

    pub fn find_or_create(provider: Provider, title: String, url: String, identifier: String) -> Option<Track> {
        return match Track::find_by(&provider, &identifier) {
            Some(track) => Some(track),
            None        => Track::create(provider, title, url, identifier)
        }
    }

    pub fn save(&self) -> bool {
        let conn = conn().unwrap();
        let stmt = conn.prepare("UPDATE track SET title=$1, url=$2 WHERE id = $3").unwrap();
        let result = stmt.query(&[&self.title, &self.url, &self.id.to_string()]);
        match result {
            Ok(_)  => return true,
            Err(_) => return false
        }
    }
}

pub struct Playlist {
    pub title:  String,
    pub tracks: Vec<Track>,
}

#[derive(Debug)]
pub struct Entry {
    pub id:  Uuid,
    pub url: String,
    pub tracks: Vec<Track>,
}

impl ToJson for Entry {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("id".to_string(),  self.id.to_string().to_json());
        d.insert("url".to_string(), self.url.to_json());
        let ref tracks = self.tracks;
        let mut t = Vec::new();
        for ref x in tracks.iter() {
            t.push(x.to_json());
        }
        d.insert("tracks".to_string(), Json::Array(t));
        Json::Object(d)
    }
}

impl Entry {
    pub fn find_by_id(id: String) -> Option<Entry> {
        let conn = conn().unwrap();
        let stmt = conn.prepare("SELECT id, url FROM entries WHERE id = $1").unwrap();
        for row in stmt.query(&[&id]).unwrap().iter() {
            return Some(Entry {
                    id: row.get(0),
                   url: row.get(1),
                tracks: Track::find_by_entry_id(row.get(0))
            });
        }
        return None
    }

    pub fn find_by_url(url: &str) -> Option<Entry> {
        let conn = conn().unwrap();
        let stmt = conn.prepare("SELECT id, url FROM entries WHERE url = $1").unwrap();
        for row in stmt.query(&[&url]).unwrap().iter() {
            return Some(Entry {
                    id: row.get(0),
                   url: row.get(1),
                tracks: Track::find_by_entry_id(row.get(0))
            });
        }
        return None
    }

    pub fn find_all() -> Vec<Entry> {
        let conn = conn().unwrap();
        let stmt = conn.prepare("SELECT id, url FROM entries").unwrap();
        let mut entries = Vec::new();
        for row in stmt.query(&[]).unwrap().iter() {
            entries.push(Entry {
                    id: row.get(0),
                   url: row.get(1),
                tracks: Track::find_by_entry_id(row.get(0))
            })
        }
        return entries
    }

    pub fn find_or_create_by_url(url: String) -> Option<Entry> {
        return match Entry::find_by_url(&url) {
            Some(entry) => Some(entry),
            None        => Entry::create_by_url(url)
        }
    }

    pub fn create_by_url(url: String) -> Option<Entry> {
        let conn = conn().unwrap();
        let stmt = conn.prepare("INSERT INTO entries (url) VALUES ($1) RETURNING id").unwrap();
        for row in stmt.query(&[&url]).unwrap().iter() {
            let entry = Entry {
                      id: row.get(0),
                     url: url,
                  tracks: Vec::new()
            };
            return Some(entry);
        }
        return None
    }

    pub fn add_track(&mut self, track: Track) {
        let conn = conn().unwrap();
        let stmt = conn.prepare("INSERT INTO track_entries (track_id, entry_id)
                                 VALUES ($1, $2)").unwrap();
        stmt.query(&[&track.id, &self.id]).unwrap();
        self.tracks.push(track);
    }

    pub fn save(&self) -> bool {
        return true
    }
}

pub fn conn() -> Result<Connection, ConnectError> {
    let opt_url = env::var("DATABASE_URL");
    match opt_url {
        Ok(url) =>
            Connection::connect(url.trim(), SslMode::None),
        Err(_)  =>
            Connection::connect(DEFAULT_DATABASE_URL, SslMode::None)
    }
}
<|endoftext|>


<commit_before>/// Calculates the frequency (equal-tempered) given A4, the semitone and the octave.
/// C4 = `note(440.0, 0u, 4u)`
///
/// ### Semitone table
///
///  0 C
///  1 C#
///  2 D
///  3 D#
///  4 E
///  5 F
///  6 F#
///  7 G
///  8 G#
///  9 A
/// 10 B
pub fn note(a4: f64, semitone: usize, octave: usize) -> f64 {
    let semitones_from_a4 = octave as isize * 12 + semitone as isize - 9 - 48;
    a4 * (semitones_from_a4 as f64 * 2.0f64.ln() / 12.0).exp()
}

/// Calculates the frequency (equal-tempered) given A4 and the MIDI note value.
/// C4 = `note_midi(440.0, 60u)`
/// A4 = `note_midi(440.0, 69u)`
pub fn note_midi(a4: f64, midi_note: usize) -> f64 {
    let semitone = midi_note % 12;
    let octave = (midi_note / 12) - 1;
    note(a4, semitone, octave)
}

#[test]
fn it_equal_tempers() {
    let threshold = 0.1;
    let c4 = 261.63;
    let a4 = 440.0;
    let a3 = 220.0;
    let d3 = 146.83;
    let fs6 = 1479.98;
    assert!(note(a4, 9, 4).abs_sub(a4) < threshold);
    assert!(note(a4, 9, 3).abs_sub(a3) < threshold);
    assert!(note(a4, 0, 4).abs_sub(c4) < threshold);
    assert!(note(a4, 2, 3).abs_sub(d3) < threshold);
    assert!(note(a4, 6, 6).abs_sub(fs6) < threshold);
    assert!(note(a4, 9, 4).abs_sub(c4) > threshold);
}

#[test]
fn it_gets_frequency_for_a_midi_note() {
    let threshold = 0.1;
    let a4 = 440.0;
    let a4_note = 69;
    let a3_note = 57;
    let c4_note = 60;

    assert!(note(a4, 9, 4).abs_sub(note_midi(a4, a4_note)) < threshold);
    assert!(note(a4, 9, 3).abs_sub(note_midi(a4, a3_note)) < threshold);
    assert!(note(a4, 9, 4).abs_sub(note_midi(a4, c4_note)) > threshold);
}
<commit_msg>Track Rust nightly: abs_sub is deprecated<commit_after>/// Calculates the frequency (equal-tempered) given A4, the semitone and the octave.
/// C4 = `note(440.0, 0u, 4u)`
///
/// ### Semitone table
///
///  0 C
///  1 C#
///  2 D
///  3 D#
///  4 E
///  5 F
///  6 F#
///  7 G
///  8 G#
///  9 A
/// 10 B
pub fn note(a4: f64, semitone: usize, octave: usize) -> f64 {
    let semitones_from_a4 = octave as isize * 12 + semitone as isize - 9 - 48;
    a4 * (semitones_from_a4 as f64 * 2.0f64.ln() / 12.0).exp()
}

/// Calculates the frequency (equal-tempered) given A4 and the MIDI note value.
/// C4 = `note_midi(440.0, 60u)`
/// A4 = `note_midi(440.0, 69u)`
pub fn note_midi(a4: f64, midi_note: usize) -> f64 {
    let semitone = midi_note % 12;
    let octave = (midi_note / 12) - 1;
    note(a4, semitone, octave)
}

#[test]
fn it_equal_tempers() {
    let threshold = 0.1;
    let c4 = 261.63;
    let a4 = 440.0;
    let a3 = 220.0;
    let d3 = 146.83;
    let fs6 = 1479.98;
    assert!((note(a4, 9, 4) - a4).abs() < threshold);
    assert!((note(a4, 9, 3) - a3).abs() < threshold);
    assert!((note(a4, 0, 4) - c4).abs() < threshold);
    assert!((note(a4, 2, 3) - d3).abs() < threshold);
    assert!((note(a4, 6, 6) - fs6).abs() < threshold);
    assert!((note(a4, 9, 4) - c4).abs() > threshold);
}

#[test]
fn it_gets_frequency_for_a_midi_note() {
    let threshold = 0.1;
    let a4 = 440.0;
    let a4_note = 69;
    let a3_note = 57;
    let c4_note = 60;

    assert!((note(a4, 9, 4) - note_midi(a4, a4_note)).abs() < threshold);
    assert!((note(a4, 9, 3) - note_midi(a4, a3_note)).abs() < threshold);
    assert!((note(a4, 9, 4) - note_midi(a4, c4_note)).abs() > threshold);
}
<|endoftext|>


<commit_before>//! Types and utilities for working with DNS names.

use std::error::Error;
use std::fmt;
use std::str::FromStr;

/// Representation of a domain name
///
/// Domain names consist of one or more labels, broken up by the character '.'.
#[derive(Debug,Hash,PartialEq,PartialOrd,Eq,Ord,Clone)]
pub struct Name {
    name: String,
}

fn first_label(name: &str) -> &str {
    match name.find(".") {
        Some(index) => &name[..index],
        None => name,
    }
}

impl Name {
    fn label(&self) -> &str {
        first_label(&self.name)
    }

    fn parent(&self) -> Option<Name> {
        match self.name.find(".") {
            Some(index) => Some(Name { name: String::from(&self.name[(index + 1)..]) }),
            None => {
                match self.name.len() {
                    0 => None,
                    _ => Some(Name { name: String::from("") }),
                }
            }
        }
    }
}

/// An error returned when parsing a domain name
#[derive(Debug,PartialEq,Clone,Copy)]
pub struct NameParseError(());

impl fmt::Display for NameParseError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.description())
    }
}

impl Error for NameParseError {
    fn description(&self) -> &str {
        "invalid domain name syntax"
    }
}

impl FromStr for Name {
    type Err = NameParseError;
    fn from_str(s: &str) -> Result<Name, NameParseError> {
        let name = String::from(s);
        Ok(Name { name: name })
    }
}

impl fmt::Display for Name {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}.", self.name)
    }
}

#[cfg(test)]
mod tests {
    use super::{Name, NameParseError};

    #[test]
    fn root_label_is_valid() {
        let name = "".parse::<Name>().unwrap();
        assert_eq!("", name.label());
    }

    #[test]
    fn root_parent_is_none() {
        let name = "".parse::<Name>().unwrap();
        assert_eq!(None, name.parent());
    }

    #[test]
    fn simple_label_is_valid() {
        let name = "raspberry".parse::<Name>().unwrap();
        assert_eq!("raspberry", name.label());
    }

    #[test]
    fn simple_parent_is_root() {
        let name = "raspberry".parse::<Name>().unwrap();
        let parent = name.parent().unwrap();
        assert_eq!("", parent.label());
    }

    #[test]
    fn multi_label_is_valid() {
        let name = "test.example.com".parse::<Name>().unwrap();
        assert_eq!("test", name.label());
    }

    #[test]
    fn multi_parent_is_valid() {
        let name = "test.example.com".parse::<Name>().unwrap();
        let parent1 = name.parent().unwrap();
        assert_eq!("example", parent1.label());
        let parent2 = parent1.parent().unwrap();
        assert_eq!("com", parent2.label());
        let parent3 = parent2.parent().unwrap();
        assert_eq!("", parent3.label());
    }
}
<commit_msg>lint: apply suggestions<commit_after>//! Types and utilities for working with DNS names.

use std::error::Error;
use std::fmt;
use std::str::FromStr;

/// Representation of a domain name
///
/// Domain names consist of one or more labels, broken up by the character '.'.
#[derive(Debug,Hash,PartialEq,PartialOrd,Eq,Ord,Clone)]
pub struct Name {
    name: String,
}

fn first_label(name: &str) -> &str {
    match name.find('.') {
        Some(index) => &name[..index],
        None => name,
    }
}

impl Name {
    fn label(&self) -> &str {
        first_label(&self.name)
    }

    fn parent(&self) -> Option<Name> {
        match self.name.find('.') {
            Some(index) => Some(Name { name: String::from(&self.name[(index + 1)..]) }),
            None => {
                match self.name.len() {
                    0 => None,
                    _ => Some(Name { name: String::from("") }),
                }
            }
        }
    }
}

/// An error returned when parsing a domain name
#[derive(Debug,PartialEq,Clone,Copy)]
pub struct NameParseError(());

impl fmt::Display for NameParseError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.description())
    }
}

impl Error for NameParseError {
    fn description(&self) -> &str {
        "invalid domain name syntax"
    }
}

impl FromStr for Name {
    type Err = NameParseError;
    fn from_str(s: &str) -> Result<Name, NameParseError> {
        let name = String::from(s);
        Ok(Name { name: name })
    }
}

impl fmt::Display for Name {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}.", self.name)
    }
}

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

    #[test]
    fn root_label_is_valid() {
        let name = "".parse::<Name>().unwrap();
        assert_eq!("", name.label());
    }

    #[test]
    fn root_parent_is_none() {
        let name = "".parse::<Name>().unwrap();
        assert_eq!(None, name.parent());
    }

    #[test]
    fn simple_label_is_valid() {
        let name = "raspberry".parse::<Name>().unwrap();
        assert_eq!("raspberry", name.label());
    }

    #[test]
    fn simple_parent_is_root() {
        let name = "raspberry".parse::<Name>().unwrap();
        let parent = name.parent().unwrap();
        assert_eq!("", parent.label());
    }

    #[test]
    fn multi_label_is_valid() {
        let name = "test.example.com".parse::<Name>().unwrap();
        assert_eq!("test", name.label());
    }

    #[test]
    fn multi_parent_is_valid() {
        let name = "test.example.com".parse::<Name>().unwrap();
        let parent1 = name.parent().unwrap();
        assert_eq!("example", parent1.label());
        let parent2 = parent1.parent().unwrap();
        assert_eq!("com", parent2.label());
        let parent3 = parent2.parent().unwrap();
        assert_eq!("", parent3.label());
    }
}
<|endoftext|>