<commit_before>use ast;
use error::{InputPos, InputSpan, Logger};
use lexer;
use lexer::{Lexer, Token};

pub struct Parser<'a> {
    tokens: Vec<lexer::Token>,
    logger: Logger<'a>,
    index: uint,
}

impl<'a> Parser<'a> {
    pub fn new(mut lexer: Lexer, logger: Logger<'a>) -> Parser<'a> {
        let mut tokens: Vec<lexer::Token> = lexer.collect();
        let end_token = lexer::Token {
            value: lexer::Eof,
            pos: tokens.last().map(|t| t.pos.clone()).unwrap_or(InputPos::start()),
        };
        tokens.push(end_token);
        Parser {
            tokens: tokens,
            logger: logger,
            index: 0,
        }
    }

    fn peek(&self) -> lexer::TokenValue {
        self.tokens[self.index].value.clone()
    }

    fn next_token(&mut self) -> lexer::TokenValue {
        self.index += 1;
        self.tokens[self.index - 1].value.clone()
    }

    fn bump(&mut self) {
        self.index += 1;
    }

    fn expect(&mut self, token: lexer::TokenValue) {
        let span_start = self.current_pos();
        let next = self.next_token();
        if  next != token {
            self.logger.report_error(format!("expected `{}` but found `{}`", token, next),
                InputSpan::new(span_start, self.current_pos()));
            self.fatal_error();
        }
    }

    fn fatal_error(&self) -> ! {
        fail!("");
    }

    fn current_pos(&self) -> InputPos {
        self.tokens[self.index].pos.clone()
    }

    pub fn parse(&mut self) -> ast::Program {
        let mut items = vec![];
        let span_start = self.current_pos();
        let mut span_end = self.current_pos();

        loop {
            match self.try_parse_item() {
                Some(item) => {
                    span_end = item.span().end;
                    items.push(item);
                },
                None => break,
            }
            println!("{}\n", items.last());
        }

        ast::Program {
            items: items,
            span: InputSpan::new(span_start, span_end),
        }
    }

    fn try_parse_item(&mut self) -> Option<ast::Item> {
        let span_start = self.current_pos();
        let item = match self.next_token() {
            lexer::Fn => ast::FunctionItem(self.parse_function()),
            lexer::Struct => ast::StructItem(self.parse_struct_decl()),
            lexer::Let => ast::LetItem(self.parse_let()),

            lexer::Eof => return None,

            invalid => {
                self.logger.report_error(format!("expected `<Item>` but found, `{}`", invalid),
                    InputSpan::new(span_start, self.current_pos()));
                self.fatal_error();
            },
        };

        Some(item)
    }

    fn parse_function(&mut self) -> ast::FunctionDeclaration {
        let span_start = self.current_pos();

        // Read function name
        let name = self.parse_name();

        // Read function args
        self.expect(lexer::LeftParen);
        let mut params = vec![];

        // Handle case with 0 args
        if self.peek() == lexer::RightParen {
            self.bump();
        }
        // Otherwise parse all the parameters
        else {
            loop {
                let param = self.parse_param();
                params.push(param);

                // Check if there is another argument
                if self.peek() == lexer::Comma {
                    self.bump()
                }
                // Otherwise check for closing paren as break
                else {
                    self.expect(lexer::RightParen);
                    break;
                }
            }
        }

        let type_span_start = self.current_pos();
        // Read function return type
        let rtype = match self.peek() {
            lexer::LeftBrace => ast::Primitive(ast::UnitType),

            lexer::RightArrow => {
                self.bump();
                let type_ = self.parse_type();
                type_
            },

            invalid => {
                self.logger.report_error(format!("expected `{{` or `->` but found `{}`", invalid),
                    InputSpan::new(type_span_start, self.current_pos()));
                self.fatal_error();
            },
        };

        // Read function body
        let body = self.parse_block();

        let span_end = self.current_pos();
        ast::FunctionDeclaration {
            name: name,
            params: params,
            rtype: rtype,
            body: body,
            span: InputSpan::new(span_start, span_end),
        }
    }

    fn parse_struct_decl(&mut self) -> ast::StructDeclaration {
        unimplemented!()
    }

    fn parse_let(&mut self) -> ast::LetStatement {
        let span_start = self.current_pos();
        let (name, opt_type) = self.parse_var_with_type();

        let opt_assignment = match self.next_token() {
            lexer::Assignment => Some(self.parse_assignment(name.clone())),
            lexer::SemiColon => None,
            invalid => {
                self.logger.report_error(format!("expected `=` or `;` but found `{}`",
                    invalid), InputSpan::new(span_start, self.current_pos()));
                self.fatal_error();
            }
        };

        // If the type wasn't specified for this variable then there needs
        let type_ = match (&opt_type, &opt_assignment) {
            (&Some(ref t), _) => t.clone(),
            (&None, &Some(ref assignment)) => {
                assignment.expression.rtype.clone()
            },
            (&None, &None) => {
                self.logger.report_error(format!("could not determine type for variable `{}`",
                    name), InputSpan::new(span_start, self.current_pos()));
                self.fatal_error();
            },
        };

        ast::LetStatement {
            name: name,
            var_type: type_,
            assignment: opt_assignment,
            span: InputSpan::new(span_start, self.current_pos()),
        }
    }

    fn parse_name(&mut self) -> String {
        let span_start = self.current_pos();
        match self.next_token() {
            lexer::Ident(name) => name.clone(),

            invalid => {
                self.logger.report_error(format!("expected `<identifer>` but found `{}`", invalid),
                    InputSpan::new(span_start, self.current_pos()));
                self.fatal_error();
            },
        }
    }

    fn parse_type(&mut self) -> ast::Type {
        let span_start = self.current_pos();
        match self.next_token() {
            lexer::Ident(name) => ast::UserType(name.clone()),
            lexer::Int => ast::Primitive(ast::IntType),
            lexer::Bool => ast::Primitive(ast::BoolType),

            invalid => {
                self.logger.report_error(format!("expected `<Type>` but found `{}`", invalid),
                    InputSpan::new(span_start, self.current_pos()));
                self.fatal_error();
            },
        }
    }

    fn parse_param(&mut self) -> (String, ast::Type) {
        let span_start = self.current_pos();
        match self.parse_var_with_type() {
            (name, Some(t)) => (name, t),
            (name, None) => {
                let span_end = self.current_pos();
                self.logger.report_error(format!("expected `<Type>` for parameter `{}`", name),
                    InputSpan::new(span_start, span_end));
                self.fatal_error();
            },
        }
    }

    fn parse_var_with_type(&mut self) -> (String, Option<ast::Type>) {
        let name = self.parse_name();

        match self.peek() {
            lexer::Colon => self.bump(),
            _ => return (name, None),
        }

        let type_ = self.parse_type();
        (name, Some(type_))
    }

    fn parse_block(&mut self) -> ast::Block {
        let span_start = self.current_pos();
        self.expect(lexer::LeftBrace);

        let mut statements = vec![];

        loop {
            if self.peek() == lexer::RightBrace {
                self.bump();
                break;
            }
            else {
                let expression = self.parse_expression();
                if self.peek() != lexer::RightBrace {
                    self.expect(lexer::SemiColon);
                    statements.push(expression);
                }
            }
        }

        ast::Block {
            statements: statements,
            span: InputSpan::new(span_start, self.current_pos()),
        }
    }

    fn parse_expression(&mut self) -> ast::Expression {
        let span_start = self.current_pos();

        match self.next_token() {
            lexer::Ident(name) => self.handle_ident(name.to_string()),
            lexer::LitNum(value) => self.handle_num(value),
            lexer::Let => {
                ast::Expression {
                    expr: box ast::LetExpr(self.parse_let()),
                    rtype: ast::Primitive(ast::UnitType),
                }
            },
            lexer::If => self.parse_if(),
            lexer::For => unimplemented!(),
            lexer::While => unimplemented!(),
            lexer::Loop => self.parse_loop(),
            lexer::Break => self.parse_break(),
            lexer::Return => self.parse_return(),
            lexer::Asm => self.parse_asm(),
            invalid => {
                let span_end = self.current_pos();
                self.logger.report_error(format!("expected `<Expression>` but found `{}`", invalid),
                    InputSpan::new(span_start, span_end));
                self.fatal_error();
            },
        }
    }

    fn handle_ident(&mut self, name: String) -> ast::Expression {
        match self.peek() {
            lexer::LeftParen => {
                self.bump();
                self.parse_call(name)
            },

            lexer::Assignment => {
                ast::Expression {
                    expr: box ast::AssignExpr(self.parse_assignment(name)),
                    rtype: ast::Primitive(ast::UnitType),
                }
            }

            lexer::Plus => unimplemented!(),
            lexer::Minus => unimplemented!(),
            lexer::PlusEq => unimplemented!(),
            lexer::MinusEq => unimplemented!(),

            _ => {
                ast::Expression {
                    expr: box ast::VariableExpr(name.clone()),
                    rtype: ast::VariableType(name),
                }
            }
        }
    }

    fn parse_call(&mut self, name: String) -> ast::Expression {
        let span_start = self.current_pos();
        let mut args = vec![];
        loop {
            args.push(self.parse_expression());

            // Check if there is another argument
            if self.peek() == lexer::Comma {
                self.bump()
            }
            // Otherwise check for closing paren as break
            else {
                self.expect(lexer::RightParen);
                break;
            }
        }

        let function_call = ast::FunctionCall {
            name: name.clone(),
            args: args,
            span: InputSpan::new(span_start, self.current_pos()),
        };

        ast::Expression {
            expr: box ast::CallExpr(function_call),
            rtype: ast::VariableType(name),
        }
    }

    fn parse_assignment(&mut self, target: String) -> ast::Assignment {
        let span_start = self.current_pos();
        ast::Assignment {
            target: target,
            expression: self.parse_expression(),
            span: InputSpan::new(span_start, self.current_pos()),
        }
    }

    fn handle_num(&mut self, val: int) -> ast::Expression {
        ast::Expression {
            expr: box ast::LitNumExpr(val),
            rtype: ast::Primitive(ast::IntType),
        }
    }

    fn parse_if(&mut self) -> ast::Expression {
        let span_start = self.current_pos();

        let condition = self.parse_expression();
        let body = self.parse_block();
        let else_block = match self.peek() {
            lexer::Else => {
                self.bump();
                if self.next_token() == lexer::If {
                    fail!("FIXME: Handle else if statements");
                }

                Some(self.parse_block())
            },
            _ => None,
        };

        let if_statement = ast::IfStatement {
            condition: condition,
            body: body,
            else_block: else_block,
            span: InputSpan::new(span_start, self.current_pos()),
        };

        let rtype = if_statement.body.rtype();

        ast::Expression {
            expr: box ast::IfExpr(if_statement),
            rtype: rtype,
        }
    }

    fn parse_loop(&mut self) -> ast::Expression {
        let span_start = self.current_pos();
        let body = self.parse_block();

        let loop_statement = ast::LoopStatement {
            body: body,
            span: InputSpan::new(span_start, self.current_pos()),
        };

        ast::Expression {
            expr: box ast::LoopExpr(loop_statement),
            rtype: ast::Primitive(ast::UnitType),
        }
    }

    fn parse_break(&mut self) -> ast::Expression {
        ast::Expression {
            expr: box ast::Break,
            rtype: ast::Primitive(ast::BottomType),
        }
    }

    fn parse_return(&mut self) -> ast::Expression {
        let expression = self.parse_expression();
        let rtype = expression.rtype.clone();
        ast::Expression {
            expr: box ast::Return(expression),
            rtype: rtype,
        }
    }

    fn parse_asm(&mut self) -> ast::Expression {
        let span_start = self.current_pos();
        self.expect(lexer::LeftBrace);

        let mut code = String::new();
        loop {
            match self.next_token() {
                lexer::LitString(ref string) => {
                    code.push_str(string.as_slice());
                    code.push_char('\n');
                },
                lexer::RightBrace => {
                    break;
                },
                invalid => {
                    self.logger.report_error(
                        format!("expected `\"<string>\"` or `}}` but found, `{}`", invalid),
                        InputSpan::new(span_start, self.current_pos()));
                    self.fatal_error();
                },
            }

            match self.next_token() {
                lexer::RightBrace => break,
                lexer::Comma => continue,
                invalid => {
                    self.logger.report_error(
                        format!("expected `,` or `}}` but found, `{}`", invalid),
                        InputSpan::new(span_start, self.current_pos()));
                    self.fatal_error();
                },
            }
        }

        ast::Expression {
            expr: box ast::AsmOpExpr(code),
            rtype: ast::Primitive(ast::AnyType),
        }
    }
}
<commit_msg>Fix bug where functions cannot be called with zero arguments.<commit_after>use ast;
use error::{InputPos, InputSpan, Logger};
use lexer;
use lexer::{Lexer, Token};

pub struct Parser<'a> {
    tokens: Vec<lexer::Token>,
    logger: Logger<'a>,
    index: uint,
}

