<commit_before>use std::str;
use std::str::Chars;
use std::iter::Enumerate;
use path_builder::*;

extern crate cairo;

pub struct PathParser<'external> {
    path_str: &'external str,
    chars_enumerator: Enumerate<Chars<'external>>,
    lookahead: Option <char>, /* None if we are in EOF */
    current_pos: usize,

    builder: &'external mut RsvgPathBuilder,

    error_message: &'static str,
    has_error: bool,

    current_x: f64,
    current_y: f64
}

impl<'external> PathParser<'external> {
    pub fn new (builder: &'external mut RsvgPathBuilder, path_str: &'external str) -> PathParser<'external> {
        PathParser {
            path_str: path_str,
            chars_enumerator: path_str.chars ().enumerate (),
            lookahead: None,
            current_pos: 0,

            builder: builder,

            error_message: "",
            has_error: false,

            current_x: 0.0,
            current_y: 0.0
        }
    }

    pub fn parse (&mut self) -> bool {
        self.getchar ();

        return self.optional_whitespace () &&
            self.moveto_drawto_command_groups () &&
            self.optional_whitespace ();
    }

    fn getchar (&mut self) {
        if let Some ((pos, c)) = self.chars_enumerator.next () {
            self.lookahead = Some (c);
            self.current_pos = pos;
        } else {
            self.lookahead = None;
            self.current_pos += 1; /* this is EOF; point just past the end the string */
        }
    }

    fn error (&mut self, message: &'static str) -> bool {
        self.error_message = message;
        self.has_error = true;
        false
    }

    fn match_char (&mut self, c: char) -> bool {
        if let Some (x) = self.lookahead {
            if c == x {
                self.getchar ();
                return true;
            }
        }

        false
    }

    fn whitespace (&mut self) -> bool {
        if let Some (c) = self.lookahead {
            if c.is_whitespace () {
                assert! (self.match_char (c));

                while let Some (c) = self.lookahead {
                    if c.is_whitespace () {
                        assert! (self.match_char (c));
                        continue;
                    } else {
                        break;
                    }
                }

                return true;
            } else {
                return false;
            }
        }

        false
    }

    fn optional_whitespace (&mut self) -> bool {
        self.whitespace ();
        true
    }

    fn optional_comma_whitespace (&mut self) -> bool {
        assert! (self.optional_whitespace ());
        if self.match_char (',') {
            self.optional_whitespace ()
        } else {
            true
        }
    }

    fn lookahead_is_digit (&self, d: &mut char) -> bool {
        if let Some (c) = self.lookahead {
            if c.is_digit (10) {
                *d = c;
                return true;
            }
        }

        false
    }

    fn number (&mut self) -> Option <f64> {
        let mut has_sign: bool;
        let mut value: f64;
        let mut sign: f64;
        let mut exponent_sign: f64;
        let mut exponent: f64;

        has_sign = false;
        sign = 1.0;
        value = 0.0;
        exponent_sign = 1.0;
        exponent = 0.0;

        if self.match_char ('+') {
            sign = 1.0;
            has_sign = true;
        } else if self.match_char ('-') {
            sign = -1.0;
            has_sign = true;
        }

        let mut c: char = ' ';

        if self.lookahead_is_digit (&mut c) {
            /* Integer part */

            while self.lookahead_is_digit (&mut c) {
                value = value * 10.0 + char_to_digit (c) as f64;

                assert! (self.match_char (c));
            }

            /* Fractional part */

            if self.match_char ('.') {
                let mut fraction: f64 = 1.0;

                let mut c: char = ' ';

                while self.lookahead_is_digit (&mut c) {
                    fraction = fraction / 10.0;
                    value += fraction * char_to_digit (c) as f64;

                    assert! (self.match_char (c));
                }
            }

            if self.match_char ('E') || self.match_char ('e') {
                /* exponent sign */

                if self.match_char ('+') {
                    exponent_sign = 1.0;
                } else if self.match_char ('-') {
                    exponent_sign = -1.0;
                }

                /* exponent */

                let mut c: char = ' ';

                if self.lookahead_is_digit (&mut c) {
                    while self.lookahead_is_digit (&mut c) {
                        exponent = exponent * 10.0 + char_to_digit (c) as f64;

                        assert! (self.match_char (c));
                    }
                } else {
                    self.error ("Expected digits for exponent");
                    return None;
                }
            }

            Some (value * sign * 10.0f64.powf (exponent * exponent_sign))
        } else {
            if has_sign {
                self.error ("Expected number after sign");
            }

            None
        }
    }

    fn coordinate_pair (&mut self) -> Option<(f64, f64)> {
        if let Some (num1) = self.number () {
            assert! (self.optional_comma_whitespace ());

            if let Some (num2) = self.number () {
                return Some ((num1, num2));
            } else {
                self.error ("Expected second coordinate of coordinate pair");
                return None
            }
        }

        None
    }

    fn lookahead_is (&self, c: char) -> bool {
        if let Some (x) = self.lookahead {
            if x == c {
                return true;
            }
        }

        false
    }

    fn emit_line_to (&mut self, absolute: bool, x: f64, y: f64) {
        if absolute {
            self.current_x = x;
            self.current_y = y;
        } else {
            self.current_x += x;
            self.current_y += y;
        }

        self.builder.line_to (self.current_x, self.current_y);
        println! ("emitting lineto {} {}", self.current_x, self.current_y);
    }

    fn lineto_argument_sequence (&mut self, absolute: bool) -> bool {
        if let Some ((x, y)) = self.coordinate_pair () {
            self.emit_line_to (absolute, x, y);

            self.whitespace ();

            if self.lookahead_is (',') {
                assert! (self.match_char (','));
                assert! (self.optional_whitespace ());

                if !self.lineto_argument_sequence (absolute) {
                    self.error ("Expected coordinate pair after comma");
                    return false;
                }
            }

            self.lineto_argument_sequence (absolute);
            true
        } else {
            false
        }
    }

    fn emit_move_to (&mut self, absolute: bool, x: f64, y: f64) {
        if absolute {
            self.current_x = x;
            self.current_y = y;
        } else {
            self.current_x += x;
            self.current_y += y;
        }

        self.builder.move_to (self.current_x, self.current_y);
        println! ("emitting moveto {} {}", self.current_x, self.current_y);
    }

    fn moveto_argument_sequence (&mut self, absolute: bool, is_initial_moveto: bool) -> bool {
        if let Some ((x, y)) = self.coordinate_pair () {
            if is_initial_moveto {
                self.emit_move_to (true, x, y);
            } else {
                self.emit_move_to (absolute, x, y);
            }

            self.whitespace ();

            if self.lookahead_is (',') {
                assert! (self.match_char (','));
                assert! (self.optional_whitespace ());

                if !self.lineto_argument_sequence (absolute) {
                    self.error ("Expected coordinate pair after comma");
                    return false;
                }
            }

            self.lineto_argument_sequence (absolute);
            true
        } else {
            self.error ("Expected coordinate pair after moveto")
        }
    }

    fn moveto (&mut self, is_initial_moveto: bool) -> bool {
        if self.lookahead_is ('M') || self.lookahead_is ('m') {
            let absolute: bool;

            if self.match_char ('M') {
                absolute = true;
            } else {
                assert! (self.match_char ('m'));
                absolute = false;
            }

            return self.optional_whitespace () &&
                self.moveto_argument_sequence (absolute, is_initial_moveto);
        }

        false
    }

    fn moveto_drawto_command_group (&mut self, is_initial_moveto: bool) -> bool {
        if self.moveto (is_initial_moveto) {
            return self.optional_whitespace () &&
                true; // FIXME self.optional_drawto_commands ();
        } else {
            false
        }
    }

    fn moveto_drawto_command_groups (&mut self) -> bool {
        if self.moveto_drawto_command_group (true) {
            loop {
                self.optional_whitespace ();
                if !self.moveto_drawto_command_group (false) {
                    break;
                }
            }

            true
        } else {
            self.error ("Expected moveto command")
        }
    }
}

