<commit_before>//! The `css_parse` module parses css stylesheets into css rule datastructures.

use css::{Declaration, Rule, Selector, SimpleSelector, Stylesheet};

use std::iter::Peekable;
use std::str::Chars;

pub struct CssParser<'a> {
    chars: Peekable<Chars<'a>>,
}

impl<'a> CssParser<'a> {
    /// Constructs a new CssParser.
    ///
    /// full_css: the complete css stylesheet to parse.
    pub fn new(full_css: &str) -> CssParser {
        CssParser { chars: full_css.chars().peekable() }
    }

    /// Entry point to parsing css, iterively parse css rules.
    pub fn parse_stylesheet(&mut self) -> Stylesheet {
        let mut stylesheet = Stylesheet::default();

        while self.chars.peek().is_some() {
            let selectors = self.parse_selectors();
            let styles = self.parse_declarations();
            let rule = Rule::new(selectors, styles);

            stylesheet.rules.push(rule);
        }

        stylesheet
    }

    /// Parse the selectors for a single rule.
    fn parse_selectors(&mut self) -> Vec<Selector> {
        let mut selectors = Vec::new();

        while self.chars.peek().map_or(false, |c| *c != '{') {
            let selector = self.parse_selector();
            selectors.push(selector);

            self.consume_while(char::is_whitespace);
            if self.chars.peek().map_or(false, |c| *c == ',') {
                self.chars.next();
            }
        }

        self.chars.next();
        selectors
    }

    /// Parse a single selector in a comma seperated list of selectors.
    fn parse_selector(&mut self) -> Selector {
        let mut sselector = SimpleSelector::default();
        let mut selector = Selector::default();

        self.consume_while(char::is_whitespace);

        sselector.tag_name = match self.chars.peek() {
            Some(&c) if is_valid_start_ident(c) => Some(self.parse_identifier()),
            _ => None,
        };

        let mut multiple_ids = false;
        while self.chars.peek().map_or(false, |c| *c != ',' && *c != '{' && !(*c).is_whitespace()) {
            match self.chars.peek() {
                Some(&c) if c =='#' =>  {
                    self.chars.next();
                    if sselector.id.is_some() || multiple_ids {
                        sselector.id = None;
                        multiple_ids = true;
                        self.parse_id();
                    } else {
                        sselector.id = self.parse_id();
                    }
                },
                Some(&c) if c == '.' => {
                    self.chars.next();
                    sselector.classes.push(self.parse_identifier());
                },
                _ => panic!("INVALID STATE IN parse_selector"), // TODO handle css errors
            }
        }

        if sselector != SimpleSelector::default() {
            selector.simple.push(sselector);
        }

        selector
    }

    /// Parse a css identifier.
    fn parse_identifier(&mut self) -> String {
        let mut ident = String::new();

        match self.chars.peek() {
            Some(&c) => {
                if is_valid_start_ident(c) {
                    ident.push_str(&self.consume_while(is_valid_ident))
                }
            },
            None => {},
        }

        ident
    }

    /// Wraps an identifier in an option
    fn parse_id(&mut self) -> Option<String> {
        match &self.parse_identifier()[..] {
            "" => None,
            s @ _ => Some(s.to_string())
        }
    }

    /// Parse all the declarations for a rule.
    fn parse_declarations(&mut self) -> Vec<Declaration> {
        let mut declarations = Vec::<Declaration>::new();

        while self.chars.peek().map_or(false, |c| *c != '}') {
            self.consume_while(char::is_whitespace);

            let property = self.consume_while(|x| x != ':');

            self.chars.next();
            self.consume_while(char::is_whitespace);

            //TODO fix for correctness
            let value = self.consume_while(|x| x != ';' && x != '\n' && x != '}');
            let declaration = Declaration::new(property, value);

            declarations.push(declaration);

            if self.chars.peek().map_or(false, |c| *c == ';') {
                self.chars.next();
            }
            self.consume_while(char::is_whitespace);
        }

        self.chars.next();
        declarations
    }

    /// Consumes characters until condition is false or there are no more chars left.
    /// Returns a string of the consumed characters.
    fn consume_while<F>(&mut self, condition: F) -> String where F : Fn(char) -> bool {
        let mut result = String::new();
        while self.chars.peek().map_or(false, |c| condition(*c)) {
            // the check above guarentees there is a value to be consumed
            result.push(self.chars.next().unwrap());
        }

        result
    }
}

/// Returns true if the char is a valid for a css identifier.
fn is_valid_ident(c: char) -> bool {
    is_valid_start_ident(c) || c.is_digit(10) || c == '-'
}

/// Returns true if the char is a valid for the first char of a css identifier.
fn is_valid_start_ident(c: char) -> bool {
    is_letter(c) || is_non_ascii(c) || c == '_'
}

/// Returns true if the char is an ASCII letter.
fn is_letter(c: char) -> bool {
    is_upper_letter(c) || is_lower_letter(c)
}

/// Returns true if the char is an ASCII uppercase char.
fn is_upper_letter(c: char) -> bool {
    c >= 'A' && c <= 'Z'
}

/// Returns true if the char is an ASCII lowercase char.
fn is_lower_letter(c: char) -> bool {
    c >= 'a' && c <= 'z'
}

/// Returns true if the char is non-ascii.
fn is_non_ascii(c: char) -> bool {
    c >= '\u{0080}'
}

//TODO
//  -deal with comments and escaping characters
//  -complex selectors
//  -cascade
//  -specificity

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

    use css::{Declaration, Rule, Selector, SimpleSelector, Stylesheet};

    /// Test a parser is constructed correctly.
    #[test]
    fn parser_regular() {
        let css = "p{lel:kek;}";
        let mut parser = CssParser::new(css);

        for character in String::from(css).chars() {
            assert_eq!(character, parser.chars.next().unwrap());
        }

        assert_eq!(None, parser.chars.peek());
    }

    /// Test an empty parser is constructed correctly.
    #[test]
    fn parser_empty() {
        let mut parser = CssParser::new("");

        for character in String::from("").chars() {
            assert_eq!(character, parser.chars.next().unwrap());
        }

        assert_eq!(None, parser.chars.peek());
    }

    /// Test an empty declaration
    #[test]
    fn declarations_empty() {
        let mut parser = CssParser::new("");
        assert_eq!(Vec::<Declaration>::new(), parser.parse_declarations());
    }

    /// Test the end of a declaration
    #[test]
    fn declarations_end() {
        let mut parser = CssParser::new("}");
        assert_eq!(Vec::<Declaration>::new(), parser.parse_declarations());
    }

    /// Test a regular declaration
    #[test]
    fn declarations_regular() {
        let mut parser = CssParser::new(
            "color:red;
             border-width: 1px;
             background-color: aqua
           }");
        let decl_col = Declaration::new(String::from("color"), String::from("red"));
        let decl_bw = Declaration::new(String::from("border-width"), String::from("1px"));
        let decl_bg_col = Declaration::new(String::from("background-color"), String::from("aqua"));

        let expected = vec![decl_col, decl_bw, decl_bg_col];
        assert_eq!(expected, parser.parse_declarations());
    }

    /// Test declaration: semi-colon missing
    #[test]
    fn declarations_invalid() {
        let mut parser = CssParser::new(
            "color:red;
             border-width: 1px
             background-color: aqua
           }");
        let decl_col = Declaration::new(String::from("color"), String::from("red"));
        let decl_bg_col = Declaration::new(String::from("background-color"), String::from("aqua"));

        let expected = vec![decl_col, decl_bg_col];
        assert_eq!(expected, parser.parse_declarations());
    }

    /// Test empty identifier
    #[test]
    fn identifier_empty() {
        let mut parser = CssParser::new("");
        assert_eq!(String::from(""), parser.parse_identifier());
    }

    /// Test end of identifier
    #[test]
    fn identifier_end() {
        let mut parser = CssParser::new(",");
        assert_eq!(String::from(""), parser.parse_identifier());
    }

    /// Test a regular identifier
    #[test]
    fn identifier_regular() {
        let mut parser = CssParser::new("identifier-one,");
        assert_eq!(String::from("identifier-one"), parser.parse_identifier());
    }

    /// Test a multi-section identifier
    #[test]
    fn identifier_long() {
        let mut parser = CssParser::new("identifier-one.class-one,");
        assert_eq!(String::from("identifier-one"), parser.parse_identifier());
    }

    /// Test an identifier beginning with -
    #[test]
    fn identifier_invalid() {
        let mut parser = CssParser::new("-identifier-one.class-one,");
        assert_eq!(String::from(""), parser.parse_identifier());
    }

    /// Test whitespace after the identifier
    #[test]
    fn identifier_whitespace() {
        let mut parser = CssParser::new("identifier p#id-one.class-one,");
        assert_eq!(String::from("identifier"), parser.parse_identifier());
    }

    /// Test an empty selector
    #[test]
    fn selector_empty() {
        let mut parser = CssParser::new("");
        assert_eq!(Selector::default(), parser.parse_selector());
    }

    /// Test selector parsing with a ,
    #[test]
    fn selector_end1() {
        let mut parser = CssParser::new(",");
        assert_eq!(Selector::default(), parser.parse_selector());
    }

    /// Test selector parsing with a {
    #[test]
    fn selector_end2() {
        let mut parser = CssParser::new("{");
        assert_eq!(Selector::default(), parser.parse_selector());
    }

    /// Test a regular selector
    #[test]
    fn selector_regular() {
        let mut parser = CssParser::new("p#id-one.class-one");

        let ex_ss = SimpleSelector::new(Some(String::from("p")), Some(String::from("id-one")), vec![String::from("class-one")]);
        let expected = Selector::new(vec![ex_ss], vec![]);

        assert_eq!(expected, parser.parse_selector());
    }

    /// Test multiple classes in a selector
    #[test]
    fn selector_multi_class() {
        let mut parser = CssParser::new(".class1.class2.class3");
        let ex_ss = SimpleSelector::new(None, None, vec![String::from("class1"), String::from("class2"), String::from("class3")]);
        let expected = Selector::new(vec![ex_ss], vec![]);
        assert_eq!(expected, parser.parse_selector());
    }

    /// Test multiple id's in a selector
    #[test]
    fn selector_multi_id() {
        let mut parser = CssParser::new("#id1#id2#id3");
        assert_eq!(Selector::default(), parser.parse_selector());
    }

    /// Test an invalid selector
    #[test]
    #[should_panic]
    fn selector_invalid() {
        let mut parser = CssParser::new("-p#id-one.class-one");
        parser.parse_selector();
    }

    /// Test selectors parsing (comma seperated list)
    #[test]
    fn selectors_empty() {
        let mut parser = CssParser::new("");
        assert_eq!(Vec::<Selector>::new(), parser.parse_selectors());
    }

    /// Test selectors parsing (comma seperated list)
    #[test]
    fn selectors_end() {
        let mut parser = CssParser::new("{");
        assert_eq!(Vec::<Selector>::new(), parser.parse_selectors());
    }

    /// Test selectors parsing (comma seperated list)
    #[test]
    fn selectors_regular() {
        let mut parser = CssParser::new("tag1, #id1, .class1, _tag-2#id-2.class-2");

        let ssel1 = SimpleSelector::new(Some(String::from("tag1")), None, vec![]);
        let sel1 =  Selector::new(vec![ssel1], vec![]);

        let ssel2 = SimpleSelector::new(None, Some(String::from("id1")), vec![]);
        let sel2 =  Selector::new(vec![ssel2], vec![]);

        let ssel3 = SimpleSelector::new(None, None, vec![String::from("class1")]);
        let sel3 =  Selector::new(vec![ssel3], vec![]);

        let ssel4 = SimpleSelector::new(Some(String::from("_tag-2")), Some(String::from("id-2")), vec![String::from("class-2")]);
        let sel4 =  Selector::new(vec![ssel4], vec![]);

        assert_eq!(vec![sel1, sel2, sel3, sel4], parser.parse_selectors());
    }

    /// Test selectors parsing (comma seperated list one invalid)
    #[test]
    fn selectors_regular_one_invalid() {
        let mut parser = CssParser::new("tag1, #id1, .-class1, _tag-2#id-2.class-2");

        let ssel1 = SimpleSelector::new(Some(String::from("tag1")), None, vec![]);
        let sel1 =  Selector::new(vec![ssel1], vec![]);

        let ssel2 = SimpleSelector::new(None, Some(String::from("id1")), vec![]);
        let sel2 =  Selector::new(vec![ssel2], vec![]);

        let ssel3 = SimpleSelector::new(Some(String::from("_tag-2")), Some(String::from("id-2")), vec![String::from("class-2")]);
        let sel3 =  Selector::new(vec![ssel3], vec![]);

        assert_eq!(vec![sel1, sel2, sel3], parser.parse_selectors());
    }

    /// Test selectors parsing (comma seperated list all invalid)
    #[test]
    fn selectors_regular_all_invalid() {
        let mut parser = CssParser::new("-tag1, #-id1, .-class1, -_tag-2#id-2.class-2");
        assert_eq!(Vec::<Selector>::new(), parser.parse_selectors());
    }

    /// Test stylesheet parsing
    #[test]
    fn stylesheet_empty() {
        let mut parser = CssParser::new("");
        assert_eq!(Stylesheet::default(), parser.parse_stylesheet())
    }

    /// Test stylesheet parsing
    #[test]
    fn stylesheet_regular() {
        let mut parser = CssParser::new(
            "p {
                 color: red;
             }
             body#id1.class1,
             .class2.class3.class4 {
                 border: solid black 1px;
                 background-color: aqua
             }");
        let p_ss = SimpleSelector::new(Some(String::from("p")), None, vec![]);
        let p = Selector::new(vec![p_ss], vec![]);
        let p_decl = Declaration::new(String::from("color"), String::from("red"));
        let rule1 = Rule::new(vec![p], vec![p_decl]);

        let body_ss1 = SimpleSelector::new(Some(String::from("body")), Some(String::from("id1")), vec![String::from("class1")]);
        let body1 = Selector::new(vec![body_ss1], vec![]);
        let body_ss2 = SimpleSelector::new(None, None, vec![String::from("class2"), String::from("class3"), String::from("class4")]);
        let body2 = Selector::new(vec![body_ss2], vec![]);
        let body_decl1 = Declaration::new(String::from("border"), String::from("solid black 1px"));
        let body_decl2 = Declaration::new(String::from("background-color"), String::from("aqua"));
        let rule2 = Rule::new(vec![body1, body2], vec![body_decl1, body_decl2]);

        assert_eq!(Stylesheet::new(vec![rule1, rule2]), parser.parse_stylesheet())
    }
}
<commit_msg>fix one css parsing oddity<commit_after>//! The `css_parse` module parses css stylesheets into css rule datastructures.