impl<'a> Parser<'a> {
    pub fn new(mut lexer: Lexer, logger: Logger<'a>) -> Parser<'a> {
        let mut tokens: Vec<lexer::Token> = lexer.collect();
        let end_token = lexer::Token {
            value: lexer::Eof,
            pos: tokens.last().map(|t| t.pos.clone()).unwrap_or(InputPos::start()),
        };
        tokens.push(end_token);
        Parser {
            tokens: tokens,
            logger: logger,
            index: 0,
        }
    }

    fn peek(&self) -> lexer::TokenValue {
        self.tokens[self.index].value.clone()
    }

    fn next_token(&mut self) -> lexer::TokenValue {
        self.index += 1;
        self.tokens[self.index - 1].value.clone()
    }

    fn bump(&mut self) {
        self.index += 1;
    }

    fn expect(&mut self, token: lexer::TokenValue) {
        let span_start = self.current_pos();
        let next = self.next_token();
        if  next != token {
            self.logger.report_error(format!("expected `{}` but found `{}`", token, next),
                InputSpan::new(span_start, self.current_pos()));
            self.fatal_error();
        }
    }

    fn fatal_error(&self) -> ! {
        fail!("");
    }

    fn current_pos(&self) -> InputPos {
        self.tokens[self.index].pos.clone()
    }

    pub fn parse(&mut self) -> ast::Program {
        let mut items = vec![];
        let span_start = self.current_pos();
        let mut span_end = self.current_pos();

        loop {
            match self.try_parse_item() {
                Some(item) => {
                    span_end = item.span().end;
                    items.push(item);
                },
                None => break,
            }
            println!("{}\n", items.last());
        }

        ast::Program {
            items: items,
            span: InputSpan::new(span_start, span_end),
        }
    }

    fn try_parse_item(&mut self) -> Option<ast::Item> {
        let span_start = self.current_pos();
        let item = match self.next_token() {
            lexer::Fn => ast::FunctionItem(self.parse_function()),
            lexer::Struct => ast::StructItem(self.parse_struct_decl()),
            lexer::Let => ast::LetItem(self.parse_let()),

            lexer::Eof => return None,

            invalid => {
                self.logger.report_error(format!("expected `<Item>` but found, `{}`", invalid),
                    InputSpan::new(span_start, self.current_pos()));
                self.fatal_error();
            },
        };

        Some(item)
    }

    fn parse_function(&mut self) -> ast::FunctionDeclaration {
        let span_start = self.current_pos();

        // Read function name
        let name = self.parse_name();

        // Read function args
        self.expect(lexer::LeftParen);
        let mut params = vec![];

        // Handle case with 0 args
        if self.peek() == lexer::RightParen {
            self.bump();
        }
        // Otherwise parse all the parameters
        else {
            loop {
                let param = self.parse_param();
                params.push(param);

                // Check if there is another argument
                if self.peek() == lexer::Comma {
                    self.bump()
                }
                // Otherwise check for closing paren as break
                else {
                    self.expect(lexer::RightParen);
                    break;
                }
            }
        }

        let type_span_start = self.current_pos();
        // Read function return type
        let rtype = match self.peek() {
            lexer::LeftBrace => ast::Primitive(ast::UnitType),

            lexer::RightArrow => {
                self.bump();
                let type_ = self.parse_type();
                type_
            },

            invalid => {
                self.logger.report_error(format!("expected `{{` or `->` but found `{}`", invalid),
                    InputSpan::new(type_span_start, self.current_pos()));
                self.fatal_error();
            },
        };

        // Read function body
        let body = self.parse_block();

        let span_end = self.current_pos();
        ast::FunctionDeclaration {
            name: name,
            params: params,
            rtype: rtype,
            body: body,
            span: InputSpan::new(span_start, span_end),
        }
    }

    fn parse_struct_decl(&mut self) -> ast::StructDeclaration {
        unimplemented!()
    }

    fn parse_let(&mut self) -> ast::LetStatement {
        let span_start = self.current_pos();
        let (name, opt_type) = self.parse_var_with_type();

        let opt_assignment = match self.next_token() {
            lexer::Assignment => Some(self.parse_assignment(name.clone())),
            lexer::SemiColon => None,
            invalid => {
                self.logger.report_error(format!("expected `=` or `;` but found `{}`",
                    invalid), InputSpan::new(span_start, self.current_pos()));
                self.fatal_error();
            }
        };

        // If the type wasn't specified for this variable then there needs
        let type_ = match (&opt_type, &opt_assignment) {
            (&Some(ref t), _) => t.clone(),
            (&None, &Some(ref assignment)) => {
                assignment.expression.rtype.clone()
            },
            (&None, &None) => {
                self.logger.report_error(format!("could not determine type for variable `{}`",
                    name), InputSpan::new(span_start, self.current_pos()));
                self.fatal_error();
            },
        };

        ast::LetStatement {
            name: name,
            var_type: type_,
            assignment: opt_assignment,
            span: InputSpan::new(span_start, self.current_pos()),
        }
    }

    fn parse_name(&mut self) -> String {
        let span_start = self.current_pos();
        match self.next_token() {
            lexer::Ident(name) => name.clone(),

            invalid => {
                self.logger.report_error(format!("expected `<identifer>` but found `{}`", invalid),
                    InputSpan::new(span_start, self.current_pos()));
                self.fatal_error();
            },
        }
    }

    fn parse_type(&mut self) -> ast::Type {
        let span_start = self.current_pos();
        match self.next_token() {
            lexer::Ident(name) => ast::UserType(name.clone()),
            lexer::Int => ast::Primitive(ast::IntType),
            lexer::Bool => ast::Primitive(ast::BoolType),

            invalid => {
                self.logger.report_error(format!("expected `<Type>` but found `{}`", invalid),
                    InputSpan::new(span_start, self.current_pos()));
                self.fatal_error();
            },
        }
    }

    fn parse_param(&mut self) -> (String, ast::Type) {
        let span_start = self.current_pos();
        match self.parse_var_with_type() {
            (name, Some(t)) => (name, t),
            (name, None) => {
                let span_end = self.current_pos();
                self.logger.report_error(format!("expected `<Type>` for parameter `{}`", name),
                    InputSpan::new(span_start, span_end));
                self.fatal_error();
            },
        }
    }

    fn parse_var_with_type(&mut self) -> (String, Option<ast::Type>) {
        let name = self.parse_name();

        match self.peek() {
            lexer::Colon => self.bump(),
            _ => return (name, None),
        }

        let type_ = self.parse_type();
        (name, Some(type_))
    }

    fn parse_block(&mut self) -> ast::Block {
        let span_start = self.current_pos();
        self.expect(lexer::LeftBrace);

        let mut statements = vec![];

        loop {
            if self.peek() == lexer::RightBrace {
                self.bump();
                break;
            }
            else {
                let expression = self.parse_expression();
                if self.peek() != lexer::RightBrace {
                    self.expect(lexer::SemiColon);
                    statements.push(expression);
                }
            }
        }

        ast::Block {
            statements: statements,
            span: InputSpan::new(span_start, self.current_pos()),
        }
    }

    fn parse_expression(&mut self) -> ast::Expression {
        let span_start = self.current_pos();

        match self.next_token() {
            lexer::Ident(name) => self.handle_ident(name.to_string()),
            lexer::LitNum(value) => self.handle_num(value),
            lexer::Let => {
                ast::Expression {
                    expr: box ast::LetExpr(self.parse_let()),
                    rtype: ast::Primitive(ast::UnitType),
                }
            },
            lexer::If => self.parse_if(),
            lexer::For => unimplemented!(),
            lexer::While => unimplemented!(),
            lexer::Loop => self.parse_loop(),
            lexer::Break => self.parse_break(),
            lexer::Return => self.parse_return(),
            lexer::Asm => self.parse_asm(),
            invalid => {
                let span_end = self.current_pos();
                self.logger.report_error(format!("expected `<Expression>` but found `{}`", invalid),
                    InputSpan::new(span_start, span_end));
                self.fatal_error();
            },
        }
    }

    fn handle_ident(&mut self, name: String) -> ast::Expression {
        match self.peek() {
            lexer::LeftParen => {
                self.bump();
                self.parse_call(name)
            },

            lexer::Assignment => {
                ast::Expression {
                    expr: box ast::AssignExpr(self.parse_assignment(name)),
                    rtype: ast::Primitive(ast::UnitType),
                }
            }

            lexer::Plus => unimplemented!(),
            lexer::Minus => unimplemented!(),
            lexer::PlusEq => unimplemented!(),
            lexer::MinusEq => unimplemented!(),

            _ => {
                ast::Expression {
                    expr: box ast::VariableExpr(name.clone()),
                    rtype: ast::VariableType(name),
                }
            }
        }
    }

    fn parse_call(&mut self, name: String) -> ast::Expression {
        let span_start = self.current_pos();
        let mut args = vec![];
        loop {
            if self.peek() == lexer::RightParen {
                self.bump();
                break;
            }

            args.push(self.parse_expression());

            // Check if there is another argument
            if self.peek() == lexer::Comma {
                self.bump()
            }
            // Otherwise check for closing paren as break
            else {
                self.expect(lexer::RightParen);
                break;
            }
        }

        let function_call = ast::FunctionCall {
            name: name.clone(),
            args: args,
            span: InputSpan::new(span_start, self.current_pos()),
        };

        ast::Expression {
            expr: box ast::CallExpr(function_call),
            rtype: ast::VariableType(name),
        }
    }

    fn parse_assignment(&mut self, target: String) -> ast::Assignment {
        let span_start = self.current_pos();
        ast::Assignment {
            target: target,
            expression: self.parse_expression(),
            span: InputSpan::new(span_start, self.current_pos()),
        }
    }

    fn handle_num(&mut self, val: int) -> ast::Expression {
        ast::Expression {
            expr: box ast::LitNumExpr(val),
            rtype: ast::Primitive(ast::IntType),
        }
    }

    fn parse_if(&mut self) -> ast::Expression {
        let span_start = self.current_pos();

        let condition = self.parse_expression();
        let body = self.parse_block();
        let else_block = match self.peek() {
            lexer::Else => {
                self.bump();
                if self.next_token() == lexer::If {
                    fail!("FIXME: Handle else if statements");
                }

                Some(self.parse_block())
            },
            _ => None,
        };

        let if_statement = ast::IfStatement {
            condition: condition,
            body: body,
            else_block: else_block,
            span: InputSpan::new(span_start, self.current_pos()),
        };

        let rtype = if_statement.body.rtype();

        ast::Expression {
            expr: box ast::IfExpr(if_statement),
            rtype: rtype,
        }
    }

    fn parse_loop(&mut self) -> ast::Expression {
        let span_start = self.current_pos();
        let body = self.parse_block();

        let loop_statement = ast::LoopStatement {
            body: body,
            span: InputSpan::new(span_start, self.current_pos()),
        };

        ast::Expression {
            expr: box ast::LoopExpr(loop_statement),
            rtype: ast::Primitive(ast::UnitType),
        }
    }

    fn parse_break(&mut self) -> ast::Expression {
        ast::Expression {
            expr: box ast::Break,
            rtype: ast::Primitive(ast::BottomType),
        }
    }

    fn parse_return(&mut self) -> ast::Expression {
        let expression = self.parse_expression();
        let rtype = expression.rtype.clone();
        ast::Expression {
            expr: box ast::Return(expression),
            rtype: rtype,
        }
    }

    fn parse_asm(&mut self) -> ast::Expression {
        let span_start = self.current_pos();
        self.expect(lexer::LeftBrace);

        let mut code = String::new();
        loop {
            match self.next_token() {
                lexer::LitString(ref string) => {
                    code.push_str(string.as_slice());
                    code.push_char('\n');
                },
                lexer::RightBrace => {
                    break;
                },
                invalid => {
                    self.logger.report_error(
                        format!("expected `\"<string>\"` or `}}` but found, `{}`", invalid),
                        InputSpan::new(span_start, self.current_pos()));
                    self.fatal_error();
                },
            }

            match self.next_token() {
                lexer::RightBrace => break,
                lexer::Comma => continue,
                invalid => {
                    self.logger.report_error(
                        format!("expected `,` or `}}` but found, `{}`", invalid),
                        InputSpan::new(span_start, self.current_pos()));
                    self.fatal_error();
                },
            }
        }

        ast::Expression {
            expr: box ast::AsmOpExpr(code),
            rtype: ast::Primitive(ast::AnyType),
        }
    }
}
<|endoftext|>


<commit_before>//! The `parser` module contains structures and functions for parsing the VQA
//! (Vector Quantized Animation) format.
//!
//! Information on the VQA format found at:
//!
//! * https://wiki.multimedia.cx/index.php/VQA#Technical_Description
//! * https://multimedia.cx/HC-VQA.TXT
<commit_msg>add form_chunk parser<commit_after>//! The `parser` module contains structures and functions for parsing the VQA
//! (Vector Quantized Animation) format.
//!
//! Information on the VQA format found at:
//!
//! * https://wiki.multimedia.cx/index.php/VQA#Technical_Description
//! * https://multimedia.cx/HC-VQA.TXT

use nom::{be_u16, be_u32, IResult};

#[derive(Debug)]
pub struct FormChunk {
    size: u32
}

named!(pub form_chunk<FormChunk>,
    do_parse!(
        tag!("FORM") >>
        size: be_u32 >>
        (FormChunk {
            size: size
        })
    )
);

#[derive(Debug)]
pub struct VQAHeader {
    version       : VQAVersion, // VQA version number
    flags         : u16,        // VQA flags
    num_frames    : u16,        // Number of frames
    width         : u16,        // Movie width (pixels)
    height        : u16,        // Movie height (pixels)
    block_width   : u8,         // Width of each image block (pixels)
    block_height  : u8,         // Height of each image block (pixels)
    frame_rate    : u8,         // Frame rate of the VQA
    cbparts       : u8,         // How many images use the same lookup table
    colors        : u16,        // Max number of colors used in VQA
    maxblocks     : u16,        // Max number of image blocks
    unk1          : u32,        // Always 0?
    unk2          : u16,        // Some kind of size?
    freq          : u16,        // Sound sampling frequency
    channels      : u8,         // Number of sound channels
    bits          : u8,         // Sound resolution
    unk3          : u32,        // Always 0?
    unk4          : u16,        // 0 in old VQAs, 4 in HiColor VQAs?
    max_cbfz_size : u32,        // 0 in old VQAs, CBFZ size in HiColor
    unk5          : u32,        // Always 0?
}

#[derive(Debug)]
pub enum VQAVersion {
    One,
    Two,
    Three
}<|endoftext|>


<commit_before>use std::i32;

use byteorder::{BigEndian, ByteOrder};

use {Header, Packet, Error, Question, Name, QueryType, QueryClass};
use {Type, Class, ResourceRecord, RRData};

impl<'a> Packet<'a> {
    pub fn parse(data: &[u8]) -> Result<Packet, Error> {
        let header = try!(Header::parse(data));
        let mut offset = Header::size();
        let mut questions = Vec::with_capacity(header.questions as usize);
        for _ in 0..header.questions {
            let name = try!(Name::scan(&data[offset..], data));
            offset += name.byte_len();
            if offset + 4 > data.len() {
                return Err(Error::UnexpectedEOF);
            }
            let qtype = try!(QueryType::parse(
                BigEndian::read_u16(&data[offset..offset+2])));
            offset += 2;
            let qclass = try!(QueryClass::parse(
                BigEndian::read_u16(&data[offset..offset+2])));
            offset += 2;
            questions.push(Question {
                qname: name,
                qtype: qtype,
                qclass: qclass,
            });
        }
        let mut answers = Vec::with_capacity(header.answers as usize);
        for _ in 0..header.answers {
            let name = try!(Name::scan(&data[offset..], data));
            offset += name.byte_len();
            if offset + 10 > data.len() {
                return Err(Error::UnexpectedEOF);
            }
            let typ = try!(Type::parse(
                BigEndian::read_u16(&data[offset..offset+2])));
            offset += 2;
            let cls = try!(Class::parse(
                BigEndian::read_u16(&data[offset..offset+2])));
            offset += 2;
            let mut ttl = BigEndian::read_u32(&data[offset..offset+4]);
            if ttl > i32::MAX as u32 {
                ttl = 0;
            }
            offset += 4;
            let rdlen = BigEndian::read_u16(&data[offset..offset+2]) as usize;
            offset += 2;
            if offset + rdlen > data.len() {
                return Err(Error::UnexpectedEOF);
            }
            let data = try!(RRData::parse(typ,
                &data[offset..offset+rdlen], data));
            answers.push(ResourceRecord {
                name: name,
                cls: cls,
                ttl: ttl,
                data: data,
            });
        }
        Ok(Packet {
            header: header,
            questions: questions,
            answers: answers,
            nameservers: Vec::new(), // TODO(tailhook)
            additional: Vec::new(), // TODO(tailhook)
        })
    }
}

#[cfg(test)]
mod test {