fn char_to_digit (c: char) -> i32 {
    c as i32 - '0' as i32
}

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

    extern crate cairo;

    fn path_segment_vectors_are_equal (a: &Vec<cairo::PathSegment>,
                                       b: &Vec<cairo::PathSegment>) -> bool {

        if a.len() != b.len () {
            return false;
        }

        if a.len () == 0 && b.len () == 0 {
            return true;
        }

        let mut iter = a.iter().zip (b);

        loop {
            if let Some ((seg1, seg2)) = iter.next () {
                match *seg1 {
                    cairo::PathSegment::MoveTo ((x, y)) => {
                        if let cairo::PathSegment::MoveTo ((ox, oy)) = *seg2 {
                            println! ("{} {} {} {}", x, y, ox, oy);
                            if (x, y) != (ox, oy) {
                                return false;
                            }
                        } else {
                            return false;
                        }
                    },

                    cairo::PathSegment::LineTo ((x, y)) => {
                        if let cairo::PathSegment::LineTo ((ox, oy)) = *seg2 {
                            println! ("{} {} {} {}", x, y, ox, oy);
                            if (x, y) != (ox, oy) {
                                return false;
                            }
                        } else {
                            return false;
                        }
                    },

                    cairo::PathSegment::CurveTo ((x2, y2), (x3, y3), (x4, y4)) => {
                        if let cairo::PathSegment::CurveTo ((ox2, oy2), (ox3, oy3), (ox4, oy4)) = *seg2 {
                            if (ox2, oy2, ox3, oy3, ox4, oy4) != (x2, y2, x3, y3, x4, y4) {
                                return false;
                            }
                        } else {
                            return false;
                        }
                    },

                    cairo::PathSegment::ClosePath => {
                        if let cairo::PathSegment::ClosePath = *seg2 {
                            /* okay */
                        } else {
                            return false;
                        }
                    }
                }
            } else {
                break;
            }
        }

        true
    }

    fn print_error (parser: &PathParser) {
        let prefix = "Error in \"";

        println! ("");
        println! ("{}{}\"", prefix, &parser.path_str);

        for _ in 0 .. (prefix.len() + parser.current_pos) {
            print! (" ");
        }

        println! ("^ pos {}", parser.current_pos);
        println! ("{}", &parser.error_message);
    }

    fn parse_path (path_str: &str) -> RsvgPathBuilder {
        let mut builder = RsvgPathBuilder::new ();

        {
            let mut parser = PathParser::new (&mut builder, path_str);
            if !parser.parse () {
                print_error (&parser);
            }
        }

        builder
    }

    fn test_parser (path_str: &str,
                    expected_segments: &Vec<cairo::PathSegment>) {
        let builder = parse_path (path_str);
        let segments = builder.get_path_segments ();

        assert! (path_segment_vectors_are_equal (expected_segments, segments));
    }

    fn moveto (x: f64, y: f64) -> cairo::PathSegment {
        cairo::PathSegment::MoveTo ((x, y))
    }

    fn lineto (x: f64, y: f64) -> cairo::PathSegment {
        cairo::PathSegment::LineTo ((x, y))
    }

    fn curveto (x2: f64, y2: f64, x3: f64, y3: f64, x4: f64, y4: f64) -> cairo::PathSegment {
        cairo::PathSegment::CurveTo ((x2, y2), (x3, y3), (x4, y4))
    }

    fn closepath () -> cairo::PathSegment {
        cairo::PathSegment::ClosePath
    }

    #[test]
    fn path_parser_handles_empty_data () {
        test_parser ("",
                     &Vec::<cairo::PathSegment>::new ());
    }

    #[test]
    fn path_parser_handles_single_moveto () {
        test_parser ("M 10 20",
                     &vec![
                         moveto (10.0, 20.0)
                     ]);

        test_parser ("M10,20",
                     &vec![
                         moveto (10.0, 20.0)
                     ]);

        test_parser ("M10 20",
                     &vec![
                         moveto (10.0, 20.0)
                     ]);

        test_parser ("    M10,20     ",
                     &vec![
                         moveto (10.0, 20.0)
                     ]);
    }

    #[test]
    fn path_parser_handles_relative_moveto () {
        test_parser ("m10 20",
                     &vec![
                         moveto (10.0, 20.0)
                     ]);
    }

    #[test]
    fn path_parser_handles_absolute_moveto_with_implicit_linetos () {
        test_parser ("M10 20 30 40",
                     &vec![
                         moveto (10.0, 20.0),
                         lineto (30.0, 40.0)
                     ]);
    }

    #[test]
    fn path_parser_handles_relative_moveto_with_implicit_linetos () {
        test_parser ("m10 20 30 40",
                     &vec![
                         moveto (10.0, 20.0),
                         lineto (40.0, 60.0)
                     ]);
    }
}
<commit_msg>path_parser.rs: Test and fix handling of numbers with decimals<commit_after>use std::str;
use std::str::Chars;
use std::iter::Enumerate;
use path_builder::*;

extern crate cairo;

pub struct PathParser<'external> {
    path_str: &'external str,
    chars_enumerator: Enumerate<Chars<'external>>,
    lookahead: Option <char>, /* None if we are in EOF */
    current_pos: usize,

    builder: &'external mut RsvgPathBuilder,

    error_message: &'static str,
    has_error: bool,

    current_x: f64,
    current_y: f64
}

impl<'external> PathParser<'external> {
    pub fn new (builder: &'external mut RsvgPathBuilder, path_str: &'external str) -> PathParser<'external> {
        PathParser {
            path_str: path_str,
            chars_enumerator: path_str.chars ().enumerate (),
            lookahead: None,
            current_pos: 0,

            builder: builder,

            error_message: "",
            has_error: false,

            current_x: 0.0,
            current_y: 0.0
        }
    }

    pub fn parse (&mut self) -> bool {
        self.getchar ();

        return self.optional_whitespace () &&
            self.moveto_drawto_command_groups () &&
            self.optional_whitespace ();
    }

    fn getchar (&mut self) {
        if let Some ((pos, c)) = self.chars_enumerator.next () {
            self.lookahead = Some (c);
            self.current_pos = pos;
        } else {
            self.lookahead = None;
            self.current_pos += 1; /* this is EOF; point just past the end the string */
        }
    }

    fn error (&mut self, message: &'static str) -> bool {
        self.error_message = message;
        self.has_error = true;
        false
    }

    fn match_char (&mut self, c: char) -> bool {
        if let Some (x) = self.lookahead {
            if c == x {
                self.getchar ();
                return true;
            }
        }

        false
    }

    fn whitespace (&mut self) -> bool {
        if let Some (c) = self.lookahead {
            if c.is_whitespace () {
                assert! (self.match_char (c));

                while let Some (c) = self.lookahead {
                    if c.is_whitespace () {
                        assert! (self.match_char (c));
                        continue;
                    } else {
                        break;
                    }
                }

                return true;
            } else {
                return false;
            }
        }

        false
    }

    fn optional_whitespace (&mut self) -> bool {
        self.whitespace ();
        true
    }

    fn optional_comma_whitespace (&mut self) -> bool {
        assert! (self.optional_whitespace ());
        if self.match_char (',') {
            self.optional_whitespace ()
        } else {
            true
        }
    }

    fn lookahead_is (&self, c: char) -> bool {
        if let Some (x) = self.lookahead {
            if x == c {
                return true;
            }
        }

        false
    }

    fn lookahead_is_digit (&self, d: &mut char) -> bool {
        if let Some (c) = self.lookahead {
            if c.is_digit (10) {
                *d = c;
                return true;
            }
        }

        false
    }

    fn number (&mut self) -> Option <f64> {
        let mut has_sign: bool;
        let mut value: f64;
        let mut sign: f64;
        let mut exponent_sign: f64;
        let mut exponent: f64;

        has_sign = false;
        sign = 1.0;
        value = 0.0;
        exponent_sign = 1.0;
        exponent = 0.0;

        if self.match_char ('+') {
            sign = 1.0;
            has_sign = true;
        } else if self.match_char ('-') {
            sign = -1.0;
            has_sign = true;
        }

        let mut c: char = ' ';

        if self.lookahead_is_digit (&mut c) || self.lookahead_is ('.') {
            /* Integer part */

            while self.lookahead_is_digit (&mut c) {
                value = value * 10.0 + char_to_digit (c) as f64;

                assert! (self.match_char (c));
            }

            /* Fractional part */

            if self.match_char ('.') {
                let mut fraction: f64 = 1.0;

                let mut c: char = ' ';

                while self.lookahead_is_digit (&mut c) {
                    fraction = fraction / 10.0;
                    value += fraction * char_to_digit (c) as f64;

                    assert! (self.match_char (c));
                }
            }

            if self.match_char ('E') || self.match_char ('e') {
                /* exponent sign */

                if self.match_char ('+') {
                    exponent_sign = 1.0;
                } else if self.match_char ('-') {
                    exponent_sign = -1.0;
                }

                /* exponent */

                let mut c: char = ' ';

                if self.lookahead_is_digit (&mut c) {
                    while self.lookahead_is_digit (&mut c) {
                        exponent = exponent * 10.0 + char_to_digit (c) as f64;

                        assert! (self.match_char (c));
                    }
                } else {
                    self.error ("Expected digits for exponent");
                    return None;
                }
            }

            Some (value * sign * 10.0f64.powf (exponent * exponent_sign))
        } else {
            if has_sign {
                self.error ("Expected number after sign");
            }

            None
        }
    }

    fn coordinate_pair (&mut self) -> Option<(f64, f64)> {
        if let Some (num1) = self.number () {
            assert! (self.optional_comma_whitespace ());

            if let Some (num2) = self.number () {
                return Some ((num1, num2));
            } else {
                self.error ("Expected second coordinate of coordinate pair");
                return None
            }
        }

        None
    }

    fn emit_line_to (&mut self, absolute: bool, x: f64, y: f64) {
        if absolute {
            self.current_x = x;
            self.current_y = y;
        } else {
            self.current_x += x;
            self.current_y += y;
        }

        self.builder.line_to (self.current_x, self.current_y);
        println! ("emitting lineto {} {}", self.current_x, self.current_y);
    }

    fn lineto_argument_sequence (&mut self, absolute: bool) -> bool {
        if let Some ((x, y)) = self.coordinate_pair () {
            self.emit_line_to (absolute, x, y);

            self.whitespace ();

            if self.lookahead_is (',') {
                assert! (self.match_char (','));
                assert! (self.optional_whitespace ());

                if !self.lineto_argument_sequence (absolute) {
                    self.error ("Expected coordinate pair after comma");
                    return false;
                }
            }

            self.lineto_argument_sequence (absolute);
            true
        } else {
            false
        }
    }

    fn emit_move_to (&mut self, absolute: bool, x: f64, y: f64) {
        if absolute {
            self.current_x = x;
            self.current_y = y;
        } else {
            self.current_x += x;
            self.current_y += y;
        }

        self.builder.move_to (self.current_x, self.current_y);
        println! ("emitting moveto {} {}", self.current_x, self.current_y);
    }

    fn moveto_argument_sequence (&mut self, absolute: bool, is_initial_moveto: bool) -> bool {
        if let Some ((x, y)) = self.coordinate_pair () {
            if is_initial_moveto {
                self.emit_move_to (true, x, y);
            } else {
                self.emit_move_to (absolute, x, y);
            }

            self.whitespace ();

            if self.lookahead_is (',') {
                assert! (self.match_char (','));
                assert! (self.optional_whitespace ());

                if !self.lineto_argument_sequence (absolute) {
                    self.error ("Expected coordinate pair after comma");
                    return false;
                }
            }

            self.lineto_argument_sequence (absolute);
            true
        } else {
            self.error ("Expected coordinate pair after moveto")
        }
    }

    fn moveto (&mut self, is_initial_moveto: bool) -> bool {
        if self.lookahead_is ('M') || self.lookahead_is ('m') {
            let absolute: bool;

            if self.match_char ('M') {
                absolute = true;
            } else {
                assert! (self.match_char ('m'));
                absolute = false;
            }

            return self.optional_whitespace () &&
                self.moveto_argument_sequence (absolute, is_initial_moveto);
        }

        false
    }

    fn moveto_drawto_command_group (&mut self, is_initial_moveto: bool) -> bool {
        if self.moveto (is_initial_moveto) {
            return self.optional_whitespace () &&
                true; // FIXME self.optional_drawto_commands ();
        } else {
            false
        }
    }

    fn moveto_drawto_command_groups (&mut self) -> bool {
        if self.moveto_drawto_command_group (true) {
            loop {
                self.optional_whitespace ();
                if !self.moveto_drawto_command_group (false) {
                    break;
                }
            }

            true
        } else {
            self.error ("Expected moveto command")
        }
    }
}

