<commit_before>#![allow(dead_code)]

use syntax::lexer::Tokenizer;
use syntax::core::tokens::Token;
use syntax::core::tokens::Token::*;
use syntax::core::keywords::Keywords;
use syntax::core::symbols::Symbols;
use syntax::ast::expr::*;
use syntax::ast::consts::*;

pub struct Parser<TokType: Tokenizer> {
    lexer: TokType,
    indent_level: usize,
    run_codegen: bool,
    ast_root: ExprWrapper,
    preview_token: Option<Token>
}

impl<TokType: Tokenizer> Parser<TokType> {
    pub fn new(tokenizer: TokType) -> Parser<TokType> {
        Parser {
            lexer: tokenizer,
            indent_level: 0,
            run_codegen: true,
            ast_root: ExprWrapper::default(Box::new(Expr::NoOp)),
            preview_token: None
        }
    }

    // Consume the next token from the lexer
    fn next_token(&mut self) -> Token {
        match self.preview_token.take() {
            Some(tok) => tok,
            None => self.lexer.get_tok()
        }
    }

    // Preview the next token without consuming it
    fn update_preview_token(&mut self) {
        self.preview_token = Some(self.next_token());
    }

    // Create an error from the current lexer's
    // state, and a message
    fn write_error(&mut self, msg: &str) {
        let (start_line, start_column, _, _) = self.lexer.get_error_pos();

        self.run_codegen = false;

        println!("Error on line: {} col: {}, {}", start_line, start_column, msg);

        // Skip to the end of the line (at Indent token) and allow parsing to continue
        loop {
            self.update_preview_token();

            // Note: This consumes the Indent token, which probably isnt ideal.
            match self.next_token() {
                Indent(depth) => {
                    self.check_indentation(depth);
                    break;
                },
                EOF => break,
                _ => ()
            }
        }
    }

    fn expect_error(&mut self, reason: &str, expect: &str, got: &str) {
        self.write_error(&format!("{}. Expected {}, but got {}", reason, expect, got));
    }

    // Perform any necessary on-start actions
    fn start(&self) {
        // Start code gen startup

        // Implicit imports

        // Generate code for implicit top level function definition
    }

    // Ensures that the indentation matches the current level of indentation
    #[allow(dead_code)]
    fn check_indentation(&mut self, depth: usize) -> isize {
        let difference = depth as isize - self.indent_level as isize;
        println!("{:?}", difference);
        if difference <= 0 {
            self.indent_level = depth;
        } else {
            self.write_error("Increased indentation level in a non standard way.");
        }

        return difference;
    }

    // Parses a variable or constant declaration
    #[allow(unused_variables)]
    #[allow(dead_code)]
    fn parse_declaration(&mut self) -> Option<ExprWrapper> {
        let token = self.next_token();
        match token {
            Identifier(name) => {
                let token1 = self.next_token();

                match token1 {
                    // Symbol(punc) => {
                    //     match punc {
                    //         symbols::Assign => {
                    //             self.parse_expression()
                    //         }
                    //         _ => Err(self.write_error("Invalid Symbol here"))
                    //     }
                    // }
                    Symbol(Symbols::Equals) => {
                        return self.parse_expression();
                    },
                    _ => self.write_error("Invalid sequence")
                }
            },
            Error(msg) => self.write_error(&msg),
            _ => self.expect_error("", "a variable name", "something else")
        }

        None
    }

    fn expect_token(&self, token: &Token, next_token: Token) -> bool {
        println!("{:?}, {:?}, {:?}", token, *token, next_token);
        *token == next_token
    }

    fn collect_args(&mut self) -> Option<Vec<ExprWrapper>> {
        let mut args = Vec::new();
        let mut tok = self.next_token();
        let mut first_arg = true;

        loop {
            println!("Start Loop - first_arg: {}", first_arg);
            if !first_arg {
                println!("Got token");
                tok = self.next_token();
            }

            if !first_arg && self.expect_token(&tok, Symbol(Symbols::Comma)) {
                println!("hit the comma!");
                tok = self.next_token();
            }

            if self.expect_token(&tok, Symbol(Symbols::ParenClose)) {
                println!("hit the close paren {:?}", tok);
                return Some(args);
            }

            let name = match tok {
                Token::Identifier(ref name) => Some(name),
                _ => {
                    self.write_error(&format!("Unsupported token {:?}.", tok));
                    None
                }
            };

            if let Some(arg) = name {
                println!("hit the ident: {}", arg);
                args.push(ExprWrapper::default(
                    Box::new(Expr::Const(Const::UTF8String(String::from_str(arg))))));
                first_arg = false;
                continue;
            }
            break;
        }
        self.write_error(&format!("Invalid syntax."));
        return None;
    }

    // Parses a print function/statement
    fn parse_print_fn(&mut self) -> Option<ExprWrapper> {
        let tok = self.next_token();
        if !self.expect_token(&tok, Symbol(Symbols::ParenOpen)) {
            return None;
        }

        println!("Before Collect");
        let name = ExprWrapper::default(
            Box::new(
                Expr::Const(
                    Const::UTF8String(
                        String::from_str("print")
                    )
                )
            )
        );
        if let Some(args) = self.collect_args() {
            return Some(ExprWrapper::default(Box::new(Expr::FnCall(name, args))));
        }
        return None;
    }

    // Parse function definitions: fn ident(args) -> type
    #[allow(unused_variables)]
    fn parse_fn(&mut self) -> Option<ExprWrapper> {
        // Get the function name
        let fn_name = match self.next_token() {
            Identifier(string) => string,
            _ => {
                self.expect_error("", "an identifier", "something else");

                return None;
            }
        };

        // Get a left paren (
        let mut tok = self.next_token();

        if !self.expect_token(&tok, Symbol(Symbols::ParenOpen)) {
            self.expect_error("", "an opening paren '('", "something else");

            return None;
        }

        // Get all args (ie a: u64)
        // ToDo: optional args (ie a = "foo": str)
        let mut args = Vec::new();

        tok = self.next_token();

        if tok != Symbol(Symbols::ParenClose) {
            loop {
                // Find sequence: ((Identifier : (Type | Identifier))(, (Identifier : (Type | Identifier)))*)?
                let arg_name = match tok {
                    Identifier(ident) => ident,
                    _ => {
                        self.expect_error("", "a function name", "something else");

                        return None;
                    }
                };

                tok = self.next_token();

                if !self.expect_token(&tok, Symbol(Symbols::Colon)) {
                    self.expect_error("", "a colon ':'", "something else");

                    return None;
                }

                match self.next_token() {
                    Type(t) => args.push((arg_name, Type(t))),
                    Identifier(ident) => args.push((arg_name, Identifier(ident))),
                    _ => {
                        self.expect_error("", "a return type", "something else");

                        return None;
                    }
                };

                match self.next_token() {
                    // Hit a closing paren, no more args
                    Symbol(Symbols::ParenClose) => break,

                    // Hit a comma, expecting more args
                    Symbol(Symbols::Comma) => (),

                    // Found something else, error
                    _ => {
                        self.expect_error("", "a closing paren ')' or comma ','", "something else");

                        return None;
                    }
                };

                tok = self.next_token();
            }
        }

        // Get right arrow ->
        tok = self.next_token();

        if !self.expect_token(&tok, Symbol(Symbols::RightThinArrow)) {
            self.expect_error("", "a thin right arrow '->'", "something else");

            return None;
        }

        // Get a return type or identifier
        tok = self.next_token();

        let return_type = match tok {
            Type(t) => {
                Type(t)
            },
            Identifier(ident) => {
                Identifier(ident)
            },
            _ => {
                self.expect_error("", "a return type", "something else");

                return None;
            }
        };

        tok = self.next_token();

        self.indent_level += 1;

        match tok {
            Indent(depth) => self.check_indentation(depth),
            _ => {
                self.expect_error("", "a new line", "something else");

                return None;
            }
        };

        // Combine the rest of the function definiton with the fn info
        let definition = self.parse_top_level_blocks();

        let expr = Box::new(Expr::FnDecl(fn_name, args, return_type, definition));

        return Some(ExprWrapper::default(expr));
    }

    // Handles top-level keywords to start parsing them
    fn handle_keywords(&mut self, keyword: Keywords) -> Option<ExprWrapper> {
        match keyword {
//            Keywords::Def => {
//                self.parse_declaration()
//            },
            Keywords::Fn => self.parse_fn(),
            Keywords::Print => {
                self.parse_print_fn()
            },
            _ => {
                self.write_error(&format!("Unsupported keyword {:?}.", keyword));
                None
            }
        }
    }

    #[allow(dead_code)]
    fn parse_expression(&self) -> Option<ExprWrapper> {
        None
    }

    // Parse numbers into their correct representation
    #[allow(unused_variables)]
    #[allow(dead_code)]
    fn parse_number(&mut self, num: &str) -> Option<ExprWrapper> {
        println!("{}", num);
        let value = 0;
        // This would normally check the ending on the thing slash information
        // about the number to pick int, uint, or float
        None
    }