    use std::net::Ipv4Addr;
    use {Packet, Header};
    use Opcode::*;
    use ResponseCode::NoError;
    use QueryType as QT;
    use QueryClass as QC;
    use Class as C;
    use RRData;

    #[test]
    fn parse_example_query() {
        let query = b"\x06%\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
                      \x07example\x03com\x00\x00\x01\x00\x01";
        let packet = Packet::parse(query).unwrap();
        assert_eq!(packet.header, Header {
            id: 1573,
            query: true,
            opcode: StandardQuery,
            authoritative: false,
            truncated: false,
            recursion_desired: true,
            recursion_available: false,
            response_code: NoError,
            questions: 1,
            answers: 0,
            nameservers: 0,
            additional: 0,
        });
        assert_eq!(packet.questions.len(), 1);
        assert_eq!(packet.questions[0].qtype, QT::A);
        assert_eq!(packet.questions[0].qclass, QC::IN);
        assert_eq!(&packet.questions[0].qname.to_string()[..], "example.com");
        assert_eq!(packet.answers.len(), 0);
    }

    #[test]
    fn parse_example_response() {
        let response = b"\x06%\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
                         \x07example\x03com\x00\x00\x01\x00\x01\
                         \xc0\x0c\x00\x01\x00\x01\x00\x00\x04\xf8\
                         \x00\x04]\xb8\xd8\"";
        let packet = Packet::parse(response).unwrap();
        assert_eq!(packet.header, Header {
            id: 1573,
            query: false,
            opcode: StandardQuery,
            authoritative: false,
            truncated: false,
            recursion_desired: true,
            recursion_available: true,
            response_code: NoError,
            questions: 1,
            answers: 1,
            nameservers: 0,
            additional: 0,
        });
        assert_eq!(packet.questions.len(), 1);
        assert_eq!(packet.questions[0].qtype, QT::A);
        assert_eq!(packet.questions[0].qclass, QC::IN);
        assert_eq!(&packet.questions[0].qname.to_string()[..], "example.com");
        assert_eq!(packet.answers.len(), 1);
        assert_eq!(&packet.answers[0].name.to_string()[..], "example.com");
        assert_eq!(packet.answers[0].cls, C::IN);
        assert_eq!(packet.answers[0].ttl, 1272);
        match packet.answers[0].data {
            RRData::A(addr) => {
                assert_eq!(addr, Ipv4Addr::new(93, 184, 216, 34));
            }
            ref x => panic!("Wrong rdata {:?}", x),
        }
    }

}