fn char_to_digit (c: char) -> i32 {
    c as i32 - '0' as i32
}

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

    extern crate cairo;

    fn path_segment_vectors_are_equal (a: &Vec<cairo::PathSegment>,
                                       b: &Vec<cairo::PathSegment>) -> bool {

        if a.len() != b.len () {
            return false;
        }

        if a.len () == 0 && b.len () == 0 {
            return true;
        }

        let mut iter = a.iter().zip (b);

        loop {
            if let Some ((seg1, seg2)) = iter.next () {
                match *seg1 {
                    cairo::PathSegment::MoveTo ((x, y)) => {
                        if let cairo::PathSegment::MoveTo ((ox, oy)) = *seg2 {
                            println! ("{} {} {} {}", x, y, ox, oy);
                            if (x, y) != (ox, oy) {
                                return false;
                            }
                        } else {
                            return false;
                        }
                    },

                    cairo::PathSegment::LineTo ((x, y)) => {
                        if let cairo::PathSegment::LineTo ((ox, oy)) = *seg2 {
                            println! ("{} {} {} {}", x, y, ox, oy);
                            if (x, y) != (ox, oy) {
                                return false;
                            }
                        } else {
                            return false;
                        }
                    },

                    cairo::PathSegment::CurveTo ((x2, y2), (x3, y3), (x4, y4)) => {
                        if let cairo::PathSegment::CurveTo ((ox2, oy2), (ox3, oy3), (ox4, oy4)) = *seg2 {
                            if (ox2, oy2, ox3, oy3, ox4, oy4) != (x2, y2, x3, y3, x4, y4) {
                                return false;
                            }
                        } else {
                            return false;
                        }
                    },

                    cairo::PathSegment::ClosePath => {
                        if let cairo::PathSegment::ClosePath = *seg2 {
                            /* okay */
                        } else {
                            return false;
                        }
                    }
                }
            } else {
                break;
            }
        }

        true
    }

    fn print_error (parser: &PathParser) {
        let prefix = "Error in \"";

        println! ("");
        println! ("{}{}\"", prefix, &parser.path_str);

        for _ in 0 .. (prefix.len() + parser.current_pos) {
            print! (" ");
        }

        println! ("^ pos {}", parser.current_pos);
        println! ("{}", &parser.error_message);
    }

    fn parse_path (path_str: &str) -> RsvgPathBuilder {
        let mut builder = RsvgPathBuilder::new ();

        {
            let mut parser = PathParser::new (&mut builder, path_str);
            if !parser.parse () {
                print_error (&parser);
            }
        }

        builder
    }

    fn test_parser (path_str: &str,
                    expected_segments: &Vec<cairo::PathSegment>) {
        let builder = parse_path (path_str);
        let segments = builder.get_path_segments ();

        assert! (path_segment_vectors_are_equal (expected_segments, segments));
    }

    fn moveto (x: f64, y: f64) -> cairo::PathSegment {
        cairo::PathSegment::MoveTo ((x, y))
    }

    fn lineto (x: f64, y: f64) -> cairo::PathSegment {
        cairo::PathSegment::LineTo ((x, y))
    }

    fn curveto (x2: f64, y2: f64, x3: f64, y3: f64, x4: f64, y4: f64) -> cairo::PathSegment {
        cairo::PathSegment::CurveTo ((x2, y2), (x3, y3), (x4, y4))
    }

    fn closepath () -> cairo::PathSegment {
        cairo::PathSegment::ClosePath
    }

    #[test]
    fn path_parser_handles_empty_data () {
        test_parser ("",
                     &Vec::<cairo::PathSegment>::new ());
    }

    #[test]
    fn path_parser_handles_numbers () {
        test_parser ("M 10 20",
                     &vec![
                         moveto (10.0, 20.0)
                     ]);

        test_parser ("M .10 0.20",
                     &vec![
                         moveto (0.10, 0.20)
                     ]);
    }

    #[test]
    fn path_parser_handles_single_moveto () {
        test_parser ("M 10 20",
                     &vec![
                         moveto (10.0, 20.0)
                     ]);

        test_parser ("M10,20",
                     &vec![
                         moveto (10.0, 20.0)
                     ]);

        test_parser ("M10 20",
                     &vec![
                         moveto (10.0, 20.0)
                     ]);

        test_parser ("    M10,20     ",
                     &vec![
                         moveto (10.0, 20.0)
                     ]);
    }

    #[test]
    fn path_parser_handles_relative_moveto () {
        test_parser ("m10 20",
                     &vec![
                         moveto (10.0, 20.0)
                     ]);
    }

    #[test]
    fn path_parser_handles_absolute_moveto_with_implicit_linetos () {
        test_parser ("M10 20 30 40",
                     &vec![
                         moveto (10.0, 20.0),
                         lineto (30.0, 40.0)
                     ]);
    }

    #[test]
    fn path_parser_handles_relative_moveto_with_implicit_linetos () {
        test_parser ("m10 20 30 40",
                     &vec![
                         moveto (10.0, 20.0),
                         lineto (40.0, 60.0)
                     ]);
    }
}
<|endoftext|>


<commit_before>//! Utilities that leverage libuv's `uv_timer_*` API

import uv = uv;
import uv::iotask;
import iotask::iotask;
import comm = core::comm;

export delayed_send, sleep, recv_timeout;

/**
 * Wait for timeout period then send provided value over a channel
 *
 * This call returns immediately. Useful as the building block for a number
 * of higher-level timer functions.
 *
 * Is not guaranteed to wait for exactly the specified time, but will wait
 * for *at least* that period of time.
 *
 * # Arguments
 *
 * * `hl_loop` - a `uv::hl::high_level_loop` that the tcp request will run on
 * * msecs - a timeout period, in milliseconds, to wait
 * * ch - a channel of type T to send a `val` on
 * * val - a value of type T to send over the provided `ch`
 */
fn delayed_send<T: copy send>(iotask: iotask,
                              msecs: uint, ch: comm::Chan<T>, val: T) {
        unsafe {
            let timer_done_po = core::comm::port::<()>();
            let timer_done_ch = core::comm::chan(timer_done_po);
            let timer_done_ch_ptr = ptr::addr_of(timer_done_ch);
            let timer = uv::ll::timer_t();
            let timer_ptr = ptr::addr_of(timer);
            do iotask::interact(iotask) |loop_ptr| {
                let init_result = uv::ll::timer_init(loop_ptr, timer_ptr);
                if (init_result == 0i32) {
                    let start_result = uv::ll::timer_start(
                        timer_ptr, delayed_send_cb, msecs, 0u);
                    if (start_result == 0i32) {
                        uv::ll::set_data_for_uv_handle(
                            timer_ptr,
                            timer_done_ch_ptr as *libc::c_void);
                    }
                    else {
                        let error_msg = uv::ll::get_last_err_info(loop_ptr);
                        fail ~"timer::delayed_send() start failed: " +
                            error_msg;
                    }
                }
                else {
                    let error_msg = uv::ll::get_last_err_info(loop_ptr);
                    fail ~"timer::delayed_send() init failed: "+error_msg;
                }
            };
            // delayed_send_cb has been processed by libuv
            core::comm::recv(timer_done_po);
            // notify the caller immediately
            core::comm::send(ch, copy(val));
            // uv_close for this timer has been processed
            core::comm::recv(timer_done_po);
    };
}

/**
 * Blocks the current task for (at least) the specified time period.
 *
 * Is not guaranteed to sleep for exactly the specified time, but will sleep
 * for *at least* that period of time.
 *
 * # Arguments
 *
 * * `iotask` - a `uv::iotask` that the tcp request will run on
 * * msecs - an amount of time, in milliseconds, for the current task to block
 */
fn sleep(iotask: iotask, msecs: uint) {
    let exit_po = core::comm::port::<()>();
    let exit_ch = core::comm::chan(exit_po);
    delayed_send(iotask, msecs, exit_ch, ());
    core::comm::recv(exit_po);
}

/**
 * Receive on a port for (up to) a specified time, then return an `option<T>`
 *
 * This call will block to receive on the provided port for up to the
 * specified timeout. Depending on whether the provided port receives in that
 * time period, `recv_timeout` will return an `option<T>` representing the
 * result.
 *
 * # Arguments
 *
 * * `iotask' - `uv::iotask` that the tcp request will run on
 * * msecs - an mount of time, in milliseconds, to wait to receive
 * * wait_port - a `core::comm::port<T>` to receive on
 *
 * # Returns
 *
 * An `option<T>` representing the outcome of the call. If the call `recv`'d
 * on the provided port in the allotted timeout period, then the result will
 * be a `some(T)`. If not, then `none` will be returned.
 */
fn recv_timeout<T: copy send>(iotask: iotask,
                              msecs: uint,
                              wait_po: comm::Port<T>) -> option<T> {
    let timeout_po = comm::port::<()>();
    let timeout_ch = comm::chan(timeout_po);
    delayed_send(iotask, msecs, timeout_ch, ());
    // FIXME: This could be written clearer (#2618)
    either::either(
        |left_val| {
            log(debug, fmt!{"recv_time .. left_val %?",
                           left_val});
            none
        }, |right_val| {
            some(*right_val)
        }, &core::comm::select2(timeout_po, wait_po)
    )
}