    // Parse the file
    #[allow(unused_variables)]
    fn parse_top_level_blocks(&mut self) -> ExprWrapper {
        self.start();

        let mut expr = Vec::new();

        // Generate AST
        loop {
            // Parse the token into the next node of the AST
            let token = self.next_token();

            println!("{:?}", token);

            match token {
                Numeric(string, type_) => {
                    panic!("Unimplemented top level token 'Numeric'");
                },
                Identifier(repr) => {
//                    self.parse_expression()
                    panic!("Unimplemented top level token 'Identifier'");
                },
                Indent(depth) => {
                    // ToDo: Keep track of indentation level when preceeding a statement
                    // Might need look ahead to see if next token is Comment or Indent
                    // which means you didn't actually dedent.

                    self.update_preview_token();

                    let difference = match self.preview_token {
//                        Some(Comment(_)) => continue,
//                        Some(Indent(_)) => continue,
                        _ => self.check_indentation(depth)
                    };

                    if difference < 0 {
                        break;
                    } else {
                        continue;
                    }

                    // If indentation decreases -=1 then should break out of this loop
                },
                BoolLiteral(lit) => {
                    panic!("Unimplemented top level token 'BoolLiteral'");
                },
                CharLiteral(lit) => {
                    panic!("Unimplemented top level token 'CharLiteral'");
                },
                StrLiteral(lit) => {
                    panic!("Unimplemented top level token 'StrLiteral'");
                },
                Keyword(keyword) => {
                    if let Some(exprwrapper) = self.handle_keywords(keyword) {
                        expr.push(exprwrapper);
                    }
                },
                Symbol(punc) => {
                    panic!("Unimplemented top level token 'Symbol'");
                },
                Comment(text) => {
                    // ToDo: Docstring, else ignore
                },
                Error(err) => {
                    self.write_error(&err);
                },
                Type(type_) => {
                    panic!("Unimplemented top level token 'Type'");
                },
                EOF => break
            };
        }

        ExprWrapper::new(Box::new(Expr::Block(expr)), 0, 0, 0, 0)
    }

    pub fn parse(&mut self) {
        self.ast_root = self.parse_top_level_blocks();
    }

    pub fn get_ast(&self) -> &ExprWrapper {
        &self.ast_root
    }

    fn run_codegen(&self) {
        self.ast_root.gen_code();
    }
}
<commit_msg>Fixed a case when blank line follows fn declaration.<commit_after>#![allow(dead_code)]

use syntax::lexer::Tokenizer;
use syntax::core::tokens::Token;
use syntax::core::tokens::Token::*;
use syntax::core::keywords::Keywords;
use syntax::core::symbols::Symbols;
use syntax::ast::expr::*;
use syntax::ast::consts::*;

pub struct Parser<TokType: Tokenizer> {
    lexer: TokType,
    indent_level: usize,
    run_codegen: bool,
    ast_root: ExprWrapper,
    preview_token: Option<Token>
}

impl<TokType: Tokenizer> Parser<TokType> {
    pub fn new(tokenizer: TokType) -> Parser<TokType> {
        Parser {
            lexer: tokenizer,
            indent_level: 0,
            run_codegen: true,
            ast_root: ExprWrapper::default(Box::new(Expr::NoOp)),
            preview_token: None
        }
    }

    // Consume the next token from the lexer
    fn next_token(&mut self) -> Token {
        match self.preview_token.take() {
            Some(tok) => tok,
            None => self.lexer.get_tok()
        }
    }

    // Preview the next token without consuming it
    fn update_preview_token(&mut self) {
        self.preview_token = Some(self.next_token());
    }

    // Create an error from the current lexer's
    // state, and a message
    fn write_error(&mut self, msg: &str) {
        let (start_line, start_column, _, _) = self.lexer.get_error_pos();

        self.run_codegen = false;

        println!("Error on line: {} col: {}, {}", start_line, start_column, msg);

        // Skip to the end of the line (at Indent token) and allow parsing to continue
        loop {
            self.update_preview_token();

            // Note: This consumes the Indent token, which probably isnt ideal.
            match self.next_token() {
                Indent(depth) => {
                    self.check_indentation(depth);
                    break;
                },
                EOF => break,
                _ => ()
            }
        }
    }

    fn expect_error(&mut self, reason: &str, expect: &str, got: &str) {
        self.write_error(&format!("{}. Expected {}, but got {}", reason, expect, got));
    }

    // Perform any necessary on-start actions
    fn start(&self) {
        // Start code gen startup

        // Implicit imports

        // Generate code for implicit top level function definition
    }

    // Ensures that the indentation matches the current level of indentation
    #[allow(dead_code)]
    fn check_indentation(&mut self, depth: usize) -> isize {
        let difference = depth as isize - self.indent_level as isize;

        if difference <= 0 {
            self.indent_level = depth;
        } else {
            self.update_preview_token();

            match self.preview_token {
                Some(Indent(_)) | Some(Comment(_)) => (),
                _ => self.write_error("Increased indentation level in a non standard way.")
            };
        }

        return difference;
    }

    // Parses a variable or constant declaration
    #[allow(unused_variables)]
    #[allow(dead_code)]
    fn parse_declaration(&mut self) -> Option<ExprWrapper> {
        let token = self.next_token();
        match token {
            Identifier(name) => {
                let token1 = self.next_token();

                match token1 {
                    // Symbol(punc) => {
                    //     match punc {
                    //         symbols::Assign => {
                    //             self.parse_expression()
                    //         }
                    //         _ => Err(self.write_error("Invalid Symbol here"))
                    //     }
                    // }
                    Symbol(Symbols::Equals) => {
                        return self.parse_expression();
                    },
                    _ => self.write_error("Invalid sequence")
                }
            },
            Error(msg) => self.write_error(&msg),
            _ => self.expect_error("", "a variable name", "something else")
        }

        None
    }

    fn expect_token(&self, token: &Token, next_token: Token) -> bool {
        println!("{:?}, {:?}, {:?}", token, *token, next_token);
        *token == next_token
    }

    fn collect_args(&mut self) -> Option<Vec<ExprWrapper>> {
        let mut args = Vec::new();
        let mut tok = self.next_token();
        let mut first_arg = true;

        loop {
            println!("Start Loop - first_arg: {}", first_arg);
            if !first_arg {
                println!("Got token");
                tok = self.next_token();
            }

            if !first_arg && self.expect_token(&tok, Symbol(Symbols::Comma)) {
                println!("hit the comma!");
                tok = self.next_token();
            }

            if self.expect_token(&tok, Symbol(Symbols::ParenClose)) {
                println!("hit the close paren {:?}", tok);
                return Some(args);
            }

            let name = match tok {
                Token::Identifier(ref name) => Some(name),
                _ => {
                    self.write_error(&format!("Unsupported token {:?}.", tok));
                    None
                }
            };

            if let Some(arg) = name {
                println!("hit the ident: {}", arg);
                args.push(ExprWrapper::default(
                    Box::new(Expr::Const(Const::UTF8String(String::from_str(arg))))));
                first_arg = false;
                continue;
            }
            break;
        }
        self.write_error(&format!("Invalid syntax."));
        return None;
    }

    // Parses a print function/statement
    fn parse_print_fn(&mut self) -> Option<ExprWrapper> {
        let tok = self.next_token();
        if !self.expect_token(&tok, Symbol(Symbols::ParenOpen)) {
            return None;
        }

        println!("Before Collect");
        let name = ExprWrapper::default(
            Box::new(
                Expr::Const(
                    Const::UTF8String(
                        String::from_str("print")
                    )
                )
            )
        );
        if let Some(args) = self.collect_args() {
            return Some(ExprWrapper::default(Box::new(Expr::FnCall(name, args))));
        }
        return None;
    }

    // Parse function definitions: fn ident(args) -> type
    #[allow(unused_variables)]
    fn parse_fn(&mut self) -> Option<ExprWrapper> {
        // Get the function name
        let fn_name = match self.next_token() {
            Identifier(string) => string,
            _ => {
                self.expect_error("", "an identifier", "something else");

                return None;
            }
        };

        // Get a left paren (
        let mut tok = self.next_token();

        if !self.expect_token(&tok, Symbol(Symbols::ParenOpen)) {
            self.expect_error("", "an opening paren '('", "something else");

            return None;
        }

        // Get all args (ie a: u64)
        // ToDo: optional args (ie a = "foo": str)
        let mut args = Vec::new();

        tok = self.next_token();

        if tok != Symbol(Symbols::ParenClose) {
            loop {
                // Find sequence: ((Identifier : (Type | Identifier))(, (Identifier : (Type | Identifier)))*)?
                let arg_name = match tok {
                    Identifier(ident) => ident,
                    _ => {
                        self.expect_error("", "a function name", "something else");

                        return None;
                    }
                };

                tok = self.next_token();

                if !self.expect_token(&tok, Symbol(Symbols::Colon)) {
                    self.expect_error("", "a colon ':'", "something else");

                    return None;
                }

                match self.next_token() {
                    Type(t) => args.push((arg_name, Type(t))),
                    Identifier(ident) => args.push((arg_name, Identifier(ident))),
                    _ => {
                        self.expect_error("", "a return type", "something else");

                        return None;
                    }
                };

                match self.next_token() {
                    // Hit a closing paren, no more args
                    Symbol(Symbols::ParenClose) => break,

                    // Hit a comma, expecting more args
                    Symbol(Symbols::Comma) => (),

                    // Found something else, error
                    _ => {
                        self.expect_error("", "a closing paren ')' or comma ','", "something else");

                        return None;
                    }
                };

                tok = self.next_token();
            }
        }

        // Get right arrow ->
        tok = self.next_token();

        if !self.expect_token(&tok, Symbol(Symbols::RightThinArrow)) {
            self.expect_error("", "a thin right arrow '->'", "something else");

            return None;
        }

        // Get a return type or identifier
        tok = self.next_token();

        let return_type = match tok {
            Type(t) => {
                Type(t)
            },
            Identifier(ident) => {
                Identifier(ident)
            },
            _ => {
                self.expect_error("", "a return type", "something else");

                return None;
            }
        };

        tok = self.next_token();

        self.indent_level += 1;

        match tok {
            Indent(depth) => self.check_indentation(depth),
            _ => {
                self.expect_error("", "a new line", "something else");

                return None;
            }
        };

        // Combine the rest of the function definiton with the fn info
        let definition = self.parse_top_level_blocks();

        let expr = Box::new(Expr::FnDecl(fn_name, args, return_type, definition));

        return Some(ExprWrapper::default(expr));
    }

    // Handles top-level keywords to start parsing them
    fn handle_keywords(&mut self, keyword: Keywords) -> Option<ExprWrapper> {
        match keyword {
//            Keywords::Def => {
//                self.parse_declaration()
//            },
            Keywords::Fn => self.parse_fn(),
            Keywords::Print => {
                self.parse_print_fn()
            },
            _ => {
                self.write_error(&format!("Unsupported keyword {:?}.", keyword));
                None
            }
        }
    }