<commit_msg>Fix parsing multiple answers<commit_after>use std::i32;

use byteorder::{BigEndian, ByteOrder};

use {Header, Packet, Error, Question, Name, QueryType, QueryClass};
use {Type, Class, ResourceRecord, RRData};

impl<'a> Packet<'a> {
    pub fn parse(data: &[u8]) -> Result<Packet, Error> {
        let header = try!(Header::parse(data));
        let mut offset = Header::size();
        let mut questions = Vec::with_capacity(header.questions as usize);
        for _ in 0..header.questions {
            let name = try!(Name::scan(&data[offset..], data));
            offset += name.byte_len();
            if offset + 4 > data.len() {
                return Err(Error::UnexpectedEOF);
            }
            let qtype = try!(QueryType::parse(
                BigEndian::read_u16(&data[offset..offset+2])));
            offset += 2;
            let qclass = try!(QueryClass::parse(
                BigEndian::read_u16(&data[offset..offset+2])));
            offset += 2;
            questions.push(Question {
                qname: name,
                qtype: qtype,
                qclass: qclass,
            });
        }
        let mut answers = Vec::with_capacity(header.answers as usize);
        for _ in 0..header.answers {
            let name = try!(Name::scan(&data[offset..], data));
            offset += name.byte_len();
            if offset + 10 > data.len() {
                return Err(Error::UnexpectedEOF);
            }
            let typ = try!(Type::parse(
                BigEndian::read_u16(&data[offset..offset+2])));
            offset += 2;
            let cls = try!(Class::parse(
                BigEndian::read_u16(&data[offset..offset+2])));
            offset += 2;
            let mut ttl = BigEndian::read_u32(&data[offset..offset+4]);
            if ttl > i32::MAX as u32 {
                ttl = 0;
            }
            offset += 4;
            let rdlen = BigEndian::read_u16(&data[offset..offset+2]) as usize;
            offset += 2;
            if offset + rdlen > data.len() {
                return Err(Error::UnexpectedEOF);
            }
            let data = try!(RRData::parse(typ,
                &data[offset..offset+rdlen], data));
            offset += rdlen;
            answers.push(ResourceRecord {
                name: name,
                cls: cls,
                ttl: ttl,
                data: data,
            });
        }
        Ok(Packet {
            header: header,
            questions: questions,
            answers: answers,
            nameservers: Vec::new(), // TODO(tailhook)
            additional: Vec::new(), // TODO(tailhook)
        })
    }
}

#[cfg(test)]
mod test {

    use std::net::Ipv4Addr;
    use {Packet, Header};
    use Opcode::*;
    use ResponseCode::NoError;
    use QueryType as QT;
    use QueryClass as QC;
    use Class as C;
    use RRData;

    #[test]
    fn parse_example_query() {
        let query = b"\x06%\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
                      \x07example\x03com\x00\x00\x01\x00\x01";
        let packet = Packet::parse(query).unwrap();
        assert_eq!(packet.header, Header {
            id: 1573,
            query: true,
            opcode: StandardQuery,
            authoritative: false,
            truncated: false,
            recursion_desired: true,
            recursion_available: false,
            response_code: NoError,
            questions: 1,
            answers: 0,
            nameservers: 0,
            additional: 0,
        });
        assert_eq!(packet.questions.len(), 1);
        assert_eq!(packet.questions[0].qtype, QT::A);
        assert_eq!(packet.questions[0].qclass, QC::IN);
        assert_eq!(&packet.questions[0].qname.to_string()[..], "example.com");
        assert_eq!(packet.answers.len(), 0);
    }

    #[test]
    fn parse_example_response() {
        let response = b"\x06%\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
                         \x07example\x03com\x00\x00\x01\x00\x01\
                         \xc0\x0c\x00\x01\x00\x01\x00\x00\x04\xf8\
                         \x00\x04]\xb8\xd8\"";
        let packet = Packet::parse(response).unwrap();
        assert_eq!(packet.header, Header {
            id: 1573,
            query: false,
            opcode: StandardQuery,
            authoritative: false,
            truncated: false,
            recursion_desired: true,
            recursion_available: true,
            response_code: NoError,
            questions: 1,
            answers: 1,
            nameservers: 0,
            additional: 0,
        });
        assert_eq!(packet.questions.len(), 1);
        assert_eq!(packet.questions[0].qtype, QT::A);
        assert_eq!(packet.questions[0].qclass, QC::IN);
        assert_eq!(&packet.questions[0].qname.to_string()[..], "example.com");
        assert_eq!(packet.answers.len(), 1);
        assert_eq!(&packet.answers[0].name.to_string()[..], "example.com");
        assert_eq!(packet.answers[0].cls, C::IN);
        assert_eq!(packet.answers[0].ttl, 1272);
        match packet.answers[0].data {
            RRData::A(addr) => {
                assert_eq!(addr, Ipv4Addr::new(93, 184, 216, 34));
            }
            ref x => panic!("Wrong rdata {:?}", x),
        }
    }

    #[test]
    fn parse_multiple_answers() {
        let response = b"\x9d\xe9\x81\x80\x00\x01\x00\x06\x00\x00\x00\x00\
            \x06google\x03com\x00\x00\x01\x00\x01\xc0\x0c\
            \x00\x01\x00\x01\x00\x00\x00\xef\x00\x04@\xe9\
            \xa4d\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\xef\
            \x00\x04@\xe9\xa4\x8b\xc0\x0c\x00\x01\x00\x01\
            \x00\x00\x00\xef\x00\x04@\xe9\xa4q\xc0\x0c\x00\
            \x01\x00\x01\x00\x00\x00\xef\x00\x04@\xe9\xa4f\
            \xc0\x0c\x00\x01\x00\x01\x00\x00\x00\xef\x00\x04@\
            \xe9\xa4e\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\xef\
            \x00\x04@\xe9\xa4\x8a";
        let packet = Packet::parse(response).unwrap();
        assert_eq!(packet.header, Header {
            id: 40425,
            query: false,
            opcode: StandardQuery,
            authoritative: false,
            truncated: false,
            recursion_desired: true,
            recursion_available: true,
            response_code: NoError,
            questions: 1,
            answers: 6,
            nameservers: 0,
            additional: 0,
        });
        assert_eq!(packet.questions.len(), 1);
        assert_eq!(packet.questions[0].qtype, QT::A);
        assert_eq!(packet.questions[0].qclass, QC::IN);
        assert_eq!(&packet.questions[0].qname.to_string()[..], "google.com");
        assert_eq!(packet.answers.len(), 6);
        let ips = vec![
            Ipv4Addr::new(64, 233, 164, 100),
            Ipv4Addr::new(64, 233, 164, 139),
            Ipv4Addr::new(64, 233, 164, 113),
            Ipv4Addr::new(64, 233, 164, 102),
            Ipv4Addr::new(64, 233, 164, 101),
            Ipv4Addr::new(64, 233, 164, 138),
        ];
        for i in 0..6 {
            assert_eq!(&packet.answers[i].name.to_string()[..], "google.com");
            assert_eq!(packet.answers[i].cls, C::IN);
            assert_eq!(packet.answers[i].ttl, 239);
            match packet.answers[i].data {
                RRData::A(addr) => {
                    assert_eq!(addr, ips[i]);
                }
                ref x => panic!("Wrong rdata {:?}", x),
            }
        }
    }

}