// INTERNAL API
extern fn delayed_send_cb(handle: *uv::ll::uv_timer_t,
                                status: libc::c_int) unsafe {
    log(debug, fmt!{"delayed_send_cb handle %? status %?", handle, status});
    let timer_done_ch =
        *(uv::ll::get_data_for_uv_handle(handle) as *comm::Chan<()>);
    let stop_result = uv::ll::timer_stop(handle);
    if (stop_result == 0i32) {
        core::comm::send(timer_done_ch, ());
        uv::ll::close(handle, delayed_send_close_cb);
    }
    else {
        let loop_ptr = uv::ll::get_loop_for_uv_handle(handle);
        let error_msg = uv::ll::get_last_err_info(loop_ptr);
        fail ~"timer::sleep() init failed: "+error_msg;
    }
}

extern fn delayed_send_close_cb(handle: *uv::ll::uv_timer_t) unsafe {
    log(debug, fmt!{"delayed_send_close_cb handle %?", handle});
    let timer_done_ch =
        *(uv::ll::get_data_for_uv_handle(handle) as *comm::Chan<()>);
    comm::send(timer_done_ch, ());
}

#[cfg(test)]
mod test {
    #[test]
    fn test_gl_timer_simple_sleep_test() {
        let hl_loop = uv::global_loop::get();
        sleep(hl_loop, 1u);
    }

    #[test]
    fn test_gl_timer_sleep_stress1() {
        let hl_loop = uv::global_loop::get();
        for iter::repeat(200u) {
            sleep(hl_loop, 1u);
        }
    }

    #[test]
    fn test_gl_timer_sleep_stress2() {
        let po = core::comm::port();
        let ch = core::comm::chan(po);
        let hl_loop = uv::global_loop::get();

        let repeat = 20u;
        let spec = {

            ~[(1u,  20u),
             (10u, 10u),
             (20u, 2u)]

        };

        for iter::repeat(repeat) {

            for spec.each |spec| {
                let (times, maxms) = spec;
                do task::spawn {
                    import rand::*;
                    let rng = rng();
                    for iter::repeat(times) {
                        sleep(hl_loop, rng.next() as uint % maxms);
                    }
                    core::comm::send(ch, ());
                }
            }
        }

        for iter::repeat(repeat * spec.len()) {
            core::comm::recv(po)
        }
    }

    // Because valgrind serializes multithreaded programs it can
    // make timing-sensitive tests fail in wierd ways. In these
    // next test we run them many times and expect them to pass
    // the majority of tries.

    #[test]
    #[cfg(ignore)]
    fn test_gl_timer_recv_timeout_before_time_passes() {
        let times = 100;
        let mut successes = 0;
        let mut failures = 0;
        let hl_loop = uv::global_loop::get();

        for iter::repeat(times as uint) {
            task::yield();

            let expected = rand::rng().gen_str(16u);
            let test_po = core::comm::port::<str>();
            let test_ch = core::comm::chan(test_po);

            do task::spawn() {
                delayed_send(hl_loop, 1u, test_ch, expected);
            };

            match recv_timeout(hl_loop, 10u, test_po) {
              some(val) => {
                assert val == expected;
                successes += 1;
              }
              _ => failures += 1
            };
        }

        assert successes > times / 2;
    }

    #[test]
    fn test_gl_timer_recv_timeout_after_time_passes() {
        let times = 100;
        let mut successes = 0;
        let mut failures = 0;
        let hl_loop = uv::global_loop::get();

        for iter::repeat(times as uint) {
            let expected = rand::rng().gen_str(16u);
            let test_po = core::comm::port::<~str>();
            let test_ch = core::comm::chan(test_po);

            do task::spawn() {
                delayed_send(hl_loop, 1000u, test_ch, expected);
            };

            match recv_timeout(hl_loop, 1u, test_po) {
              none => successes += 1,
              _ => failures += 1
            };
        }

        assert successes > times / 2;
    }
}
<commit_msg>reduce stress constants in std::timer::tests<commit_after>//! Utilities that leverage libuv's `uv_timer_*` API

import uv = uv;
import uv::iotask;
import iotask::iotask;
import comm = core::comm;

export delayed_send, sleep, recv_timeout;

/**
 * Wait for timeout period then send provided value over a channel
 *
 * This call returns immediately. Useful as the building block for a number
 * of higher-level timer functions.
 *
 * Is not guaranteed to wait for exactly the specified time, but will wait
 * for *at least* that period of time.
 *
 * # Arguments
 *
 * * `hl_loop` - a `uv::hl::high_level_loop` that the tcp request will run on
 * * msecs - a timeout period, in milliseconds, to wait
 * * ch - a channel of type T to send a `val` on
 * * val - a value of type T to send over the provided `ch`
 */
fn delayed_send<T: copy send>(iotask: iotask,
                              msecs: uint, ch: comm::Chan<T>, val: T) {
        unsafe {
            let timer_done_po = core::comm::port::<()>();
            let timer_done_ch = core::comm::chan(timer_done_po);
            let timer_done_ch_ptr = ptr::addr_of(timer_done_ch);
            let timer = uv::ll::timer_t();
            let timer_ptr = ptr::addr_of(timer);
            do iotask::interact(iotask) |loop_ptr| {
                let init_result = uv::ll::timer_init(loop_ptr, timer_ptr);
                if (init_result == 0i32) {
                    let start_result = uv::ll::timer_start(
                        timer_ptr, delayed_send_cb, msecs, 0u);
                    if (start_result == 0i32) {
                        uv::ll::set_data_for_uv_handle(
                            timer_ptr,
                            timer_done_ch_ptr as *libc::c_void);
                    }
                    else {
                        let error_msg = uv::ll::get_last_err_info(loop_ptr);
                        fail ~"timer::delayed_send() start failed: " +
                            error_msg;
                    }
                }
                else {
                    let error_msg = uv::ll::get_last_err_info(loop_ptr);
                    fail ~"timer::delayed_send() init failed: "+error_msg;
                }
            };
            // delayed_send_cb has been processed by libuv
            core::comm::recv(timer_done_po);
            // notify the caller immediately
            core::comm::send(ch, copy(val));
            // uv_close for this timer has been processed
            core::comm::recv(timer_done_po);
    };
}

/**
 * Blocks the current task for (at least) the specified time period.
 *
 * Is not guaranteed to sleep for exactly the specified time, but will sleep
 * for *at least* that period of time.
 *
 * # Arguments
 *
 * * `iotask` - a `uv::iotask` that the tcp request will run on
 * * msecs - an amount of time, in milliseconds, for the current task to block
 */
fn sleep(iotask: iotask, msecs: uint) {
    let exit_po = core::comm::port::<()>();
    let exit_ch = core::comm::chan(exit_po);
    delayed_send(iotask, msecs, exit_ch, ());
    core::comm::recv(exit_po);
}

/**
 * Receive on a port for (up to) a specified time, then return an `option<T>`
 *
 * This call will block to receive on the provided port for up to the
 * specified timeout. Depending on whether the provided port receives in that
 * time period, `recv_timeout` will return an `option<T>` representing the
 * result.
 *
 * # Arguments
 *
 * * `iotask' - `uv::iotask` that the tcp request will run on
 * * msecs - an mount of time, in milliseconds, to wait to receive
 * * wait_port - a `core::comm::port<T>` to receive on
 *
 * # Returns
 *
 * An `option<T>` representing the outcome of the call. If the call `recv`'d
 * on the provided port in the allotted timeout period, then the result will
 * be a `some(T)`. If not, then `none` will be returned.
 */
fn recv_timeout<T: copy send>(iotask: iotask,
                              msecs: uint,
                              wait_po: comm::Port<T>) -> option<T> {
    let timeout_po = comm::port::<()>();
    let timeout_ch = comm::chan(timeout_po);
    delayed_send(iotask, msecs, timeout_ch, ());
    // FIXME: This could be written clearer (#2618)
    either::either(
        |left_val| {
            log(debug, fmt!{"recv_time .. left_val %?",
                           left_val});
            none
        }, |right_val| {
            some(*right_val)
        }, &core::comm::select2(timeout_po, wait_po)
    )
}

// INTERNAL API
extern fn delayed_send_cb(handle: *uv::ll::uv_timer_t,
                                status: libc::c_int) unsafe {
    log(debug, fmt!{"delayed_send_cb handle %? status %?", handle, status});
    let timer_done_ch =
        *(uv::ll::get_data_for_uv_handle(handle) as *comm::Chan<()>);
    let stop_result = uv::ll::timer_stop(handle);
    if (stop_result == 0i32) {
        core::comm::send(timer_done_ch, ());
        uv::ll::close(handle, delayed_send_close_cb);
    }
    else {
        let loop_ptr = uv::ll::get_loop_for_uv_handle(handle);
        let error_msg = uv::ll::get_last_err_info(loop_ptr);
        fail ~"timer::sleep() init failed: "+error_msg;
    }
}

extern fn delayed_send_close_cb(handle: *uv::ll::uv_timer_t) unsafe {
    log(debug, fmt!{"delayed_send_close_cb handle %?", handle});
    let timer_done_ch =
        *(uv::ll::get_data_for_uv_handle(handle) as *comm::Chan<()>);
    comm::send(timer_done_ch, ());
}

#[cfg(test)]
mod test {
    #[test]
    fn test_gl_timer_simple_sleep_test() {
        let hl_loop = uv::global_loop::get();
        sleep(hl_loop, 1u);
    }

    #[test]
    fn test_gl_timer_sleep_stress1() {
        let hl_loop = uv::global_loop::get();
        for iter::repeat(50u) {
            sleep(hl_loop, 1u);
        }
    }