use css::{Declaration, Rule, Selector, SimpleSelector, Stylesheet};

use std::iter::Peekable;
use std::str::Chars;

pub struct CssParser<'a> {
    chars: Peekable<Chars<'a>>,
}

impl<'a> CssParser<'a> {
    /// Constructs a new CssParser.
    ///
    /// full_css: the complete css stylesheet to parse.
    pub fn new(full_css: &str) -> CssParser {
        CssParser { chars: full_css.chars().peekable() }
    }

    /// Entry point to parsing css, iterively parse css rules.
    pub fn parse_stylesheet(&mut self) -> Stylesheet {
        let mut stylesheet = Stylesheet::default();

        while self.chars.peek().is_some() {
            let selectors = self.parse_selectors();
            let styles = self.parse_declarations();
            let rule = Rule::new(selectors, styles);

            stylesheet.rules.push(rule);
        }

        stylesheet
    }

    /// Parse the selectors for a single rule.
    fn parse_selectors(&mut self) -> Vec<Selector> {
        let mut selectors = Vec::new();

        while self.chars.peek().map_or(false, |c| *c != '{') {
            let selector = self.parse_selector();
            selectors.push(selector);

            self.consume_while(char::is_whitespace);
            if self.chars.peek().map_or(false, |c| *c == ',') {
                self.chars.next();
            }
        }

        self.chars.next();
        selectors
    }

    /// Parse a single selector in a comma seperated list of selectors.
    fn parse_selector(&mut self) -> Selector {
        let mut sselector = SimpleSelector::default();
        let mut selector = Selector::default();

        self.consume_while(char::is_whitespace);

        sselector.tag_name = match self.chars.peek() {
            Some(&c) if is_valid_start_ident(c) => Some(self.parse_identifier()),
            _ => None,
        };

        let mut multiple_ids = false;
        while self.chars.peek().map_or(false, |c| *c != ',' && *c != '{' && !(*c).is_whitespace()) {
            match self.chars.peek() {
                Some(&c) if c =='#' =>  {
                    self.chars.next();
                    if sselector.id.is_some() || multiple_ids {
                        sselector.id = None;
                        multiple_ids = true;
                        self.parse_id();
                    } else {
                        sselector.id = self.parse_id();
                    }
                },
                Some(&c) if c == '.' => {
                    self.chars.next();
                    sselector.classes.push(self.parse_identifier());
                },
                _ => panic!("INVALID STATE IN parse_selector"), // TODO handle css errors
            }
        }

        if sselector != SimpleSelector::default() {
            selector.simple.push(sselector);
        }

        selector
    }

    /// Parse a css identifier.
    fn parse_identifier(&mut self) -> String {
        let mut ident = String::new();

        match self.chars.peek() {
            Some(&c) => {
                if is_valid_start_ident(c) {
                    ident.push_str(&self.consume_while(is_valid_ident))
                }
            },
            None => {},
        }

        ident
    }

    /// Wraps an identifier in an option
    fn parse_id(&mut self) -> Option<String> {
        match &self.parse_identifier()[..] {
            "" => None,
            s @ _ => Some(s.to_string())
        }
    }

    /// Parse all the declarations for a rule.
    fn parse_declarations(&mut self) -> Vec<Declaration> {
        let mut declarations = Vec::<Declaration>::new();

        while self.chars.peek().map_or(false, |c| *c != '}') {
            self.consume_while(char::is_whitespace);

            let property = self.consume_while(|x| x != ':');

            self.chars.next();
            self.consume_while(char::is_whitespace);

            let value = self.consume_while(|x| x != ';' && x != '\n' && x != '}');
            let declaration = Declaration::new(property, value);

            if self.chars.peek().map_or(false, |c| *c == ';') {
                declarations.push(declaration);
                self.chars.next();
            } else {
                self.consume_while(char::is_whitespace);
                if self.chars.peek().map_or(false, |c| *c == '}') {
                    declarations.push(declaration);
                }
            }
            self.consume_while(char::is_whitespace);
        }

        self.chars.next();
        declarations
    }

    /// Consumes characters until condition is false or there are no more chars left.
    /// Returns a string of the consumed characters.
    fn consume_while<F>(&mut self, condition: F) -> String where F : Fn(char) -> bool {
        let mut result = String::new();
        while self.chars.peek().map_or(false, |c| condition(*c)) {
            // the check above guarentees there is a value to be consumed
            result.push(self.chars.next().unwrap());
        }

        result
    }
}

/// Returns true if the char is a valid for a css identifier.
fn is_valid_ident(c: char) -> bool {
    is_valid_start_ident(c) || c.is_digit(10) || c == '-'
}

/// Returns true if the char is a valid for the first char of a css identifier.
fn is_valid_start_ident(c: char) -> bool {
    is_letter(c) || is_non_ascii(c) || c == '_'
}

/// Returns true if the char is an ASCII letter.
fn is_letter(c: char) -> bool {
    is_upper_letter(c) || is_lower_letter(c)
}

/// Returns true if the char is an ASCII uppercase char.
fn is_upper_letter(c: char) -> bool {
    c >= 'A' && c <= 'Z'
}

/// Returns true if the char is an ASCII lowercase char.
fn is_lower_letter(c: char) -> bool {
    c >= 'a' && c <= 'z'
}

/// Returns true if the char is non-ascii.
fn is_non_ascii(c: char) -> bool {
    c >= '\u{0080}'
}