<|endoftext|>


<commit_before>use std::str::from_utf8;
use nom::IResult;

#[derive(Debug,PartialEq,Eq)]
pub struct PosixHeader<'a> {
    pub name:     & 'a str,
    pub mode:     & 'a str,
    pub uid:      & 'a str,
    pub gid:      & 'a str,
    pub size:     & 'a str,
    pub mtime:    & 'a str,
    pub chksum:   & 'a str,
    pub typeflag: char,
    pub linkname: & 'a str,
    pub ustar:    Option<UStarHeader<'a>>
}

#[derive(Debug,PartialEq,Eq)]
pub struct UStarHeader<'a> {
    pub magic:    & 'a str,
    pub version:  & 'a str,
    pub uname:    & 'a str,
    pub gname:    & 'a str,
    pub devmajor: & 'a str,
    pub devminor: & 'a str,
    pub prefix:   & 'a str,
}

#[derive(Debug,PartialEq,Eq)]
pub struct TarEntry<'a> {
    pub header:   PosixHeader<'a>,
    pub contents: & 'a str
}

fn parse_ustar(i: &[u8]) -> IResult<&[u8], Option<UStarHeader>> {
    chain!(i,
        magic:    map_res!(take!(6),   from_utf8) ~
        version:  map_res!(take!(2),   from_utf8) ~
        uname:    map_res!(take!(32),  from_utf8) ~
        gname:    map_res!(take!(32),  from_utf8) ~
        devmajor: map_res!(take!(8),   from_utf8) ~
        devminor: map_res!(take!(8),   from_utf8) ~
        prefix:   map_res!(take!(155), from_utf8),
        ||{
            match magic {
                "ustar" => Some(UStarHeader{
                    magic:    magic,
                    version:  version,
                    uname:    uname,
                    gname:    gname,
                    devmajor: devmajor,
                    devminor: devminor,
                    prefix:   prefix
                }),
                _ => None,
            }
        }
    )
}

fn parse_header(i: &[u8]) -> IResult<&[u8], PosixHeader> {
    chain!(i,
        name:     map_res!(take!(100), from_utf8) ~
        mode:     map_res!(take!(8),   from_utf8) ~
        uid:      map_res!(take!(8),   from_utf8) ~
        gid:      map_res!(take!(8),   from_utf8) ~
        size:     map_res!(take!(12),  from_utf8) ~
        mtime:    map_res!(take!(12),  from_utf8) ~
        chksum:   map_res!(take!(8),   from_utf8) ~
        typeflag: take!(1)                        ~
        linkname: map_res!(take!(100), from_utf8) ~
        ustar:    parse_ustar                     ~
        take!(12), /* padding to 512 */
        ||{
            PosixHeader {
                name:     name,
                mode:     mode,
                uid:      uid,
                gid:      gid,
                size:     size,
                mtime:    mtime,
                chksum:   chksum,
                typeflag: typeflag[0] as char,
                linkname: linkname,
                ustar:    ustar
            }
        }
    )
}

fn parse_entry(i: &[u8]) -> IResult<&[u8], TarEntry> {
    chain!(i,
        header: parse_header,
        /* TODO: contents */
        ||{
            TarEntry {
                header: header,
                contents: ""
            }
        }
    )
}

pub fn parse_tar(i: &[u8]) -> IResult<&[u8], Vec<TarEntry>> {
    many0!(i, parse_entry)
}
<commit_msg>add str_to_u32<commit_after>use std::str::from_utf8;
use nom::IResult;

#[derive(Debug,PartialEq,Eq)]
pub struct PosixHeader<'a> {
    pub name:     & 'a str,
    pub mode:     & 'a str,
    pub uid:      & 'a str,
    pub gid:      & 'a str,
    pub size:     & 'a str,
    pub mtime:    & 'a str,
    pub chksum:   & 'a str,
    pub typeflag: char,
    pub linkname: & 'a str,
    pub ustar:    Option<UStarHeader<'a>>
}

#[derive(Debug,PartialEq,Eq)]
pub struct UStarHeader<'a> {
    pub magic:    & 'a str,
    pub version:  & 'a str,
    pub uname:    & 'a str,
    pub gname:    & 'a str,
    pub devmajor: & 'a str,
    pub devminor: & 'a str,
    pub prefix:   & 'a str,
}

#[derive(Debug,PartialEq,Eq)]
pub struct TarEntry<'a> {
    pub header:   PosixHeader<'a>,
    pub contents: & 'a str
}

fn str_to_u32(s: &str, base: u32) -> u32 {
    let mut u = 0;
    let mut f = 1;

    for c in s.chars().rev() {
        u += f * ((c as u32) - ('0' as u32));
        f *= base;
    }

    u
}

pub fn octal_to_u32(o: &str) -> u32 {
    str_to_u32(o, 8)
}

pub fn decimal_to_u32(d: &str) -> u32 {
    str_to_u32(d, 10)
}

fn parse_ustar(i: &[u8]) -> IResult<&[u8], Option<UStarHeader>> {
    chain!(i,
        magic:    map_res!(take!(6),   from_utf8) ~
        version:  map_res!(take!(2),   from_utf8) ~
        uname:    map_res!(take!(32),  from_utf8) ~
        gname:    map_res!(take!(32),  from_utf8) ~
        devmajor: map_res!(take!(8),   from_utf8) ~
        devminor: map_res!(take!(8),   from_utf8) ~
        prefix:   map_res!(take!(155), from_utf8),
        ||{
            match magic {
                "ustar" => Some(UStarHeader{
                    magic:    magic,
                    version:  version,
                    uname:    uname,
                    gname:    gname,
                    devmajor: devmajor,
                    devminor: devminor,
                    prefix:   prefix
                }),
                _ => None,
            }
        }
    )
}

fn parse_header(i: &[u8]) -> IResult<&[u8], PosixHeader> {
    chain!(i,
        name:     map_res!(take!(100), from_utf8) ~
        mode:     map_res!(take!(8),   from_utf8) ~
        uid:      map_res!(take!(8),   from_utf8) ~
        gid:      map_res!(take!(8),   from_utf8) ~
        size:     map_res!(take!(12),  from_utf8) ~
        mtime:    map_res!(take!(12),  from_utf8) ~
        chksum:   map_res!(take!(8),   from_utf8) ~
        typeflag: take!(1)                        ~
        linkname: map_res!(take!(100), from_utf8) ~
        ustar:    parse_ustar                     ~
        take!(12), /* padding to 512 */
        ||{
            PosixHeader {
                name:     name,
                mode:     mode,
                uid:      uid,
                gid:      gid,
                size:     size,
                mtime:    mtime,
                chksum:   chksum,
                typeflag: typeflag[0] as char,
                linkname: linkname,
                ustar:    ustar
            }
        }
    )
}

fn parse_entry(i: &[u8]) -> IResult<&[u8], TarEntry> {
    chain!(i,
        header: parse_header,
        /* TODO: contents */
        ||{
            TarEntry {
                header: header,
                contents: ""
            }
        }
    )
}

pub fn parse_tar(i: &[u8]) -> IResult<&[u8], Vec<TarEntry>> {
    many0!(i, parse_entry)
}

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

    #[test]
    fn octal_to_u32_test() {
        match octal_to_u32("756") {
            494 => {},
            o => panic!("octal_to_u32 failed, expected 494 but got {}", o)
        }
        match octal_to_u32("") {
            0 => {},
            o => panic!("octal_to_u32 failed, expected 0 but got {}", o)
        }
    }

    #[test]
    fn decimal_to_u32_test() {
        match decimal_to_u32("756") {
            756 => {},
            d => panic!("decimal_to_u32 failed, expected 756 but got {}", d)
        }
        match decimal_to_u32("") {
            0 => {},
            d => panic!("decimal_to_u32 failed, expected 0 but got {}", d)
        }
    }
}
<|endoftext|>


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

use std::net::{Ipv4Addr, SocketAddrV4};
use std::sync::Arc;

use slog::{info, o, Logger};
use tokio::io::Result;
use tokio::net::UdpSocket;

use crate::config::{Config, ConnectionConfig};

/// Server is the UDP server main implementation
pub struct Server {
    log: Logger,
}

impl Server {
    pub fn new(base: Logger) -> Self {
        let log = base.new(o!("source" => "server::Server"));
        return Server { log };
    }

    /// start the async processing of UDP packets
    pub async fn run(self, config: Arc<Config>) -> Result<()> {
        let Server { log } = self;
        info!(log, "Starting on port {}", config.local.port);

        // TOXO: work from here. Probably need a loop at this point?
        let _socket = Server::bind(&config).await?;

        match &config.connections {
            ConnectionConfig::Sender { address, .. } => {
                info!(log, "Sender configuration"; "address" => address)
            }
            ConnectionConfig::Receiver { endpoints } => {
                info!(log, "Receiver configuration"; "endpoints" => endpoints.len())
            }
        };

        return Ok(());
    }