    #[test]
    fn test_gl_timer_sleep_stress2() {
        let po = core::comm::port();
        let ch = core::comm::chan(po);
        let hl_loop = uv::global_loop::get();

        let repeat = 20u;
        let spec = {

            ~[(1u,  20u),
             (10u, 10u),
             (20u, 2u)]

        };

        for iter::repeat(repeat) {

            for spec.each |spec| {
                let (times, maxms) = spec;
                do task::spawn {
                    import rand::*;
                    let rng = rng();
                    for iter::repeat(times) {
                        sleep(hl_loop, rng.next() as uint % maxms);
                    }
                    core::comm::send(ch, ());
                }
            }
        }

        for iter::repeat(repeat * spec.len()) {
            core::comm::recv(po)
        }
    }

    // Because valgrind serializes multithreaded programs it can
    // make timing-sensitive tests fail in wierd ways. In these
    // next test we run them many times and expect them to pass
    // the majority of tries.

    #[test]
    #[cfg(ignore)]
    fn test_gl_timer_recv_timeout_before_time_passes() {
        let times = 100;
        let mut successes = 0;
        let mut failures = 0;
        let hl_loop = uv::global_loop::get();

        for iter::repeat(times as uint) {
            task::yield();

            let expected = rand::rng().gen_str(16u);
            let test_po = core::comm::port::<str>();
            let test_ch = core::comm::chan(test_po);

            do task::spawn() {
                delayed_send(hl_loop, 1u, test_ch, expected);
            };

            match recv_timeout(hl_loop, 10u, test_po) {
              some(val) => {
                assert val == expected;
                successes += 1;
              }
              _ => failures += 1
            };
        }

        assert successes > times / 2;
    }