    #[allow(dead_code)]
    fn parse_expression(&self) -> Option<ExprWrapper> {
        None
    }

    // Parse numbers into their correct representation
    #[allow(unused_variables)]
    #[allow(dead_code)]
    fn parse_number(&mut self, num: &str) -> Option<ExprWrapper> {
        println!("{}", num);
        let value = 0;
        // This would normally check the ending on the thing slash information
        // about the number to pick int, uint, or float
        None
    }

    // Parse the file
    #[allow(unused_variables)]
    fn parse_top_level_blocks(&mut self) -> ExprWrapper {
        self.start();

        let mut expr = Vec::new();

        // Generate AST
        loop {
            // Parse the token into the next node of the AST
            let token = self.next_token();

            println!("{:?}", token);

            match token {
                Numeric(string, type_) => {
                    panic!("Unimplemented top level token 'Numeric'");
                },
                Identifier(repr) => {
//                    self.parse_expression()
                    panic!("Unimplemented top level token 'Identifier'");
                },
                Indent(depth) => {
                    // Look ahead. If you find another Indent token it's a blank line
                    // and didn't actually dedent. Same is true for single line comments
                    // however this isn't guarenteed for multi line comments (because
                    // you could have code after the end of the comment).
                    // ToDo: Account to multiline comments
                    self.update_preview_token();

                    let difference = match self.preview_token {
                        Some(Comment(_)) => continue,
                        Some(Indent(_)) => continue,
                        _ => self.check_indentation(depth)
                    };

                    // Break if you dedent (cannot happen at top level) else continue
                    if difference < 0 {
                        break;
                    }
                },
                BoolLiteral(lit) => {
                    panic!("Unimplemented top level token 'BoolLiteral'");
                },
                CharLiteral(lit) => {
                    panic!("Unimplemented top level token 'CharLiteral'");
                },
                StrLiteral(lit) => {
                    panic!("Unimplemented top level token 'StrLiteral'");
                },
                Keyword(keyword) => {
                    if let Some(exprwrapper) = self.handle_keywords(keyword) {
                        expr.push(exprwrapper);
                    }
                },
                Symbol(punc) => {
                    panic!("Unimplemented top level token 'Symbol'");
                },
                Comment(text) => {
                    // ToDo: Docstring, else ignore
                },
                Error(err) => {
                    self.write_error(&err);
                },
                Type(type_) => {
                    panic!("Unimplemented top level token 'Type'");
                },
                EOF => break
            };
        }

        ExprWrapper::new(Box::new(Expr::Block(expr)), 0, 0, 0, 0)
    }

    pub fn parse(&mut self) {
        self.ast_root = self.parse_top_level_blocks();
    }

    pub fn get_ast(&self) -> &ExprWrapper {
        &self.ast_root
    }

    fn run_codegen(&self) {
        self.ast_root.gen_code();
    }
}
<|endoftext|>


<commit_before>extern crate winapi;
extern crate user32;

use self::user32::*;
use self::winapi::*;

use ::{KeyboardControllable, Key, MouseControllable, MouseButton};
use win::keycodes::*;
use std::mem::*;

/// The main struct for handling the event emitting
pub struct Enigo {
    current_x: i32,
    current_y: i32,
}

impl Enigo {
    // TODO(dustin): do the right initialisation

    /// Constructs a new `Enigo` instance.
    ///
    /// # Example
    ///
    /// ```no_run
    /// use enigo::*;
    /// let mut enigo = Enigo::new();
    /// ```
    pub fn new() -> Self {
        Enigo {
            current_x: 0,
            current_y: 0,
        }
    }
}

impl MouseControllable for Enigo {
    fn mouse_move_to(&mut self, x: i32, y: i32) {
        // TODO(dustin): use interior mutability
        self.current_x = x;
        self.current_y = y;
        unsafe { SetCursorPos(self.current_x, self.current_y) };
    }

    fn mouse_move_relative(&mut self, x: i32, y: i32) {
        // TODO(dustin): use interior mutability
        self.current_x += x;
        self.current_y += y;
        unsafe { SetCursorPos(self.current_x, self.current_y) };
    }