    /// bind binds the local configured port
    async fn bind(config: &Arc<Config>) -> Result<UdpSocket> {
        let addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), config.local.port);
        return UdpSocket::bind(addr).await;
    }
}
<commit_msg>Test for bind<commit_after>/*
 * Copyright 2020 Google LLC All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use std::net::{Ipv4Addr, SocketAddrV4};
use std::sync::Arc;

use slog::{info, o, Logger};
use tokio::io::Result;
use tokio::net::UdpSocket;

use crate::config::{Config, ConnectionConfig};

/// Server is the UDP server main implementation
pub struct Server {
    log: Logger,
}

impl Server {
    pub fn new(base: Logger) -> Self {
        let log = base.new(o!("source" => "server::Server"));
        return Server { log };
    }

    /// start the async processing of UDP packets
    pub async fn run(self, config: Arc<Config>) -> Result<()> {
        let Server { log } = self;
        info!(log, "Starting on port {}", config.local.port);

        // TOXO: work from here. Probably need a loop at this point?
        let _socket = Server::bind(&config).await?;

        match &config.connections {
            ConnectionConfig::Sender { address, .. } => {
                info!(log, "Sender configuration"; "address" => address)
            }
            ConnectionConfig::Receiver { endpoints } => {
                info!(log, "Receiver configuration"; "endpoints" => endpoints.len())
            }
        };

        return Ok(());
    }

    /// bind binds the local configured port
    async fn bind(config: &Config) -> Result<UdpSocket> {
        let addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), config.local.port);
        return UdpSocket::bind(addr).await;
    }
}

#[cfg(test)]
mod tests {
    use std::net::{IpAddr, Ipv4Addr, SocketAddr};

    use crate::config::{Config, ConnectionConfig, Local};
    use crate::server::Server;

    #[tokio::test]
    async fn bind() {
        let config = Config {
            local: Local { port: 12345 },
            connections: ConnectionConfig::Receiver {
                endpoints: Vec::new(),
            },
        };
        let socket = Server::bind(&config).await.unwrap();
        let addr = socket.local_addr().unwrap();

        let expected = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 12345);
        assert_eq!(expected, addr)
    }
}
<|endoftext|>


<commit_before>extern crate dbus;
use self::dbus::{Connection, ConnectionItem, Message, NameFlag, ReleaseNameReply};

use super::error::DBusError;
use super::interface::DBusInterface;
use super::object::DBusObject;
use super::signal::DBusSignal;

use std::collections::btree_map::{BTreeMap, Entry};
use std::error::Error;

pub struct DBusServer<'a> {
    conn: &'a Connection,
    name: String,

    objects: BTreeMap<String, DBusObject<'a>>,
    signals: BTreeMap<DBusSignal, Vec<fn (&Connection, &DBusSignal) -> ()>>
}

impl<'a> DBusServer<'a> {
    pub fn new(conn: &'a Connection, name: &str) -> Result<DBusServer<'a>, dbus::Error> {
        try!(conn.register_name(name, NameFlag::DoNotQueue as u32));

        Ok(DBusServer {
            conn: conn,
            name: name.to_string(),

            objects: BTreeMap::new(),
            signals: BTreeMap::new(),
        })
    }

    pub fn add_object(&mut self, path: &str, ifaces: BTreeMap<String, Box<DBusInterface>>) -> Result<&DBusObject<'a>, Box<Error>> {
        match self.objects.entry(path.to_string()) {
            Entry::Vacant(v)    => Ok(v.insert(try!(DBusObject::new(self.conn, ifaces, path)))),
            Entry::Occupied(_)  => Err(Box::new(DBusError::PathAlreadyRegistered(path.to_string()))),
        }
    }

    pub fn remove_object(&mut self, path: &str) -> Result<(), DBusError> {
        match self.objects.remove(path) {
            Some(_) => Ok(()),
            None    => Err(DBusError::NoSuchPath(path.to_string())),
        }
    }

    pub fn connect(&mut self, signal: DBusSignal, callback: fn (&Connection, &DBusSignal) -> ()) -> () {
        match self.signals.entry(signal) {
            Entry::Vacant(v)    => { v.insert(vec![callback]); },
            Entry::Occupied(o)  => o.into_mut().push(callback),
        };
    }

    pub fn run(&mut self) -> () {
        self.conn.iter(100).fold((), |_, item| {
            match item {
                ConnectionItem::MethodCall(m)   => self._call_method(m),
                ConnectionItem::Signal(s)       => self._match_signal(s),
                ConnectionItem::Nothing         => (),
            }
        });
    }

    fn _call_method(&mut self, m: Message) -> () {
        // TODO: Implement.
    }

    fn _match_signal(&self, m: Message) -> () {
        // TODO: Implement.
    }
}

impl<'a> Drop for DBusServer<'a> {
    fn drop(&mut self) {
        let res = self.conn.release_name(&self.name[..]);
        match res {
            Ok(reply) =>
                match reply {
                    ReleaseNameReply::Released    => (),
                    ReleaseNameReply::NonExistent => panic!("internal error: non-existent name {}?!", self.name),
                    ReleaseNameReply::NotOwner    => panic!("internal error: not the owner of {}?!", self.name),
                },
            Err(err) => println!("failed to release {}: {:?}: {:?}", self.name, err.name(), err.message()),
        }
    }
}
<commit_msg>server: use &String over &String[..]<commit_after>extern crate dbus;
use self::dbus::{Connection, ConnectionItem, Message, NameFlag, ReleaseNameReply};

use super::error::DBusError;
use super::interface::DBusInterface;
use super::object::DBusObject;
use super::signal::DBusSignal;

use std::collections::btree_map::{BTreeMap, Entry};
use std::error::Error;

pub struct DBusServer<'a> {
    conn: &'a Connection,
    name: String,

    objects: BTreeMap<String, DBusObject<'a>>,
    signals: BTreeMap<DBusSignal, Vec<fn (&Connection, &DBusSignal) -> ()>>
}

impl<'a> DBusServer<'a> {
    pub fn new(conn: &'a Connection, name: &str) -> Result<DBusServer<'a>, dbus::Error> {
        try!(conn.register_name(name, NameFlag::DoNotQueue as u32));

        Ok(DBusServer {
            conn: conn,
            name: name.to_string(),

            objects: BTreeMap::new(),
            signals: BTreeMap::new(),
        })
    }

    pub fn add_object(&mut self, path: &str, ifaces: BTreeMap<String, Box<DBusInterface>>) -> Result<&DBusObject<'a>, Box<Error>> {
        match self.objects.entry(path.to_string()) {
            Entry::Vacant(v)    => Ok(v.insert(try!(DBusObject::new(self.conn, ifaces, path)))),
            Entry::Occupied(_)  => Err(Box::new(DBusError::PathAlreadyRegistered(path.to_string()))),
        }
    }

    pub fn remove_object(&mut self, path: &str) -> Result<(), DBusError> {
        match self.objects.remove(path) {
            Some(_) => Ok(()),
            None    => Err(DBusError::NoSuchPath(path.to_string())),
        }
    }

    pub fn connect(&mut self, signal: DBusSignal, callback: fn (&Connection, &DBusSignal) -> ()) -> () {
        match self.signals.entry(signal) {
            Entry::Vacant(v)    => { v.insert(vec![callback]); },
            Entry::Occupied(o)  => o.into_mut().push(callback),
        };
    }

    pub fn run(&mut self) -> () {
        self.conn.iter(100).fold((), |_, item| {
            match item {
                ConnectionItem::MethodCall(m)   => self._call_method(m),
                ConnectionItem::Signal(s)       => self._match_signal(s),
                ConnectionItem::Nothing         => (),
            }
        });
    }

    fn _call_method(&mut self, m: Message) -> () {
        // TODO: Implement.
    }

    fn _match_signal(&self, m: Message) -> () {
        // TODO: Implement.
    }
}

impl<'a> Drop for DBusServer<'a> {
    fn drop(&mut self) {
        let res = self.conn.release_name(&self.name);
        match res {
            Ok(reply) =>
                match reply {
                    ReleaseNameReply::Released    => (),
                    ReleaseNameReply::NonExistent => panic!("internal error: non-existent name {}?!", self.name),
                    ReleaseNameReply::NotOwner    => panic!("internal error: not the owner of {}?!", self.name),
                },
            Err(err) => println!("failed to release {}: {:?}: {:?}", self.name, err.name(), err.message()),
        }
    }
}
<|endoftext|>


<commit_before>use hyper::{Body, Client, Method, Request};
#[allow(unused)]
use log::{info, warn};

use serde_json::json;
use std::fs;
use std::process::exit;

use librespot::core::authentication::Credentials;
use librespot::core::config::SessionConfig;
use librespot::core::keymaster;
use librespot::core::session::Session;
use librespot::core::spotify_id::SpotifyId;

use librespot::playback::audio_backend;
use librespot::playback::config::{AudioFormat, PlayerConfig};
use librespot::playback::player::{Player, PlayerEvent};

const VERSION: &'static str = concat!(env!("CARGO_PKG_NAME"), " v", env!("CARGO_PKG_VERSION"));

const SCOPES: &str = "user-read-private,playlist-read-private,playlist-read-collaborative,playlist-modify-public,playlist-modify-private,user-follow-modify,user-follow-read,user-library-read,user-library-modify,user-top-read,user-read-recently-played";

#[cfg(debug_assertions)]
const DEBUGMODE: bool = true;
#[cfg(not(debug_assertions))]
const DEBUGMODE: bool = false;

pub fn check(version_info: String) {
    println!("ok {}", version_info.to_string());

    let capabilities = json!({
        "version": env!("CARGO_PKG_VERSION").to_string(),
        "autoplay": true,
        "lms-auth": true,
        "volume-normalisation": true,
        "debug": DEBUGMODE,
        "ogg-direct": true,
        "save-token": true,
        "podcasts": true,
        "zeroconf-port": true
    });

    println!("{}", capabilities.to_string());
    exit(0);
}

// inspired by examples/get_token.rs
pub async fn get_token(
    client_id: Option<String>,
    scopes: Option<String>,
    save_token: Option<String>,
    last_credentials: Option<Credentials>,
    session_config: SessionConfig,
) {
    match last_credentials {
        Some(last_credentials) => {
            if let Some(client_id) = client_id {
                let scopes = scopes.unwrap_or(SCOPES.to_string());

                let session = Session::connect(session_config, last_credentials, None)
                    .await
                    .unwrap();

                let token = keymaster::get_token(&session, &client_id, &scopes)
                    .await
                    .unwrap();

                let json_token = json!({
                    // keep backwards compatibility with older versions
                    "accessToken": token.access_token.to_string(),
                    "expiresIn": token.expires_in,
                });

                if let Some(save_token) = save_token {
                    fs::write(save_token.to_string(), format!("{}", json_token))
                        .expect("Can't write token file");
                } else {
                    println!("{}", json_token);
                }
            } else {
                println!("Use --client-id to provide a CLIENT_ID");
            }
        }
        None => {
            println!("Missing credentials");
        }
    }
}

// inspired by examples/play.rs
pub async fn play_track(
    track_id: String,
    start_position: u32,
    last_credentials: Option<Credentials>,
    player_config: PlayerConfig,
    session_config: SessionConfig,
) {
    match last_credentials {
        Some(last_credentials) => {
            let backend = audio_backend::find(None).unwrap();
            let audio_format = AudioFormat::default();

            let track = SpotifyId::from_uri(
                track_id
                    .replace("spotty://", "spotify:track:")
                    .replace("://", ":")
                    .as_str(),
            );

            match track {
                Ok(track) => {
                    let session = Session::connect(session_config, last_credentials, None)
                        .await
                        .unwrap();

                    let (mut player, _) = Player::new(player_config, session, None, move || {
                        backend(None, audio_format)
                    });

                    player.load(track, true, start_position);
                    player.await_end_of_track().await;
                }
                Err(error) => {
                    warn!("Problem getting a Spotify ID for {}: {:?}", track_id, error);
                    return;
                }
            };
        }
        None => {
            println!("Missing credentials");
        }
    }
}

// Connect mode support

#[derive(Clone)]
pub struct LMS {
    base_url: Option<String>,
    player_mac: Option<String>,
    auth: Option<String>,
}

#[allow(unused)]
impl LMS {
    pub fn new(base_url: Option<String>, player_mac: Option<String>, auth: Option<String>) -> LMS {
        LMS {
            base_url: Some(format!(
                "http://{}/jsonrpc.js",
                base_url.unwrap_or("localhost:9000".to_string())
            )),
            player_mac: player_mac,
            auth: auth,
        }
    }

    pub fn is_configured(&self) -> bool {
        if self.base_url != None {
            if self.player_mac != None {
                return true;
            }
        }

        return false;
    }

    pub async fn signal_event(&self, event: PlayerEvent) {
        let mut command = r#"["spottyconnect","change"]"#.to_string();

        match event {
            PlayerEvent::Changed {
                old_track_id,
                new_track_id,
            } => {
                #[cfg(debug_assertions)]
                info!(
                    "event: changed, old track: {}, new track: {}",
                    old_track_id.to_base62(),
                    new_track_id.to_base62()
                );
                command = format!(
                    r#"["spottyconnect","change","{}","{}"]"#,
                    new_track_id.to_base62().to_string(),
                    old_track_id.to_base62().to_string()
                );
            }
            PlayerEvent::Started { track_id, .. } => {
                #[cfg(debug_assertions)]
                info!("event: started, track: {}", track_id.to_base62());
                command = format!(
                    r#"["spottyconnect","start","{}"]"#,
                    track_id.to_base62().to_string()
                );
            }
            PlayerEvent::Stopped { track_id, .. } => {
                #[cfg(debug_assertions)]
                info!("event: stopped, track: {}", track_id.to_base62());
                command = r#"["spottyconnect","stop"]"#.to_string();
            }
            PlayerEvent::Playing {
                track_id,
                duration_ms,
                position_ms,
                ..
            } => {
                #[cfg(debug_assertions)]
                info!(
                    "event: playing, track: {}, duration: {}, position: {}",
                    track_id.to_base62(),
                    duration_ms,
                    position_ms
                );
                // we're not implementing the seek event here, as it's going to read player state anyway
                // but signal a change if the new position has changed and is > 0
                if position_ms <= 0 {
                    return;
                }
                command = r#"["spottyconnect","change"]"#.to_string();
            }
            PlayerEvent::Paused {
                track_id,
                duration_ms,
                position_ms,
                ..
            } => {
                #[cfg(debug_assertions)]
                info!(
                    "event: paused, track: {}, duration: {}, position: {}",
                    track_id.to_base62(),
                    duration_ms,
                    position_ms
                );
                command = r#"["spottyconnect","stop"]"#.to_string();
            }
            PlayerEvent::VolumeSet { volume } => {
                let mut new_volume = volume as u32;
                if new_volume > 0 {
                    new_volume = new_volume * 100 / u32::pow(2, 16);
                }

                if new_volume > 100 {
                    new_volume = 100;
                };

                #[cfg(debug_assertions)]
                info!("event: volume: {}", volume);
                // we're not using the volume here, as LMS will read player state anyway
                command = format!(r#"["spottyconnect","volume",{}]"#, new_volume.to_string());
            }
            _ => return,
        }

        if !self.is_configured() {
            #[cfg(debug_assertions)]
            warn!("LMS connection is not configured");
            #[cfg(debug_assertions)]
            info!("{}", command);
            return;
        }

        if let Some(ref base_url) = self.base_url {
            #[cfg(debug_assertions)]
            info!("Base URL to talk to LMS: {}", base_url);

            if let Some(ref player_mac) = self.player_mac {
                #[cfg(debug_assertions)]
                info!("Player MAC address to control: {}", player_mac);

                #[cfg(debug_assertions)]
                info!("Command to send to player: {}", command);

                let json = format!(
                    r#"{{"id": 1,"method":"slim.request","params":["{}",{}]}}"#,
                    player_mac, command
                );

                let mut auth_header = "".to_string();
                if let Some(ref auth) = self.auth {
                    auth_header = auth.trim().to_string();
                }

                let req = Request::builder()
                    .method(Method::POST)
                    .uri(base_url.to_string())
                    .header("user-agent", format!("{}", VERSION))
                    .header("content-type", "application/json")
                    .header("authorization", format!("Basic {}", auth_header))
                    .header("x-scanner", "1")
                    .body(Body::from(json.clone()))
                    .unwrap();

                let client = Client::new();
                let resp = client.request(req).await;

                match resp {
                    Ok(resp) => {
                        #[cfg(debug_assertions)]
                        info!("Response: {}", resp.status());
                    }
                    Err(error) => {
                        warn!("Problem posting to {} / {}: {:?}", base_url, json, error);
                    }
                }
            }
        }
    }
}
<commit_msg>Update LMS integration to<commit_after>use hyper::{Body, Client, Method, Request};
#[allow(unused)]
use log::{info, warn};

use serde_json::json;
use std::fs;
use std::process::exit;

use librespot::core::authentication::Credentials;
use librespot::core::config::SessionConfig;
use librespot::core::keymaster;
use librespot::core::session::Session;
use librespot::core::spotify_id::SpotifyId;

use librespot::playback::audio_backend;
use librespot::playback::config::{AudioFormat, PlayerConfig};
use librespot::playback::player::{Player, PlayerEvent};

const VERSION: &'static str = concat!(env!("CARGO_PKG_NAME"), " v", env!("CARGO_PKG_VERSION"));

const SCOPES: &str = "user-read-private,playlist-read-private,playlist-read-collaborative,playlist-modify-public,playlist-modify-private,user-follow-modify,user-follow-read,user-library-read,user-library-modify,user-top-read,user-read-recently-played";

#[cfg(debug_assertions)]
const DEBUGMODE: bool = true;
#[cfg(not(debug_assertions))]
const DEBUGMODE: bool = false;

pub fn check(version_info: String) {
    println!("ok {}", version_info.to_string());

    let capabilities = json!({
        "version": env!("CARGO_PKG_VERSION").to_string(),
        "autoplay": true,
        "lms-auth": true,
        "volume-normalisation": true,
        "debug": DEBUGMODE,
        "ogg-direct": true,
        "save-token": true,
        "podcasts": true,
        "zeroconf-port": true
    });

    println!("{}", capabilities.to_string());
    exit(0);
}

// inspired by examples/get_token.rs
pub async fn get_token(
    client_id: Option<String>,
    scopes: Option<String>,
    save_token: Option<String>,
    last_credentials: Option<Credentials>,
    session_config: SessionConfig,
) {
    match last_credentials {
        Some(last_credentials) => {
            if let Some(client_id) = client_id {
                let scopes = scopes.unwrap_or(SCOPES.to_string());

                let session = Session::connect(session_config, last_credentials, None)
                    .await
                    .unwrap();

                let token = keymaster::get_token(&session, &client_id, &scopes)
                    .await
                    .unwrap();

                let json_token = json!({
                    // keep backwards compatibility with older versions
                    "accessToken": token.access_token.to_string(),
                    "expiresIn": token.expires_in,
                });

                if let Some(save_token) = save_token {
                    fs::write(save_token.to_string(), format!("{}", json_token))
                        .expect("Can't write token file");
                } else {
                    println!("{}", json_token);
                }
            } else {
                println!("Use --client-id to provide a CLIENT_ID");
            }
        }
        None => {
            println!("Missing credentials");
        }
    }
}

// inspired by examples/play.rs
pub async fn play_track(
    track_id: String,
    start_position: u32,
    last_credentials: Option<Credentials>,
    player_config: PlayerConfig,
    session_config: SessionConfig,
) {
    match last_credentials {
        Some(last_credentials) => {
            let backend = audio_backend::find(None).unwrap();
            let audio_format = AudioFormat::default();

            let track = SpotifyId::from_uri(
                track_id
                    .replace("spotty://", "spotify:track:")
                    .replace("://", ":")
                    .as_str(),
            );

            match track {
                Ok(track) => {
                    let session = Session::connect(session_config, last_credentials, None)
                        .await
                        .unwrap();

                    let (mut player, _) = Player::new(player_config, session, None, move || {
                        backend(None, audio_format)
                    });

                    player.load(track, true, start_position);
                    player.await_end_of_track().await;
                }
                Err(error) => {
                    warn!("Problem getting a Spotify ID for {}: {:?}", track_id, error);
                    return;
                }
            };
        }
        None => {
            println!("Missing credentials");
        }
    }
}

// Connect mode support

#[derive(Clone)]
pub struct LMS {
    base_url: Option<String>,
    player_mac: Option<String>,
    auth: Option<String>,
}

#[allow(unused)]
impl LMS {
    pub fn new(base_url: Option<String>, player_mac: Option<String>, auth: Option<String>) -> LMS {
        LMS {
            base_url: Some(format!(
                "http://{}/jsonrpc.js",
                base_url.unwrap_or("localhost:9000".to_string())
            )),
            player_mac: player_mac,
            auth: auth,
        }
    }

    pub fn is_configured(&self) -> bool {
        if self.base_url != None {
            if self.player_mac != None {
                return true;
            }
        }

        return false;
    }

    pub async fn signal_event(&self, event: PlayerEvent) {
        let mut command = r#"["spottyconnect","change"]"#.to_string();

        match event {
            PlayerEvent::Changed {
                old_track_id,
                new_track_id,
            } => {
                #[cfg(debug_assertions)]
                info!(
                    "event: changed, old track: {}, new track: {}",
                    old_track_id.to_base62().unwrap_or_default(),
                    new_track_id.to_base62().unwrap_or_default()
                );
                command = format!(
                    r#"["spottyconnect","change","{}","{}"]"#,
                    new_track_id.to_base62().unwrap_or_default().to_string(),
                    old_track_id.to_base62().unwrap_or_default().to_string()
                );
            }
            PlayerEvent::Started { track_id, .. } => {
                #[cfg(debug_assertions)]
                info!(
                    "event: started, track: {}",
                    track_id.to_base62().unwrap_or_default()
                );
                command = format!(
                    r#"["spottyconnect","start","{}"]"#,
                    track_id.to_base62().unwrap_or_default().to_string()
                );
            }
            PlayerEvent::Stopped { track_id, .. } => {
                #[cfg(debug_assertions)]
                info!(
                    "event: stopped, track: {}",
                    track_id.to_base62().unwrap_or_default()
                );
                command = r#"["spottyconnect","stop"]"#.to_string();
            }
            PlayerEvent::Playing {
                track_id,
                duration_ms,
                position_ms,
                ..
            } => {
                #[cfg(debug_assertions)]
                info!(
                    "event: playing, track: {}, duration: {}, position: {}",
                    track_id.to_base62().unwrap_or_default(),
                    duration_ms,
                    position_ms
                );
                // we're not implementing the seek event here, as it's going to read player state anyway
                // but signal a change if the new position has changed and is > 0
                if position_ms <= 0 {
                    return;
                }
                command = r#"["spottyconnect","change"]"#.to_string();
            }
            PlayerEvent::Paused {
                track_id,
                duration_ms,
                position_ms,
                ..
            } => {
                #[cfg(debug_assertions)]
                info!(
                    "event: paused, track: {}, duration: {}, position: {}",
                    track_id.to_base62().unwrap_or_default(),
                    duration_ms,
                    position_ms
                );
                command = r#"["spottyconnect","stop"]"#.to_string();
            }
            PlayerEvent::VolumeSet { volume } => {
                let mut new_volume = volume as u32;
                if new_volume > 0 {
                    new_volume = new_volume * 100 / u32::pow(2, 16);
                }

                if new_volume > 100 {
                    new_volume = 100;
                };

                #[cfg(debug_assertions)]
                info!("event: volume: {}", volume);
                // we're not using the volume here, as LMS will read player state anyway
                command = format!(r#"["spottyconnect","volume",{}]"#, new_volume.to_string());
            }
            _ => return,
        }

        if !self.is_configured() {
            #[cfg(debug_assertions)]
            warn!("LMS connection is not configured");
            #[cfg(debug_assertions)]
            info!("{}", command);
            return;
        }

        if let Some(ref base_url) = self.base_url {
            #[cfg(debug_assertions)]
            info!("Base URL to talk to LMS: {}", base_url);

            if let Some(ref player_mac) = self.player_mac {
                #[cfg(debug_assertions)]
                info!("Player MAC address to control: {}", player_mac);

                #[cfg(debug_assertions)]
                info!("Command to send to player: {}", command);

                let json = format!(
                    r#"{{"id": 1,"method":"slim.request","params":["{}",{}]}}"#,
                    player_mac, command
                );

                let mut auth_header = "".to_string();
                if let Some(ref auth) = self.auth {
                    auth_header = auth.trim().to_string();
                }

                let req = Request::builder()
                    .method(Method::POST)
                    .uri(base_url.to_string())
                    .header("user-agent", format!("{}", VERSION))
                    .header("content-type", "application/json")
                    .header("authorization", format!("Basic {}", auth_header))
                    .header("x-scanner", "1")
                    .body(Body::from(json.clone()))
                    .unwrap();

                let client = Client::new();
                let resp = client.request(req).await;

                match resp {
                    Ok(resp) => {
                        #[cfg(debug_assertions)]
                        info!("Response: {}", resp.status());
                    }
                    Err(error) => {
                        warn!("Problem posting to {} / {}: {:?}", base_url, json, error);
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Fundamental traits for ODE

use ndarray::*;
use ndarray_linalg::*;

pub trait ModelSize<D: Dimension> {
    fn model_size(&self) -> D::Pattern;
}

/// Equation of motion (Explicit)
pub trait Explicit<S, D>: ModelSize<D>
    where S: DataMut,
          D: Dimension
{
    type Scalar: Scalar;
    type Time: RealScalar;
    /// calculate right hand side (rhs) of Explicit from current state
    fn rhs<'a>(&self, &'a mut ArrayBase<S, D>) -> &'a mut ArrayBase<S, D>;
}

pub trait SemiImplicitDiag<Sn, Sd, D>: ModelSize<D>
    where Sn: DataMut,
          Sd: Data,
          D: Dimension
{
    type Scalar: Scalar;
    type Time: RealScalar;
    /// non-linear part of stiff equation
    fn nlin<'a>(&self, &'a mut ArrayBase<Sn, D>) -> &'a mut ArrayBase<Sn, D>;
    /// Linear part of Explicit (assume to be diagonalized)
    fn diag(&self) -> ArrayBase<Sd, D>;
}

/// Time-evolution operator
pub trait TimeEvolutionBase<S, D>: ModelSize<D>
    where S: DataMut,
          D: Dimension
{
    type Scalar: Scalar;
    type Time: RealScalar;
    /// calculate next step
    fn iterate<'a>(&self, &'a mut ArrayBase<S, D>) -> &'a mut ArrayBase<S, D>;
}

/// Interface for time-step
pub trait TimeStep {
    type Time: RealScalar;
    fn get_dt(&self) -> Self::Time;
    fn set_dt(&mut self, dt: Self::Time);
}

pub trait TimeEvolution<A, D>
    : TimeEvolutionBase<OwnedRepr<A>, D, Scalar = A, Time = A::Real>
    + TimeEvolutionBase<OwnedRcRepr<A>, D, Scalar = A, Time = A::Real>
    + for<'a> TimeEvolutionBase<ViewRepr<&'a mut A>, D, Scalar = A, Time = A::Real>
    + TimeStep<Time = A::Real>
    where A: Scalar,
          D: Dimension
{
}
<commit_msg>Split SemiImplicitDiag into SemiImplicit{Linear,NonLinear}<commit_after>//! Fundamental traits for ODE

use ndarray::*;
use ndarray_linalg::*;

pub trait ModelSize<D: Dimension> {
    fn model_size(&self) -> D::Pattern;
}

/// Interface for time-step
pub trait TimeStep {
    type Time: RealScalar;
    fn get_dt(&self) -> Self::Time;
    fn set_dt(&mut self, dt: Self::Time);
}

/// Equation of motion (Explicit)
pub trait Explicit<S, D>: ModelSize<D> + TimeStep
    where S: DataMut,
          D: Dimension
{
    type Scalar: Scalar;
    /// calculate right hand side (rhs) of Explicit from current state
    fn rhs<'a>(&self, &'a mut ArrayBase<S, D>) -> &'a mut ArrayBase<S, D>;
}

pub trait SemiImplicitNonLinear<S, D>: ModelSize<D> + TimeStep
    where S: DataMut,
          D: Dimension
{
    type Scalar: Scalar;
    /// non-linear part of stiff equation
    fn nlin<'a>(&self, &'a mut ArrayBase<S, D>) -> &'a mut ArrayBase<S, D>;
}

pub trait SemiImplicitLinear<S, D>: ModelSize<D> + TimeStep
    where S: DataMut,
          D: Dimension
{
    type Scalar: Scalar;
    /// Linear part of stiff equation
    fn lin<'a>(&self, &'a mut ArrayBase<S, D>) -> &'a mut ArrayBase<S, D>;
}

/// Time-evolution operator
pub trait TimeEvolutionBase<S, D>: ModelSize<D>
    where S: DataMut,
          D: Dimension
{
    type Scalar: Scalar;
    type Time: RealScalar;
    /// calculate next step
    fn iterate<'a>(&self, &'a mut ArrayBase<S, D>) -> &'a mut ArrayBase<S, D>;
}

pub trait TimeEvolution<A, D>
    : TimeEvolutionBase<OwnedRepr<A>, D, Scalar = A, Time = A::Real>
    + TimeEvolutionBase<OwnedRcRepr<A>, D, Scalar = A, Time = A::Real>
    + for<'a> TimeEvolutionBase<ViewRepr<&'a mut A>, D, Scalar = A, Time = A::Real>
    + TimeStep<Time = A::Real>
    where A: Scalar,
          D: Dimension
{
}
<|endoftext|>