    #[test]
    fn test_gl_timer_recv_timeout_after_time_passes() {
        let times = 100;
        let mut successes = 0;
        let mut failures = 0;
        let hl_loop = uv::global_loop::get();

        for iter::repeat(times as uint) {
            let expected = rand::rng().gen_str(16u);
            let test_po = core::comm::port::<~str>();
            let test_ch = core::comm::chan(test_po);

            do task::spawn() {
                delayed_send(hl_loop, 50u, test_ch, expected);
            };

            match recv_timeout(hl_loop, 1u, test_po) {
              none => successes += 1,
              _ => failures += 1
            };
        }

        assert successes > times / 2;
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use config::text::Reader;

pub struct Nature {
    pub gravity: f32,
    pub density: f32,
    pub scale_general: f32,
    pub movement_detection_threshold: u8,
}

pub struct Impulse {
    pub elastic_restriction: f32,
    pub elastic_time_scale_factor: f32,
    pub rolling_scale: f32,
    pub normal_threshold: f32,
    pub k_wheel: f32,
    pub factors: [f32; 2],
    pub k_friction: f32,
}

pub struct Car {
    pub rudder_step: u16,
    pub rudder_max: u16,
    pub rudder_k_decr: f32,
    pub traction_incr: u16,
    pub traction_decr: u16,
}

pub struct Global {
    pub speed_factor: f32,
    pub mobility_factor: f32,
    pub water_speed_factor: f32,
    pub air_speed_factor: f32,
    pub underground_speed_factor: f32,
    pub k_traction_turbo: f32,
    pub f_brake_max: f32,
}

pub struct Helicopter {
    pub max_height: u16,
    pub height_incr: u16,
    pub height_decr: u16,
    pub k_thrust: f32,
    pub k_rotate: f32,
    pub k_strife: f32,
    pub max_time: u8,
    pub convert: [f32; 2],
    pub rudder_decr: f32,
    pub traction_decr: f32,
    pub z_offset: f32,
    pub ampl: f32,
    pub dphi: u16,
    pub circle_radius: [f32; 2],
    pub circle_dphi: u16,
}

pub struct Drag {
    pub speed_vw: (f32, f32),
    pub wheel_speed: f32,
    pub z: f32,
    pub free_vw: (f32, f32),
    pub wheel_vw: (f32, f32),
    pub spring_vw: (f32, f32),
    pub coll_vw: (f32, f32),
    pub helicopter_vw: (f32, f32),
    pub float_vw: (f32, f32),
    pub friction_vw: (f32, f32),
    pub abs_stop_vw: (f32, f32),
    pub stuff: f32,
    pub swamp: f32,
    pub mole: f32,
    pub abs_min_vw: (f32, f32),
}

pub struct Common {
    pub nature: Nature,
    pub impulse: Impulse,
    pub car: Car,
    pub global: Global,
    pub heli: Helicopter,
    //pub drag: Drag,
}

fn get_pair(reader: &mut Reader<File>, name: &str) -> (f32, f32) {
    let sv = format!("V_{}:", name);
    let sw = format!("W_{}:", name);
    (
        reader.next_key_value(&sv),
        reader.next_key_value(&sw),
    )
}

pub fn load(file: File) -> Common {
    let mut fi = Reader::new(file);
    fi.advance();
    assert_eq!(fi.cur(), "COMMON:\t\t2");
    Common {
        nature: Nature {
            gravity: fi.next_key_value("g:"),
            density: fi.next_key_value("density:"),
            scale_general: {
                fi.advance(); //skip dt0
                fi.next_key_value("scale_general:")
            },
            movement_detection_threshold: {
                fi.advance(); //num_calls_analysis
                let mdt = fi.next_key_value("movement_detection_threshould:");
                fi.advance(); //num_skip_updates
                fi.advance(); //wheel_analyze
                fi.advance(); //analysis_off
                mdt
            },
        },
        impulse: Impulse {
            elastic_restriction: fi.next_key_value("elastic_restriction:"),
            elastic_time_scale_factor: fi.next_key_value("elastic_time_scale_factor:"),
            rolling_scale: fi.next_key_value("rolling_scale:"),
            normal_threshold: fi.next_key_value("normal_threshould:"),
            k_wheel: fi.next_key_value("k_wheel:"),
            factors: [
                fi.next_key_value("horizontal_impulse_factor:"),
                fi.next_key_value("vertical_impulse_factor:"),
            ],
            k_friction: fi.next_key_value("k_friction_impulse:"),
        },
        car: Car {
            rudder_step: fi.next_key_value("rudder_step:"),
            rudder_max: fi.next_key_value("rudder_max:"),
            rudder_k_decr: fi.next_key_value("rudder_k_decr:"),
            traction_incr: fi.next_key_value("traction_increment:"),
            traction_decr: fi.next_key_value("traction_decrement:"),
        },
        global: Global {
            speed_factor: fi.next_key_value("global_speed_factor:"),
            mobility_factor: fi.next_key_value("global_mobility_factor:"),
            water_speed_factor: fi.next_key_value("global_water_speed_factor:"),
            air_speed_factor: fi.next_key_value("global_air_speed_factor:"),
            underground_speed_factor: fi.next_key_value("global_underground_speed_factor:"),
            k_traction_turbo: fi.next_key_value("k_traction_turbo:"),
            f_brake_max: fi.next_key_value("f_brake_max:"),
        },
        heli: Helicopter {
            max_height: fi.next_key_value("max_helicopter_height:"),
            height_incr: fi.next_key_value("helicopter_height_incr:"),
            height_decr: fi.next_key_value("helicopter_height_decr:"),
            k_thrust: fi.next_key_value("k_helicopter_thrust:"),
            k_rotate: fi.next_key_value("k_helicopter_rotate:"),
            k_strife: fi.next_key_value("k_helicopter_strife:"),
            max_time: fi.next_key_value("max_helicopter_time:"),
            convert: [
                fi.next_key_value("heli_x_convert:"),
                fi.next_key_value("heli_y_convert:"),
            ],
            rudder_decr: fi.next_key_value("heli_rudder_decr:"),
            traction_decr: fi.next_key_value("heli_traction_decr:"),
            z_offset: fi.next_key_value("heli_z_offset:"),
            ampl: fi.next_key_value("helicopter_ampl:"),
            dphi: fi.next_key_value("helicopter_dphi:"),
            circle_radius: [
                fi.next_key_value("helicopter_circle_radius_x:"),
                fi.next_key_value("helicopter_circle_radius_y:"),
            ],
            circle_dphi: fi.next_key_value("helicopter_circle_dphi:"),
        },
    }
}
<commit_msg>Common params - drag<commit_after>use std::fs::File;
use config::text::Reader;

pub struct Nature {
    pub gravity: f32,
    pub density: f32,
    pub scale_general: f32,
    pub movement_detection_threshold: u8,
}

pub struct Impulse {
    pub elastic_restriction: f32,
    pub elastic_time_scale_factor: f32,
    pub rolling_scale: f32,
    pub normal_threshold: f32,
    pub k_wheel: f32,
    pub factors: [f32; 2],
    pub k_friction: f32,
}

pub struct Car {
    pub rudder_step: u16,
    pub rudder_max: u16,
    pub rudder_k_decr: f32,
    pub traction_incr: u16,
    pub traction_decr: u16,
}

pub struct Global {
    pub speed_factor: f32,
    pub mobility_factor: f32,
    pub water_speed_factor: f32,
    pub air_speed_factor: f32,
    pub underground_speed_factor: f32,
    pub k_traction_turbo: f32,
    pub f_brake_max: f32,
}

pub struct Helicopter {
    pub max_height: u16,
    pub height_incr: u16,
    pub height_decr: u16,
    pub k_thrust: f32,
    pub k_rotate: f32,
    pub k_strife: f32,
    pub max_time: u8,
    pub convert: [f32; 2],
    pub rudder_decr: f32,
    pub traction_decr: f32,
    pub z_offset: f32,
    pub ampl: f32,
    pub dphi: u16,
    pub circle_radius: [f32; 2],
    pub circle_dphi: u16,
}

pub struct Drag {
    pub speed_vw: (f32, f32),
    pub wheel_speed: f32,
    pub z: f32,
    pub free_vw: (f32, f32),
    pub wheel_vw: (f32, f32),
    pub spring_vw: (f32, f32),
    pub coll_vw: (f32, f32),
    pub helicopter_vw: (f32, f32),
    pub float_vw: (f32, f32),
    pub friction_vw: (f32, f32),
    pub abs_stop_vw: (f32, f32),
    pub stuff: f32,
    pub swamp: f32,
    pub mole: f32,
    pub abs_min_vw: (f32, f32),
}

pub struct Common {
    pub nature: Nature,
    pub impulse: Impulse,
    pub car: Car,
    pub global: Global,
    pub heli: Helicopter,
    pub drag: Drag,
}

fn get_pair(reader: &mut Reader<File>, name: &str) -> (f32, f32) {
    let sv = format!("V_{}:", name);
    let sw = format!("W_{}:", name);
    (
        reader.next_key_value(&sv),
        reader.next_key_value(&sw),
    )
}

pub fn load(file: File) -> Common {
    let mut fi = Reader::new(file);
    fi.advance();
    assert_eq!(fi.cur(), "COMMON:\t\t2");
    Common {
        nature: Nature {
            gravity: fi.next_key_value("g:"),
            density: fi.next_key_value("density:"),
            scale_general: {
                fi.advance(); //skip dt0
                fi.next_key_value("scale_general:")
            },
            movement_detection_threshold: {
                fi.advance(); //num_calls_analysis
                let mdt = fi.next_key_value("movement_detection_threshould:");
                fi.advance(); //num_skip_updates
                fi.advance(); //wheel_analyze
                fi.advance(); //analysis_off
                mdt
            },
        },
        impulse: Impulse {
            elastic_restriction: fi.next_key_value("elastic_restriction:"),
            elastic_time_scale_factor: fi.next_key_value("elastic_time_scale_factor:"),
            rolling_scale: fi.next_key_value("rolling_scale:"),
            normal_threshold: fi.next_key_value("normal_threshould:"),
            k_wheel: fi.next_key_value("k_wheel:"),
            factors: [
                fi.next_key_value("horizontal_impulse_factor:"),
                fi.next_key_value("vertical_impulse_factor:"),
            ],
            k_friction: fi.next_key_value("k_friction_impulse:"),
        },
        car: Car {
            rudder_step: fi.next_key_value("rudder_step:"),
            rudder_max: fi.next_key_value("rudder_max:"),
            rudder_k_decr: fi.next_key_value("rudder_k_decr:"),
            traction_incr: fi.next_key_value("traction_increment:"),
            traction_decr: fi.next_key_value("traction_decrement:"),
        },
        global: Global {
            speed_factor: fi.next_key_value("global_speed_factor:"),
            mobility_factor: fi.next_key_value("global_mobility_factor:"),
            water_speed_factor: fi.next_key_value("global_water_speed_factor:"),
            air_speed_factor: fi.next_key_value("global_air_speed_factor:"),
            underground_speed_factor: fi.next_key_value("global_underground_speed_factor:"),
            k_traction_turbo: fi.next_key_value("k_traction_turbo:"),
            f_brake_max: fi.next_key_value("f_brake_max:"),
        },
        heli: Helicopter {
            max_height: fi.next_key_value("max_helicopter_height:"),
            height_incr: fi.next_key_value("helicopter_height_incr:"),
            height_decr: fi.next_key_value("helicopter_height_decr:"),
            k_thrust: fi.next_key_value("k_helicopter_thrust:"),
            k_rotate: fi.next_key_value("k_helicopter_rotate:"),
            k_strife: fi.next_key_value("k_helicopter_strife:"),
            max_time: fi.next_key_value("max_helicopter_time:"),
            convert: [
                fi.next_key_value("heli_x_convert:"),
                fi.next_key_value("heli_y_convert:"),
            ],
            rudder_decr: fi.next_key_value("heli_rudder_decr:"),
            traction_decr: fi.next_key_value("heli_traction_decr:"),
            z_offset: fi.next_key_value("heli_z_offset:"),
            ampl: fi.next_key_value("helicopter_ampl:"),
            dphi: fi.next_key_value("helicopter_dphi:"),
            circle_radius: [
                fi.next_key_value("helicopter_circle_radius_x:"),
                fi.next_key_value("helicopter_circle_radius_y:"),
            ],
            circle_dphi: fi.next_key_value("helicopter_circle_dphi:"),
        },
        drag: Drag {
            speed_vw: get_pair(&mut fi, "drag_speed"),
            wheel_speed: fi.next_key_value("V_drag_wheel_speed:"),
            z: fi.next_key_value("V_drag_z:"),
            free_vw: get_pair(&mut fi, "drag_free"),
            wheel_vw: get_pair(&mut fi, "drag_wheel"),
            spring_vw: get_pair(&mut fi, "drag_spring"),
            coll_vw: get_pair(&mut fi, "drag_coll"),
            helicopter_vw: get_pair(&mut fi, "drag_helicopter"),
            float_vw: get_pair(&mut fi, "drag_float"),
            friction_vw: get_pair(&mut fi, "drag_friction"),
            abs_stop_vw: get_pair(&mut fi, "abs_stop"),
            stuff: fi.next_key_value("V_drag_stuff:"),
            swamp: fi.next_key_value("V_drag_swamp:"),
            mole: fi.next_key_value("V_drag_mole:"),
            abs_min_vw: get_pair(&mut fi, "abs_min"),
        },
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Anatoly Ikorsky
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use BoxFuture;
use conn::Conn;
use errors::*;
use lib_futures::Async;
use lib_futures::Async::Ready;
use lib_futures::Async::NotReady;
use lib_futures::Future;
use lib_futures::task::{park, Task};
use queryable::Queryable;
use queryable::transaction::{Transaction, TransactionOptions};
use std::fmt;
use opts::Opts;
use self::futures::*;
use std::cell::Ref;
use std::cell::RefCell;
use std::cell::RefMut;
use std::rc::Rc;
use tokio::reactor::Handle;

pub mod futures;

pub struct Inner {
    closed: bool,
    new: Vec<BoxFuture<Conn>>,
    idle: Vec<Conn>,
    disconnecting: Vec<BoxFuture<()>>,
    dropping: Vec<BoxFuture<Conn>>,
    rollback: Vec<BoxFuture<Conn>>,
    tasks: Vec<Task>,
}

#[derive(Clone)]
/// Asynchronous pool of MySql connections.
pub struct Pool {
    handle: Handle,
    opts: Opts,
    inner: Rc<RefCell<Inner>>,
    min: usize,
    max: usize,
}

impl fmt::Debug for Pool {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Pool")
            .field("min", &self.min)
            .field("max", &self.max)
            .field("new connections count", &self.inner_ref().new.len())
            .field("idle connections count", &self.inner_ref().idle.len())
            .field("disconnecting connections count",
                   &self.inner_ref().disconnecting.len())
            .finish()
    }
}

impl Pool {
    /// Creates new pool of connections.
    pub fn new<O: Into<Opts>>(opts: O, handle: &Handle) -> Pool {
        let opts = opts.into();
        let pool_min = opts.get_pool_min();
        let pool_max = opts.get_pool_max();
        let pool = Pool {
            handle: handle.clone(),
            opts: opts,
            inner: Rc::new(RefCell::new(Inner {
                closed: false,
                new: Vec::with_capacity(pool_min),
                idle: Vec::new(),
                disconnecting: Vec::new(),
                dropping: Vec::new(),
                rollback: Vec::new(),
                tasks: Vec::new(),
            })),
            min: pool_min,
            max: pool_max,
        };

        pool
    }

    /// Returns future that resolves to `Conn`.
    pub fn get_conn(&self) -> GetConn {
        new_get_conn(self)
    }

    /// Shortcut for `get_conn` followed by `start_transaction`.
    pub fn start_transaction(&self, options: TransactionOptions) -> BoxFuture<Transaction<Conn>> {
        let fut = self.get_conn()
            .and_then(|conn| {
                Queryable::start_transaction(conn, options)
            });
        Box::new(fut)
    }

    /// Returns future that disconnects this pool from server and resolves to `()`.
    ///
    /// Active connections taken from this pool should be disconnected manually.
    /// Also all pending and new `GetConn`'s will resolve to error.
    pub fn disconnect(mut self) -> DisconnectPool {
        if !self.inner_ref().closed {
            self.inner_mut().closed = true;
            while let Some(conn) = self.take_conn() {
                self.inner_mut().disconnecting.push(conn.disconnect());
            }
        }
        new_disconnect_pool(self)
    }

    /// Returns true if futures is in queue.
    fn in_queue(&self) -> bool {
        let inner = self.inner_ref();
        let count =
            inner.new.len() + inner.disconnecting.len() +
            inner.dropping.len() + inner.rollback.len();
        count > 0
    }

    /// A way to take connection from a pool.
    fn take_conn(&mut self) -> Option<Conn> {
        if self.in_queue() {
            // Do not return connection until queue is empty
            return None;
        }
        while self.inner_ref().idle.len() > 0 {
            let conn = self.inner_mut().idle.pop();
            let conn = conn.and_then(|mut conn| {
                if conn.expired() {
                    self.inner_mut().disconnecting.push(conn.disconnect());
                    None
                } else {
                    conn.pool = Some(self.clone());
                    Some(conn)
                }
            });
            if conn.is_some() {
                return conn;
            }
        }
        None
    }

    /// A way to return connection taken from a pool.
    fn return_conn(&mut self, conn: Conn) {
        if self.inner_ref().closed {
            return;
        }

        if conn.has_result.is_some() {
            self.inner_mut().dropping.push(conn.drop_result());
        } else if conn.in_transaction {
            self.inner_mut().rollback.push(conn.rollback_transaction())
        } else {
            let idle_len = self.inner_ref().idle.len();
            if idle_len >= self.min {
                self.inner_mut().disconnecting.push(conn.disconnect());
            } else {
                self.inner_mut().idle.push(conn);
            }
        }

        while let Some(task) = self.inner_mut().tasks.pop() {
            task.unpark()
        }
    }

    fn inner_ref(&self) -> Ref<Inner> {
        self.inner.borrow()
    }

    fn inner_mut(&mut self) -> RefMut<Inner> {
        self.inner.borrow_mut()
    }

    /// Will manage lifetime of futures stored in a pool.
    fn handle_futures(&mut self) -> Result<()> {
        if !self.in_queue() {
            // There is no futures in queue
            return Ok(());
        }

        macro_rules! handle {
            ($vec:ident { $($p:pat => $b:block,)+ }) => ({
                let len = self.inner_ref().$vec.len();
                let mut done_fut_idxs = Vec::new();
                for i in 0..len {
                    let result = self.inner_mut().$vec.get_mut(i).unwrap().poll();
                    match result {
                        Ok(Ready(_)) | Err(_) => done_fut_idxs.push(i),
                        _ => (),
                    }

                    let out: Result<()> = match result {
                        $($p => $b),+
                        _ => {
                            Ok(())
                        }
                    };

                    match out {
                        Err(err) => {
                            // early return in case of error
                            while let Some(i) = done_fut_idxs.pop() {
                                let _ = self.inner_mut().$vec.swap_remove(i);
                            }
                            return Err(err)
                        }
                        _ => (),
                    }
                }

                while let Some(i) = done_fut_idxs.pop() {
                    let _ = self.inner_mut().$vec.swap_remove(i);
                }
            });
        }

        let mut handled = false;

        // Handle closing connections.
        handle!(disconnecting {
            Ok(Ready(_)) => {
                handled = true;
                Ok(())
            },
            Err(_) => { Ok(()) },
        });

        // Handle dirty connections.
        handle!(dropping {
            Ok(Ready(conn)) => {
                let closed = self.inner_ref().closed;
                if closed {
                    self.inner_mut().disconnecting.push(conn.disconnect());
                } else {
                    self.return_conn(conn);
                }
                handled = true;
                Ok(())
            },
            Err(_) => { Ok(()) },
        });

        // Handle in-transaction connections
        handle!(rollback {
            Ok(Ready(conn)) => {
                let closed = self.inner_ref().closed;
                if closed {
                    self.inner_mut().disconnecting.push(conn.disconnect());
                } else {
                    self.return_conn(conn);
                }
                handled = true;
                Ok(())
            },
            Err(_) => { Ok(()) },
        });

        // Handle connecting connections.
        handle!(new {
            Ok(Ready(conn)) => {
                let closed = self.inner_ref().closed;
                if closed {
                    self.inner_mut().disconnecting.push(conn.disconnect());
                } else {
                    self.return_conn(conn);
                }
                handled = true;
                Ok(())
            },
            Err(err) => {
                if ! self.inner_ref().closed {
                    Err(err)
                } else {
                    Ok(())
                }
            },
        });

        if handled {
            self.handle_futures()
        } else {
            Ok(())
        }
    }

    /// Will poll pool for connection.
    fn poll(&mut self) -> Result<Async<Conn>> {
        if self.inner_ref().closed {
            return Err(ErrorKind::PoolDisconnected.into());
        }

        self.handle_futures()?;

        match self.take_conn() {
            Some(conn) => Ok(Ready(conn)),
            None => {
                let new_len = self.inner_ref().new.len();
                let idle_len = self.inner_ref().idle.len();
                if new_len == 0 && idle_len < self.max {
                    let new_conn = Conn::new(self.opts.clone(), &self.handle);
                    self.inner_mut().new.push(new_conn);
                    self.poll()
                } else {
                    self.inner_mut().tasks.push(park());
                    Ok(NotReady)
                }
            },
        }
    }
}

impl Drop for Conn {
    fn drop(&mut self) {
        if let Some(mut pool) = self.pool.take() {
            let conn = self.take();
            if conn.stream.is_some() {
                pool.return_conn(conn)
            } // drop incomplete connection
        }
    }
}

#[cfg(test)]
mod test {
    use conn::pool::Pool;
    use lib_futures::Future;
    use queryable::Queryable;
    use test_misc::DATABASE_URL;
    use tokio::reactor::Core;

    #[test]
    fn should_connect() {
        let mut lp = Core::new().unwrap();

        let pool = Pool::new(&**DATABASE_URL, &lp.handle());
        let fut = pool.get_conn()
            .and_then(|conn| {
                Queryable::ping(conn).map(|_| ())
            })
            .and_then(|_| pool.disconnect());

        lp.run(fut).unwrap();
    }

    #[test]
    fn should_hold_bounds() {
        let mut lp = Core::new().unwrap();

        let pool = Pool::new(format!("{}?pool_min=1&pool_max=2", &**DATABASE_URL),
                             &lp.handle());
        let pool_clone = pool.clone();
        let fut = pool.get_conn()
            .join(pool.get_conn())
            .and_then(|(mut conn1, conn2)| {
                let new_conn = pool_clone.get_conn();
                conn1.pool.as_mut().unwrap().handle_futures().unwrap();
                assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().new.len(), 0);
                assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().idle.len(), 0);
                assert_eq!(conn2.pool.as_ref().unwrap().inner_ref().disconnecting.len(), 0);
                assert_eq!(conn2.pool.as_ref().unwrap().inner_ref().dropping.len(), 0);
                new_conn
            })
            .and_then(|conn1| {
                assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().new.len(), 0);
                assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().idle.len(), 0);
                assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().disconnecting.len(), 0);
                assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().dropping.len(), 0);
                Ok(())
            })
            .and_then(|_| {
                assert_eq!(pool.inner_ref().new.len(), 0);
                assert_eq!(pool.inner_ref().idle.len(), 1);
                assert_eq!(pool.inner_ref().disconnecting.len(), 0);
                assert_eq!(pool.inner_ref().dropping.len(), 0);
                pool.disconnect()
            });

        lp.run(fut).unwrap();
    }

    #[cfg(feature = "nightly")]
    mod bench {
        use test;
        use conn::pool::Pool;
        use tokio::reactor::Core;
        use lib_futures::Future;
        use test_misc::DATABASE_URL;

        #[bench]
        fn connect(bencher: &mut test::Bencher) {
            let mut lp = Core::new().unwrap();
            let pool = Pool::new(&**DATABASE_URL, &lp.handle());

            bencher.iter(|| {
                let fut = pool.get_conn().and_then(|conn| conn.ping());
                lp.run(fut).unwrap();
            })
        }
    }
}
<commit_msg>Add should_start_transaction test to the Pool<commit_after>// Copyright (c) 2016 Anatoly Ikorsky
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use BoxFuture;
use conn::Conn;
use errors::*;
use lib_futures::Async;
use lib_futures::Async::Ready;
use lib_futures::Async::NotReady;
use lib_futures::Future;
use lib_futures::task::{park, Task};
use queryable::Queryable;
use queryable::transaction::{Transaction, TransactionOptions};
use std::fmt;
use opts::Opts;
use self::futures::*;
use std::cell::Ref;
use std::cell::RefCell;
use std::cell::RefMut;
use std::rc::Rc;
use tokio::reactor::Handle;