//TODO
//  -deal with comments and escaping characters
//  -complex selectors
//  -cascade
//  -specificity

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

    use css::{Declaration, Rule, Selector, SimpleSelector, Stylesheet};

    /// Test a parser is constructed correctly.
    #[test]
    fn parser_regular() {
        let css = "p{lel:kek;}";
        let mut parser = CssParser::new(css);

        for character in String::from(css).chars() {
            assert_eq!(character, parser.chars.next().unwrap());
        }

        assert_eq!(None, parser.chars.peek());
    }

    /// Test an empty parser is constructed correctly.
    #[test]
    fn parser_empty() {
        let mut parser = CssParser::new("");

        for character in String::from("").chars() {
            assert_eq!(character, parser.chars.next().unwrap());
        }

        assert_eq!(None, parser.chars.peek());
    }

    /// Test an empty declaration
    #[test]
    fn declarations_empty() {
        let mut parser = CssParser::new("");
        assert_eq!(Vec::<Declaration>::new(), parser.parse_declarations());
    }

    /// Test the end of a declaration
    #[test]
    fn declarations_end() {
        let mut parser = CssParser::new("}");
        assert_eq!(Vec::<Declaration>::new(), parser.parse_declarations());
    }

    /// Test a regular declaration
    #[test]
    fn declarations_regular() {
        let mut parser = CssParser::new(
            "color:red;
             border-width: 1px;
             background-color: aqua
           }");
        let decl_col = Declaration::new(String::from("color"), String::from("red"));
        let decl_bw = Declaration::new(String::from("border-width"), String::from("1px"));
        let decl_bg_col = Declaration::new(String::from("background-color"), String::from("aqua"));

        let expected = vec![decl_col, decl_bw, decl_bg_col];
        assert_eq!(expected, parser.parse_declarations());
    }

    /// Test declaration: semi-colon missing
    #[test]
    fn declarations_invalid() {
        let mut parser = CssParser::new(
            "color:red;
             border-width: 1px
             background-color: aqua
           }");
        let decl_col = Declaration::new(String::from("color"), String::from("red"));
        let decl_bg_col = Declaration::new(String::from("background-color"), String::from("aqua"));

        let expected = vec![decl_col, decl_bg_col];
        assert_eq!(expected, parser.parse_declarations());
    }

    /// Test empty identifier
    #[test]
    fn identifier_empty() {
        let mut parser = CssParser::new("");
        assert_eq!(String::from(""), parser.parse_identifier());
    }

    /// Test end of identifier
    #[test]
    fn identifier_end() {
        let mut parser = CssParser::new(",");
        assert_eq!(String::from(""), parser.parse_identifier());
    }

    /// Test a regular identifier
    #[test]
    fn identifier_regular() {
        let mut parser = CssParser::new("identifier-one,");
        assert_eq!(String::from("identifier-one"), parser.parse_identifier());
    }

    /// Test a multi-section identifier
    #[test]
    fn identifier_long() {
        let mut parser = CssParser::new("identifier-one.class-one,");
        assert_eq!(String::from("identifier-one"), parser.parse_identifier());
    }

    /// Test an identifier beginning with -
    #[test]
    fn identifier_invalid() {
        let mut parser = CssParser::new("-identifier-one.class-one,");
        assert_eq!(String::from(""), parser.parse_identifier());
    }

    /// Test whitespace after the identifier
    #[test]
    fn identifier_whitespace() {
        let mut parser = CssParser::new("identifier p#id-one.class-one,");
        assert_eq!(String::from("identifier"), parser.parse_identifier());
    }

    /// Test an empty selector
    #[test]
    fn selector_empty() {
        let mut parser = CssParser::new("");
        assert_eq!(Selector::default(), parser.parse_selector());
    }

    /// Test selector parsing with a ,
    #[test]
    fn selector_end1() {
        let mut parser = CssParser::new(",");
        assert_eq!(Selector::default(), parser.parse_selector());
    }

    /// Test selector parsing with a {
    #[test]
    fn selector_end2() {
        let mut parser = CssParser::new("{");
        assert_eq!(Selector::default(), parser.parse_selector());
    }

    /// Test a regular selector
    #[test]
    fn selector_regular() {
        let mut parser = CssParser::new("p#id-one.class-one");

        let ex_ss = SimpleSelector::new(Some(String::from("p")), Some(String::from("id-one")), vec![String::from("class-one")]);
        let expected = Selector::new(vec![ex_ss], vec![]);

        assert_eq!(expected, parser.parse_selector());
    }

    /// Test multiple classes in a selector
    #[test]
    fn selector_multi_class() {
        let mut parser = CssParser::new(".class1.class2.class3");
        let ex_ss = SimpleSelector::new(None, None, vec![String::from("class1"), String::from("class2"), String::from("class3")]);
        let expected = Selector::new(vec![ex_ss], vec![]);
        assert_eq!(expected, parser.parse_selector());
    }

    /// Test multiple id's in a selector
    #[test]
    fn selector_multi_id() {
        let mut parser = CssParser::new("#id1#id2#id3");
        assert_eq!(Selector::default(), parser.parse_selector());
    }

    /// Test an invalid selector
    #[test]
    #[should_panic]
    fn selector_invalid() {
        let mut parser = CssParser::new("-p#id-one.class-one");
        parser.parse_selector();
    }

    /// Test selectors parsing (comma seperated list)
    #[test]
    fn selectors_empty() {
        let mut parser = CssParser::new("");
        assert_eq!(Vec::<Selector>::new(), parser.parse_selectors());
    }

    /// Test selectors parsing (comma seperated list)
    #[test]
    fn selectors_end() {
        let mut parser = CssParser::new("{");
        assert_eq!(Vec::<Selector>::new(), parser.parse_selectors());
    }

    /// Test selectors parsing (comma seperated list)
    #[test]
    fn selectors_regular() {
        let mut parser = CssParser::new("tag1, #id1, .class1, _tag-2#id-2.class-2");

        let ssel1 = SimpleSelector::new(Some(String::from("tag1")), None, vec![]);
        let sel1 =  Selector::new(vec![ssel1], vec![]);

        let ssel2 = SimpleSelector::new(None, Some(String::from("id1")), vec![]);
        let sel2 =  Selector::new(vec![ssel2], vec![]);

        let ssel3 = SimpleSelector::new(None, None, vec![String::from("class1")]);
        let sel3 =  Selector::new(vec![ssel3], vec![]);

        let ssel4 = SimpleSelector::new(Some(String::from("_tag-2")), Some(String::from("id-2")), vec![String::from("class-2")]);
        let sel4 =  Selector::new(vec![ssel4], vec![]);

        assert_eq!(vec![sel1, sel2, sel3, sel4], parser.parse_selectors());
    }

    /// Test selectors parsing (comma seperated list one invalid)
    #[test]
    fn selectors_regular_one_invalid() {
        let mut parser = CssParser::new("tag1, #id1, .-class1, _tag-2#id-2.class-2");

        let ssel1 = SimpleSelector::new(Some(String::from("tag1")), None, vec![]);
        let sel1 =  Selector::new(vec![ssel1], vec![]);

        let ssel2 = SimpleSelector::new(None, Some(String::from("id1")), vec![]);
        let sel2 =  Selector::new(vec![ssel2], vec![]);

        let ssel3 = SimpleSelector::new(Some(String::from("_tag-2")), Some(String::from("id-2")), vec![String::from("class-2")]);
        let sel3 =  Selector::new(vec![ssel3], vec![]);

        assert_eq!(vec![sel1, sel2, sel3], parser.parse_selectors());
    }

    /// Test selectors parsing (comma seperated list all invalid)
    #[test]
    fn selectors_regular_all_invalid() {
        let mut parser = CssParser::new("-tag1, #-id1, .-class1, -_tag-2#id-2.class-2");
        assert_eq!(Vec::<Selector>::new(), parser.parse_selectors());
    }

    /// Test stylesheet parsing
    #[test]
    fn stylesheet_empty() {
        let mut parser = CssParser::new("");
        assert_eq!(Stylesheet::default(), parser.parse_stylesheet())
    }

    /// Test stylesheet parsing
    #[test]
    fn stylesheet_regular() {
        let mut parser = CssParser::new(
            "p {
                 color: red;
             }
             body#id1.class1,
             .class2.class3.class4 {
                 border: solid black 1px;
                 background-color: aqua
             }");
        let p_ss = SimpleSelector::new(Some(String::from("p")), None, vec![]);
        let p = Selector::new(vec![p_ss], vec![]);
        let p_decl = Declaration::new(String::from("color"), String::from("red"));
        let rule1 = Rule::new(vec![p], vec![p_decl]);

        let body_ss1 = SimpleSelector::new(Some(String::from("body")), Some(String::from("id1")), vec![String::from("class1")]);
        let body1 = Selector::new(vec![body_ss1], vec![]);
        let body_ss2 = SimpleSelector::new(None, None, vec![String::from("class2"), String::from("class3"), String::from("class4")]);
        let body2 = Selector::new(vec![body_ss2], vec![]);
        let body_decl1 = Declaration::new(String::from("border"), String::from("solid black 1px"));
        let body_decl2 = Declaration::new(String::from("background-color"), String::from("aqua"));
        let rule2 = Rule::new(vec![body1, body2], vec![body_decl1, body_decl2]);

        assert_eq!(Stylesheet::new(vec![rule1, rule2]), parser.parse_stylesheet())
    }
}
<|endoftext|>


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

#[allow(dead_code,non_camel_case_types,non_snake_case)]
mod ffi;

use std::path::Path;
use libc::{c_uint,c_ulong};

#[allow(dead_code,non_camel_case_types,non_snake_case)]
mod enums {
    use super::ffi as ffi;

    include!(concat!(env!("OUT_DIR"), "/demux-enums.rs"));
}

pub use self::enums::{Input,Output,PesType};

pub struct Demux {
    device: DeviceFileDescriptor
}

use super::device::{DeviceFileDescriptor,BlockMode,ReadWriteMode,DeviceResult};

impl Demux {
    pub fn open(file: &Path, rw_mode: ReadWriteMode, block_mode: BlockMode) -> DeviceResult<Demux> {
        let device = try!(DeviceFileDescriptor::open(file, rw_mode, block_mode));
        Ok(Demux { device: device })
    }

    pub fn read(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    // Should this even exist here?
    pub fn write(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn start(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::DMX_START as c_ulong)
    }

    pub fn stop(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::DMX_STOP as c_ulong)
    }