    fn mouse_down(&mut self, button: MouseButton) {
        unsafe {
            let mut input = INPUT {
                type_: INPUT_MOUSE,
                u: transmute_copy(&MOUSEINPUT {
                                      dx: 0,
                                      dy: 0,
                                      mouseData: 0,
                                      dwFlags: match button {
                                          MouseButton::Left => MOUSEEVENTF_LEFTDOWN,
                                          MouseButton::Middle => MOUSEEVENTF_MIDDLEDOWN,
                                          MouseButton::Right => MOUSEEVENTF_RIGHTDOWN,

                                          _ => unimplemented!(),
                                      },
                                      time: 0,
                                      dwExtraInfo: 0,
                                  }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }
    }

    fn mouse_up(&mut self, button: MouseButton) {
        unsafe {
            let mut input = INPUT {
                type_: INPUT_MOUSE,
                u: transmute_copy(&MOUSEINPUT {
                                      dx: 0,
                                      dy: 0,
                                      mouseData: 0,
                                      dwFlags: match button {
                                          MouseButton::Left => MOUSEEVENTF_LEFTUP,
                                          MouseButton::Middle => MOUSEEVENTF_MIDDLEUP,
                                          MouseButton::Right => MOUSEEVENTF_RIGHTUP,

                                          _ => unimplemented!(),
                                      },
                                      time: 0,
                                      dwExtraInfo: 0,
                                  }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }
    }

    fn mouse_click(&mut self, button: MouseButton) {
        self.mouse_down(button);
        self.mouse_up(button);
    }

    fn mouse_scroll_x(&mut self, length: i32) {
        let mut scroll_direction = 1 * 50; // 1 left -1 right
        let mut length = length;

        if length < 0 {
            length *= -1;
            scroll_direction *= -1;
        }

        for _ in 0..length {
            unsafe {
                let mut input = INPUT {
                    type_: INPUT_MOUSE,
                    u: transmute_copy(&MOUSEINPUT {
                                          dx: 0,
                                          dy: 0,
                                          mouseData: transmute_copy(&scroll_direction),
                                          dwFlags: MOUSEEVENTF_HWHEEL,
                                          time: 0,
                                          dwExtraInfo: 0,
                                      }),
                };

                SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
            }
        }
    }

    fn mouse_scroll_y(&mut self, length: i32) {
        let mut scroll_direction = -1 * 50; // 1 left -1 right
        let mut length = length;

        if length < 0 {
            length *= -1;
            scroll_direction *= -1;
        }

        for _ in 0..length {
            unsafe {
                let mut input = INPUT {
                    type_: INPUT_MOUSE,
                    u: transmute_copy(&MOUSEINPUT {
                                          dx: 0,
                                          dy: 0,
                                          mouseData: transmute_copy(&scroll_direction),
                                          dwFlags: MOUSEEVENTF_WHEEL,
                                          time: 0,
                                          dwExtraInfo: 0,
                                      }),
                };

                SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
            }
        }
    }
}

impl KeyboardControllable for Enigo {
    fn key_sequence(&mut self, sequence: &str) {
        let mut buffer = [0; 2];

        for c in sequence.chars() {
            //Windows uses uft-16 encoding. We need to check
            //for variable length characters. As such some
            //characters can be 32 bit long and those are
            //encoded in such called hight and low surrogates
            //each 16 bit wide that needs to be send after
            //another to the SendInput function without
            //being interrupted by "keyup"
            let result = c.encode_utf16(&mut buffer);
            if result.len() == 1 {
                self.unicode_key_click(result[0]);
            } else {
                for utf16_surrogate in result {
                    self.unicode_key_down(utf16_surrogate.clone());
                }
                //do i need to produce a keyup?
                //self.unicode_key_up(0);
            }
        }
    }

    fn key_click(&mut self, key: Key) {
        let keycode = self.key_to_keycode(key);

        use std::{thread, time};
        thread::sleep(time::Duration::from_millis(20));

        unsafe {
            let mut input = INPUT {
                type_: INPUT_KEYBOARD,
                u: transmute_copy(&KEYBDINPUT {
                                      wVk: keycode,
                                      wScan: 0,
                                      dwFlags: 0,
                                      time: 0,
                                      dwExtraInfo: 0,
                                  }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }

        thread::sleep(time::Duration::from_millis(20));

        unsafe {
            let mut input = INPUT {
                type_: INPUT_KEYBOARD,
                u: transmute_copy(&KEYBDINPUT {
                                      wVk: keycode,
                                      wScan: 0,
                                      dwFlags: KEYEVENTF_KEYUP,
                                      time: 0,
                                      dwExtraInfo: 0,
                                  }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }

        thread::sleep(time::Duration::from_millis(20));
    }

    fn key_down(&mut self, key: Key) {
        //unimplemented!();
        unsafe {
            let mut input = INPUT {
                type_: INPUT_KEYBOARD,
                u: transmute_copy(&KEYBDINPUT {
                                      wVk: self.key_to_keycode(key),
                                      wScan: 0,
                                      dwFlags: 0,
                                      time: 0,
                                      dwExtraInfo: 0,
                                  }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }
    }

    fn key_up(&mut self, key: Key) {
        //unimplemented!();
        unsafe {
            let mut input = INPUT {
                type_: INPUT_KEYBOARD,
                u: transmute_copy(&KEYBDINPUT {
                                      wVk: self.key_to_keycode(key),
                                      wScan: 0,
                                      dwFlags: KEYEVENTF_KEYUP,
                                      time: 0,
                                      dwExtraInfo: 0,
                                  }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }
    }
}

impl Enigo {
    fn unicode_key_click(&self, unicode_char: u16) {
        use std::{thread, time};
        thread::sleep(time::Duration::from_millis(20));
        self.unicode_key_down(unicode_char);
        self.unicode_key_up(unicode_char);
        thread::sleep(time::Duration::from_millis(20));
    }

    fn unicode_key_down(&self, unicode_char: u16) {
        unsafe {
            let mut input = INPUT {
                type_: INPUT_KEYBOARD,
                u: transmute_copy(&KEYBDINPUT {
                                      wVk: 0,
                                      wScan: unicode_char,
                                      dwFlags: KEYEVENTF_UNICODE,
                                      time: 0,
                                      dwExtraInfo: 0,
                                  }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }
    }

    fn unicode_key_up(&self, unicode_char: u16) {
        unsafe {
            let mut input = INPUT {
                type_: INPUT_KEYBOARD,
                u: transmute_copy(&KEYBDINPUT {
                                      wVk: 0,
                                      wScan: unicode_char,
                                      dwFlags: KEYEVENTF_UNICODE | KEYEVENTF_KEYUP,
                                      time: 0,
                                      dwExtraInfo: 0,
                                  }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }
    }

    fn key_to_keycode(&self, key: Key) -> u16 {
        //do not use the codes from crate winapi they're
        //wrongly typed with i32 instead of i16 use the
        //ones provided by keycodes.re that are prefixed
        //with an 'E' infront of the original name
        match key {
            Key::TAB => EVK_TAB,
            Key::RETURN => EVK_RETURN,
            Key::SHIFT => EVK_SHIFT,
            Key::CONTROL => EVK_CONTROL,
            Key::A => EVK_A,
            _ => 0,
        }
    }
}
<commit_msg>small doc fix<commit_after>extern crate winapi;
extern crate user32;

use self::user32::*;
use self::winapi::*;

use ::{KeyboardControllable, Key, MouseControllable, MouseButton};
use win::keycodes::*;
use std::mem::*;

/// The main struct for handling the event emitting
pub struct Enigo {
    current_x: i32,
    current_y: i32,
}

impl Enigo {
    // TODO(dustin): do the right initialisation

    /// Constructs a new `Enigo` instance.
    ///
    /// # Example
    ///
    /// ```no_run
    /// use enigo::*;
    /// let mut enigo = Enigo::new();
    /// ```
    pub fn new() -> Self {
        Enigo {
            current_x: 0,
            current_y: 0,
        }
    }
}

impl MouseControllable for Enigo {
    fn mouse_move_to(&mut self, x: i32, y: i32) {
        // TODO(dustin): use interior mutability
        self.current_x = x;
        self.current_y = y;
        unsafe { SetCursorPos(self.current_x, self.current_y) };
    }

    fn mouse_move_relative(&mut self, x: i32, y: i32) {
        // TODO(dustin): use interior mutability
        self.current_x += x;
        self.current_y += y;
        unsafe { SetCursorPos(self.current_x, self.current_y) };
    }

    fn mouse_down(&mut self, button: MouseButton) {
        unsafe {
            let mut input = INPUT {
                type_: INPUT_MOUSE,
                u: transmute_copy(&MOUSEINPUT {
                                      dx: 0,
                                      dy: 0,
                                      mouseData: 0,
                                      dwFlags: match button {
                                          MouseButton::Left => MOUSEEVENTF_LEFTDOWN,
                                          MouseButton::Middle => MOUSEEVENTF_MIDDLEDOWN,
                                          MouseButton::Right => MOUSEEVENTF_RIGHTDOWN,

                                          _ => unimplemented!(),
                                      },
                                      time: 0,
                                      dwExtraInfo: 0,
                                  }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }
    }

    fn mouse_up(&mut self, button: MouseButton) {
        unsafe {
            let mut input = INPUT {
                type_: INPUT_MOUSE,
                u: transmute_copy(&MOUSEINPUT {
                                      dx: 0,
                                      dy: 0,
                                      mouseData: 0,
                                      dwFlags: match button {
                                          MouseButton::Left => MOUSEEVENTF_LEFTUP,
                                          MouseButton::Middle => MOUSEEVENTF_MIDDLEUP,
                                          MouseButton::Right => MOUSEEVENTF_RIGHTUP,

                                          _ => unimplemented!(),
                                      },
                                      time: 0,
                                      dwExtraInfo: 0,
                                  }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }
    }

    fn mouse_click(&mut self, button: MouseButton) {
        self.mouse_down(button);
        self.mouse_up(button);
    }

    fn mouse_scroll_x(&mut self, length: i32) {
        let mut scroll_direction = 1 * 50; // 1 left -1 right
        let mut length = length;

        if length < 0 {
            length *= -1;
            scroll_direction *= -1;
        }

        for _ in 0..length {
            unsafe {
                let mut input = INPUT {
                    type_: INPUT_MOUSE,
                    u: transmute_copy(&MOUSEINPUT {
                                          dx: 0,
                                          dy: 0,
                                          mouseData: transmute_copy(&scroll_direction),
                                          dwFlags: MOUSEEVENTF_HWHEEL,
                                          time: 0,
                                          dwExtraInfo: 0,
                                      }),
                };

                SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
            }
        }
    }

    fn mouse_scroll_y(&mut self, length: i32) {
        let mut scroll_direction = -1 * 50; // 1 left -1 right
        let mut length = length;

        if length < 0 {
            length *= -1;
            scroll_direction *= -1;
        }

        for _ in 0..length {
            unsafe {
                let mut input = INPUT {
                    type_: INPUT_MOUSE,
                    u: transmute_copy(&MOUSEINPUT {
                                          dx: 0,
                                          dy: 0,
                                          mouseData: transmute_copy(&scroll_direction),
                                          dwFlags: MOUSEEVENTF_WHEEL,
                                          time: 0,
                                          dwExtraInfo: 0,
                                      }),
                };

                SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
            }
        }
    }
}

impl KeyboardControllable for Enigo {
    fn key_sequence(&mut self, sequence: &str) {
        let mut buffer = [0; 2];

        for c in sequence.chars() {
            //Windows uses uft-16 encoding. We need to check
            //for variable length characters. As such some
            //characters can be 32 bit long and those are
            //encoded in such called hight and low surrogates
            //each 16 bit wide that needs to be send after
            //another to the SendInput function without
            //being interrupted by "keyup"
            let result = c.encode_utf16(&mut buffer);
            if result.len() == 1 {
                self.unicode_key_click(result[0]);
            } else {
                for utf16_surrogate in result {
                    self.unicode_key_down(utf16_surrogate.clone());
                }
                //do i need to produce a keyup?
                //self.unicode_key_up(0);
            }
        }
    }

    fn key_click(&mut self, key: Key) {
        let keycode = self.key_to_keycode(key);

        use std::{thread, time};
        thread::sleep(time::Duration::from_millis(20));

        unsafe {
            let mut input = INPUT {
                type_: INPUT_KEYBOARD,
                u: transmute_copy(&KEYBDINPUT {
                                      wVk: keycode,
                                      wScan: 0,
                                      dwFlags: 0,
                                      time: 0,
                                      dwExtraInfo: 0,
                                  }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }

        thread::sleep(time::Duration::from_millis(20));

        unsafe {
            let mut input = INPUT {
                type_: INPUT_KEYBOARD,
                u: transmute_copy(&KEYBDINPUT {
                                      wVk: keycode,
                                      wScan: 0,
                                      dwFlags: KEYEVENTF_KEYUP,
                                      time: 0,
                                      dwExtraInfo: 0,
                                  }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }

        thread::sleep(time::Duration::from_millis(20));
    }

    fn key_down(&mut self, key: Key) {
        unsafe {
            let mut input = INPUT {
                type_: INPUT_KEYBOARD,
                u: transmute_copy(&KEYBDINPUT {
                                      wVk: self.key_to_keycode(key),
                                      wScan: 0,
                                      dwFlags: 0,
                                      time: 0,
                                      dwExtraInfo: 0,
                                  }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }
    }

    fn key_up(&mut self, key: Key) {
        unsafe {
            let mut input = INPUT {
                type_: INPUT_KEYBOARD,
                u: transmute_copy(&KEYBDINPUT {
                                      wVk: self.key_to_keycode(key),
                                      wScan: 0,
                                      dwFlags: KEYEVENTF_KEYUP,
                                      time: 0,
                                      dwExtraInfo: 0,
                                  }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }
    }
}

impl Enigo {
    fn unicode_key_click(&self, unicode_char: u16) {
        use std::{thread, time};
        thread::sleep(time::Duration::from_millis(20));
        self.unicode_key_down(unicode_char);
        self.unicode_key_up(unicode_char);
        thread::sleep(time::Duration::from_millis(20));
    }

    fn unicode_key_down(&self, unicode_char: u16) {
        unsafe {
            let mut input = INPUT {
                type_: INPUT_KEYBOARD,
                u: transmute_copy(&KEYBDINPUT {
                                      wVk: 0,
                                      wScan: unicode_char,
                                      dwFlags: KEYEVENTF_UNICODE,
                                      time: 0,
                                      dwExtraInfo: 0,
                                  }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }
    }

    fn unicode_key_up(&self, unicode_char: u16) {
        unsafe {
            let mut input = INPUT {
                type_: INPUT_KEYBOARD,
                u: transmute_copy(&KEYBDINPUT {
                                      wVk: 0,
                                      wScan: unicode_char,
                                      dwFlags: KEYEVENTF_UNICODE | KEYEVENTF_KEYUP,
                                      time: 0,
                                      dwExtraInfo: 0,
                                  }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }
    }

    fn key_to_keycode(&self, key: Key) -> u16 {
        //do not use the codes from crate winapi they're
        //wrongly typed with i32 instead of i16 use the
        //ones provided by win/keycodes.rs that are prefixed
        //with an 'E' infront of the original name
        match key {
            Key::TAB => EVK_TAB,
            Key::RETURN => EVK_RETURN,
            Key::SHIFT => EVK_SHIFT,
            Key::CONTROL => EVK_CONTROL,
            Key::A => EVK_A,
            _ => 0,
        }
    }
}
<|endoftext|>


<commit_before>extern crate termion;

use self::termion::event;
use self::termion::raw::{RawTerminal, IntoRawMode};
use self::termion::screen::AlternateScreen;
use self::termion::input::TermRead;
use self::termion::cursor;
use self::termion::color;
use std::io::{self, Write};
use std::iter;

use super::base::*;

macro_rules! decode_color {
    ($x:expr, $c:expr) => {{
        match $c {
            Color::Reset => format!("{}", $x(color::Reset)),
            Color::Black => format!("{}", $x(color::Black)),
            Color::White => format!("{}", $x(color::White)),
            Color::Grey => format!("{}", $x(color::LightBlack)),
        }
    }}
}

impl From<event::Key> for Key {
    fn from(k: event::Key) -> Key {
        match k {
            event::Key::Backspace => Key::Backspace,
            event::Key::Left => Key::Left,
            event::Key::Right => Key::Right,
            event::Key::Up => Key::Up,
            event::Key::Down => Key::Down,
            event::Key::Home => Key::Home,
            event::Key::End => Key::End,
            event::Key::PageUp => Key::PageUp,
            event::Key::PageDown => Key::PageDown,
            event::Key::Delete => Key::Delete,
            event::Key::Insert => Key::Insert,
            event::Key::F(n) => Key::F(n),
            event::Key::Char(c) => Key::Char(c),
            event::Key::Alt(c) => Key::Alt(Box::new(Key::Char(c))),
            event::Key::Ctrl(c) => Key::Ctrl(Box::new(Key::Char(c))),
            event::Key::Null => Key::Null,
            event::Key::Esc => Key::Esc,
            event::Key::__IsNotComplete => panic!("got a weird key from termios"),
        }
    }
}

impl From<event::MouseEvent> for MouseEvent {
    fn from(e: event::MouseEvent) -> MouseEvent {
        match e {
            event::MouseEvent::Press(b, x, y) => MouseEvent::Press(MouseButton::from(b), x as i32, y as i32),
            event::MouseEvent::Release(x, y) => MouseEvent::Release(x as i32, y as i32),
            event::MouseEvent::Hold(x, y) => MouseEvent::Hold(x as i32, y as i32),
        }
    }
}

impl From<event::MouseButton> for MouseButton {
    fn from(b: event::MouseButton) -> MouseButton {
        match b {
            event::MouseButton::Left => MouseButton::Left,
            event::MouseButton::Right => MouseButton::Right,
            event::MouseButton::Middle => MouseButton::Middle,
            event::MouseButton::WheelUp => MouseButton::WheelUp,
            event::MouseButton::WheelDown => MouseButton::WheelDown,
        }
    }
}

impl From<event::Event> for Event {
    fn from(e: event::Event) -> Event {
        match e {
            event::Event::Key(k) => Event::Key(k.into()),
            event::Event::Mouse(m) => Event::Mouse(m.into()),
            event::Event::Unsupported(v) => {
                let vals = v.iter().map(|x| *x as u32).collect();
                if vals == [27, 91, 49, 59, 50, 65] {
                    Event::Key(Key::Shift(Box::new(Key::Up)))
                } else if vals == [27, 91, 49, 59, 50, 66] {
                    Event::Key(Key::Shift(Box::new(Key::Down)))
                } else if vals == [27, 91, 49, 59, 50, 67] {
                    Event::Key(Key::Shift(Box::new(Key::Right)))
                } else if vals == [27, 91, 49, 59, 50, 68] {
                    Event::Key(Key::Shift(Box::new(Key::Left)))
                } else {
                    Event::Unsupported(vals)
                }
            }
        }
    }
}

pub struct Terminal {
    out: AlternateScreen<RawTerminal<io::Stdout>>,
}

impl Terminal {
    pub fn keys(&mut self) -> iter::Map<termion::input::Events<io::Stdin>, fn(io::Result<event::Event>) -> Event> {
        fn extract(e: io::Result<event::Event>) -> Event { Event::from(e.unwrap()) }
        io::stdin().events().map(extract)
    }
}

impl Write for Terminal {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        self.out.write(data)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.out.flush()
    }
}

impl Default for Terminal {
    fn default() -> Terminal {
        Terminal {
            out: AlternateScreen::from(io::stdout().into_raw_mode().unwrap()),
        }
    }
}

impl TermImpl for Terminal {
    fn get_size(&self) -> (i32, i32) {
        let (x, y) = termion::terminal_size().unwrap();
        (x as i32, y as i32)
    }

    fn goto(&mut self, (x, y): (i32, i32)) {
        write!(self.out, "{}", cursor::Goto(x as u16, y as u16)).unwrap();
    }

    fn set_color_fg(&mut self, c: Color) {
        write!(self.out, "{}", decode_color!(color::Fg, c)).unwrap();
    }

    fn set_color_bg(&mut self, c: Color) {
        write!(self.out, "{}", decode_color!(color::Bg, c)).unwrap();
    }

    fn clear(&mut self) {
        write!(self.out, "{}", termion::clear::All).unwrap();
    }
}
<commit_msg>Document escape sequences expected on Unix<commit_after>extern crate termion;

use self::termion::event;
use self::termion::raw::{RawTerminal, IntoRawMode};
use self::termion::screen::AlternateScreen;
use self::termion::input::TermRead;
use self::termion::cursor;
use self::termion::color;
use std::io::{self, Write};
use std::iter;

use super::base::*;

macro_rules! decode_color {
    ($x:expr, $c:expr) => {{
        match $c {
            Color::Reset => format!("{}", $x(color::Reset)),
            Color::Black => format!("{}", $x(color::Black)),
            Color::White => format!("{}", $x(color::White)),
            Color::Grey => format!("{}", $x(color::LightBlack)),
        }
    }}
}

impl From<event::Key> for Key {
    fn from(k: event::Key) -> Key {
        match k {
            event::Key::Backspace => Key::Backspace,
            event::Key::Left => Key::Left,
            event::Key::Right => Key::Right,
            event::Key::Up => Key::Up,
            event::Key::Down => Key::Down,
            event::Key::Home => Key::Home,
            event::Key::End => Key::End,
            event::Key::PageUp => Key::PageUp,
            event::Key::PageDown => Key::PageDown,
            event::Key::Delete => Key::Delete,
            event::Key::Insert => Key::Insert,
            event::Key::F(n) => Key::F(n),
            event::Key::Char(c) => Key::Char(c),
            event::Key::Alt(c) => Key::Alt(Box::new(Key::Char(c))),
            event::Key::Ctrl(c) => Key::Ctrl(Box::new(Key::Char(c))),
            event::Key::Null => Key::Null,
            event::Key::Esc => Key::Esc,
            event::Key::__IsNotComplete => panic!("got a weird key from termios"),
        }
    }
}

impl From<event::MouseEvent> for MouseEvent {
    fn from(e: event::MouseEvent) -> MouseEvent {
        match e {
            event::MouseEvent::Press(b, x, y) => MouseEvent::Press(MouseButton::from(b), x as i32, y as i32),
            event::MouseEvent::Release(x, y) => MouseEvent::Release(x as i32, y as i32),
            event::MouseEvent::Hold(x, y) => MouseEvent::Hold(x as i32, y as i32),
        }
    }
}

impl From<event::MouseButton> for MouseButton {
    fn from(b: event::MouseButton) -> MouseButton {
        match b {
            event::MouseButton::Left => MouseButton::Left,
            event::MouseButton::Right => MouseButton::Right,
            event::MouseButton::Middle => MouseButton::Middle,
            event::MouseButton::WheelUp => MouseButton::WheelUp,
            event::MouseButton::WheelDown => MouseButton::WheelDown,
        }
    }
}

impl From<event::Event> for Event {
    fn from(e: event::Event) -> Event {
        match e {
            event::Event::Key(k) => Event::Key(k.into()),
            event::Event::Mouse(m) => Event::Mouse(m.into()),
            event::Event::Unsupported(v) => {
                let vals = v.iter().map(|x| *x as u32).collect();
                if vals == [27, 91, 49, 59, 50, 65] { // <Esc>[1;2A
                    Event::Key(Key::Shift(Box::new(Key::Up)))
                } else if vals == [27, 91, 49, 59, 50, 66] { // <Esc>[1;2B
                    Event::Key(Key::Shift(Box::new(Key::Down)))
                } else if vals == [27, 91, 49, 59, 50, 67] { // <Esc>[1;2C
                    Event::Key(Key::Shift(Box::new(Key::Right)))
                } else if vals == [27, 91, 49, 59, 50, 68] { // <Esc>[1;2D
                    Event::Key(Key::Shift(Box::new(Key::Left)))
                } else {
                    Event::Unsupported(vals)
                }
            }
        }
    }
}

pub struct Terminal {
    out: AlternateScreen<RawTerminal<io::Stdout>>,
}

impl Terminal {
    pub fn keys(&mut self) -> iter::Map<termion::input::Events<io::Stdin>, fn(io::Result<event::Event>) -> Event> {
        fn extract(e: io::Result<event::Event>) -> Event { Event::from(e.unwrap()) }
        io::stdin().events().map(extract)
    }
}

impl Write for Terminal {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        self.out.write(data)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.out.flush()
    }
}

impl Default for Terminal {
    fn default() -> Terminal {
        Terminal {
            out: AlternateScreen::from(io::stdout().into_raw_mode().unwrap()),
        }
    }
}

impl TermImpl for Terminal {
    fn get_size(&self) -> (i32, i32) {
        let (x, y) = termion::terminal_size().unwrap();
        (x as i32, y as i32)
    }

    fn goto(&mut self, (x, y): (i32, i32)) {
        write!(self.out, "{}", cursor::Goto(x as u16, y as u16)).unwrap();
    }

    fn set_color_fg(&mut self, c: Color) {
        write!(self.out, "{}", decode_color!(color::Fg, c)).unwrap();
    }

    fn set_color_bg(&mut self, c: Color) {
        write!(self.out, "{}", decode_color!(color::Bg, c)).unwrap();
    }

    fn clear(&mut self) {
        write!(self.out, "{}", termion::clear::All).unwrap();
    }
}
<|endoftext|>


<commit_before>use rusqlite::Connection;
use std::env;
use std::fs::create_dir_all;

pub fn db_exists() -> bool {
    let tmp = env::home_dir();
    let mut path_buf = tmp.unwrap();
    path_buf.push("Film-O-Mat");
    path_buf.push("database");
    path_buf.set_extension("db");
    path_buf.as_path().exists()
}

pub fn create_database() {
    let tmp = env::home_dir();
    let mut path_buf = tmp.unwrap();
    path_buf.push("Film-O-Mat");

    // creates path if not existing
    create_dir_all(&path_buf);

    path_buf.push("database");
    path_buf.set_extension("db");

    let conn = Connection::open(path_buf).unwrap();

    // Example of SQL-Statement
    conn.execute("CREATE TABLE IF NOT EXISTS person (
                  id              INTEGER PRIMARY KEY,
                  name            TEXT NOT NULL,
                  time_created    TEXT NOT NULL,
                  data            BLOB
                  )",
                 &[])
        .unwrap();
}
<commit_msg>added creation of database-tables<commit_after>use rusqlite::Connection;
use std::env;
use std::fs::create_dir_all;

pub fn db_exists() -> bool {
    let tmp = env::home_dir();
    let mut path_buf = tmp.unwrap();
    path_buf.push("Film-O-Mat");
    path_buf.push("database");
    path_buf.set_extension("db");
    path_buf.as_path().exists()
}

pub fn create_database() {
    let tmp = env::home_dir();
    let mut path_buf = tmp.unwrap();
    path_buf.push("Film-O-Mat");

    // creates path if not existing
    create_dir_all(&path_buf);

    path_buf.push("database");
    path_buf.set_extension("db");

    let conn = Connection::open(path_buf).unwrap();

    // Example of SQL-Statement
    conn.execute("CREATE TABLE IF NOT EXISTS movies (
                  id              INTEGER PRIMARY KEY,
                  name            TEXT NOT NULL,
                  year            TEXT NOT NULL,
                  genre           TEXT NOT NULL,
                  director        TEXT NOT NULL
                  )",
                 &[])
        .unwrap();

    conn.execute("CREATE TABLE IF NOT EXISTS actors (
                  id              INTEGER PRIMARY KEY,
                  name            TEXT NOT NULL
                  )",
                 &[])
        .unwrap();

    conn.execute("CREATE TABLE IF NOT EXISTS rankings (
                  id              INTEGER PRIMARY KEY,
                  movie_id        INTEGER,
                  score           TEXT NOT NULL,
                  number          INTEGER NOT NULL,
                  FOREIGN KEY(movie_id) REFERENCES movies(id)
                  )",
                 &[])
        .unwrap();

    conn.execute("CREATE TABLE IF NOT EXISTS crew (
                  actor_id        INTEGER,
                  movie_id        INTEGER,
                  FOREIGN KEY(movie_id) REFERENCES movies(id),
                  FOREIGN KEY(actor_id) REFERENCES actors(id)
                  )",
                 &[])
        .unwrap();
}
<|endoftext|>


<commit_before><commit_msg>Use uninitialized memory for client padding<commit_after><|endoftext|>


<commit_before>// Copyright (C) 2020-2022, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

//! Delivery rate estimation.
//!
//! This implements the algorithm for estimating delivery rate as described in
//! <https://tools.ietf.org/html/draft-cheng-iccrg-delivery-rate-estimation-01>

use std::time::Duration;
use std::time::Instant;

use crate::recovery::Acked;
use crate::recovery::Sent;

#[derive(Debug)]
pub struct Rate {
    delivered: usize,

    delivered_time: Instant,

    first_sent_time: Instant,

    // Packet number of the last sent packet with app limited.
    end_of_app_limited: u64,

    // Packet number of the last sent packet.
    last_sent_packet: u64,

    // Packet number of the largest acked packet.
    largest_acked: u64,

    // Sample of rate estimation.
    rate_sample: RateSample,
}

impl Default for Rate {
    fn default() -> Self {
        let now = Instant::now();

        Rate {
            delivered: 0,

            delivered_time: now,

            first_sent_time: now,

            end_of_app_limited: 0,

            last_sent_packet: 0,

            largest_acked: 0,

            rate_sample: RateSample::default(),
        }
    }
}

impl Rate {
    pub fn on_packet_sent(
        &mut self, pkt: &mut Sent, bytes_in_flight: usize, now: Instant,
    ) {
        // No packets in flight yet?
        if bytes_in_flight == 0 {
            self.first_sent_time = now;
            self.delivered_time = now;
        }

        pkt.first_sent_time = self.first_sent_time;
        pkt.delivered_time = self.delivered_time;
        pkt.delivered = self.delivered;
        pkt.is_app_limited = self.app_limited();

        self.last_sent_packet = pkt.pkt_num;
    }

    // Update the delivery rate sample when a packet is acked.
    pub fn update_rate_sample(&mut self, pkt: &Acked, now: Instant) {
        self.delivered += pkt.size;
        self.delivered_time = now;

        // Update info using the newest packet. If rate_sample is not yet
        // initialized, initialize with the first packet.
        if self.rate_sample.prior_time.is_none() ||
            pkt.delivered > self.rate_sample.prior_delivered
        {
            self.rate_sample.prior_delivered = pkt.delivered;
            self.rate_sample.prior_time = Some(pkt.delivered_time);
            self.rate_sample.is_app_limited = pkt.is_app_limited;
            self.rate_sample.send_elapsed =
                pkt.time_sent.saturating_duration_since(pkt.first_sent_time);
            self.rate_sample.rtt = pkt.rtt;
            self.rate_sample.ack_elapsed = self
                .delivered_time
                .saturating_duration_since(pkt.delivered_time);

            self.first_sent_time = pkt.time_sent;
        }

        self.largest_acked = self.largest_acked.max(pkt.pkt_num);
    }

    pub fn generate_rate_sample(&mut self, min_rtt: Duration) {
        // End app-limited phase if bubble is ACKed and gone.
        if self.app_limited() && self.largest_acked > self.end_of_app_limited {
            self.update_app_limited(false);
        }

        if self.rate_sample.prior_time.is_some() {
            let interval = self
                .rate_sample
                .send_elapsed
                .max(self.rate_sample.ack_elapsed);

            self.rate_sample.delivered =
                self.delivered - self.rate_sample.prior_delivered;
            self.rate_sample.interval = interval;

            if interval < min_rtt {
                self.rate_sample.interval = Duration::ZERO;

                // No reliable sample.
                return;
            }

            if !interval.is_zero() {
                // Fill in rate_sample with a rate sample.
                self.rate_sample.delivery_rate =
                    (self.rate_sample.delivered as f64 / interval.as_secs_f64())
                        as u64;
            }
        }
    }

    pub fn update_app_limited(&mut self, v: bool) {
        self.end_of_app_limited = if v { self.last_sent_packet.max(1) } else { 0 }
    }

    pub fn app_limited(&mut self) -> bool {
        self.end_of_app_limited != 0
    }

    pub fn _delivered(&self) -> usize {
        self.delivered
    }

    pub fn sample_delivery_rate(&self) -> u64 {
        self.rate_sample.delivery_rate
    }

    pub fn _sample_rtt(&self) -> Duration {
        self.rate_sample.rtt
    }

    pub fn _sample_is_app_limited(&self) -> bool {
        self.rate_sample.is_app_limited
    }
}

#[derive(Default, Debug)]
struct RateSample {
    delivery_rate: u64,

    is_app_limited: bool,

    interval: Duration,

    delivered: usize,

    prior_delivered: usize,

    prior_time: Option<Instant>,

    send_elapsed: Duration,

    ack_elapsed: Duration,

    rtt: Duration,
}

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

    use crate::recovery::*;

    #[test]
    fn rate_check() {
        let config = Config::new(0xbabababa).unwrap();
        let mut r = Recovery::new(&config);

        let now = Instant::now();
        let mss = r.max_datagram_size();

        // Send 2 packets.
        for pn in 0..2 {
            let pkt = Sent {
                pkt_num: pn,
                frames: vec![],
                time_sent: now,
                time_acked: None,
                time_lost: None,
                size: mss,
                ack_eliciting: true,
                in_flight: true,
                delivered: 0,
                delivered_time: now,
                first_sent_time: now,
                is_app_limited: false,
                has_data: false,
            };

            r.on_packet_sent(
                pkt,
                packet::EPOCH_APPLICATION,
                HandshakeStatus::default(),
                now,
                "",
            );
        }

        let rtt = Duration::from_millis(50);
        let now = now + rtt;

        // Ack 2 packets.
        for pn in 0..2 {
            let acked = Acked {
                pkt_num: pn,
                time_sent: now,
                size: mss,
                rtt,
                delivered: 0,
                delivered_time: now,
                first_sent_time: now - rtt,
                is_app_limited: false,
            };

            r.delivery_rate.update_rate_sample(&acked, now);
        }

        // Update rate sample after 1 rtt.
        r.delivery_rate.generate_rate_sample(rtt);

        // Bytes acked so far.
        assert_eq!(r.delivery_rate._delivered(), 2400);

        // Estimated delivery rate = (1200 x 2) / 0.5s = 48000.
        assert_eq!(r.delivery_rate(), 48000);
    }

    #[test]
    fn app_limited_cwnd_full() {
        let config = Config::new(0xbabababa).unwrap();
        let mut r = Recovery::new(&config);

        let now = Instant::now();
        let mss = r.max_datagram_size();

        // Send 10 packets to fill cwnd.
        for pn in 0..10 {
            let pkt = Sent {
                pkt_num: pn,
                frames: vec![],
                time_sent: now,
                time_acked: None,
                time_lost: None,
                size: mss,
                ack_eliciting: true,
                in_flight: true,
                delivered: 0,
                delivered_time: now,
                first_sent_time: now,
                is_app_limited: false,
                has_data: false,
            };

            r.on_packet_sent(
                pkt,
                packet::EPOCH_APPLICATION,
                HandshakeStatus::default(),
                now,
                "",
            );
        }

        assert_eq!(r.app_limited(), false);
        assert_eq!(r.delivery_rate._sample_is_app_limited(), false);
    }

    #[test]
    fn app_limited_check() {
        let config = Config::new(0xbabababa).unwrap();
        let mut r = Recovery::new(&config);

        let now = Instant::now();
        let mss = r.max_datagram_size();

        // Send 5 packets.
        for pn in 0..5 {
            let pkt = Sent {
                pkt_num: pn,
                frames: vec![],
                time_sent: now,
                time_acked: None,
                time_lost: None,
                size: mss,
                ack_eliciting: true,
                in_flight: true,
                delivered: 0,
                delivered_time: now,
                first_sent_time: now,
                is_app_limited: false,
                has_data: false,
            };

            r.on_packet_sent(
                pkt,
                packet::EPOCH_APPLICATION,
                HandshakeStatus::default(),
                now,
                "",
            );
        }

        let rtt = Duration::from_millis(50);
        let now = now + rtt;

        let mut acked = ranges::RangeSet::default();
        acked.insert(0..5);

        assert_eq!(
            r.on_ack_received(
                &acked,
                25,
                packet::EPOCH_APPLICATION,
                HandshakeStatus::default(),
                now,
                "",
            ),
            Ok(()),
        );

        assert_eq!(r.app_limited(), true);

        // Rate sample is not app limited (all acked).
        assert_eq!(r.delivery_rate._sample_is_app_limited(), false);
        assert_eq!(r.delivery_rate._sample_rtt(), rtt);
    }
}
<commit_msg>delivery_rate: fix typo of rtt value<commit_after>// Copyright (C) 2020-2022, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

//! Delivery rate estimation.
//!
//! This implements the algorithm for estimating delivery rate as described in
//! <https://tools.ietf.org/html/draft-cheng-iccrg-delivery-rate-estimation-01>

use std::time::Duration;
use std::time::Instant;

use crate::recovery::Acked;
use crate::recovery::Sent;

#[derive(Debug)]
pub struct Rate {
    delivered: usize,

    delivered_time: Instant,

    first_sent_time: Instant,

    // Packet number of the last sent packet with app limited.
    end_of_app_limited: u64,

    // Packet number of the last sent packet.
    last_sent_packet: u64,

    // Packet number of the largest acked packet.
    largest_acked: u64,

    // Sample of rate estimation.
    rate_sample: RateSample,
}

impl Default for Rate {
    fn default() -> Self {
        let now = Instant::now();

        Rate {
            delivered: 0,

            delivered_time: now,

            first_sent_time: now,

            end_of_app_limited: 0,

            last_sent_packet: 0,

            largest_acked: 0,

            rate_sample: RateSample::default(),
        }
    }
}

impl Rate {
    pub fn on_packet_sent(
        &mut self, pkt: &mut Sent, bytes_in_flight: usize, now: Instant,
    ) {
        // No packets in flight yet?
        if bytes_in_flight == 0 {
            self.first_sent_time = now;
            self.delivered_time = now;
        }

        pkt.first_sent_time = self.first_sent_time;
        pkt.delivered_time = self.delivered_time;
        pkt.delivered = self.delivered;
        pkt.is_app_limited = self.app_limited();

        self.last_sent_packet = pkt.pkt_num;
    }

    // Update the delivery rate sample when a packet is acked.
    pub fn update_rate_sample(&mut self, pkt: &Acked, now: Instant) {
        self.delivered += pkt.size;
        self.delivered_time = now;

        // Update info using the newest packet. If rate_sample is not yet
        // initialized, initialize with the first packet.
        if self.rate_sample.prior_time.is_none() ||
            pkt.delivered > self.rate_sample.prior_delivered
        {
            self.rate_sample.prior_delivered = pkt.delivered;
            self.rate_sample.prior_time = Some(pkt.delivered_time);
            self.rate_sample.is_app_limited = pkt.is_app_limited;
            self.rate_sample.send_elapsed =
                pkt.time_sent.saturating_duration_since(pkt.first_sent_time);
            self.rate_sample.rtt = pkt.rtt;
            self.rate_sample.ack_elapsed = self
                .delivered_time
                .saturating_duration_since(pkt.delivered_time);

            self.first_sent_time = pkt.time_sent;
        }

        self.largest_acked = self.largest_acked.max(pkt.pkt_num);
    }

    pub fn generate_rate_sample(&mut self, min_rtt: Duration) {
        // End app-limited phase if bubble is ACKed and gone.
        if self.app_limited() && self.largest_acked > self.end_of_app_limited {
            self.update_app_limited(false);
        }

        if self.rate_sample.prior_time.is_some() {
            let interval = self
                .rate_sample
                .send_elapsed
                .max(self.rate_sample.ack_elapsed);

            self.rate_sample.delivered =
                self.delivered - self.rate_sample.prior_delivered;
            self.rate_sample.interval = interval;

            if interval < min_rtt {
                self.rate_sample.interval = Duration::ZERO;

                // No reliable sample.
                return;
            }

            if !interval.is_zero() {
                // Fill in rate_sample with a rate sample.
                self.rate_sample.delivery_rate =
                    (self.rate_sample.delivered as f64 / interval.as_secs_f64())
                        as u64;
            }
        }
    }

    pub fn update_app_limited(&mut self, v: bool) {
        self.end_of_app_limited = if v { self.last_sent_packet.max(1) } else { 0 }
    }

    pub fn app_limited(&mut self) -> bool {
        self.end_of_app_limited != 0
    }

    pub fn _delivered(&self) -> usize {
        self.delivered
    }

    pub fn sample_delivery_rate(&self) -> u64 {
        self.rate_sample.delivery_rate
    }

    pub fn _sample_rtt(&self) -> Duration {
        self.rate_sample.rtt
    }

    pub fn _sample_is_app_limited(&self) -> bool {
        self.rate_sample.is_app_limited
    }
}

#[derive(Default, Debug)]
struct RateSample {
    delivery_rate: u64,

    is_app_limited: bool,

    interval: Duration,

    delivered: usize,

    prior_delivered: usize,

    prior_time: Option<Instant>,

    send_elapsed: Duration,

    ack_elapsed: Duration,

    rtt: Duration,
}

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

    use crate::recovery::*;

    #[test]
    fn rate_check() {
        let config = Config::new(0xbabababa).unwrap();
        let mut r = Recovery::new(&config);

        let now = Instant::now();
        let mss = r.max_datagram_size();

        // Send 2 packets.
        for pn in 0..2 {
            let pkt = Sent {
                pkt_num: pn,
                frames: vec![],
                time_sent: now,
                time_acked: None,
                time_lost: None,
                size: mss,
                ack_eliciting: true,
                in_flight: true,
                delivered: 0,
                delivered_time: now,
                first_sent_time: now,
                is_app_limited: false,
                has_data: false,
            };

            r.on_packet_sent(
                pkt,
                packet::EPOCH_APPLICATION,
                HandshakeStatus::default(),
                now,
                "",
            );
        }

        let rtt = Duration::from_millis(50);
        let now = now + rtt;

        // Ack 2 packets.
        for pn in 0..2 {
            let acked = Acked {
                pkt_num: pn,
                time_sent: now,
                size: mss,
                rtt,
                delivered: 0,
                delivered_time: now,
                first_sent_time: now - rtt,
                is_app_limited: false,
            };

            r.delivery_rate.update_rate_sample(&acked, now);
        }

        // Update rate sample after 1 rtt.
        r.delivery_rate.generate_rate_sample(rtt);

        // Bytes acked so far.
        assert_eq!(r.delivery_rate._delivered(), 2400);

        // Estimated delivery rate = (1200 x 2) / 0.05s = 48000.
        assert_eq!(r.delivery_rate(), 48000);
    }

    #[test]
    fn app_limited_cwnd_full() {
        let config = Config::new(0xbabababa).unwrap();
        let mut r = Recovery::new(&config);

        let now = Instant::now();
        let mss = r.max_datagram_size();

        // Send 10 packets to fill cwnd.
        for pn in 0..10 {
            let pkt = Sent {
                pkt_num: pn,
                frames: vec![],
                time_sent: now,
                time_acked: None,
                time_lost: None,
                size: mss,
                ack_eliciting: true,
                in_flight: true,
                delivered: 0,
                delivered_time: now,
                first_sent_time: now,
                is_app_limited: false,
                has_data: false,
            };

            r.on_packet_sent(
                pkt,
                packet::EPOCH_APPLICATION,
                HandshakeStatus::default(),
                now,
                "",
            );
        }

        assert_eq!(r.app_limited(), false);
        assert_eq!(r.delivery_rate._sample_is_app_limited(), false);
    }

    #[test]
    fn app_limited_check() {
        let config = Config::new(0xbabababa).unwrap();
        let mut r = Recovery::new(&config);

        let now = Instant::now();
        let mss = r.max_datagram_size();

        // Send 5 packets.
        for pn in 0..5 {
            let pkt = Sent {
                pkt_num: pn,
                frames: vec![],
                time_sent: now,
                time_acked: None,
                time_lost: None,
                size: mss,
                ack_eliciting: true,
                in_flight: true,
                delivered: 0,
                delivered_time: now,
                first_sent_time: now,
                is_app_limited: false,
                has_data: false,
            };

            r.on_packet_sent(
                pkt,
                packet::EPOCH_APPLICATION,
                HandshakeStatus::default(),
                now,
                "",
            );
        }

        let rtt = Duration::from_millis(50);
        let now = now + rtt;

        let mut acked = ranges::RangeSet::default();
        acked.insert(0..5);

        assert_eq!(
            r.on_ack_received(
                &acked,
                25,
                packet::EPOCH_APPLICATION,
                HandshakeStatus::default(),
                now,
                "",
            ),
            Ok(()),
        );

        assert_eq!(r.app_limited(), true);

        // Rate sample is not app limited (all acked).
        assert_eq!(r.delivery_rate._sample_is_app_limited(), false);
        assert_eq!(r.delivery_rate._sample_rtt(), rtt);
    }
}
<|endoftext|>


<commit_before>// Copyright © 2017, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate bragi;
extern crate iron_test;
extern crate serde_json;
use super::BragiHandler;
use super::{count_types, get_types, to_json};
use hyper::status::StatusCode::BadRequest;

pub fn bragi_filter_types_test(es_wrapper: ::ElasticSearchWrapper) {
    let bragi = BragiHandler::new(format!("{}/munin", es_wrapper.host()));

    // ******************************************
    // we the OSM dataset, three-cities bano dataset and a stop file
    // the current dataset are thus (load order matters):
    // - osm_fixture.osm.pbf
    // - bano-three_cities
    // - stops.txt
    // ******************************************
    let osm2mimir = concat!(env!("OUT_DIR"), "/../../../osm2mimir");
    info!("Launching {}", osm2mimir);
    ::launch_and_assert(osm2mimir,
                        vec!["--input=./tests/fixtures/osm_fixture.osm.pbf".into(),
                             "--import-way".into(),
                             "--import-admin".into(),
                             "--import-poi".into(),
                             "--level=8".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    let bano2mimir = concat!(env!("OUT_DIR"), "/../../../bano2mimir");
    info!("Launching {}", bano2mimir);
    ::launch_and_assert(bano2mimir,
                        vec!["--input=./tests/fixtures/bano-three_cities.csv".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    let stops2mimir = concat!(env!("OUT_DIR"), "/../../../stops2mimir");
    info!("Launching {}", stops2mimir);
    ::launch_and_assert(stops2mimir,
                        vec!["--input=./tests/fixtures/stops.txt".into(),
                             "--dataset=dataset1".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    no_type_no_dataset_test(&bragi);
    type_stop_area_no_dataset_test(&bragi);
    type_poi_and_dataset_test(&bragi);
    type_poi_and_city_no_dataset_test(&bragi);
    type_stop_area_dataset_test(&bragi);
    unvalid_type_test(&bragi);
}

fn no_type_no_dataset_test(bragi: &BragiHandler) {
    // with this query we should not find any stops
    let response = bragi.get("/autocomplete?q=14 juillet");
    let types = get_types(&response);
    let count = count_types(&types, "public_transport:stop_area");
    assert_eq!(count, 0);
}

fn type_stop_area_no_dataset_test(bragi: &BragiHandler) {
    // with this query we should not find any stops
    let response = bragi.get("/autocomplete?q=14 juillet&type[]=public_transport:stop_area");
    let types = get_types(&response);
    let count = count_types(&types, "public_transport:stop_area");
    assert_eq!(count, 0);
}

fn type_poi_and_dataset_test(bragi: &BragiHandler) {
    // with this query we should only find pois
    let response = bragi.get("/autocomplete?q=14 juillet&pt_dataset=dataset1&type[]=poi");
    let types = get_types(&response);
    assert_eq!(count_types(&types, "public_transport:stop_area"), 0);
    assert_eq!(count_types(&types, "city"), 0);
    assert_eq!(count_types(&types, "street"), 0);
    assert_eq!(count_types(&types, "house"), 0);
    assert!(count_types(&types, "poi") > 0);
}

fn type_poi_and_city_no_dataset_test(bragi: &BragiHandler) {
    // with this query we should only find pois and cities
    let response = bragi.get("/autocomplete?q=melun&type[]=poi&type[]=city");
    let types = get_types(&response);
    assert_eq!(count_types(&types, "public_transport:stop_area"), 0);
    assert_eq!(count_types(&types, "street"), 0);
    assert_eq!(count_types(&types, "house"), 0);
    assert!(count_types(&types, "city") > 0);
    assert!(count_types(&types, "poi") > 0);
}

fn type_stop_area_dataset_test(bragi: &BragiHandler) {
    // with this query we should only find stop areas
    let response =
        bragi.get("/autocomplete?q=Vaux-le-Pénil&pt_dataset=dataset1&type[]=public_transport:\
                   stop_area");
    let types = get_types(&response);
    assert!(count_types(&types, "public_transport:stop_area") > 0);
    assert_eq!(count_types(&types, "street"), 0);
    assert_eq!(count_types(&types, "house"), 0);
    assert_eq!(count_types(&types, "city"), 0);
    assert_eq!(count_types(&types, "poi"), 0);
}

fn unvalid_type_test(bragi: &BragiHandler) {
    let response = bragi.raw_get("/autocomplete?q=melun&type[]=unvalid");
    assert!(response.is_err());

    let iron_error = response.unwrap_err();
    assert_eq!(iron_error.response.status.unwrap(), BadRequest);

    let json = to_json(iron_error.response);
    let error_msg = json.pointer("/long")
        .unwrap()
        .as_str()
        .unwrap();

    assert!(error_msg.contains("unvalid is not a valid type"))
}
<commit_msg>added test with percent encoded param<commit_after>// Copyright © 2017, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate bragi;
extern crate iron_test;
extern crate serde_json;
use super::BragiHandler;
use super::{count_types, get_types, to_json};
use hyper::status::StatusCode::BadRequest;

pub fn bragi_filter_types_test(es_wrapper: ::ElasticSearchWrapper) {
    let bragi = BragiHandler::new(format!("{}/munin", es_wrapper.host()));

    // ******************************************
    // we the OSM dataset, three-cities bano dataset and a stop file
    // the current dataset are thus (load order matters):
    // - osm_fixture.osm.pbf
    // - bano-three_cities
    // - stops.txt
    // ******************************************
    let osm2mimir = concat!(env!("OUT_DIR"), "/../../../osm2mimir");
    info!("Launching {}", osm2mimir);
    ::launch_and_assert(osm2mimir,
                        vec!["--input=./tests/fixtures/osm_fixture.osm.pbf".into(),
                             "--import-way".into(),
                             "--import-admin".into(),
                             "--import-poi".into(),
                             "--level=8".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    let bano2mimir = concat!(env!("OUT_DIR"), "/../../../bano2mimir");
    info!("Launching {}", bano2mimir);
    ::launch_and_assert(bano2mimir,
                        vec!["--input=./tests/fixtures/bano-three_cities.csv".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    let stops2mimir = concat!(env!("OUT_DIR"), "/../../../stops2mimir");
    info!("Launching {}", stops2mimir);
    ::launch_and_assert(stops2mimir,
                        vec!["--input=./tests/fixtures/stops.txt".into(),
                             "--dataset=dataset1".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    no_type_no_dataset_test(&bragi);
    type_stop_area_no_dataset_test(&bragi);
    type_poi_and_dataset_test(&bragi);
    type_poi_and_city_no_dataset_test(&bragi);
    type_stop_area_dataset_test(&bragi);
    unvalid_type_test(&bragi);
}

fn no_type_no_dataset_test(bragi: &BragiHandler) {
    // with this query we should not find any stops
    let response = bragi.get("/autocomplete?q=14 juillet");
    let types = get_types(&response);
    let count = count_types(&types, "public_transport:stop_area");
    assert_eq!(count, 0);
}

fn type_stop_area_no_dataset_test(bragi: &BragiHandler) {
    // with this query we should not find any stops
    let response = bragi.get("/autocomplete?q=14 juillet&type[]=public_transport:stop_area");
    let types = get_types(&response);
    let count = count_types(&types, "public_transport:stop_area");
    assert_eq!(count, 0);
}

fn type_poi_and_dataset_test(bragi: &BragiHandler) {
    // with this query we should only find pois
    let response = bragi.get("/autocomplete?q=14 juillet&pt_dataset=dataset1&type[]=poi");
    let types = get_types(&response);
    assert_eq!(count_types(&types, "public_transport:stop_area"), 0);
    assert_eq!(count_types(&types, "city"), 0);
    assert_eq!(count_types(&types, "street"), 0);
    assert_eq!(count_types(&types, "house"), 0);
    assert!(count_types(&types, "poi") > 0);
}

fn type_poi_and_city_no_dataset_test(bragi: &BragiHandler) {
    // with this query we should only find pois and cities
    let response = bragi.get("/autocomplete?q=melun&type[]=poi&type[]=city");
    let types = get_types(&response);
    assert_eq!(count_types(&types, "public_transport:stop_area"), 0);
    assert_eq!(count_types(&types, "street"), 0);
    assert_eq!(count_types(&types, "house"), 0);
    assert!(count_types(&types, "city") > 0);
    assert!(count_types(&types, "poi") > 0);
}

fn type_poi_and_city_with_percent_encoding_no_dataset_test(bragi: &BragiHandler) {
    // Same test as before but with percent encoded type param
    let response = bragi.get("/autocomplete?q=melun&type%5B%5D=poi&type%5B%5D=city");
    let types = get_types(&response);
    assert_eq!(count_types(&types, "public_transport:stop_area"), 0);
    assert_eq!(count_types(&types, "street"), 0);
    assert_eq!(count_types(&types, "house"), 0);
    assert!(count_types(&types, "city") > 0);
    assert!(count_types(&types, "poi") > 0);
}

fn type_stop_area_dataset_test(bragi: &BragiHandler) {
    // with this query we should only find stop areas
    let response =
        bragi.get("/autocomplete?q=Vaux-le-Pénil&pt_dataset=dataset1&type[]=public_transport:\
                   stop_area");
    let types = get_types(&response);
    assert!(count_types(&types, "public_transport:stop_area") > 0);
    assert_eq!(count_types(&types, "street"), 0);
    assert_eq!(count_types(&types, "house"), 0);
    assert_eq!(count_types(&types, "city"), 0);
    assert_eq!(count_types(&types, "poi"), 0);
}

fn unvalid_type_test(bragi: &BragiHandler) {
    let response = bragi.raw_get("/autocomplete?q=melun&type[]=unvalid");
    assert!(response.is_err());

    let iron_error = response.unwrap_err();
    assert_eq!(iron_error.response.status.unwrap(), BadRequest);

    let json = to_json(iron_error.response);
    let error_msg = json.pointer("/long")
        .unwrap()
        .as_str()
        .unwrap();

    assert!(error_msg.contains("unvalid is not a valid type"))
}
<|endoftext|>