pub mod futures;

pub struct Inner {
    closed: bool,
    new: Vec<BoxFuture<Conn>>,
    idle: Vec<Conn>,
    disconnecting: Vec<BoxFuture<()>>,
    dropping: Vec<BoxFuture<Conn>>,
    rollback: Vec<BoxFuture<Conn>>,
    tasks: Vec<Task>,
}

#[derive(Clone)]
/// Asynchronous pool of MySql connections.
pub struct Pool {
    handle: Handle,
    opts: Opts,
    inner: Rc<RefCell<Inner>>,
    min: usize,
    max: usize,
}

impl fmt::Debug for Pool {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Pool")
            .field("min", &self.min)
            .field("max", &self.max)
            .field("new connections count", &self.inner_ref().new.len())
            .field("idle connections count", &self.inner_ref().idle.len())
            .field("disconnecting connections count",
                   &self.inner_ref().disconnecting.len())
            .finish()
    }
}

impl Pool {
    /// Creates new pool of connections.
    pub fn new<O: Into<Opts>>(opts: O, handle: &Handle) -> Pool {
        let opts = opts.into();
        let pool_min = opts.get_pool_min();
        let pool_max = opts.get_pool_max();
        let pool = Pool {
            handle: handle.clone(),
            opts: opts,
            inner: Rc::new(RefCell::new(Inner {
                closed: false,
                new: Vec::with_capacity(pool_min),
                idle: Vec::new(),
                disconnecting: Vec::new(),
                dropping: Vec::new(),
                rollback: Vec::new(),
                tasks: Vec::new(),
            })),
            min: pool_min,
            max: pool_max,
        };

        pool
    }

    /// Returns future that resolves to `Conn`.
    pub fn get_conn(&self) -> GetConn {
        new_get_conn(self)
    }

    /// Shortcut for `get_conn` followed by `start_transaction`.
    pub fn start_transaction(&self, options: TransactionOptions) -> BoxFuture<Transaction<Conn>> {
        let fut = self.get_conn()
            .and_then(|conn| {
                Queryable::start_transaction(conn, options)
            });
        Box::new(fut)
    }

    /// Returns future that disconnects this pool from server and resolves to `()`.
    ///
    /// Active connections taken from this pool should be disconnected manually.
    /// Also all pending and new `GetConn`'s will resolve to error.
    pub fn disconnect(mut self) -> DisconnectPool {
        if !self.inner_ref().closed {
            self.inner_mut().closed = true;
            while let Some(conn) = self.take_conn() {
                self.inner_mut().disconnecting.push(conn.disconnect());
            }
        }
        new_disconnect_pool(self)
    }

    /// Returns true if futures is in queue.
    fn in_queue(&self) -> bool {
        let inner = self.inner_ref();
        let count =
            inner.new.len() + inner.disconnecting.len() +
            inner.dropping.len() + inner.rollback.len();
        count > 0
    }