    pub fn set_filter(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn set_pes_filter(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn set_buffer_size(&self, buffer_size: u32) -> DeviceResult<()> {
        let mut ffi_size = buffer_size as c_ulong;
        self.device.ioctl_pointer(ffi::DMX_SET_BUFFER_SIZE as c_ulong, &mut ffi_size)
    }

    pub fn get_system_time_counter(&self, num: u32) -> DeviceResult<SystemTimeCounter> {
        let mut ffi_stc = ffi::Struct_dmx_stc { num: num as c_uint, base: 0, stc: 0 };
        try!(self.device.ioctl_pointer(ffi::DMX_GET_STC as c_ulong, &mut ffi_stc));
        Ok(SystemTimeCounter { base: ffi_stc.base, counter: ffi_stc.stc })
    }

    pub fn get_pes_pids(&self) -> DeviceResult<[u16; 5]> {
        unimplemented!();
    }

    /// This function is undocumented in the official, and doesn't seem to be actually in use.
    /// It is still nevertheless included here, if it is used by out-of-tree DVB drivers.
    pub fn get_caps(&self) -> DeviceResult<DemuxCaps> {
        let mut ffi_caps = ffi::Struct_dmx_caps { caps: 0, num_decoders: 0 };
        try!(self.device.ioctl_pointer(ffi::DMX_GET_CAPS as c_ulong, &mut ffi_caps));
        Ok(DemuxCaps { caps: ffi_caps.caps, num_decoders: ffi_caps.num_decoders as i32 })
    }

    pub fn set_source(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn add_pid(&self, pid: u16) -> DeviceResult<()> {
        let mut ffi_pid = pid;
        self.device.ioctl_pointer(ffi::DMX_ADD_PID as c_ulong, &mut ffi_pid)
    }

    pub fn remove_pid(&self, pid: u16) -> DeviceResult<()> {
        let mut ffi_pid = pid;
        self.device.ioctl_pointer(ffi::DMX_REMOVE_PID as c_ulong, &mut ffi_pid)
    }
}

pub struct DemuxCaps {
    pub caps: u32,
    pub num_decoders: i32
}

pub struct SystemTimeCounter {
    pub base: u32,
    pub counter: u64
}

pub struct DemuxFilter {
    pub filter: [u8; ffi::DMX_FILTER_SIZE as usize],
    pub mask: [u8; ffi::DMX_FILTER_SIZE as usize],
    pub mode: [u8; ffi::DMX_FILTER_SIZE as usize],
}

pub struct SectionFilterParams {
    pub pid: u16,
    pub filter: DemuxFilter,
    pub timeout: u32,
    // pub flags: flags::SectionFilterFlags
}

pub struct PesFilterParams {
    pub pid: u16,
    pub input: Input,
    pub output: Output,
    pub pes_type: PesType,
    pub flags: u32
}<commit_msg>Implement get_pes_pids().<commit_after>// Copyright 2015 Ilkka Rauta
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[allow(dead_code,non_camel_case_types,non_snake_case)]
mod ffi;

use std::path::Path;
use libc::{c_uint,c_ulong};

#[allow(dead_code,non_camel_case_types,non_snake_case)]
mod enums {
    use super::ffi as ffi;

    include!(concat!(env!("OUT_DIR"), "/demux-enums.rs"));
}

pub use self::enums::{Input,Output,PesType};

pub struct Demux {
    device: DeviceFileDescriptor
}

use super::device::{DeviceFileDescriptor,BlockMode,ReadWriteMode,DeviceResult};

impl Demux {
    pub fn open(file: &Path, rw_mode: ReadWriteMode, block_mode: BlockMode) -> DeviceResult<Demux> {
        let device = try!(DeviceFileDescriptor::open(file, rw_mode, block_mode));
        Ok(Demux { device: device })
    }

    pub fn read(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    // Should this even exist here?
    pub fn write(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn start(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::DMX_START as c_ulong)
    }

    pub fn stop(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::DMX_STOP as c_ulong)
    }

    pub fn set_filter(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn set_pes_filter(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn set_buffer_size(&self, buffer_size: u32) -> DeviceResult<()> {
        let mut ffi_size = buffer_size as c_ulong;
        self.device.ioctl_pointer(ffi::DMX_SET_BUFFER_SIZE as c_ulong, &mut ffi_size)
    }

    pub fn get_system_time_counter(&self, num: u32) -> DeviceResult<SystemTimeCounter> {
        let mut ffi_stc = ffi::Struct_dmx_stc { num: num as c_uint, base: 0, stc: 0 };
        try!(self.device.ioctl_pointer(ffi::DMX_GET_STC as c_ulong, &mut ffi_stc));
        Ok(SystemTimeCounter { base: ffi_stc.base, counter: ffi_stc.stc })
    }

    pub fn get_pes_pids(&self) -> DeviceResult<[u16; 5]> {
        let mut ffi_pids = [0u16; 5];
        try!(self.device.ioctl_pointer(ffi::DMX_GET_PES_PIDS as c_ulong, ffi_pids.as_mut_ptr()));
        Ok(ffi_pids)
    }

    /// This function is undocumented in the official, and doesn't seem to be actually in use.
    /// It is still nevertheless included here, if it is used by out-of-tree DVB drivers.
    pub fn get_caps(&self) -> DeviceResult<DemuxCaps> {
        let mut ffi_caps = ffi::Struct_dmx_caps { caps: 0, num_decoders: 0 };
        try!(self.device.ioctl_pointer(ffi::DMX_GET_CAPS as c_ulong, &mut ffi_caps));
        Ok(DemuxCaps { caps: ffi_caps.caps, num_decoders: ffi_caps.num_decoders as i32 })
    }

    pub fn set_source(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn add_pid(&self, pid: u16) -> DeviceResult<()> {
        let mut ffi_pid = pid;
        self.device.ioctl_pointer(ffi::DMX_ADD_PID as c_ulong, &mut ffi_pid)
    }

    pub fn remove_pid(&self, pid: u16) -> DeviceResult<()> {
        let mut ffi_pid = pid;
        self.device.ioctl_pointer(ffi::DMX_REMOVE_PID as c_ulong, &mut ffi_pid)
    }
}

pub struct DemuxCaps {
    pub caps: u32,
    pub num_decoders: i32
}

pub struct SystemTimeCounter {
    pub base: u32,
    pub counter: u64
}

pub struct DemuxFilter {
    pub filter: [u8; ffi::DMX_FILTER_SIZE as usize],
    pub mask: [u8; ffi::DMX_FILTER_SIZE as usize],
    pub mode: [u8; ffi::DMX_FILTER_SIZE as usize],
}

pub struct SectionFilterParams {
    pub pid: u16,
    pub filter: DemuxFilter,
    pub timeout: u32,
    // pub flags: flags::SectionFilterFlags
}

pub struct PesFilterParams {
    pub pid: u16,
    pub input: Input,
    pub output: Output,
    pub pes_type: PesType,
    pub flags: u32
}<|endoftext|>


<commit_before>pub const NUM_DIRECTIONS: usize = 4;

use self::Direction::*;

#[derive(Debug, Copy, Clone)]
pub enum Direction {
  North,
  South,
  East,
  West,
}

impl Direction {
  pub fn opposite(self) -> Self {
    match self {
      North => South,
      South => North,
      East => West,
      West => East,
    }
  }
}
<commit_msg>Add up/down direction.<commit_after>pub const NUM_DIRECTIONS: usize = 6;

use self::Direction::*;

#[derive(Debug, Copy, Clone)]
pub enum Direction {
  North,
  South,
  East,
  West,
  Up,
  Down,
}

impl Direction {
  pub fn opposite(self) -> Self {
    match self {
      North => South,
      South => North,
      East => West,
      West => East,
      Up => Down,
      Down => Up,
    }
  }
}
<|endoftext|>


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

use std::thread;
use std::net::{TcpListener, ToSocketAddrs};
use std::ops::DerefMut;
use std::os::unix::io::RawFd;
use std::collections::LinkedList;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{
    channel,
    Sender,
    Receiver
};

use epoll;
use epoll::util::*;
use epoll::EpollEvent;
use simple_stream::nbetstream::NbetStream;
use stats;
use types::*;
use socket::Socket;
use resources::ResourcePool;

// When added to epoll, these will be the conditions of kernel notification:
//
// EPOLLIN      - Available for read
// EPOLLRDHUP   - Connection has been closed
// EPOLLONESHOT - After an event has been received, and reported, do not track
//                further changes until explicitly told to do so.
const EVENTS: u32 = (
    event_type::EPOLLET | // Set fd to EdgeTrigger mode
    event_type::EPOLLIN |
    event_type::EPOLLRDHUP |
    event_type::EPOLLONESHOT |
    event_type::EPOLLERR |
    event_type::EPOLLHUP);

pub fn begin<T, K>(address: T, handler: Box<K>) where
    T: ToSocketAddrs + Send + 'static,
    K: EventHandler + Send + Sync + 'static {
    // Master socket list
    let sockets = Arc::new(Mutex::new(LinkedList::<Socket>::new()));

    // Epoll instance
    let result = epoll::create1(0);
    if result.is_err() {
        let err = result.unwrap_err();
        error!("Unable to create epoll instance: {}", err);
        panic!()
    }
    let epfd = result.unwrap();

    // EpollEvent handler thread
    let epfd1 = epfd.clone();
    let sockets1 = sockets.clone();
    let (tx_ep_event, rx_ep_event): (Sender<EpollEvent>, Receiver<EpollEvent>) = channel();
    let safe_handler = Arc::new(Mutex::new(*handler));
    thread::Builder::new()
        .name("EpollEvent Handler".to_string())
        .spawn(move || {
            epoll_event_handler(epfd1, rx_ep_event, sockets1, safe_handler);
        }).unwrap();

    // Epoll wait thread
    let epfd2 = epfd.clone();
    thread::Builder::new()
        .name("Epoll Wait".to_string())
        .spawn(move || {
            epoll_wait_loop(epfd2, tx_ep_event);
        }).unwrap();

    // New connection thread
    let epfd3 = epfd.clone();
    let sockets2 = sockets.clone();
    let prox = thread::Builder::new()
        .name("TCP Incoming Listener".to_string())
        .spawn(move || {
            listen(address, epfd3, sockets2);
        }).unwrap();

    // Stay alive forever
    let _ = prox.join();
}

fn listen<T: ToSocketAddrs>(address: T, epfd: RawFd, sockets: SocketList) {
    let listener = TcpListener::bind(address).unwrap();
    for connection in listener.incoming() {
        if connection.is_err() {
            warn!("Error encountered during TCP connection: {}", connection.unwrap_err());
            continue;
        }

        let result = NbetStream::new(connection.unwrap());
        if result.is_err() {
            warn!("Error creating nbstream: {:?}", result.unwrap_err());
            continue;
        }

        let socket_ptr;
        let socket = Socket::new(result.unwrap());
        { // Begin Mutex lock
            let mut guard = match sockets.lock() {
                Ok(guard) => guard,
                Err(poisoned) => {
                    warn!("SocketList Mutex failed, using anyway...");
                    poisoned.into_inner()
                }
            };
            let socket_list = guard.deref_mut();
            socket_list.push_back(socket.clone());
            socket_ptr = socket_list.back_mut().unwrap() as *mut Socket;
        } // End Mutex lock

        // Add to epoll
        let sfd = socket.raw_fd();
        let mut event = EpollEvent {
            data: socket_ptr as u64,
            events: EVENTS
        };
        let _ = epoll::ctl(epfd, ctl_op::ADD, sfd, &mut event).map_err(|e| {
            error!("CtrlError during add: {}", e);
        });
    }
    drop(listener);
}

fn epoll_wait_loop(epfd: RawFd, tx_handler: Sender<EpollEvent>) {
    // Maximum number of events we want to be notified of at one time
    let mut events = Vec::<EpollEvent>::with_capacity(100);
    unsafe { events.set_len(100); }

    loop {
        match epoll::wait(epfd, &mut events[..], -1) {
            Ok(num_events) => {
                for x in 0..num_events as usize {
                    let _ = tx_handler.send(events[x]);
                }
            }
            Err(e) => {
                error!("Error on epoll::wait(): {}", e);
                panic!()
            }
        }
    }
}

fn epoll_event_handler(epfd: RawFd,
                       rx: Receiver<EpollEvent>,
                       sockets: SocketList,
                       handler: SafeHandler) {
    // Types of events we care about
    const READ_EVENT: u32 = event_type::EPOLLIN;
    const DROP_EVENT: u32 = event_type::EPOLLRDHUP | event_type::EPOLLHUP | event_type::EPOLLERR;

    // Thread pool
    let mut pool = ResourcePool::new();

    for event in rx.iter() {
        // Get a pointer to the socket in the list
        let socket;
        { // Begin Mutex lock
            let _ = match sockets.lock() {
                Ok(guard) => guard,
                Err(poisoned) => {
                    warn!("SocketList Mutex failed, using anyway...");
                    poisoned.into_inner()
                }
            };
            socket = event.data as *mut Socket;
        } // End Mutex lock

        if (event.events & DROP_EVENT) > 0 {
            trace!("Received drop event");
            let t_epfd = epfd.clone();
            let socket_list = sockets.clone();
            let t_handler = handler.clone();
            let socketfd = unsafe { (*socket).raw_fd() };
            let socketid = unsafe { (*socket).id() };

            pool.run(move || {
                epoll_remove_fd(t_epfd, socketfd);
                remove_socket_from_list(socketid, socket_list.clone());
                { // EventHandler Mutex locked
                    let mut guard = match t_handler.lock() {
                        Ok(guard) => guard,
                        Err(poisoned) => {
                            warn!("EventHandler Mutex failed, using anyway...");
                            poisoned.into_inner()
                        }
                    };
                    let e_handler = guard.deref_mut();
                    e_handler.on_socket_closed(socketid);
                } // EventHandler Mutex unlocked
            });
        } else if (event.events & READ_EVENT) > 0 {
            let t_epfd = epfd.clone();
            let mut s_clone = unsafe { (*socket).clone() };
            let socketfd = s_clone.raw_fd();
            let socket_list = sockets.clone();
            let t_handler = handler.clone();
            let socket_ptr = socket as u64;

            pool.run(move || {
                match s_clone.read() {
                    Ok(_) => {
                        for msg in s_clone.buffer().iter() {
                            let debug_msg = msg.clone();
                            match String::from_utf8(debug_msg) {
                                Ok(msg_str) => trace!("msg: {}", msg_str),
                                Err(_) => trace!("msg not UTF-8")
                            };

                            { // EventHandler Mutex locked
                                let mut guard = match t_handler.lock() {
                                    Ok(guard) => guard,
                                    Err(poisoned) => {
                                        warn!("EventHandler Mutex failed, using anyway...");
                                        poisoned.into_inner()
                                    }
                                };
                                let e_handler = guard.deref_mut();
                                e_handler.on_data_received(s_clone.clone(),
                                    socket_list.clone(), msg.clone());
                            } // EventHandler Mutex unlocked

                            // Track message received event and num bytes received
                            stats::msg_recv();
                            stats::bytes_recv(msg.len());

                            // Add socket's fd to epoll watch list
                            //
                            // Rust's TcpStream clone method makes use of the F_DUPFD flag
                            // for duplicating file descriptors. This means the fd we just read
                            // from and/or the original fd added to epoll for this stream cannot
                            // be used to MOD, or DEL and ADD again, in order to re-register for
                            // the same events, with the same fd.
                            // The originally added fd is essentially invalid at this point, but
                            // lucky for us, Rust sets the CLOEXEC flag for fds, which means that
                            // the system will clean them up when they go out of scope. Also,
                            // epoll removes fds when the system clears them, so we should be OK
                            // from any internal fd leaks here. All we really care about, is if
                            // we receive the EEXIST from the call. In this case, we must apply
                            // the adjustment as a MOD
                            let mut event = EpollEvent {
                                data: socket_ptr,
                                events: EVENTS
                            };
                            let s_id = s_clone.id();
                            match epoll::ctl(t_epfd.clone(), ctl_op::ADD, socketfd, &mut event) {
                                Ok(_) => trace!("Socket back in epoll list"),
                                Err(e) => {
                                    if e == CtlError::EEXIST {
                                        trace!("Fd already exists in epoll, trying ctl::MOD");
                                        match epoll::ctl(t_epfd.clone(), ctl_op::MOD, socketfd,
                                            &mut event) {
                                            Ok(_) => trace!("Socket back in epoll list with mod"),
                                            Err(_) => {
                                                warn!("Error modifying socket in epoll...")
                                            }
                                        };
                                    } else {
                                        warn!("Epoll CtrlError during mod: {}", e);
                                        warn!("s.id: {}", s_id);
                                        warn!("epfd: {}", t_epfd.clone());
                                        warn!("fd: {}", socketfd);
                                    }
                                }
                            };
                        }
                    }
                    Err(e) => {
                        debug!("Error reading socket: {}", e);
                        // We really don't care what happened, it all results in the same
                        // outcome - remove the socket from system...
                        let s_id = s_clone.id();
                        epoll_remove_fd(t_epfd, socketfd);
                        remove_socket_from_list(s_id, socket_list.clone());
                        let mut guard = match t_handler.lock() {
                            Ok(guard) => guard,
                            Err(poisoned) => {
                                warn!("SocketList Mutex failed, using anyway...");
                                poisoned.into_inner()
                            }
                        };
                        let e_handler = guard.deref_mut();
                        e_handler.on_socket_closed(s_id);
                    }
                };
            });
        } else { warn!("Unknown epoll event received: {}", event.data); continue; }
    }
}

fn epoll_remove_fd(epfd: RawFd, fd: RawFd) {
    debug!("remove_socket_from_epoll");

    // In kernel versions before 2.6.9, the EPOLL_CTL_DEL operation required
    // a non-null pointer in event, even though this argument is ignored.
    // Since Linux 2.6.9, event can be specified as NULL when using
    // EPOLL_CTL_DEL.  Applications that need to be portable to kernels
    // before 2.6.9 should specify a non-null pointer in event.
    let mut rm_event = EpollEvent {
        data: 0 as u64,
        events: 0 as u32
    };

    // Depending on how fds are duplicated with .clone(), this may fail.
    //
    // If the failure case is CtlError::ENOENT, we do not care, because
    // epoll will clean the up the descriptor after they are all dropped from
    // program memory
    match epoll::ctl(epfd, ctl_op::DEL, fd, &mut rm_event) {
        Ok(()) => trace!("Socket removed from epoll watch list"),
        Err(e) => {
            match e {
                CtlError::ENOENT => {
                    trace!("Fd not found in epoll, will remove when fd is syscall closed");
                }
                _ => warn!("Epoll CtrlError during del: {}", e)
            }
        }
    };
}

/// Removes socket_ids from master list
fn remove_socket_from_list(socket_id: u32, sockets: SocketList) {
    debug!("remove_socket_from_list");

    let mut s_guard = match sockets.lock() {
        Ok(guard) => guard,
        Err(poisoned) => {
            warn!("SocketList Mutex was poisoned, using anyway");
            poisoned.into_inner()
        }
    };
    let s_list = s_guard.deref_mut();

    let mut s_found = false;
    let mut index = 1usize;
    for s in s_list.iter() {
        if s.id() == socket_id {
            s_found = true;
            break;
        }
        index += 1;
    }

    if !s_found { return; }

    if index == 1 {
        s_list.pop_front();
    } else {
        let mut split = s_list.split_off(index - 1);
        split.pop_front();
        s_list.append(&mut split);
    }

    stats::conn_lost();

    trace!("socket removed from list");
}
<commit_msg>Removed un-needed variable assignment<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

use std::thread;
use std::net::{TcpListener, ToSocketAddrs};
use std::ops::DerefMut;
use std::os::unix::io::RawFd;
use std::collections::LinkedList;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{
    channel,
    Sender,
    Receiver
};

use epoll;
use epoll::util::*;
use epoll::EpollEvent;
use simple_stream::nbetstream::NbetStream;
use stats;
use types::*;
use socket::Socket;
use resources::ResourcePool;

// When added to epoll, these will be the conditions of kernel notification:
//
// EPOLLIN      - Available for read
// EPOLLRDHUP   - Connection has been closed
// EPOLLONESHOT - After an event has been received, and reported, do not track
//                further changes until explicitly told to do so.
const EVENTS: u32 = (
    event_type::EPOLLET | // Set fd to EdgeTrigger mode
    event_type::EPOLLIN |
    event_type::EPOLLRDHUP |
    event_type::EPOLLONESHOT |
    event_type::EPOLLERR |
    event_type::EPOLLHUP);

pub fn begin<T, K>(address: T, handler: Box<K>) where
    T: ToSocketAddrs + Send + 'static,
    K: EventHandler + Send + Sync + 'static {
    // Master socket list
    let sockets = Arc::new(Mutex::new(LinkedList::<Socket>::new()));

    // Epoll instance
    let result = epoll::create1(0);
    if result.is_err() {
        let err = result.unwrap_err();
        error!("Unable to create epoll instance: {}", err);
        panic!()
    }
    let epfd = result.unwrap();

    // EpollEvent handler thread
    let epfd1 = epfd.clone();
    let sockets1 = sockets.clone();
    let (tx_ep_event, rx_ep_event): (Sender<EpollEvent>, Receiver<EpollEvent>) = channel();
    let safe_handler = Arc::new(Mutex::new(*handler));
    thread::Builder::new()
        .name("EpollEvent Handler".to_string())
        .spawn(move || {
            epoll_event_handler(epfd1, rx_ep_event, sockets1, safe_handler);
        }).unwrap();

    // Epoll wait thread
    let epfd2 = epfd.clone();
    thread::Builder::new()
        .name("Epoll Wait".to_string())
        .spawn(move || {
            epoll_wait_loop(epfd2, tx_ep_event);
        }).unwrap();

    // New connection thread
    let epfd3 = epfd.clone();
    let sockets2 = sockets.clone();
    let prox = thread::Builder::new()
        .name("TCP Incoming Listener".to_string())
        .spawn(move || {
            listen(address, epfd3, sockets2);
        }).unwrap();

    // Stay alive forever
    let _ = prox.join();
}

fn listen<T: ToSocketAddrs>(address: T, epfd: RawFd, sockets: SocketList) {
    let listener = TcpListener::bind(address).unwrap();
    for connection in listener.incoming() {
        if connection.is_err() {
            warn!("Error encountered during TCP connection: {}", connection.unwrap_err());
            continue;
        }

        let result = NbetStream::new(connection.unwrap());
        if result.is_err() {
            warn!("Error creating nbstream: {:?}", result.unwrap_err());
            continue;
        }

        let socket_ptr;
        let socket = Socket::new(result.unwrap());
        { // Begin Mutex lock
            let mut guard = match sockets.lock() {
                Ok(guard) => guard,
                Err(poisoned) => {
                    warn!("SocketList Mutex failed, using anyway...");
                    poisoned.into_inner()
                }
            };
            let socket_list = guard.deref_mut();
            socket_list.push_back(socket.clone());
            socket_ptr = socket_list.back_mut().unwrap() as *mut Socket;
        } // End Mutex lock

        // Add to epoll
        let mut event = EpollEvent {
            data: socket_ptr as u64,
            events: EVENTS
        };
        let _ = epoll::ctl(epfd, ctl_op::ADD, socket.raw_fd(), &mut event).map_err(|e| {
            error!("CtrlError during add: {}", e);
        });
    }
    drop(listener);
}

fn epoll_wait_loop(epfd: RawFd, tx_handler: Sender<EpollEvent>) {
    // Maximum number of events we want to be notified of at one time
    let mut events = Vec::<EpollEvent>::with_capacity(100);
    unsafe { events.set_len(100); }

    loop {
        match epoll::wait(epfd, &mut events[..], -1) {
            Ok(num_events) => {
                for x in 0..num_events as usize {
                    let _ = tx_handler.send(events[x]);
                }
            }
            Err(e) => {
                error!("Error on epoll::wait(): {}", e);
                panic!()
            }
        }
    }
}

fn epoll_event_handler(epfd: RawFd,
                       rx: Receiver<EpollEvent>,
                       sockets: SocketList,
                       handler: SafeHandler) {
    // Types of events we care about
    const READ_EVENT: u32 = event_type::EPOLLIN;
    const DROP_EVENT: u32 = event_type::EPOLLRDHUP | event_type::EPOLLHUP | event_type::EPOLLERR;

    // Thread pool
    let mut pool = ResourcePool::new();

    for event in rx.iter() {
        // Get a pointer to the socket in the list
        let socket;
        { // Begin Mutex lock
            let _ = match sockets.lock() {
                Ok(guard) => guard,
                Err(poisoned) => {
                    warn!("SocketList Mutex failed, using anyway...");
                    poisoned.into_inner()
                }
            };
            socket = event.data as *mut Socket;
        } // End Mutex lock

        if (event.events & DROP_EVENT) > 0 {
            trace!("Received drop event");
            let t_epfd = epfd.clone();
            let socket_list = sockets.clone();
            let t_handler = handler.clone();
            let socketfd = unsafe { (*socket).raw_fd() };
            let socketid = unsafe { (*socket).id() };

            pool.run(move || {
                epoll_remove_fd(t_epfd, socketfd);
                remove_socket_from_list(socketid, socket_list.clone());
                { // EventHandler Mutex locked
                    let mut guard = match t_handler.lock() {
                        Ok(guard) => guard,
                        Err(poisoned) => {
                            warn!("EventHandler Mutex failed, using anyway...");
                            poisoned.into_inner()
                        }
                    };
                    let e_handler = guard.deref_mut();
                    e_handler.on_socket_closed(socketid);
                } // EventHandler Mutex unlocked
            });
        } else if (event.events & READ_EVENT) > 0 {
            let t_epfd = epfd.clone();
            let mut s_clone = unsafe { (*socket).clone() };
            let socketfd = s_clone.raw_fd();
            let socket_list = sockets.clone();
            let t_handler = handler.clone();
            let socket_ptr = socket as u64;

            pool.run(move || {
                match s_clone.read() {
                    Ok(_) => {
                        for msg in s_clone.buffer().iter() {
                            let debug_msg = msg.clone();
                            match String::from_utf8(debug_msg) {
                                Ok(msg_str) => trace!("msg: {}", msg_str),
                                Err(_) => trace!("msg not UTF-8")
                            };

                            { // EventHandler Mutex locked
                                let mut guard = match t_handler.lock() {
                                    Ok(guard) => guard,
                                    Err(poisoned) => {
                                        warn!("EventHandler Mutex failed, using anyway...");
                                        poisoned.into_inner()
                                    }
                                };
                                let e_handler = guard.deref_mut();
                                e_handler.on_data_received(s_clone.clone(),
                                    socket_list.clone(), msg.clone());
                            } // EventHandler Mutex unlocked

                            // Track message received event and num bytes received
                            stats::msg_recv();
                            stats::bytes_recv(msg.len());

                            // Add socket's fd to epoll watch list
                            //
                            // Rust's TcpStream clone method makes use of the F_DUPFD flag
                            // for duplicating file descriptors. This means the fd we just read
                            // from and/or the original fd added to epoll for this stream cannot
                            // be used to MOD, or DEL and ADD again, in order to re-register for
                            // the same events, with the same fd.
                            // The originally added fd is essentially invalid at this point, but
                            // lucky for us, Rust sets the CLOEXEC flag for fds, which means that
                            // the system will clean them up when they go out of scope. Also,
                            // epoll removes fds when the system clears them, so we should be OK
                            // from any internal fd leaks here. All we really care about, is if
                            // we receive the EEXIST from the call. In this case, we must apply
                            // the adjustment as a MOD
                            let mut event = EpollEvent {
                                data: socket_ptr,
                                events: EVENTS
                            };
                            let s_id = s_clone.id();
                            match epoll::ctl(t_epfd.clone(), ctl_op::ADD, socketfd, &mut event) {
                                Ok(_) => trace!("Socket back in epoll list"),
                                Err(e) => {
                                    if e == CtlError::EEXIST {
                                        trace!("Fd already exists in epoll, trying ctl::MOD");
                                        match epoll::ctl(t_epfd.clone(), ctl_op::MOD, socketfd,
                                            &mut event) {
                                            Ok(_) => trace!("Socket back in epoll list with mod"),
                                            Err(_) => {
                                                warn!("Error modifying socket in epoll...")
                                            }
                                        };
                                    } else {
                                        warn!("Epoll CtrlError during mod: {}", e);
                                        warn!("s.id: {}", s_id);
                                        warn!("epfd: {}", t_epfd.clone());
                                        warn!("fd: {}", socketfd);
                                    }
                                }
                            };
                        }
                    }
                    Err(e) => {
                        debug!("Error reading socket: {}", e);
                        // We really don't care what happened, it all results in the same
                        // outcome - remove the socket from system...
                        let s_id = s_clone.id();
                        epoll_remove_fd(t_epfd, socketfd);
                        remove_socket_from_list(s_id, socket_list.clone());
                        let mut guard = match t_handler.lock() {
                            Ok(guard) => guard,
                            Err(poisoned) => {
                                warn!("SocketList Mutex failed, using anyway...");
                                poisoned.into_inner()
                            }
                        };
                        let e_handler = guard.deref_mut();
                        e_handler.on_socket_closed(s_id);
                    }
                };
            });
        } else { warn!("Unknown epoll event received: {}", event.data); continue; }
    }
}

fn epoll_remove_fd(epfd: RawFd, fd: RawFd) {
    debug!("remove_socket_from_epoll");

    // In kernel versions before 2.6.9, the EPOLL_CTL_DEL operation required
    // a non-null pointer in event, even though this argument is ignored.
    // Since Linux 2.6.9, event can be specified as NULL when using
    // EPOLL_CTL_DEL.  Applications that need to be portable to kernels
    // before 2.6.9 should specify a non-null pointer in event.
    let mut rm_event = EpollEvent {
        data: 0 as u64,
        events: 0 as u32
    };

    // Depending on how fds are duplicated with .clone(), this may fail.
    //
    // If the failure case is CtlError::ENOENT, we do not care, because
    // epoll will clean the up the descriptor after they are all dropped from
    // program memory
    match epoll::ctl(epfd, ctl_op::DEL, fd, &mut rm_event) {
        Ok(()) => trace!("Socket removed from epoll watch list"),
        Err(e) => {
            match e {
                CtlError::ENOENT => {
                    trace!("Fd not found in epoll, will remove when fd is syscall closed");
                }
                _ => warn!("Epoll CtrlError during del: {}", e)
            }
        }
    };
}

/// Removes socket_ids from master list
fn remove_socket_from_list(socket_id: u32, sockets: SocketList) {
    debug!("remove_socket_from_list");

    let mut s_guard = match sockets.lock() {
        Ok(guard) => guard,
        Err(poisoned) => {
            warn!("SocketList Mutex was poisoned, using anyway");
            poisoned.into_inner()
        }
    };
    let s_list = s_guard.deref_mut();

    let mut s_found = false;
    let mut index = 1usize;
    for s in s_list.iter() {
        if s.id() == socket_id {
            s_found = true;
            break;
        }
        index += 1;
    }

    if !s_found { return; }

    if index == 1 {
        s_list.pop_front();
    } else {
        let mut split = s_list.split_off(index - 1);
        split.pop_front();
        s_list.append(&mut split);
    }

    stats::conn_lost();

    trace!("socket removed from list");
}
<|endoftext|>


<commit_before>// Copyright 2014 Alexis Mousset. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! ESMTP features

use std::str::FromStr;
use std::fmt::{Display, Formatter, Result};
use std::result::Result as RResult;

use common::CRLF;
use response::Response;
use self::Extension::{EightBitMime, SmtpUtfEight, StartTls, Size};

/// Supported ESMTP keywords
#[derive(PartialEq,Eq,Copy,Clone,Debug)]
pub enum Extension {
    /// 8BITMIME keyword
    ///
    /// RFC 6152 : https://tools.ietf.org/html/rfc6152
    EightBitMime,
    /// SMTPUTF8 keyword
    ///
    /// RFC 6531 : https://tools.ietf.org/html/rfc6531
    SmtpUtfEight,
    /// STARTTLS keyword
    ///
    /// RFC 2487 : http://tools.ietf.org/html/rfc2487
    StartTls,
    /// SIZE keyword
    ///
    /// RFC 1427 : https://tools.ietf.org/html/rfc1427
    Size(usize),
}

impl Display for Extension {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write! (f, "{}",
            match self {
                &EightBitMime => "8BITMIME".to_string(),
                &SmtpUtfEight => "SMTPUTF8".to_string(),
                &StartTls => "STARTTLS".to_string(),
                &Size(ref size) => format!("SIZE={}", size),
            }
        )
    }
}

impl FromStr for Extension {
    // TODO: check RFC
    type Err = &'static str;
    fn from_str(s: &str) -> RResult<Extension, &'static str> {
        let splitted : Vec<&str> = s.splitn(1, ' ').collect();
        match splitted.len() {
            1 => match splitted[0] {
                     "8BITMIME" => Ok(EightBitMime),
                     "SMTPUTF8" => Ok(SmtpUtfEight),
                     "STARTTLS" => Ok(StartTls),
                     _ => Err("Unknown extension"),
                 },
            2 => match (splitted[0], splitted[1].parse::<usize>()) {
                     ("SIZE", Ok(size)) => Ok(Size(size)),
                     _ => Err("Can't parse size"),
                 },
            _ => Err("Empty extension?"),
        }
    }
}

impl Extension {
    /// Checks if the ESMTP keyword is the same
    pub fn same_extension_as(&self, other: &Extension) -> bool {
        if self == other {
            return true;
        }
        match (self, other) {
            (&Size(_), &Size(_)) => true,
            _ => false,
        }
    }

    /// Parses supported ESMTP features
    pub fn parse_esmtp_response(message: &str) -> Vec<Extension> {
        let mut esmtp_features = Vec::new();
        for line in message.split(CRLF) {
            if let Ok(Response{code: 250, message}) = line.parse::<Response>() {
                if let Ok(keyword) = message.unwrap().as_slice().parse::<Extension>() {
                    esmtp_features.push(keyword);
                };
            }
        }
        esmtp_features
    }

    /// Returns the string to add to the mail command
    pub fn client_mail_option(&self) -> Option<&str> {
        match *self {
            EightBitMime => Some("BODY=8BITMIME"),
            _ => None,
        }
    }
}

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

    #[test]
    fn test_fmt() {
        assert_eq!(format!("{}", Extension::EightBitMime), "8BITMIME".to_string());
        assert_eq!(format!("{}", Extension::Size(42)), "SIZE=42".to_string());
    }

    #[test]
    fn test_from_str() {
        assert_eq!("8BITMIME".parse::<Extension>(), Ok(Extension::EightBitMime));
        assert_eq!("SIZE 42".parse::<Extension>(), Ok(Extension::Size(42)));
        assert!("SIZ 42".parse::<Extension>().is_err());
        assert!("SIZE 4a2".parse::<Extension>().is_err());
        // TODO: accept trailing spaces ?
        assert!("SIZE 42 ".parse::<Extension>().is_err());
    }

    #[test]
    fn test_same_extension_as() {
        assert_eq!(Extension::EightBitMime.same_extension_as(&Extension::EightBitMime), true);
        assert_eq!(Extension::Size(42).same_extension_as(&Extension::Size(42)), true);
        assert_eq!(Extension::Size(42).same_extension_as(&Extension::Size(43)), true);
        assert_eq!(Extension::Size(42).same_extension_as(&Extension::EightBitMime), false);
        assert_eq!(Extension::EightBitMime.same_extension_as(&Extension::SmtpUtfEight), false);
    }

    #[test]
    fn test_parse_esmtp_response() {
        assert_eq!(Extension::parse_esmtp_response("me\r\n250-8BITMIME\r\n250 SIZE 42"),
            vec!(Extension::EightBitMime, Extension::Size(42)));
        assert_eq!(Extension::parse_esmtp_response("me\r\n250-8BITMIME\r\n250 UNKNON 42"),
            vec!(Extension::EightBitMime));
        assert_eq!(Extension::parse_esmtp_response("me\r\n250-9BITMIME\r\n250 SIZE a"),
            vec!());
        assert_eq!(Extension::parse_esmtp_response("me\r\n250-SIZE 42\r\n250 SIZE 43"),
            vec!(Extension::Size(42), Extension::Size(43)));
        assert_eq!(Extension::parse_esmtp_response(""),
            vec!());
    }
}
<commit_msg>Add AUTH extensions<commit_after>// Copyright 2014 Alexis Mousset. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! ESMTP features

use std::str::FromStr;
use std::result::Result;

use common::CRLF;
use response::Response;
use self::Extension::{PlainAuthentication, CramMd5Authentication, EightBitMime, SmtpUtfEight, StartTls, Size};

/// Supported ESMTP keywords
#[derive(PartialEq,Eq,Copy,Clone,Debug)]
pub enum Extension {
    /// 8BITMIME keyword
    ///
    /// RFC 6152 : https://tools.ietf.org/html/rfc6152
    EightBitMime,
    /// SMTPUTF8 keyword
    ///
    /// RFC 6531 : https://tools.ietf.org/html/rfc6531
    SmtpUtfEight,
    /// STARTTLS keyword
    ///
    /// RFC 2487 : http://tools.ietf.org/html/rfc2487
    StartTls,
    /// SIZE keyword
    ///
    /// RFC 1427 : https://tools.ietf.org/html/rfc1427
    Size(usize),
    /// AUTH PLAIN
    PlainAuthentication,
    /// AUTH CRAM-MD5
    CramMd5Authentication,
}

impl FromStr for Extension {
    // TODO: check RFC
    type Err = &'static str;
    fn from_str(s: &str) -> Result<Extension, &'static str> {
        let splitted : Vec<&str> = s.splitn(1, ' ').collect();
        match splitted.len() {
            1 => match splitted[0] {
                     "8BITMIME" => Ok(EightBitMime),
                     "SMTPUTF8" => Ok(SmtpUtfEight),
                     "STARTTLS" => Ok(StartTls),
                     _ => Err("Unknown extension"),
                 },
            2 => match (splitted[0], splitted[1].parse::<usize>()) {
                     ("SIZE", Ok(size)) => Ok(Size(size)),
                     _ => Err("Can't parse size"),
                 },
            _ => Err("Empty extension?"),
        }
    }
}