    /// A way to take connection from a pool.
    fn take_conn(&mut self) -> Option<Conn> {
        if self.in_queue() {
            // Do not return connection until queue is empty
            return None;
        }
        while self.inner_ref().idle.len() > 0 {
            let conn = self.inner_mut().idle.pop();
            let conn = conn.and_then(|mut conn| {
                if conn.expired() {
                    self.inner_mut().disconnecting.push(conn.disconnect());
                    None
                } else {
                    conn.pool = Some(self.clone());
                    Some(conn)
                }
            });
            if conn.is_some() {
                return conn;
            }
        }
        None
    }

    /// A way to return connection taken from a pool.
    fn return_conn(&mut self, conn: Conn) {
        if self.inner_ref().closed {
            return;
        }

        if conn.has_result.is_some() {
            self.inner_mut().dropping.push(conn.drop_result());
        } else if conn.in_transaction {
            self.inner_mut().rollback.push(conn.rollback_transaction())
        } else {
            let idle_len = self.inner_ref().idle.len();
            if idle_len >= self.min {
                self.inner_mut().disconnecting.push(conn.disconnect());
            } else {
                self.inner_mut().idle.push(conn);
            }
        }

        while let Some(task) = self.inner_mut().tasks.pop() {
            task.unpark()
        }
    }

    fn inner_ref(&self) -> Ref<Inner> {
        self.inner.borrow()
    }

    fn inner_mut(&mut self) -> RefMut<Inner> {
        self.inner.borrow_mut()
    }

    /// Will manage lifetime of futures stored in a pool.
    fn handle_futures(&mut self) -> Result<()> {
        if !self.in_queue() {
            // There is no futures in queue
            return Ok(());
        }

        macro_rules! handle {
            ($vec:ident { $($p:pat => $b:block,)+ }) => ({
                let len = self.inner_ref().$vec.len();
                let mut done_fut_idxs = Vec::new();
                for i in 0..len {
                    let result = self.inner_mut().$vec.get_mut(i).unwrap().poll();
                    match result {
                        Ok(Ready(_)) | Err(_) => done_fut_idxs.push(i),
                        _ => (),
                    }

                    let out: Result<()> = match result {
                        $($p => $b),+
                        _ => {
                            Ok(())
                        }
                    };

                    match out {
                        Err(err) => {
                            // early return in case of error
                            while let Some(i) = done_fut_idxs.pop() {
                                let _ = self.inner_mut().$vec.swap_remove(i);
                            }
                            return Err(err)
                        }
                        _ => (),
                    }
                }

                while let Some(i) = done_fut_idxs.pop() {
                    let _ = self.inner_mut().$vec.swap_remove(i);
                }
            });
        }

        let mut handled = false;

        // Handle closing connections.
        handle!(disconnecting {
            Ok(Ready(_)) => {
                handled = true;
                Ok(())
            },
            Err(_) => { Ok(()) },
        });

        // Handle dirty connections.
        handle!(dropping {
            Ok(Ready(conn)) => {
                let closed = self.inner_ref().closed;
                if closed {
                    self.inner_mut().disconnecting.push(conn.disconnect());
                } else {
                    self.return_conn(conn);
                }
                handled = true;
                Ok(())
            },
            Err(_) => { Ok(()) },
        });

        // Handle in-transaction connections
        handle!(rollback {
            Ok(Ready(conn)) => {
                let closed = self.inner_ref().closed;
                if closed {
                    self.inner_mut().disconnecting.push(conn.disconnect());
                } else {
                    self.return_conn(conn);
                }
                handled = true;
                Ok(())
            },
            Err(_) => { Ok(()) },
        });

        // Handle connecting connections.
        handle!(new {
            Ok(Ready(conn)) => {
                let closed = self.inner_ref().closed;
                if closed {
                    self.inner_mut().disconnecting.push(conn.disconnect());
                } else {
                    self.return_conn(conn);
                }
                handled = true;
                Ok(())
            },
            Err(err) => {
                if ! self.inner_ref().closed {
                    Err(err)
                } else {
                    Ok(())
                }
            },
        });

        if handled {
            self.handle_futures()
        } else {
            Ok(())
        }
    }

    /// Will poll pool for connection.
    fn poll(&mut self) -> Result<Async<Conn>> {
        if self.inner_ref().closed {
            return Err(ErrorKind::PoolDisconnected.into());
        }

        self.handle_futures()?;

        match self.take_conn() {
            Some(conn) => Ok(Ready(conn)),
            None => {
                let new_len = self.inner_ref().new.len();
                let idle_len = self.inner_ref().idle.len();
                if new_len == 0 && idle_len < self.max {
                    let new_conn = Conn::new(self.opts.clone(), &self.handle);
                    self.inner_mut().new.push(new_conn);
                    self.poll()
                } else {
                    self.inner_mut().tasks.push(park());
                    Ok(NotReady)
                }
            },
        }
    }
}

impl Drop for Conn {
    fn drop(&mut self) {
        if let Some(mut pool) = self.pool.take() {
            let conn = self.take();
            if conn.stream.is_some() {
                pool.return_conn(conn)
            } // drop incomplete connection
        }
    }
}

#[cfg(test)]
mod test {
    use TransactionOptions;
    use conn::pool::Pool;
    use lib_futures::Future;
    use queryable::Queryable;
    use test_misc::DATABASE_URL;
    use tokio::reactor::Core;

    #[test]
    fn should_connect() {
        let mut lp = Core::new().unwrap();

        let pool = Pool::new(&**DATABASE_URL, &lp.handle());
        let fut = pool.get_conn()
            .and_then(|conn| {
                conn.ping().map(|_| ())
            })
            .and_then(|_| pool.disconnect());

        lp.run(fut).unwrap();
    }

    #[test]
    fn should_start_transaction() {
        let mut lp = Core::new().unwrap();

        let pool = Pool::new(format!("{}?pool_min=1&pool_max=1", &**DATABASE_URL),
                             &lp.handle());
        let fut = pool.start_transaction(TransactionOptions::default())
            .and_then(|transaction| {
                transaction.drop_query("CREATE TEMPORARY TABLE tmp(id int)")
            })
            .and_then(|transaction| {
                transaction.batch_exec("INSERT INTO tmp (id) VALUES (?)", vec![(1,), (2,)])
            })
            .and_then(|transaction| {
                transaction.prep_exec("SELECT * FROM tmp", ())
            })
            .map(|_| ())
            .and_then({let pool = pool.clone(); move |_| pool.get_conn()})
            .and_then(|conn| conn.first("SELECT COUNT(*) FROM tmp"))
            .and_then(|(_, row_opt)| {
                assert_eq!(row_opt, Some((0u8,)));
                pool.disconnect()
            });

        lp.run(fut).unwrap();
    }

    #[test]
    fn should_hold_bounds() {
        let mut lp = Core::new().unwrap();

        let pool = Pool::new(format!("{}?pool_min=1&pool_max=2", &**DATABASE_URL),
                             &lp.handle());
        let pool_clone = pool.clone();
        let fut = pool.get_conn()
            .join(pool.get_conn())
            .and_then(|(mut conn1, conn2)| {
                let new_conn = pool_clone.get_conn();
                conn1.pool.as_mut().unwrap().handle_futures().unwrap();
                assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().new.len(), 0);
                assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().idle.len(), 0);
                assert_eq!(conn2.pool.as_ref().unwrap().inner_ref().disconnecting.len(), 0);
                assert_eq!(conn2.pool.as_ref().unwrap().inner_ref().dropping.len(), 0);
                new_conn
            })
            .and_then(|conn1| {
                assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().new.len(), 0);
                assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().idle.len(), 0);
                assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().disconnecting.len(), 0);
                assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().dropping.len(), 0);
                Ok(())
            })
            .and_then(|_| {
                assert_eq!(pool.inner_ref().new.len(), 0);
                assert_eq!(pool.inner_ref().idle.len(), 1);
                assert_eq!(pool.inner_ref().disconnecting.len(), 0);
                assert_eq!(pool.inner_ref().dropping.len(), 0);
                pool.disconnect()
            });

        lp.run(fut).unwrap();
    }

    #[cfg(feature = "nightly")]
    mod bench {
        use test;
        use conn::pool::Pool;
        use tokio::reactor::Core;
        use lib_futures::Future;
        use test_misc::DATABASE_URL;

        #[bench]
        fn connect(bencher: &mut test::Bencher) {
            let mut lp = Core::new().unwrap();
            let pool = Pool::new(&**DATABASE_URL, &lp.handle());

            bencher.iter(|| {
                let fut = pool.get_conn().and_then(|conn| conn.ping());
                lp.run(fut).unwrap();
            })
        }
    }
}
<|endoftext|>


<commit_before>use learning::Model;
use math::linalg::matrix::Matrix;
use math::linalg::vector::Vector;

pub struct LinRegressor {
	b: Vector<f64>
}

impl Model<Matrix<f64>, Vector<f64>> for LinRegressor {

	fn predict(&self, data: Matrix<f64>) -> Vector<f64> {
		data * b
	}

	fn train(&mut self, data: Matrix<f64>, values: Vector<f64>) {
		let xt = data.transpose();

		self.b = ((&xt * data).inverse() * &xt) * values;
	}
}
<commit_msg>Bug fix.<commit_after>use learning::Model;
use math::linalg::matrix::Matrix;
use math::linalg::vector::Vector;

pub struct LinRegressor {
	pub b: Vector<f64>
}

impl Model<Matrix<f64>, Vector<f64>> for LinRegressor {

	fn predict(&self, data: Matrix<f64>) -> Vector<f64> {
		data * &self.b
	}

	fn train(&mut self, data: Matrix<f64>, values: Vector<f64>) {
		let xt = data.transpose();

		self.b = ((&xt * data).inverse() * &xt) * values;
	}
}
<|endoftext|>