impl Extension {
    /// Checks if the ESMTP keyword is the same
    pub fn same_extension_as(&self, other: &Extension) -> bool {
        if self == other {
            return true;
        }
        match (self, other) {
            (&Size(_), &Size(_)) => true,
            _ => false,
        }
    }

    /// Parses supported ESMTP features
    pub fn parse_esmtp_response(message: &str) -> Vec<Extension> {
        let mut esmtp_features = Vec::new();
        for line in message.split(CRLF) {
            if let Ok(Response{code: 250, message}) = line.parse::<Response>() {
                if let Ok(keyword) = message.unwrap().as_slice().parse::<Extension>() {
                    esmtp_features.push(keyword);
                };
            }
        }
        esmtp_features
    }

    /// Returns the string to add to the mail command
    pub fn client_mail_option(&self) -> Option<&str> {
        match *self {
            EightBitMime => Some("BODY=8BITMIME"),
            _ => None,
        }
    }
}

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

    #[test]
    fn test_from_str() {
        assert_eq!("8BITMIME".parse::<Extension>(), Ok(Extension::EightBitMime));
        assert_eq!("SIZE 42".parse::<Extension>(), Ok(Extension::Size(42)));
        assert!("SIZ 42".parse::<Extension>().is_err());
        assert!("SIZE 4a2".parse::<Extension>().is_err());
        // TODO: accept trailing spaces ?
        assert!("SIZE 42 ".parse::<Extension>().is_err());
    }

    #[test]
    fn test_same_extension_as() {
        assert_eq!(Extension::EightBitMime.same_extension_as(&Extension::EightBitMime), true);
        assert_eq!(Extension::Size(42).same_extension_as(&Extension::Size(42)), true);
        assert_eq!(Extension::Size(42).same_extension_as(&Extension::Size(43)), true);
        assert_eq!(Extension::Size(42).same_extension_as(&Extension::EightBitMime), false);
        assert_eq!(Extension::EightBitMime.same_extension_as(&Extension::SmtpUtfEight), false);
    }

    #[test]
    fn test_parse_esmtp_response() {
        assert_eq!(Extension::parse_esmtp_response("me\r\n250-8BITMIME\r\n250 SIZE 42"),
            vec!(Extension::EightBitMime, Extension::Size(42)));
        assert_eq!(Extension::parse_esmtp_response("me\r\n250-8BITMIME\r\n250 UNKNON 42"),
            vec!(Extension::EightBitMime));
        assert_eq!(Extension::parse_esmtp_response("me\r\n250-9BITMIME\r\n250 SIZE a"),
            vec!());
        assert_eq!(Extension::parse_esmtp_response("me\r\n250-SIZE 42\r\n250 SIZE 43"),
            vec!(Extension::Size(42), Extension::Size(43)));
        assert_eq!(Extension::parse_esmtp_response(""),
            vec!());
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 Genymobile
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use std::cell::RefCell;
use std::io;
use std::ptr;
use std::rc::{Rc, Weak};
use log::Level;

use super::binary;
use super::client::{Client, ClientChannel};
use super::connection::{Connection, ConnectionId};
use super::ipv4_header::Protocol;
use super::ipv4_packet::Ipv4Packet;
use super::selector::Selector;
use super::tcp_connection::TcpConnection;
use super::udp_connection::UdpConnection;

const TAG: &'static str = "Router";

pub struct Router {
    client: Weak<RefCell<Client>>,
    // there are typically only few connections per client, HashMap would be less efficient
    connections: Vec<Rc<RefCell<Connection>>>,
}

impl Router {
    pub fn new() -> Self {
        Self {
            client: Weak::new(),
            connections: Vec::new(),
        }
    }

    // expose client initialization after construction to break cyclic initialization dependencies
    pub fn set_client(&mut self, client: Weak<RefCell<Client>>) {
        self.client = client;
    }

    pub fn send_to_network(
        &mut self,
        selector: &mut Selector,
        client_channel: &mut ClientChannel,
        ipv4_packet: &Ipv4Packet,
    ) {
        if ipv4_packet.is_valid() {
            match self.connection(selector, ipv4_packet) {
                Ok(index) => {
                    let closed = {
                        let connection_ref = self.connections.get_mut(index).unwrap();
                        let mut connection = connection_ref.borrow_mut();
                        connection.send_to_network(selector, client_channel, ipv4_packet);
                        if connection.is_closed() {
                            debug!(
                                target: TAG,
                                "Removing connection from router: {}",
                                connection.id()
                            );
                            true
                        } else {
                            false
                        }
                    };
                    if closed {
                        // the connection is closed, remove it
                        self.connections.swap_remove(index);
                    }
                }
                Err(err) => error!(target: TAG, "Cannot create route, dropping packet: {}", err),
            }
        } else {
            warn!(target: TAG, "Dropping invalid packet");
            if log_enabled!(target: TAG, Level::Trace) {
                trace!(target: TAG, "{}", binary::to_string(ipv4_packet.raw()));
            }
        }
    }

    fn connection(
        &mut self,
        selector: &mut Selector,
        ipv4_packet: &Ipv4Packet,
    ) -> io::Result<usize> {
        let (ipv4_header_data, transport_header_data) = ipv4_packet.headers_data();
        let transport_header_data = transport_header_data.expect("No transport");
        let id = ConnectionId::from_headers(ipv4_header_data, transport_header_data);
        let index = match self.find_index(&id) {
            Some(index) => index,
            None => {
                let connection =
                    Self::create_connection(selector, id, self.client.clone(), ipv4_packet)?;
                let index = self.connections.len();
                self.connections.push(connection);
                index
            }
        };
        Ok(index)
    }

    fn create_connection(
        selector: &mut Selector,
        id: ConnectionId,
        client: Weak<RefCell<Client>>,
        ipv4_packet: &Ipv4Packet,
    ) -> io::Result<Rc<RefCell<Connection>>> {
        let (ipv4_header, transport_header) = ipv4_packet.headers();
        let transport_header = transport_header.expect("No transport");
        match id.protocol() {
            Protocol::Tcp => Ok(TcpConnection::new(
                selector,
                id,
                client,
                ipv4_header,
                transport_header,
            )?),
            Protocol::Udp => Ok(UdpConnection::new(
                selector,
                id,
                client,
                ipv4_header,
                transport_header,
            )?),
            p => Err(io::Error::new(
                io::ErrorKind::Other,
                format!("Unsupported protocol: {:?}", p),
            )),
        }
    }

    fn find_index(&self, id: &ConnectionId) -> Option<usize> {
        self.connections.iter().position(|connection| {
            connection.borrow().id() == id
        })
    }

    pub fn remove(&mut self, connection: &Connection) {
        let index = self.connections
            .iter()
            .position(|item| {
                // compare (thin) pointers to find the connection to remove
                binary::ptr_data_eq(connection, item.as_ptr())
            })
            .expect("Removing an unknown connection");
        debug!(
            target: TAG,
            "Self-removing connection from router: {}",
            connection.id()
        );
        self.connections.swap_remove(index);
    }

    pub fn clear(&mut self, selector: &mut Selector) {
        for connection in &mut self.connections {
            connection.borrow_mut().close(selector);
        }
        self.connections.clear();
    }

    pub fn clean_expired_connections(&mut self, selector: &mut Selector) {
        // remove the last items first, otherwise i might not be less than len() on swap_remove(i)
        for i in (0..self.connections.len()).rev() {
            let expired = {
                let mut connection = self.connections[i].borrow_mut();
                if connection.is_expired() {
                    debug!(
                        target: TAG,
                        "Removing expired connection from router: {}",
                        connection.id()
                    );
                    connection.close(selector);
                    true
                } else {
                    false
                }
            };
            if expired {
                self.connections.swap_remove(i);
            }
        }
    }
}
<commit_msg>Remove unused import warning<commit_after>/*
 * Copyright (C) 2017 Genymobile
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use std::cell::RefCell;
use std::io;
use std::rc::{Rc, Weak};
use log::Level;

use super::binary;
use super::client::{Client, ClientChannel};
use super::connection::{Connection, ConnectionId};
use super::ipv4_header::Protocol;
use super::ipv4_packet::Ipv4Packet;
use super::selector::Selector;
use super::tcp_connection::TcpConnection;
use super::udp_connection::UdpConnection;

const TAG: &'static str = "Router";

pub struct Router {
    client: Weak<RefCell<Client>>,
    // there are typically only few connections per client, HashMap would be less efficient
    connections: Vec<Rc<RefCell<Connection>>>,
}

impl Router {
    pub fn new() -> Self {
        Self {
            client: Weak::new(),
            connections: Vec::new(),
        }
    }

    // expose client initialization after construction to break cyclic initialization dependencies
    pub fn set_client(&mut self, client: Weak<RefCell<Client>>) {
        self.client = client;
    }

    pub fn send_to_network(
        &mut self,
        selector: &mut Selector,
        client_channel: &mut ClientChannel,
        ipv4_packet: &Ipv4Packet,
    ) {
        if ipv4_packet.is_valid() {
            match self.connection(selector, ipv4_packet) {
                Ok(index) => {
                    let closed = {
                        let connection_ref = self.connections.get_mut(index).unwrap();
                        let mut connection = connection_ref.borrow_mut();
                        connection.send_to_network(selector, client_channel, ipv4_packet);
                        if connection.is_closed() {
                            debug!(
                                target: TAG,
                                "Removing connection from router: {}",
                                connection.id()
                            );
                            true
                        } else {
                            false
                        }
                    };
                    if closed {
                        // the connection is closed, remove it
                        self.connections.swap_remove(index);
                    }
                }
                Err(err) => error!(target: TAG, "Cannot create route, dropping packet: {}", err),
            }
        } else {
            warn!(target: TAG, "Dropping invalid packet");
            if log_enabled!(target: TAG, Level::Trace) {
                trace!(target: TAG, "{}", binary::to_string(ipv4_packet.raw()));
            }
        }
    }

    fn connection(
        &mut self,
        selector: &mut Selector,
        ipv4_packet: &Ipv4Packet,
    ) -> io::Result<usize> {
        let (ipv4_header_data, transport_header_data) = ipv4_packet.headers_data();
        let transport_header_data = transport_header_data.expect("No transport");
        let id = ConnectionId::from_headers(ipv4_header_data, transport_header_data);
        let index = match self.find_index(&id) {
            Some(index) => index,
            None => {
                let connection =
                    Self::create_connection(selector, id, self.client.clone(), ipv4_packet)?;
                let index = self.connections.len();
                self.connections.push(connection);
                index
            }
        };
        Ok(index)
    }

    fn create_connection(
        selector: &mut Selector,
        id: ConnectionId,
        client: Weak<RefCell<Client>>,
        ipv4_packet: &Ipv4Packet,
    ) -> io::Result<Rc<RefCell<Connection>>> {
        let (ipv4_header, transport_header) = ipv4_packet.headers();
        let transport_header = transport_header.expect("No transport");
        match id.protocol() {
            Protocol::Tcp => Ok(TcpConnection::new(
                selector,
                id,
                client,
                ipv4_header,
                transport_header,
            )?),
            Protocol::Udp => Ok(UdpConnection::new(
                selector,
                id,
                client,
                ipv4_header,
                transport_header,
            )?),
            p => Err(io::Error::new(
                io::ErrorKind::Other,
                format!("Unsupported protocol: {:?}", p),
            )),
        }
    }

    fn find_index(&self, id: &ConnectionId) -> Option<usize> {
        self.connections.iter().position(|connection| {
            connection.borrow().id() == id
        })
    }

    pub fn remove(&mut self, connection: &Connection) {
        let index = self.connections
            .iter()
            .position(|item| {
                // compare (thin) pointers to find the connection to remove
                binary::ptr_data_eq(connection, item.as_ptr())
            })
            .expect("Removing an unknown connection");
        debug!(
            target: TAG,
            "Self-removing connection from router: {}",
            connection.id()
        );
        self.connections.swap_remove(index);
    }

    pub fn clear(&mut self, selector: &mut Selector) {
        for connection in &mut self.connections {
            connection.borrow_mut().close(selector);
        }
        self.connections.clear();
    }

    pub fn clean_expired_connections(&mut self, selector: &mut Selector) {
        // remove the last items first, otherwise i might not be less than len() on swap_remove(i)
        for i in (0..self.connections.len()).rev() {
            let expired = {
                let mut connection = self.connections[i].borrow_mut();
                if connection.is_expired() {
                    debug!(
                        target: TAG,
                        "Removing expired connection from router: {}",
                        connection.id()
                    );
                    connection.close(selector);
                    true
                } else {
                    false
                }
            };
            if expired {
                self.connections.swap_remove(i);
            }
        }
    }
}
<|endoftext|>


<commit_before>fn gen_regex_obj(pat:&String){

}
fn main() {
  let pat = "aa*bba";

}
<commit_msg>Update main.rs<commit_after>mod automata;

use automata::even_zeros_dfa;

fn main() {
    let string = "101111111111000".to_string();
    even_zeros_dfa::init_fsm(&string);
}
<|endoftext|>