<commit_before>extern crate forth;

use forth::{Error, Forth, Value};

#[test]
fn no_input_no_stack() {
    assert_eq!(Vec::<Value>::new(), Forth::new().stack());
}

#[test]
#[ignore]
fn numbers_just_get_pushed_onto_the_stack() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 3 4 5").is_ok());
    assert_eq!(vec![1, 2, 3, 4, 5], f.stack());
}

#[test]
#[ignore]
fn non_word_characters_are_separators() {
    let mut f = Forth::new();
    assert!(f.eval("1\u{0000}2\u{0001}3\n4\r5 6\t7").is_ok());
    assert_eq!(vec![1, 2, 3, 4, 5, 6, 7], f.stack());
}

#[test]
#[ignore]
fn can_add_two_numbers() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 +").is_ok());
    assert_eq!(vec![3], f.stack());
}

#[test]
#[ignore]
fn addition_error() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::StackUnderflow), f.eval("1 +"));
    assert_eq!(Err(Error::StackUnderflow), f.eval("+"));
}

#[test]
#[ignore]
fn can_subtract_two_numbers() {
    let mut f = Forth::new();
    assert!(f.eval("3 4 -").is_ok());
    assert_eq!(vec![-1], f.stack());
}

#[test]
#[ignore]
fn subtraction_error() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::StackUnderflow), f.eval("1 -"));
    assert_eq!(Err(Error::StackUnderflow), f.eval("-"));
}

#[test]
#[ignore]
fn can_multiply_two_numbers() {
    let mut f = Forth::new();
    assert!(f.eval("2 4 *").is_ok());
    assert_eq!(vec![8], f.stack());
}

#[test]
#[ignore]
fn multiplication_error() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::StackUnderflow), f.eval("1 *"));
    assert_eq!(Err(Error::StackUnderflow), f.eval("*"));
}

#[test]
#[ignore]
fn can_divide_two_numbers() {
    let mut f = Forth::new();
    assert!(f.eval("12 3 /").is_ok());
    assert_eq!(vec![4], f.stack());
}

#[test]
#[ignore]
fn performs_integer_division() {
    let mut f = Forth::new();
    assert!(f.eval("8 3 /").is_ok());
    assert_eq!(vec![2], f.stack());
}

#[test]
#[ignore]
fn division_error() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::StackUnderflow), f.eval("1 /"));
    assert_eq!(Err(Error::StackUnderflow), f.eval("/"));
}

#[test]
#[ignore]
fn errors_if_dividing_by_zero() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::DivisionByZero), f.eval("4 0 /"));
}

#[test]
#[ignore]
fn addition_and_subtraction() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 + 4 -").is_ok());
    assert_eq!(vec![-1], f.stack());
}

#[test]
#[ignore]
fn multiplication_and_division() {
    let mut f = Forth::new();
    assert!(f.eval("2 4 * 3 /").is_ok());
    assert_eq!(vec![2], f.stack());
}

#[test]
#[ignore]
fn dup() {
    let mut f = Forth::new();
    assert!(f.eval("1 DUP").is_ok());
    assert_eq!(vec![1, 1], f.stack());
}

#[test]
#[ignore]
fn dup_case_insensitive() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 Dup").is_ok());
    assert_eq!(vec![1, 2, 2], f.stack());
}

#[test]
#[ignore]
fn dup_error() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::StackUnderflow), f.eval("dup"));
}

#[test]
#[ignore]
fn drop() {
    let mut f = Forth::new();
    assert!(f.eval("1 drop").is_ok());
    assert_eq!(Vec::<Value>::new(), f.stack());
}

#[test]
#[ignore]
fn drop_with_two() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 drop").is_ok());
    assert_eq!(vec![1], f.stack());
}

#[test]
#[ignore]
fn drop_error() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::StackUnderflow), f.eval("drop"));
}

#[test]
#[ignore]
fn swap() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 swap").is_ok());
    assert_eq!(vec![2, 1], f.stack());
}

#[test]
#[ignore]
fn swap_with_three() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 3 swap").is_ok());
    assert_eq!(vec![1, 3, 2], f.stack());
}

#[test]
#[ignore]
fn swap_error() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::StackUnderflow), f.eval("1 swap"));
    assert_eq!(Err(Error::StackUnderflow), f.eval("swap"));
}

#[test]
#[ignore]
fn over() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 over").is_ok());
    assert_eq!(vec![1, 2, 1], f.stack());
}

#[test]
#[ignore]
fn over_with_three() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 3 over").is_ok());
    assert_eq!(vec![1, 2, 3, 2], f.stack());
}

#[test]
#[ignore]
fn over_error() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::StackUnderflow), f.eval("1 over"));
    assert_eq!(Err(Error::StackUnderflow), f.eval("over"));
}

#[test]
#[ignore]
fn defining_a_new_word() {
    let mut f = Forth::new();
    assert!(f.eval(": CoUnT 1 2 3 ;").is_ok());
    assert!(f.eval("count COUNT").is_ok());
    assert_eq!(vec![1, 2, 3, 1, 2, 3], f.stack());
}

#[test]
#[ignore]
fn redefining_an_existing_word() {
    let mut f = Forth::new();
    assert!(f.eval(": foo dup ;").is_ok());
    assert!(f.eval(": foo dup dup ;").is_ok());
    assert!(f.eval("1 foo").is_ok());
    assert_eq!(vec![1, 1, 1], f.stack());
}

#[test]
#[ignore]
fn redefining_an_existing_built_in_word() {
    let mut f = Forth::new();
    assert!(f.eval(": swap dup ;").is_ok());
    assert!(f.eval("1 swap").is_ok());
    assert_eq!(vec![1, 1], f.stack());
}

#[test]
#[ignore]
fn defining_words_with_odd_characters() {
    let mut f = Forth::new();
    assert!(f.eval(": € 220371 ; €").is_ok());
    assert_eq!(vec![220371], f.stack());
}

#[test]
#[ignore]
fn defining_a_number() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::InvalidWord), f.eval(": 1 2 ;"));
}

#[test]
#[ignore]
fn malformed_word_definition() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::InvalidWord), f.eval(":"));
    assert_eq!(Err(Error::InvalidWord), f.eval(": foo"));
    assert_eq!(Err(Error::InvalidWord), f.eval(": foo 1"));
}

#[test]
#[ignore]
fn calling_non_existing_word() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::UnknownWord), f.eval("1 foo"));
}
<commit_msg>forth: test user-defined words with built-ins<commit_after>extern crate forth;

use forth::{Error, Forth, Value};

#[test]
fn no_input_no_stack() {
    assert_eq!(Vec::<Value>::new(), Forth::new().stack());
}

#[test]
#[ignore]
fn numbers_just_get_pushed_onto_the_stack() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 3 4 5").is_ok());
    assert_eq!(vec![1, 2, 3, 4, 5], f.stack());
}

#[test]
#[ignore]
fn non_word_characters_are_separators() {
    let mut f = Forth::new();
    assert!(f.eval("1\u{0000}2\u{0001}3\n4\r5 6\t7").is_ok());
    assert_eq!(vec![1, 2, 3, 4, 5, 6, 7], f.stack());
}

#[test]
#[ignore]
fn can_add_two_numbers() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 +").is_ok());
    assert_eq!(vec![3], f.stack());
}

#[test]
#[ignore]
fn addition_error() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::StackUnderflow), f.eval("1 +"));
    assert_eq!(Err(Error::StackUnderflow), f.eval("+"));
}

#[test]
#[ignore]
fn can_subtract_two_numbers() {
    let mut f = Forth::new();
    assert!(f.eval("3 4 -").is_ok());
    assert_eq!(vec![-1], f.stack());
}

#[test]
#[ignore]
fn subtraction_error() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::StackUnderflow), f.eval("1 -"));
    assert_eq!(Err(Error::StackUnderflow), f.eval("-"));
}

#[test]
#[ignore]
fn can_multiply_two_numbers() {
    let mut f = Forth::new();
    assert!(f.eval("2 4 *").is_ok());
    assert_eq!(vec![8], f.stack());
}

#[test]
#[ignore]
fn multiplication_error() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::StackUnderflow), f.eval("1 *"));
    assert_eq!(Err(Error::StackUnderflow), f.eval("*"));
}

#[test]
#[ignore]
fn can_divide_two_numbers() {
    let mut f = Forth::new();
    assert!(f.eval("12 3 /").is_ok());
    assert_eq!(vec![4], f.stack());
}

#[test]
#[ignore]
fn performs_integer_division() {
    let mut f = Forth::new();
    assert!(f.eval("8 3 /").is_ok());
    assert_eq!(vec![2], f.stack());
}

#[test]
#[ignore]
fn division_error() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::StackUnderflow), f.eval("1 /"));
    assert_eq!(Err(Error::StackUnderflow), f.eval("/"));
}

#[test]
#[ignore]
fn errors_if_dividing_by_zero() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::DivisionByZero), f.eval("4 0 /"));
}

#[test]
#[ignore]
fn addition_and_subtraction() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 + 4 -").is_ok());
    assert_eq!(vec![-1], f.stack());
}

#[test]
#[ignore]
fn multiplication_and_division() {
    let mut f = Forth::new();
    assert!(f.eval("2 4 * 3 /").is_ok());
    assert_eq!(vec![2], f.stack());
}

#[test]
#[ignore]
fn dup() {
    let mut f = Forth::new();
    assert!(f.eval("1 DUP").is_ok());
    assert_eq!(vec![1, 1], f.stack());
}

#[test]
#[ignore]
fn dup_case_insensitive() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 Dup").is_ok());
    assert_eq!(vec![1, 2, 2], f.stack());
}

#[test]
#[ignore]
fn dup_error() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::StackUnderflow), f.eval("dup"));
}

#[test]
#[ignore]
fn drop() {
    let mut f = Forth::new();
    assert!(f.eval("1 drop").is_ok());
    assert_eq!(Vec::<Value>::new(), f.stack());
}

#[test]
#[ignore]
fn drop_with_two() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 drop").is_ok());
    assert_eq!(vec![1], f.stack());
}

#[test]
#[ignore]
fn drop_error() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::StackUnderflow), f.eval("drop"));
}

#[test]
#[ignore]
fn swap() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 swap").is_ok());
    assert_eq!(vec![2, 1], f.stack());
}

#[test]
#[ignore]
fn swap_with_three() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 3 swap").is_ok());
    assert_eq!(vec![1, 3, 2], f.stack());
}

#[test]
#[ignore]
fn swap_error() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::StackUnderflow), f.eval("1 swap"));
    assert_eq!(Err(Error::StackUnderflow), f.eval("swap"));
}

#[test]
#[ignore]
fn over() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 over").is_ok());
    assert_eq!(vec![1, 2, 1], f.stack());
}

#[test]
#[ignore]
fn over_with_three() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 3 over").is_ok());
    assert_eq!(vec![1, 2, 3, 2], f.stack());
}

#[test]
#[ignore]
fn over_error() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::StackUnderflow), f.eval("1 over"));
    assert_eq!(Err(Error::StackUnderflow), f.eval("over"));
}

// User-defined words

#[test]
#[ignore]
fn can_consist_of_built_in_words() {
    let mut f = Forth::new();
    assert!(f.eval(": dup-twice dup dup ;").is_ok());
    assert!(f.eval("1 dup-twice").is_ok());
    assert_eq!(vec![1, 1, 1], f.stack());
}

#[test]
#[ignore]
fn definitions_are_case_insensitive() {
    let mut f = Forth::new();
    assert!(f.eval(": CoUnT 1 2 3 ;").is_ok());
    assert!(f.eval("count COUNT").is_ok());
    assert_eq!(vec![1, 2, 3, 1, 2, 3], f.stack());
}

#[test]
#[ignore]
fn redefining_an_existing_word() {
    let mut f = Forth::new();
    assert!(f.eval(": foo dup ;").is_ok());
    assert!(f.eval(": foo dup dup ;").is_ok());
    assert!(f.eval("1 foo").is_ok());
    assert_eq!(vec![1, 1, 1], f.stack());
}

#[test]
#[ignore]
fn redefining_an_existing_built_in_word() {
    let mut f = Forth::new();
    assert!(f.eval(": swap dup ;").is_ok());
    assert!(f.eval("1 swap").is_ok());
    assert_eq!(vec![1, 1], f.stack());
}

#[test]
#[ignore]
fn defining_words_with_odd_characters() {
    let mut f = Forth::new();
    assert!(f.eval(": € 220371 ; €").is_ok());
    assert_eq!(vec![220371], f.stack());
}

#[test]
#[ignore]
fn defining_a_number() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::InvalidWord), f.eval(": 1 2 ;"));
}

#[test]
#[ignore]
fn malformed_word_definition() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::InvalidWord), f.eval(":"));
    assert_eq!(Err(Error::InvalidWord), f.eval(": foo"));
    assert_eq!(Err(Error::InvalidWord), f.eval(": foo 1"));
}

#[test]
#[ignore]
fn calling_non_existing_word() {
    let mut f = Forth::new();
    assert_eq!(Err(Error::UnknownWord), f.eval("1 foo"));
}
<|endoftext|>


<commit_before>extern crate cairo;

#[derive(Debug)]
#[derive(PartialEq)]
pub enum Segment {
    Degenerate {            // A single lone point
        x: f64,
        y: f64
    },

    LineOrCurve {
        x1: f64, y1: f64,
        x2: f64, y2: f64,
        x3: f64, y3: f64,
        x4: f64, y4: f64
    },
}

enum SegmentState {
    Start,
    End
}

/* This converts a cairo_path_t into a list of curveto-like segments.  Each segment can be:
 *
 * 1. Segment::Degenerate => the segment is actually a single point (x, y)
 *
 * 2. Segment::LineOrCurve => either a lineto or a curveto (or the effective lineto that results from a closepath).
 *    We have the following points:
 *       P1 = (x1, y1)
 *       P2 = (x2, y2)
 *       P3 = (x3, y3)
 *       P4 = (x4, y4)
 *
 *    The start and end points are P1 and P4, respectively.
 *    The tangent at the start point is given by the vector (P2 - P1).
 *    The tangent at the end point is given by the vector (P4 - P3).
 *    The tangents also work if the segment refers to a lineto (they will both just point in the same direction).
 */

const EPSILON: f64 = 1e-10;

fn double_equals (a: f64, b: f64) -> bool {
    (a - b).abs () < EPSILON
}

pub fn path_to_segments (path: cairo::Path) -> Vec<Segment> {
    let mut last_x: f64;
    let mut last_y: f64;
    let mut cur_x: f64;
    let mut cur_y: f64;
    let mut subpath_start_x: f64;
    let mut subpath_start_y: f64;
    let mut segments: Vec<Segment>;
    let mut state: SegmentState;

    cur_x = 0.0;
    cur_y = 0.0;
    subpath_start_x = 0.0;
    subpath_start_y = 0.0;

    segments = Vec::new ();
    state = SegmentState::End;

    for cairo_segment in path.iter () {
        last_x = cur_x;
        last_y = cur_y;

        let needs_new_segment: bool;
        let seg: Segment;

        match cairo_segment {
            cairo::PathSegment::MoveTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                seg = Segment::Degenerate {
                    x: cur_x,
                    y: cur_y
                };
                needs_new_segment = true;

                subpath_start_x = cur_x;
                subpath_start_y = cur_y;

                state = SegmentState::Start;
            },

            cairo::PathSegment::LineTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                seg = Segment::LineOrCurve {
                    x1: last_x,
                    y1: last_y,

                    x2: cur_x,
                    y2: cur_y,

                    x3: last_x,
                    y3: last_y,

                    x4: cur_x,
                    y4: cur_y,
                };

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = true;
                    }
                }
            },

            cairo::PathSegment::CurveTo ((mut x2, mut y2), (mut x3, mut y3), (x4, y4)) => {
                cur_x = x4;
                cur_y = y4;

                /* Fix the tangents for when the middle control points coincide with their respective endpoints */

                let x1 = last_x;
                let y1 = last_y;

                if double_equals (x2, x1) && double_equals (y2, y1) {
                    x2 = x3;
                    y2 = y3;
                }

                if double_equals (x3, x4) && double_equals (y3, y4) {
                    x3 = x2;
                    y3 = y2;
                }

                seg = Segment::LineOrCurve {
                    x1: x1,
                    y1: y1,

                    x2: x2,
                    y2: y2,

                    x3: x3,
                    y3: y3,

                    x4: x4,
                    y4: y4,
                };

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = true;
                    }
                }
            }

            cairo::PathSegment::ClosePath => {
                cur_x = subpath_start_x;
                cur_y = subpath_start_y;

                seg = Segment::LineOrCurve {
                    x1: last_x,
                    y1: last_y,

                    x2: cur_x,
                    y2: cur_y,

                    x3: last_x,
                    y3: last_y,

                    x4: cur_x,
                    y4: cur_y,
                };

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = false;
                        /* nothing; closepath after moveto (or a single lone closepath) does nothing */
                    }
                }
            }
        }

        if needs_new_segment {
            segments.push (seg);
        } else {
            let len = segments.len ();
            segments[len - 1] = seg;
        }
    }

    segments
}

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

    fn setup_open_path () -> cairo::Path {
        let surf = cairo::ImageSurface::create (cairo::Format::Rgb24, 1, 1);
        let cr = cairo::Context::new (&surf);

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);

        let path = cr.copy_path ();
        path
    }

    #[test]
    fn path_to_segments_handles_open_path () {
        let expected_segments: Vec<Segment> = vec![
            Segment::LineOrCurve { x1: 10.0, y1: 10.0, x2: 20.0, y2: 10.0, x3: 10.0, y3: 10.0, x4: 20.0, y4: 10.0 },
            Segment::LineOrCurve { x1: 20.0, y1: 10.0, x2: 20.0, y2: 20.0, x3: 20.0, y3: 10.0, x4: 20.0, y4: 20.0 }
        ];

        let path = setup_open_path ();
        let segments = path_to_segments (path);

        assert_eq! (expected_segments, segments);
    }
}
<commit_msg>marker.rs: In tests, factor out creation of helper cairo::Context<commit_after>extern crate cairo;

#[derive(Debug)]
#[derive(PartialEq)]
pub enum Segment {
    Degenerate {            // A single lone point
        x: f64,
        y: f64
    },

    LineOrCurve {
        x1: f64, y1: f64,
        x2: f64, y2: f64,
        x3: f64, y3: f64,
        x4: f64, y4: f64
    },
}

enum SegmentState {
    Start,
    End
}

/* This converts a cairo_path_t into a list of curveto-like segments.  Each segment can be:
 *
 * 1. Segment::Degenerate => the segment is actually a single point (x, y)
 *
 * 2. Segment::LineOrCurve => either a lineto or a curveto (or the effective lineto that results from a closepath).
 *    We have the following points:
 *       P1 = (x1, y1)
 *       P2 = (x2, y2)
 *       P3 = (x3, y3)
 *       P4 = (x4, y4)
 *
 *    The start and end points are P1 and P4, respectively.
 *    The tangent at the start point is given by the vector (P2 - P1).
 *    The tangent at the end point is given by the vector (P4 - P3).
 *    The tangents also work if the segment refers to a lineto (they will both just point in the same direction).
 */

const EPSILON: f64 = 1e-10;

fn double_equals (a: f64, b: f64) -> bool {
    (a - b).abs () < EPSILON
}

pub fn path_to_segments (path: cairo::Path) -> Vec<Segment> {
    let mut last_x: f64;
    let mut last_y: f64;
    let mut cur_x: f64;
    let mut cur_y: f64;
    let mut subpath_start_x: f64;
    let mut subpath_start_y: f64;
    let mut segments: Vec<Segment>;
    let mut state: SegmentState;

    cur_x = 0.0;
    cur_y = 0.0;
    subpath_start_x = 0.0;
    subpath_start_y = 0.0;

    segments = Vec::new ();
    state = SegmentState::End;

    for cairo_segment in path.iter () {
        last_x = cur_x;
        last_y = cur_y;

        let needs_new_segment: bool;
        let seg: Segment;

        match cairo_segment {
            cairo::PathSegment::MoveTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                seg = Segment::Degenerate {
                    x: cur_x,
                    y: cur_y
                };
                needs_new_segment = true;

                subpath_start_x = cur_x;
                subpath_start_y = cur_y;

                state = SegmentState::Start;
            },

            cairo::PathSegment::LineTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                seg = Segment::LineOrCurve {
                    x1: last_x,
                    y1: last_y,

                    x2: cur_x,
                    y2: cur_y,

                    x3: last_x,
                    y3: last_y,

                    x4: cur_x,
                    y4: cur_y,
                };

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = true;
                    }
                }
            },

            cairo::PathSegment::CurveTo ((mut x2, mut y2), (mut x3, mut y3), (x4, y4)) => {
                cur_x = x4;
                cur_y = y4;

                /* Fix the tangents for when the middle control points coincide with their respective endpoints */

                let x1 = last_x;
                let y1 = last_y;

                if double_equals (x2, x1) && double_equals (y2, y1) {
                    x2 = x3;
                    y2 = y3;
                }

                if double_equals (x3, x4) && double_equals (y3, y4) {
                    x3 = x2;
                    y3 = y2;
                }

                seg = Segment::LineOrCurve {
                    x1: x1,
                    y1: y1,

                    x2: x2,
                    y2: y2,

                    x3: x3,
                    y3: y3,

                    x4: x4,
                    y4: y4,
                };

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = true;
                    }
                }
            }

            cairo::PathSegment::ClosePath => {
                cur_x = subpath_start_x;
                cur_y = subpath_start_y;

                seg = Segment::LineOrCurve {
                    x1: last_x,
                    y1: last_y,

                    x2: cur_x,
                    y2: cur_y,

                    x3: last_x,
                    y3: last_y,

                    x4: cur_x,
                    y4: cur_y,
                };

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = false;
                        /* nothing; closepath after moveto (or a single lone closepath) does nothing */
                    }
                }
            }
        }

        if needs_new_segment {
            segments.push (seg);
        } else {
            let len = segments.len ();
            segments[len - 1] = seg;
        }
    }

    segments
}

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

    fn create_cr () -> cairo::Context {
        let surf = cairo::ImageSurface::create (cairo::Format::Rgb24, 1, 1);
        let cr = cairo::Context::new (&surf);

        cr
    }

    fn setup_open_path () -> cairo::Path {
        let cr = create_cr ();

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);

        let path = cr.copy_path ();
        path
    }

    #[test]
    fn path_to_segments_handles_open_path () {
        let expected_segments: Vec<Segment> = vec![
            Segment::LineOrCurve { x1: 10.0, y1: 10.0, x2: 20.0, y2: 10.0, x3: 10.0, y3: 10.0, x4: 20.0, y4: 10.0 },
            Segment::LineOrCurve { x1: 20.0, y1: 10.0, x2: 20.0, y2: 20.0, x3: 20.0, y3: 10.0, x4: 20.0, y4: 20.0 }
        ];

        let path = setup_open_path ();
        let segments = path_to_segments (path);

        assert_eq! (expected_segments, segments);
    }
}
<|endoftext|>


<commit_before>//! Visitor for a run-time value with a given layout: Traverse enums, structs and other compound
//! types until we arrive at the leaves, with custom handling for primitive types.

use rustc::ty::layout::{self, TyLayout};
use rustc::ty;
use rustc::mir::interpret::{
    EvalResult,
};

use super::{
    Machine, EvalContext, MPlaceTy, OpTy, ImmTy,
};

// A thing that we can project into, and that has a layout.
// This wouldn't have to depend on `Machine` but with the current type inference,
// that's just more convenient to work with (avoids repeating all the `Machine` bounds).
pub trait Value<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: Copy
{
    /// Get this value's layout.
    fn layout(&self) -> TyLayout<'tcx>;

    /// Make this into an `OpTy`.
    fn to_op(
        self,
        ecx: &EvalContext<'a, 'mir, 'tcx, M>,
    ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>>;

    /// Create this from an `MPlaceTy`.
    fn from_mem_place(MPlaceTy<'tcx, M::PointerTag>) -> Self;

    /// Project to the given enum variant.
    fn project_downcast(
        self,
        ecx: &EvalContext<'a, 'mir, 'tcx, M>,
        variant: usize,
    ) -> EvalResult<'tcx, Self>;

    /// Project to the n-th field.
    fn project_field(
        self,
        ecx: &EvalContext<'a, 'mir, 'tcx, M>,
        field: u64,
    ) -> EvalResult<'tcx, Self>;
}

// Operands and memory-places are both values.
// Places in general are not due to `place_field` having to do `force_allocation`.
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
    for OpTy<'tcx, M::PointerTag>
{
    #[inline(always)]
    fn layout(&self) -> TyLayout<'tcx> {
        self.layout
    }

    #[inline(always)]
    fn to_op(
        self,
        _ecx: &EvalContext<'a, 'mir, 'tcx, M>,
    ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
        Ok(self)
    }

    #[inline(always)]
    fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self {
        mplace.into()
    }

    #[inline(always)]
    fn project_downcast(
        self,
        ecx: &EvalContext<'a, 'mir, 'tcx, M>,
        variant: usize,
    ) -> EvalResult<'tcx, Self> {
        ecx.operand_downcast(self, variant)
    }

    #[inline(always)]
    fn project_field(
        self,
        ecx: &EvalContext<'a, 'mir, 'tcx, M>,
        field: u64,
    ) -> EvalResult<'tcx, Self> {
        ecx.operand_field(self, field)
    }
}
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
    for MPlaceTy<'tcx, M::PointerTag>
{
    #[inline(always)]
    fn layout(&self) -> TyLayout<'tcx> {
        self.layout
    }

    #[inline(always)]
    fn to_op(
        self,
        _ecx: &EvalContext<'a, 'mir, 'tcx, M>,
    ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
        Ok(self.into())
    }

    #[inline(always)]
    fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self {
        mplace
    }

    #[inline(always)]
    fn project_downcast(
        self,
        ecx: &EvalContext<'a, 'mir, 'tcx, M>,
        variant: usize,
    ) -> EvalResult<'tcx, Self> {
        ecx.mplace_downcast(self, variant)
    }

    #[inline(always)]
    fn project_field(
        self,
        ecx: &EvalContext<'a, 'mir, 'tcx, M>,
        field: u64,
    ) -> EvalResult<'tcx, Self> {
        ecx.mplace_field(self, field)
    }
}

macro_rules! make_value_visitor {
    ($visitor_trait_name:ident, $($mutability:ident)*) => {
        // How to traverse a value and what to do when we are at the leaves.
        pub trait $visitor_trait_name<'a, 'mir, 'tcx: 'mir+'a, M: Machine<'a, 'mir, 'tcx>>: Sized {
            type V: Value<'a, 'mir, 'tcx, M>;

            /// The visitor must have an `EvalContext` in it.
            fn ecx(&$($mutability)* self)
                -> &$($mutability)* EvalContext<'a, 'mir, 'tcx, M>;

            // Recursive actions, ready to be overloaded.
            /// Visit the given value, dispatching as appropriate to more specialized visitors.
            #[inline(always)]
            fn visit_value(&mut self, v: Self::V) -> EvalResult<'tcx>
            {
                self.walk_value(v)
            }
            /// Visit the given value as a union.  No automatic recursion can happen here.
            #[inline(always)]
            fn visit_union(&mut self, _v: Self::V) -> EvalResult<'tcx>
            {
                Ok(())
            }
            /// Visit this vale as an aggregate, you are even getting an iterator yielding
            /// all the fields (still in an `EvalResult`, you have to do error handling yourself).
            /// Recurses into the fields.
            #[inline(always)]
            fn visit_aggregate(
                &mut self,
                v: Self::V,
                fields: impl Iterator<Item=EvalResult<'tcx, Self::V>>,
            ) -> EvalResult<'tcx> {
                self.walk_aggregate(v, fields)
            }
            /// Called each time we recurse down to a field, passing in old and new value.
            /// This gives the visitor the chance to track the stack of nested fields that
            /// we are descending through.
            #[inline(always)]
            fn visit_field(
                &mut self,
                _old_val: Self::V,
                _field: usize,
                new_val: Self::V,
            ) -> EvalResult<'tcx> {
                self.visit_value(new_val)
            }

            /// Called whenever we reach a value with uninhabited layout.
            /// Recursing to fields will *always* continue after this!  This is not meant to control
            /// whether and how we descend recursively/ into the scalar's fields if there are any,
            /// it is meant to provide the chance for additional checks when a value of uninhabited
            /// layout is detected.
            #[inline(always)]
            fn visit_uninhabited(&mut self) -> EvalResult<'tcx>
            { Ok(()) }
            /// Called whenever we reach a value with scalar layout.
            /// We do NOT provide a `ScalarMaybeUndef` here to avoid accessing memory if the
            /// visitor is not even interested in scalars.
            /// Recursing to fields will *always* continue after this!  This is not meant to control
            /// whether and how we descend recursively/ into the scalar's fields if there are any,
            /// it is meant to provide the chance for additional checks when a value of scalar
            /// layout is detected.
            #[inline(always)]
            fn visit_scalar(&mut self, _v: Self::V, _layout: &layout::Scalar) -> EvalResult<'tcx>
            { Ok(()) }

            /// Called whenever we reach a value of primitive type.  There can be no recursion
            /// below such a value.  This is the leave function.
            #[inline(always)]
            fn visit_primitive(&mut self, _val: ImmTy<'tcx, M::PointerTag>) -> EvalResult<'tcx>
            { Ok(()) }

            // Default recursors. Not meant to be overloaded.
            fn walk_aggregate(
                &mut self,
                v: Self::V,
                fields: impl Iterator<Item=EvalResult<'tcx, Self::V>>,
            ) -> EvalResult<'tcx> {
                // Now iterate over it.
                for (idx, field_val) in fields.enumerate() {
                    self.visit_field(v, idx, field_val?)?;
                }
                Ok(())
            }
            fn walk_value(&mut self, v: Self::V) -> EvalResult<'tcx>
            {
                // If this is a multi-variant layout, we have find the right one and proceed with
                // that.
                match v.layout().variants {
                    layout::Variants::NicheFilling { .. } |
                    layout::Variants::Tagged { .. } => {
                        let op = v.to_op(self.ecx())?;
                        let idx = self.ecx().read_discriminant(op)?.1;
                        let inner = v.project_downcast(self.ecx(), idx)?;
                        trace!("walk_value: variant layout: {:#?}", inner.layout());
                        // recurse with the inner type
                        return self.visit_field(v, idx, inner);
                    }
                    layout::Variants::Single { .. } => {}
                }

                // Even for single variants, we might be able to get a more refined type:
                // If it is a trait object, switch to the actual type that was used to create it.
                match v.layout().ty.sty {
                    ty::Dynamic(..) => {
                        // immediate trait objects are not a thing
                        let dest = v.to_op(self.ecx())?.to_mem_place();
                        let inner = self.ecx().unpack_dyn_trait(dest)?.1;
                        trace!("walk_value: dyn object layout: {:#?}", inner.layout);
                        // recurse with the inner type
                        return self.visit_field(v, 0, Value::from_mem_place(inner));
                    },
                    _ => {},
                };

                // If this is a scalar, visit it as such.
                // Things can be aggregates and have scalar layout at the same time, and that
                // is very relevant for `NonNull` and similar structs: We need to visit them
                // at their scalar layout *before* descending into their fields.
                // FIXME: We could avoid some redundant checks here. For newtypes wrapping
                // scalars, we do the same check on every "level" (e.g. first we check
                // MyNewtype and then the scalar in there).
                match v.layout().abi {
                    layout::Abi::Uninhabited => {
                        self.visit_uninhabited()?;
                    }
                    layout::Abi::Scalar(ref layout) => {
                        self.visit_scalar(v, layout)?;
                    }
                    // FIXME: Should we do something for ScalarPair? Vector?
                    _ => {}
                }

                // Check primitive types.  We do this after checking the scalar layout,
                // just to have that done as well.  Primitives can have varying layout,
                // so we check them separately and before aggregate handling.
                // It is CRITICAL that we get this check right, or we might be
                // validating the wrong thing!
                let primitive = match v.layout().fields {
                    // Primitives appear as Union with 0 fields - except for Boxes and fat pointers.
                    layout::FieldPlacement::Union(0) => true,
                    _ => v.layout().ty.builtin_deref(true).is_some(),
                };
                if primitive {
                    let op = v.to_op(self.ecx())?;
                    let val = self.ecx().read_immediate(op)?;
                    return self.visit_primitive(val);
                }

                // Proceed into the fields.
                match v.layout().fields {
                    layout::FieldPlacement::Union(fields) => {
                        // Empty unions are not accepted by rustc. That's great, it means we can
                        // use that as an unambiguous signal for detecting primitives.  Make sure
                        // we did not miss any primitive.
                        debug_assert!(fields > 0);
                        self.visit_union(v)?;
                    },
                    layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
                        // FIXME: We collect in a vec because otherwise there are lifetime errors:
                        // Projecting to a field needs (mutable!) access to `ecx`.
                        let fields: Vec<EvalResult<'tcx, Self::V>> =
                            (0..offsets.len()).map(|i| {
                                v.project_field(self.ecx(), i as u64)
                            })
                            .collect();
                        self.visit_aggregate(v, fields.into_iter())?;
                    },
                    layout::FieldPlacement::Array { .. } => {
                        // Let's get an mplace first.
                        let mplace = if v.layout().is_zst() {
                            // it's a ZST, the memory content cannot matter
                            MPlaceTy::dangling(v.layout(), self.ecx())
                        } else {
                            // non-ZST array/slice/str cannot be immediate
                            v.to_op(self.ecx())?.to_mem_place()
                        };
                        // Now we can go over all the fields.
                        let iter = self.ecx().mplace_array_fields(mplace)?
                            .map(|f| f.and_then(|f| {
                                Ok(Value::from_mem_place(f))
                            }));
                        self.visit_aggregate(v, iter)?;
                    }
                }
                Ok(())
            }
        }
    }
}

make_value_visitor!(ValueVisitor,);
make_value_visitor!(MutValueVisitor,mut);
<commit_msg>walk_value: more tracing<commit_after>//! Visitor for a run-time value with a given layout: Traverse enums, structs and other compound
//! types until we arrive at the leaves, with custom handling for primitive types.

use rustc::ty::layout::{self, TyLayout};
use rustc::ty;
use rustc::mir::interpret::{
    EvalResult,
};

use super::{
    Machine, EvalContext, MPlaceTy, OpTy, ImmTy,
};

// A thing that we can project into, and that has a layout.
// This wouldn't have to depend on `Machine` but with the current type inference,
// that's just more convenient to work with (avoids repeating all the `Machine` bounds).
pub trait Value<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: Copy
{
    /// Get this value's layout.
    fn layout(&self) -> TyLayout<'tcx>;

    /// Make this into an `OpTy`.
    fn to_op(
        self,
        ecx: &EvalContext<'a, 'mir, 'tcx, M>,
    ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>>;

    /// Create this from an `MPlaceTy`.
    fn from_mem_place(MPlaceTy<'tcx, M::PointerTag>) -> Self;

    /// Project to the given enum variant.
    fn project_downcast(
        self,
        ecx: &EvalContext<'a, 'mir, 'tcx, M>,
        variant: usize,
    ) -> EvalResult<'tcx, Self>;

    /// Project to the n-th field.
    fn project_field(
        self,
        ecx: &EvalContext<'a, 'mir, 'tcx, M>,
        field: u64,
    ) -> EvalResult<'tcx, Self>;
}

// Operands and memory-places are both values.
// Places in general are not due to `place_field` having to do `force_allocation`.
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
    for OpTy<'tcx, M::PointerTag>
{
    #[inline(always)]
    fn layout(&self) -> TyLayout<'tcx> {
        self.layout
    }

    #[inline(always)]
    fn to_op(
        self,
        _ecx: &EvalContext<'a, 'mir, 'tcx, M>,
    ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
        Ok(self)
    }

    #[inline(always)]
    fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self {
        mplace.into()
    }

    #[inline(always)]
    fn project_downcast(
        self,
        ecx: &EvalContext<'a, 'mir, 'tcx, M>,
        variant: usize,
    ) -> EvalResult<'tcx, Self> {
        ecx.operand_downcast(self, variant)
    }

    #[inline(always)]
    fn project_field(
        self,
        ecx: &EvalContext<'a, 'mir, 'tcx, M>,
        field: u64,
    ) -> EvalResult<'tcx, Self> {
        ecx.operand_field(self, field)
    }
}
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
    for MPlaceTy<'tcx, M::PointerTag>
{
    #[inline(always)]
    fn layout(&self) -> TyLayout<'tcx> {
        self.layout
    }

    #[inline(always)]
    fn to_op(
        self,
        _ecx: &EvalContext<'a, 'mir, 'tcx, M>,
    ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
        Ok(self.into())
    }

    #[inline(always)]
    fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self {
        mplace
    }

    #[inline(always)]
    fn project_downcast(
        self,
        ecx: &EvalContext<'a, 'mir, 'tcx, M>,
        variant: usize,
    ) -> EvalResult<'tcx, Self> {
        ecx.mplace_downcast(self, variant)
    }

    #[inline(always)]
    fn project_field(
        self,
        ecx: &EvalContext<'a, 'mir, 'tcx, M>,
        field: u64,
    ) -> EvalResult<'tcx, Self> {
        ecx.mplace_field(self, field)
    }
}

macro_rules! make_value_visitor {
    ($visitor_trait_name:ident, $($mutability:ident)*) => {
        // How to traverse a value and what to do when we are at the leaves.
        pub trait $visitor_trait_name<'a, 'mir, 'tcx: 'mir+'a, M: Machine<'a, 'mir, 'tcx>>: Sized {
            type V: Value<'a, 'mir, 'tcx, M>;

            /// The visitor must have an `EvalContext` in it.
            fn ecx(&$($mutability)* self)
                -> &$($mutability)* EvalContext<'a, 'mir, 'tcx, M>;

            // Recursive actions, ready to be overloaded.
            /// Visit the given value, dispatching as appropriate to more specialized visitors.
            #[inline(always)]
            fn visit_value(&mut self, v: Self::V) -> EvalResult<'tcx>
            {
                self.walk_value(v)
            }
            /// Visit the given value as a union.  No automatic recursion can happen here.
            #[inline(always)]
            fn visit_union(&mut self, _v: Self::V) -> EvalResult<'tcx>
            {
                Ok(())
            }
            /// Visit this vale as an aggregate, you are even getting an iterator yielding
            /// all the fields (still in an `EvalResult`, you have to do error handling yourself).
            /// Recurses into the fields.
            #[inline(always)]
            fn visit_aggregate(
                &mut self,
                v: Self::V,
                fields: impl Iterator<Item=EvalResult<'tcx, Self::V>>,
            ) -> EvalResult<'tcx> {
                self.walk_aggregate(v, fields)
            }
            /// Called each time we recurse down to a field, passing in old and new value.
            /// This gives the visitor the chance to track the stack of nested fields that
            /// we are descending through.
            #[inline(always)]
            fn visit_field(
                &mut self,
                _old_val: Self::V,
                _field: usize,
                new_val: Self::V,
            ) -> EvalResult<'tcx> {
                self.visit_value(new_val)
            }

            /// Called whenever we reach a value with uninhabited layout.
            /// Recursing to fields will *always* continue after this!  This is not meant to control
            /// whether and how we descend recursively/ into the scalar's fields if there are any,
            /// it is meant to provide the chance for additional checks when a value of uninhabited
            /// layout is detected.
            #[inline(always)]
            fn visit_uninhabited(&mut self) -> EvalResult<'tcx>
            { Ok(()) }
            /// Called whenever we reach a value with scalar layout.
            /// We do NOT provide a `ScalarMaybeUndef` here to avoid accessing memory if the
            /// visitor is not even interested in scalars.
            /// Recursing to fields will *always* continue after this!  This is not meant to control
            /// whether and how we descend recursively/ into the scalar's fields if there are any,
            /// it is meant to provide the chance for additional checks when a value of scalar
            /// layout is detected.
            #[inline(always)]
            fn visit_scalar(&mut self, _v: Self::V, _layout: &layout::Scalar) -> EvalResult<'tcx>
            { Ok(()) }

            /// Called whenever we reach a value of primitive type.  There can be no recursion
            /// below such a value.  This is the leave function.
            #[inline(always)]
            fn visit_primitive(&mut self, _val: ImmTy<'tcx, M::PointerTag>) -> EvalResult<'tcx>
            { Ok(()) }

            // Default recursors. Not meant to be overloaded.
            fn walk_aggregate(
                &mut self,
                v: Self::V,
                fields: impl Iterator<Item=EvalResult<'tcx, Self::V>>,
            ) -> EvalResult<'tcx> {
                // Now iterate over it.
                for (idx, field_val) in fields.enumerate() {
                    self.visit_field(v, idx, field_val?)?;
                }
                Ok(())
            }
            fn walk_value(&mut self, v: Self::V) -> EvalResult<'tcx>
            {
                trace!("walk_value: type: {}", v.layout().ty);
                // If this is a multi-variant layout, we have find the right one and proceed with
                // that.
                match v.layout().variants {
                    layout::Variants::NicheFilling { .. } |
                    layout::Variants::Tagged { .. } => {
                        let op = v.to_op(self.ecx())?;
                        let idx = self.ecx().read_discriminant(op)?.1;
                        let inner = v.project_downcast(self.ecx(), idx)?;
                        trace!("walk_value: variant layout: {:#?}", inner.layout());
                        // recurse with the inner type
                        return self.visit_field(v, idx, inner);
                    }
                    layout::Variants::Single { .. } => {}
                }

                // Even for single variants, we might be able to get a more refined type:
                // If it is a trait object, switch to the actual type that was used to create it.
                match v.layout().ty.sty {
                    ty::Dynamic(..) => {
                        // immediate trait objects are not a thing
                        let dest = v.to_op(self.ecx())?.to_mem_place();
                        let inner = self.ecx().unpack_dyn_trait(dest)?.1;
                        trace!("walk_value: dyn object layout: {:#?}", inner.layout);
                        // recurse with the inner type
                        return self.visit_field(v, 0, Value::from_mem_place(inner));
                    },
                    _ => {},
                };

                // If this is a scalar, visit it as such.
                // Things can be aggregates and have scalar layout at the same time, and that
                // is very relevant for `NonNull` and similar structs: We need to visit them
                // at their scalar layout *before* descending into their fields.
                // FIXME: We could avoid some redundant checks here. For newtypes wrapping
                // scalars, we do the same check on every "level" (e.g. first we check
                // MyNewtype and then the scalar in there).
                match v.layout().abi {
                    layout::Abi::Uninhabited => {
                        self.visit_uninhabited()?;
                    }
                    layout::Abi::Scalar(ref layout) => {
                        self.visit_scalar(v, layout)?;
                    }
                    // FIXME: Should we do something for ScalarPair? Vector?
                    _ => {}
                }

                // Check primitive types.  We do this after checking the scalar layout,
                // just to have that done as well.  Primitives can have varying layout,
                // so we check them separately and before aggregate handling.
                // It is CRITICAL that we get this check right, or we might be
                // validating the wrong thing!
                let primitive = match v.layout().fields {
                    // Primitives appear as Union with 0 fields - except for Boxes and fat pointers.
                    layout::FieldPlacement::Union(0) => true,
                    _ => v.layout().ty.builtin_deref(true).is_some(),
                };
                if primitive {
                    let op = v.to_op(self.ecx())?;
                    let val = self.ecx().read_immediate(op)?;
                    return self.visit_primitive(val);
                }

                // Proceed into the fields.
                match v.layout().fields {
                    layout::FieldPlacement::Union(fields) => {
                        // Empty unions are not accepted by rustc. That's great, it means we can
                        // use that as an unambiguous signal for detecting primitives.  Make sure
                        // we did not miss any primitive.
                        debug_assert!(fields > 0);
                        self.visit_union(v)?;
                    },
                    layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
                        // FIXME: We collect in a vec because otherwise there are lifetime errors:
                        // Projecting to a field needs (mutable!) access to `ecx`.
                        let fields: Vec<EvalResult<'tcx, Self::V>> =
                            (0..offsets.len()).map(|i| {
                                v.project_field(self.ecx(), i as u64)
                            })
                            .collect();
                        self.visit_aggregate(v, fields.into_iter())?;
                    },
                    layout::FieldPlacement::Array { .. } => {
                        // Let's get an mplace first.
                        let mplace = if v.layout().is_zst() {
                            // it's a ZST, the memory content cannot matter
                            MPlaceTy::dangling(v.layout(), self.ecx())
                        } else {
                            // non-ZST array/slice/str cannot be immediate
                            v.to_op(self.ecx())?.to_mem_place()
                        };
                        // Now we can go over all the fields.
                        let iter = self.ecx().mplace_array_fields(mplace)?
                            .map(|f| f.and_then(|f| {
                                Ok(Value::from_mem_place(f))
                            }));
                        self.visit_aggregate(v, iter)?;
                    }
                }
                Ok(())
            }
        }
    }
}

make_value_visitor!(ValueVisitor,);
make_value_visitor!(MutValueVisitor,mut);
<|endoftext|>


<commit_before>use std::iter;

pub fn verse(n: int) -> ~str {
    match n {
        0 =>
            ~"No more bottles of beer on the wall, no more bottles of beer.\nGo to the store and buy some more, 99 bottles of beer on the wall.\n",
        1 =>
            ~"1 bottle of beer on the wall, 1 bottle of beer.\nTake it down and pass it around, no more bottles of beer on the wall.\n",
        2 =>
            ~"2 bottles of beer on the wall, 2 bottles of beer.\nTake one down and pass it around, 1 bottle of beer on the wall.\n",
        n if n > 2 && n <= 99 =>
            [n.to_str(), ~" bottles of beer on the wall, ",
             n.to_str(), ~" bottles of beer.\n",
             ~"Take one down and pass it around, ",
             (n - 1).to_str(), ~" bottles of beer on the wall.\n"].concat(),
        _ =>
            fail!(),
    }
}

pub fn sing(start: int, end: int) -> ~str {
    iter::range_inclusive(end, start)
        .invert()
        .map(verse)
        .collect::<~[~str]>()
        .connect("\n") + "\n"
}
<commit_msg>rust - clean up beer-song<commit_after>use std::iter;

pub fn verse(n: int) -> ~str {
    match n {
        0 =>
            ~"No more bottles of beer on the wall, no more bottles of beer.\nGo to the store and buy some more, 99 bottles of beer on the wall.\n",
        1 =>
            ~"1 bottle of beer on the wall, 1 bottle of beer.\nTake it down and pass it around, no more bottles of beer on the wall.\n",
        2 =>
            ~"2 bottles of beer on the wall, 2 bottles of beer.\nTake one down and pass it around, 1 bottle of beer on the wall.\n",
        n if n > 2 && n <= 99 =>
            format!("{n} bottles of beer on the wall, {n} bottles of beer.\nTake one down and pass it around, {n_minus_1} bottles of beer on the wall.\n", n=n, n_minus_1=n - 1),
        _ =>
            fail!(),
    }
}

pub fn sing(start: int, end: int) -> ~str {
    let mut s = iter::range_inclusive(end, start)
        .invert()
        .map(verse)
        .to_owned_vec()
        .connect("\n");
    s.push_char('\n');
    s
}
<|endoftext|>


<commit_before>//! Contains the entry point code for handling an incoming connection.
//!
use std::net::TcpStream;
use net;
use auth;
use parse;
use super::query;
use net::types::*;
use storage::{Rows};
use storage::types::{SqlType, Column};
use net::Error;

pub fn handle(mut stream: TcpStream) {
    // Logging about the new connection
    let addr = stream.peer_addr()
        .map(|a| a.to_string())
        .unwrap_or("???".into());
    info!("Handling connection from {}", addr);

    // Perform handshake, check user login --> done
    let res = net::do_handshake(&mut stream);
    let _ = match res {
        Ok((user, pw)) => {
            info!("Connection established. Handshake sent");
            match auth::find_user(&user, &pw) {
                Ok(_) => {
                    match net::send_info_package(&mut stream,
                        PkgType::AccGranted)
                    {
                        Ok(_) => {},
                        Err(_) => return
                    }
                },
                Err(_) => {
                    let _ =
                        net::send_info_package(&mut stream, PkgType::AccDenied);
                    // Loops for user-convienience?
                    return
                }
            }
        },
        _ => {
            let _ = net::send_info_package(&mut stream, PkgType::AccDenied);
            return
        }
    };

    // Read commands from the client (with help of `net`) --> done
    loop {
        //get the command from the stream
        let command_res = net::read_commands(&mut stream);

        // TODO: Dispatch commands (handle easy ones directly, forward others)
        match command_res {
            Ok(cmd) =>
            match cmd {
                // exit the session and shutdown the connection
                Command::Quit => {
                    match net::send_info_package(&mut stream, PkgType::Ok) {
                        Ok(_) => {
                            debug!("Client disconnected properly.");
                            return
                        },
                        Err(_) =>
                            warn!("Failed to send packet. Connection close.")
                    }
                },
                // send OK-Package, unused value can be checked to try again and
                // eventually close to connection as timeout issue
                Command::Ping => {
                    match net::send_info_package(&mut stream, PkgType::Ok) {
                        Ok(_) => { },
                        Err(_) => warn!("Failed to send packet.")
                    }
                },
                // send the query string for parsing
                // TODO: If query -> Call parser to obtain AST
                // TODO: If query -> Pass AST to query executer
                // TODO: Send results
                Command::Query(q) => {

                    debug!("Query received, dispatch query to parser.");

                    let ast = parse::parse(&q);

                    match ast {
                        Ok(tree) => {
                            println!("{:?}", tree);

                            // Dummy Row
                            let r = query::execute_from_ast(tree, & mut auth::User {
                                _name: "DummyUser".into(),
                                _currentDatabase: None} ).
                                unwrap_or(
                                    Rows { data: vec![], columns: vec![Column::new("default",
                                                    SqlType::Int, false, "default", false)]});

                            // Send response package
                            match net::send_response_package(&mut stream, r) {
                                Ok(_) => { },
                                Err(_) => warn!("Failed to send packet.")
                            }
                        },

                        Err(error) => {
                            println!("{:?}", error);
                            match net::send_error_package(&mut stream, Error::UnEoq(error).into()) {
                                Ok(_) => {},
                                Err(_) => warn!("Failed to send error.")
                            }
                        }
                    }
                    continue
                }
            },
            Err(_) => continue // TODO: error handling
        }
    }
}
<commit_msg>replaced println macros with dabug and error macros<commit_after>//! Contains the entry point code for handling an incoming connection.
//!
use std::net::TcpStream;
use net;
use auth;
use parse;
use super::query;
use net::types::*;
use storage::{Rows};
use storage::types::{SqlType, Column};
use net::Error;

pub fn handle(mut stream: TcpStream) {
    // Logging about the new connection
    let addr = stream.peer_addr()
        .map(|a| a.to_string())
        .unwrap_or("???".into());
    info!("Handling connection from {}", addr);

    // Perform handshake, check user login --> done
    let res = net::do_handshake(&mut stream);
    let _ = match res {
        Ok((user, pw)) => {
            info!("Connection established. Handshake sent");
            match auth::find_user(&user, &pw) {
                Ok(_) => {
                    match net::send_info_package(&mut stream,
                        PkgType::AccGranted)
                    {
                        Ok(_) => {},
                        Err(_) => return
                    }
                },
                Err(_) => {
                    let _ =
                        net::send_info_package(&mut stream, PkgType::AccDenied);
                    // Loops for user-convienience?
                    return
                }
            }
        },
        _ => {
            let _ = net::send_info_package(&mut stream, PkgType::AccDenied);
            return
        }
    };

    // Read commands from the client (with help of `net`) --> done
    loop {
        //get the command from the stream
        let command_res = net::read_commands(&mut stream);

        // TODO: Dispatch commands (handle easy ones directly, forward others)
        match command_res {
            Ok(cmd) =>
            match cmd {
                // exit the session and shutdown the connection
                Command::Quit => {
                    match net::send_info_package(&mut stream, PkgType::Ok) {
                        Ok(_) => {
                            debug!("Client disconnected properly.");
                            return
                        },
                        Err(_) =>
                            warn!("Failed to send packet. Connection close.")
                    }
                },
                // send OK-Package, unused value can be checked to try again and
                // eventually close to connection as timeout issue
                Command::Ping => {
                    match net::send_info_package(&mut stream, PkgType::Ok) {
                        Ok(_) => { },
                        Err(_) => warn!("Failed to send packet.")
                    }
                },
                // send the query string for parsing
                // TODO: If query -> Call parser to obtain AST
                // TODO: If query -> Pass AST to query executer
                // TODO: Send results
                Command::Query(q) => {

                    debug!("Query received, dispatch query to parser.");

                    let ast = parse::parse(&q);

                    match ast {
                        Ok(tree) => {
                            debug!("{:?}", tree);

                            // Dummy Row
                            let r = query::execute_from_ast(tree, & mut auth::User {
                                _name: "DummyUser".into(),
                                _currentDatabase: None} ).
                                unwrap_or(
                                    Rows { data: vec![], columns: vec![Column::new("error occurred",
                                                    SqlType::Int, false, "error", false)]});

                            // Send response package
                            match net::send_response_package(&mut stream, r) {
                                Ok(_) => { },
                                Err(_) => warn!("Failed to send packet.")
                            }
                        },

                        Err(error) => {
                            error!("{:?}", error);
                            match net::send_error_package(&mut stream, Error::UnEoq(error).into()) {
                                Ok(_) => {},
                                Err(_) => warn!("Failed to send error.")
                            }
                        }
                    }
                    continue
                }
            },
            Err(_) => continue // TODO: error handling
        }
    }
}
<|endoftext|>


<commit_before>use std::{collections::HashMap, net::SocketAddr};
use std::{thread, time};

use anyhow::Result;
use glam::vec2;
use laminar::{Packet, Socket};
use legion::*;
use log::{info, LevelFilter};
use rand::prelude::*;
use simplelog::{Config, TermLogger, TerminalMode};

use zombenum_shared::components::{Component, GameEntityId};
use zombenum_shared::entities::make_player;
use zombenum_shared::get_registry;

mod network;
mod systems;

#[allow(dead_code)]
mod serialize;

use network::receive::get_user_events;
use network::send::{send_server_updates, ScheduledUpdates};

const SERVER: &str = "0.0.0.0:14191";
fn main() -> Result<()> {
    TermLogger::init(LevelFilter::Info, Config::default(), TerminalMode::Mixed)?;

    let mut world = World::default();
    let registry = get_registry();
    let mut resources = Resources::default();
    let mut schedule = Schedule::builder()
        .add_system(systems::movement_system())
        .build();

    info!("Starting server");

    let mut socket = Socket::bind(SERVER)?;
    let (sender, receiver) = (socket.get_packet_sender(), socket.get_event_receiver());
    let _thread = thread::spawn(move || socket.start_polling());

    // A list of all connected users with their respective game entity id.
    let mut connected_users: HashMap<SocketAddr, GameEntityId> = HashMap::new();

    let tick_duration = time::Duration::from_millis(10);
    loop {
        let time_at_start = time::Instant::now();
        // Get all received events, sort them by event and return them in a unified struct.
        let events = get_user_events(&receiver, &mut connected_users)?;

        let mut scheduled_updates = ScheduledUpdates::new();

        // Player joins the game
        for player_id in events.join_game {
            info!("Player {:?} just joined", player_id);
            let mut rng = thread_rng();
            let player = make_player(
                vec2(rng.gen_range(-1.0..1.0), rng.gen_range(-1.0..1.0)),
                player_id,
            );

            world.push(player.clone());

            let mut components = Vec::new();
            components.push(Component::GameEntityId(player.0));
            components.push(Component::Position(player.1));
            components.push(Component::Player(player.2));
            components.push(Component::Drawable(player.3));
            scheduled_updates.added_entities.push(components);
        }

        resources.insert(scheduled_updates);

        // Run systems here.
        schedule.execute(&mut world, &mut resources);

        let scheduled_updates = resources
            .get::<&ScheduledUpdates>()
            .expect("We put it there.");

        send_server_updates(*scheduled_updates)?;

        // We aim to keep every tick the same consistent length.
        // In order to achieve that, we'll sleep only as long as we still have time budget left over
        // after every loop.
        let time_at_end = time::Instant::now();
        let loop_duration = time_at_end - time_at_start;
        let time_to_sleep = tick_duration.checked_sub(loop_duration).unwrap_or_default();
        thread::sleep(time_to_sleep);
    }
}
<commit_msg>Fix resource getter<commit_after>use std::{collections::HashMap, net::SocketAddr};
use std::{thread, time};

use anyhow::Result;
use glam::vec2;
use laminar::{Packet, Socket};
use legion::*;
use log::{info, LevelFilter};
use rand::prelude::*;
use simplelog::{Config, TermLogger, TerminalMode};

use zombenum_shared::components::{Component, GameEntityId};
use zombenum_shared::entities::make_player;
use zombenum_shared::get_registry;

mod network;
mod systems;

#[allow(dead_code)]
mod serialize;

use network::receive::get_user_events;
use network::send::{send_server_updates, ScheduledUpdates};

const SERVER: &str = "0.0.0.0:14191";
fn main() -> Result<()> {
    TermLogger::init(LevelFilter::Info, Config::default(), TerminalMode::Mixed)?;

    let mut world = World::default();
    let registry = get_registry();
    let mut resources = Resources::default();
    let mut schedule = Schedule::builder()
        .add_system(systems::movement_system())
        .build();

    info!("Starting server");

    let mut socket = Socket::bind(SERVER)?;
    let (sender, receiver) = (socket.get_packet_sender(), socket.get_event_receiver());
    let _thread = thread::spawn(move || socket.start_polling());

    // A list of all connected users with their respective game entity id.
    let mut connected_users: HashMap<SocketAddr, GameEntityId> = HashMap::new();

    let tick_duration = time::Duration::from_millis(10);
    loop {
        let time_at_start = time::Instant::now();
        // Get all received events, sort them by event and return them in a unified struct.
        let events = get_user_events(&receiver, &mut connected_users)?;

        let mut scheduled_updates = ScheduledUpdates::new();

        // Player joins the game
        for player_id in events.join_game {
            info!("Player {:?} just joined", player_id);
            let mut rng = thread_rng();
            let player = make_player(
                vec2(rng.gen_range(-1.0..1.0), rng.gen_range(-1.0..1.0)),
                player_id,
            );

            world.push(player.clone());

            let mut components = Vec::new();
            components.push(Component::GameEntityId(player.0));
            components.push(Component::Position(player.1));
            components.push(Component::Player(player.2));
            components.push(Component::Drawable(player.3));
            scheduled_updates.added_entities.push(components);
        }

        resources.insert(scheduled_updates);

        // Run systems here.
        schedule.execute(&mut world, &mut resources);

        let scheduled_updates = resources
            .get::<ScheduledUpdates>()
            .expect("We put it there.");

        send_server_updates(&scheduled_updates)?;

        // We aim to keep every tick the same consistent length.
        // In order to achieve that, we'll sleep only as long as we still have time budget left over
        // after every loop.
        let time_at_end = time::Instant::now();
        let loop_duration = time_at_end - time_at_start;
        let time_to_sleep = tick_duration.checked_sub(loop_duration).unwrap_or_default();
        thread::sleep(time_to_sleep);
    }
}
<|endoftext|>


<commit_before>import driver.session;
import front.ast;
import std.Map.hashmap;
import std.Option;
import std.Option.some;
import std.Option.none;
import std.Int;
import std.Vec;
import util.common;

type fn_id_of_local = std.Map.hashmap[ast.def_id, ast.def_id];
type env = rec(mutable vec[ast.def_id] current_context, // fn or obj
               fn_id_of_local idmap,
               session.session sess);

fn current_context(&env e) -> ast.def_id {
    ret e.current_context.(Vec.len(e.current_context) - 1u);
}

fn enter_item(@env e, &@ast.item i) {
    alt (i.node) {
        case (ast.item_fn(?name, _, _, ?id, _)) {
            Vec.push(e.current_context, id);
        }
        case (ast.item_obj(_, _, _, ?ids, _)) {
            Vec.push(e.current_context, ids.ty);
        }
        case (_) {}
    }
}

fn leave_item(@env e, &@ast.item i) {
    alt (i.node) {
        case (ast.item_fn(?name, _, _, ?id, _)) {
            Vec.pop(e.current_context);
        }
        case (ast.item_obj(_, _, _, ?ids, _)) {
            Vec.pop(e.current_context);
        }
        case (_) {}
    }
}

fn walk_expr(@env e, &@ast.expr x) {
    alt (x.node) {
        case (ast.expr_for(?d, _, _, _)) {
            alt (d.node) {
                case (ast.decl_local(?local)) {
                    e.idmap.insert(local.id, current_context(*e));
                }
                case (_) { }
            }
        }
        case (ast.expr_for_each(?d, _, _, _)) {
            alt (d.node) {
                case (ast.decl_local(?local)) {
                    e.idmap.insert(local.id, current_context(*e));
                }
                case (_) { }
            }
        }
        case (ast.expr_path(_, ?def, _)) {
            auto local_id;
            alt (Option.get(def)) {
                case (ast.def_local(?id)) { local_id = id; }
                case (_) { ret; }
            }

            auto df = ast.def_id_of_def(Option.get(def));
            auto def_context = Option.get(e.idmap.find(df));

            if (current_context(*e) != def_context) {
                e.sess.span_err(x.span,
                                "attempted dynamic environment-capture");
            }
        }
        case (_) { }
    }
}

fn walk_block(@env e, &ast.block b) {
    for each (@tup(ast.ident, ast.block_index_entry) it in
              b.node.index.items()) {
        alt (it._1) {
            case (ast.bie_local(?local)) {
                e.idmap.insert(local.id, current_context(*e));
            }
            case (_) { }
        }
    }
}

fn check_for_captures(session.session sess, @ast.crate crate) {
    let vec[ast.def_id] curctx = vec();
    auto env = @rec(mutable current_context = curctx,
                    idmap = common.new_def_hash[ast.def_id](),
                    sess = sess);
    auto visitor = rec(visit_item_pre = bind enter_item(env, _),
                       visit_item_post = bind leave_item(env, _),
                       visit_block_pre = bind walk_block(env, _),
                       visit_expr_pre = bind walk_expr(env, _)
                       with walk.default_visitor());
    walk.walk_crate(visitor, *crate);
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Stop depending on block indices in capture.rs<commit_after>import driver.session;
import front.ast;
import std.Map.hashmap;
import std.Option;
import std.Option.some;
import std.Option.none;
import std.Int;
import std.Vec;
import util.common;

type fn_id_of_local = std.Map.hashmap[ast.def_id, ast.def_id];
type env = rec(mutable vec[ast.def_id] current_context, // fn or obj
               fn_id_of_local idmap,
               session.session sess);

fn current_context(&env e) -> ast.def_id {
    ret e.current_context.(Vec.len(e.current_context) - 1u);
}

fn enter_item(@env e, &@ast.item i) {
    alt (i.node) {
        case (ast.item_fn(?name, _, _, ?id, _)) {
            Vec.push(e.current_context, id);
        }
        case (ast.item_obj(_, _, _, ?ids, _)) {
            Vec.push(e.current_context, ids.ty);
        }
        case (_) {}
    }
}

fn leave_item(@env e, &@ast.item i) {
    alt (i.node) {
        case (ast.item_fn(?name, _, _, ?id, _)) {
            Vec.pop(e.current_context);
        }
        case (ast.item_obj(_, _, _, ?ids, _)) {
            Vec.pop(e.current_context);
        }
        case (_) {}
    }
}

fn walk_expr(@env e, &@ast.expr x) {
    alt (x.node) {
        case (ast.expr_for(?d, _, _, _)) {
            alt (d.node) {
                case (ast.decl_local(?local)) {
                    e.idmap.insert(local.id, current_context(*e));
                }
                case (_) { }
            }
        }
        case (ast.expr_for_each(?d, _, _, _)) {
            alt (d.node) {
                case (ast.decl_local(?local)) {
                    e.idmap.insert(local.id, current_context(*e));
                }
                case (_) { }
            }
        }
        case (ast.expr_path(_, ?def, _)) {
            auto local_id;
            alt (Option.get(def)) {
                case (ast.def_local(?id)) { local_id = id; }
                case (_) { ret; }
            }

            auto df = ast.def_id_of_def(Option.get(def));
            auto def_context = Option.get(e.idmap.find(df));

            if (current_context(*e) != def_context) {
                e.sess.span_err(x.span,
                                "attempted dynamic environment-capture");
            }
        }
        case (_) { }
    }
}

fn walk_block(@env e, &ast.block b) {
    for (@ast.stmt st in b.node.stmts) {
        alt (st.node) {
            case (ast.stmt_decl(?d,_)) {
                alt (d.node) {
                    case (ast.decl_local(?loc)) {
                        e.idmap.insert(loc.id, current_context(*e));
                    }
                    case (_) { }
                }
            }
            case (_) { }
        }
    }
}

fn check_for_captures(session.session sess, @ast.crate crate) {
    let vec[ast.def_id] curctx = vec();
    auto env = @rec(mutable current_context = curctx,
                    idmap = common.new_def_hash[ast.def_id](),
                    sess = sess);
    auto visitor = rec(visit_item_pre = bind enter_item(env, _),
                       visit_item_post = bind leave_item(env, _),
                       visit_block_pre = bind walk_block(env, _),
                       visit_expr_pre = bind walk_expr(env, _)
                       with walk.default_visitor());
    walk.walk_crate(visitor, *crate);
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>use std::collections::HashMap;

use crate::controllers::frontend_prelude::*;

use crate::controllers::helpers::*;

use crate::controllers::helpers::pagination::{Paginated, PaginationOptions};
use crate::models::{
    CrateOwner, Email, Follow, NewEmail, OwnerKind, User, Version, VersionOwnerAction,
};
use crate::schema::{crate_owners, crates, emails, follows, users, versions};
use crate::views::{EncodableMe, EncodablePrivateUser, EncodableVersion, OwnedCrate};

/// Handles the `GET /me` route.
pub fn me(req: &mut dyn RequestExt) -> EndpointResult {
    let user_id = req.authenticate()?.forbid_api_token_auth()?.user_id();
    let conn = req.db_conn()?;

    let (user, verified, email, verification_sent): (User, Option<bool>, Option<String>, bool) =
        users::table
            .find(user_id)
            .left_join(emails::table)
            .select((
                users::all_columns,
                emails::verified.nullable(),
                emails::email.nullable(),
                emails::token_generated_at.nullable().is_not_null(),
            ))
            .first(&*conn)?;

    let owned_crates = CrateOwner::by_owner_kind(OwnerKind::User)
        .inner_join(crates::table)
        .filter(crate_owners::owner_id.eq(user_id))
        .select((crates::id, crates::name, crate_owners::email_notifications))
        .order(crates::name.asc())
        .load(&*conn)?
        .into_iter()
        .map(|(id, name, email_notifications)| OwnedCrate {
            id,
            name,
            email_notifications,
        })
        .collect();

    let verified = verified.unwrap_or(false);
    let verification_sent = verified || verification_sent;
    Ok(req.json(&EncodableMe {
        user: EncodablePrivateUser::from(user, email, verified, verification_sent),
        owned_crates,
    }))
}

/// Handles the `GET /me/updates` route.
pub fn updates(req: &mut dyn RequestExt) -> EndpointResult {
    use diesel::dsl::any;

    let authenticated_user = req.authenticate()?.forbid_api_token_auth()?;
    let user = authenticated_user.user();

    let followed_crates = Follow::belonging_to(&user).select(follows::crate_id);
    let query = versions::table
        .inner_join(crates::table)
        .left_outer_join(users::table)
        .filter(crates::id.eq(any(followed_crates)))
        .order(versions::created_at.desc())
        .select((
            versions::all_columns,
            crates::name,
            users::all_columns.nullable(),
        ))
        .pages_pagination(PaginationOptions::builder().gather(req)?);
    let conn = req.db_conn()?;
    let data: Paginated<(Version, String, Option<User>)> = query.load(&*conn)?;
    let more = data.next_page_params().is_some();
    let versions = data.iter().map(|(v, _, _)| v).cloned().collect::<Vec<_>>();
    let data = data
        .into_iter()
        .zip(VersionOwnerAction::for_versions(&conn, &versions)?.into_iter())
        .map(|((v, cn, pb), voas)| (v, cn, pb, voas))
        .collect::<Vec<_>>();

    let versions = data
        .into_iter()
        .map(|(version, crate_name, published_by, actions)| {
            EncodableVersion::from(version, &crate_name, published_by, actions)
        })
        .collect();

    #[derive(Serialize)]
    struct R {
        versions: Vec<EncodableVersion>,
        meta: Meta,
    }
    #[derive(Serialize)]
    struct Meta {
        more: bool,
    }
    Ok(req.json(&R {
        versions,
        meta: Meta { more },
    }))
}

/// Handles the `PUT /users/:user_id` route.
pub fn update_user(req: &mut dyn RequestExt) -> EndpointResult {
    use self::emails::user_id;
    use diesel::insert_into;

    let authenticated_user = req.authenticate()?;

    let mut body = String::new();
    req.body().read_to_string(&mut body)?;

    let param_user_id = &req.params()["user_id"];
    let conn = req.db_conn()?;
    let user = authenticated_user.user();

    // need to check if current user matches user to be updated
    if &user.id.to_string() != param_user_id {
        return Err(bad_request("current user does not match requested user"));
    }

    #[derive(Deserialize)]
    struct UserUpdate {
        user: User,
    }

    #[derive(Deserialize)]
    struct User {
        email: Option<String>,
    }

    let user_update: UserUpdate =
        serde_json::from_str(&body).map_err(|_| bad_request("invalid json request"))?;

    let user_email = match &user_update.user.email {
        Some(email) => email.trim(),
        None => return Err(bad_request("empty email rejected")),
    };

    if user_email.is_empty() {
        return Err(bad_request("empty email rejected"));
    }

    conn.transaction::<_, Box<dyn AppError>, _>(|| {
        let new_email = NewEmail {
            user_id: user.id,
            email: user_email,
        };

        let token: String = insert_into(emails::table)
            .values(&new_email)
            .on_conflict(user_id)
            .do_update()
            .set(&new_email)
            .returning(emails::token)
            .get_result(&*conn)
            .map_err(|_| server_error("Error in creating token"))?;

        // This swallows any errors that occur while attempting to send the email. Some users have
        // an invalid email set in their GitHub profile, and we should let them sign in even though
        // we're trying to silently use their invalid address during signup and can't send them an
        // email. They'll then have to provide a valid email address.
        let _ = req
            .app()
            .emails
            .send_user_confirm(user_email, &user.gh_login, &token);

        Ok(())
    })?;

    ok_true()
}

/// Handles the `PUT /confirm/:email_token` route
pub fn confirm_user_email(req: &mut dyn RequestExt) -> EndpointResult {
    use diesel::update;

    let conn = req.db_conn()?;
    let req_token = &req.params()["email_token"];

    let updated_rows = update(emails::table.filter(emails::token.eq(req_token)))
        .set(emails::verified.eq(true))
        .execute(&*conn)?;

    if updated_rows == 0 {
        return Err(bad_request("Email belonging to token not found."));
    }

    ok_true()
}

/// Handles `PUT /user/:user_id/resend` route
pub fn regenerate_token_and_send(req: &mut dyn RequestExt) -> EndpointResult {
    use diesel::dsl::sql;
    use diesel::update;

    let param_user_id = req.params()["user_id"]
        .parse::<i32>()
        .chain_error(|| bad_request("invalid user_id"))?;
    let authenticated_user = req.authenticate()?;
    let conn = req.db_conn()?;
    let user = authenticated_user.user();

    // need to check if current user matches user to be updated
    if user.id != param_user_id {
        return Err(bad_request("current user does not match requested user"));
    }

    conn.transaction(|| {
        let email: Email = update(Email::belonging_to(&user))
            .set(emails::token.eq(sql("DEFAULT")))
            .get_result(&*conn)
            .map_err(|_| bad_request("Email could not be found"))?;

        req.app()
            .emails
            .send_user_confirm(&email.email, &user.gh_login, &email.token)
    })?;

    ok_true()
}

/// Handles `PUT /me/email_notifications` route
pub fn update_email_notifications(req: &mut dyn RequestExt) -> EndpointResult {
    use self::crate_owners::dsl::*;
    use diesel::pg::upsert::excluded;

    #[derive(Deserialize)]
    struct CrateEmailNotifications {
        id: i32,
        email_notifications: bool,
    }

    let mut body = String::new();
    req.body().read_to_string(&mut body)?;
    let updates: HashMap<i32, bool> = serde_json::from_str::<Vec<CrateEmailNotifications>>(&body)
        .map_err(|_| bad_request("invalid json request"))?
        .iter()
        .map(|c| (c.id, c.email_notifications))
        .collect();

    let user_id = req.authenticate()?.user_id();
    let conn = req.db_conn()?;

    // Build inserts from existing crates belonging to the current user
    let to_insert = CrateOwner::by_owner_kind(OwnerKind::User)
        .filter(owner_id.eq(user_id))
        .select((crate_id, owner_id, owner_kind, email_notifications))
        .load(&*conn)?
        .into_iter()
        // Remove records whose `email_notifications` will not change from their current value
        .map(
            |(c_id, o_id, o_kind, e_notifications): (i32, i32, i32, bool)| {
                let current_e_notifications = *updates.get(&c_id).unwrap_or(&e_notifications);
                (
                    crate_id.eq(c_id),
                    owner_id.eq(o_id),
                    owner_kind.eq(o_kind),
                    email_notifications.eq(current_e_notifications),
                )
            },
        )
        .collect::<Vec<_>>();

    // Upsert crate owners; this should only actually exectute updates
    diesel::insert_into(crate_owners)
        .values(&to_insert)
        .on_conflict((crate_id, owner_id, owner_kind))
        .do_update()
        .set(email_notifications.eq(excluded(email_notifications)))
        .execute(&*conn)?;

    ok_true()
}
<commit_msg>Auto merge of #3865 - nipunn1313:clippy, r=Turbo87<commit_after>use std::collections::HashMap;

use crate::controllers::frontend_prelude::*;

use crate::controllers::helpers::*;

use crate::controllers::helpers::pagination::{Paginated, PaginationOptions};
use crate::models::{
    CrateOwner, Email, Follow, NewEmail, OwnerKind, User, Version, VersionOwnerAction,
};
use crate::schema::{crate_owners, crates, emails, follows, users, versions};
use crate::views::{EncodableMe, EncodablePrivateUser, EncodableVersion, OwnedCrate};

/// Handles the `GET /me` route.
pub fn me(req: &mut dyn RequestExt) -> EndpointResult {
    let user_id = req.authenticate()?.forbid_api_token_auth()?.user_id();
    let conn = req.db_conn()?;

    let (user, verified, email, verification_sent): (User, Option<bool>, Option<String>, bool) =
        users::table
            .find(user_id)
            .left_join(emails::table)
            .select((
                users::all_columns,
                emails::verified.nullable(),
                emails::email.nullable(),
                emails::token_generated_at.nullable().is_not_null(),
            ))
            .first(&*conn)?;

    let owned_crates = CrateOwner::by_owner_kind(OwnerKind::User)
        .inner_join(crates::table)
        .filter(crate_owners::owner_id.eq(user_id))
        .select((crates::id, crates::name, crate_owners::email_notifications))
        .order(crates::name.asc())
        .load(&*conn)?
        .into_iter()
        .map(|(id, name, email_notifications)| OwnedCrate {
            id,
            name,
            email_notifications,
        })
        .collect();

    let verified = verified.unwrap_or(false);
    let verification_sent = verified || verification_sent;
    Ok(req.json(&EncodableMe {
        user: EncodablePrivateUser::from(user, email, verified, verification_sent),
        owned_crates,
    }))
}

/// Handles the `GET /me/updates` route.
pub fn updates(req: &mut dyn RequestExt) -> EndpointResult {
    use diesel::dsl::any;

    let authenticated_user = req.authenticate()?.forbid_api_token_auth()?;
    let user = authenticated_user.user();

    let followed_crates = Follow::belonging_to(&user).select(follows::crate_id);
    let query = versions::table
        .inner_join(crates::table)
        .left_outer_join(users::table)
        .filter(crates::id.eq(any(followed_crates)))
        .order(versions::created_at.desc())
        .select((
            versions::all_columns,
            crates::name,
            users::all_columns.nullable(),
        ))
        .pages_pagination(PaginationOptions::builder().gather(req)?);
    let conn = req.db_conn()?;
    let data: Paginated<(Version, String, Option<User>)> = query.load(&*conn)?;
    let more = data.next_page_params().is_some();
    let versions = data.iter().map(|(v, _, _)| v).cloned().collect::<Vec<_>>();
    let data = data
        .into_iter()
        .zip(VersionOwnerAction::for_versions(&conn, &versions)?.into_iter())
        .map(|((v, cn, pb), voas)| (v, cn, pb, voas));

    let versions = data
        .into_iter()
        .map(|(version, crate_name, published_by, actions)| {
            EncodableVersion::from(version, &crate_name, published_by, actions)
        })
        .collect();

    #[derive(Serialize)]
    struct R {
        versions: Vec<EncodableVersion>,
        meta: Meta,
    }
    #[derive(Serialize)]
    struct Meta {
        more: bool,
    }
    Ok(req.json(&R {
        versions,
        meta: Meta { more },
    }))
}

/// Handles the `PUT /users/:user_id` route.
pub fn update_user(req: &mut dyn RequestExt) -> EndpointResult {
    use self::emails::user_id;
    use diesel::insert_into;

    let authenticated_user = req.authenticate()?;

    let mut body = String::new();
    req.body().read_to_string(&mut body)?;

    let param_user_id = &req.params()["user_id"];
    let conn = req.db_conn()?;
    let user = authenticated_user.user();

    // need to check if current user matches user to be updated
    if &user.id.to_string() != param_user_id {
        return Err(bad_request("current user does not match requested user"));
    }

    #[derive(Deserialize)]
    struct UserUpdate {
        user: User,
    }

    #[derive(Deserialize)]
    struct User {
        email: Option<String>,
    }

    let user_update: UserUpdate =
        serde_json::from_str(&body).map_err(|_| bad_request("invalid json request"))?;

    let user_email = match &user_update.user.email {
        Some(email) => email.trim(),
        None => return Err(bad_request("empty email rejected")),
    };

    if user_email.is_empty() {
        return Err(bad_request("empty email rejected"));
    }

    conn.transaction::<_, Box<dyn AppError>, _>(|| {
        let new_email = NewEmail {
            user_id: user.id,
            email: user_email,
        };

        let token: String = insert_into(emails::table)
            .values(&new_email)
            .on_conflict(user_id)
            .do_update()
            .set(&new_email)
            .returning(emails::token)
            .get_result(&*conn)
            .map_err(|_| server_error("Error in creating token"))?;

        // This swallows any errors that occur while attempting to send the email. Some users have
        // an invalid email set in their GitHub profile, and we should let them sign in even though
        // we're trying to silently use their invalid address during signup and can't send them an
        // email. They'll then have to provide a valid email address.
        let _ = req
            .app()
            .emails
            .send_user_confirm(user_email, &user.gh_login, &token);

        Ok(())
    })?;

    ok_true()
}

/// Handles the `PUT /confirm/:email_token` route
pub fn confirm_user_email(req: &mut dyn RequestExt) -> EndpointResult {
    use diesel::update;

    let conn = req.db_conn()?;
    let req_token = &req.params()["email_token"];

    let updated_rows = update(emails::table.filter(emails::token.eq(req_token)))
        .set(emails::verified.eq(true))
        .execute(&*conn)?;

    if updated_rows == 0 {
        return Err(bad_request("Email belonging to token not found."));
    }

    ok_true()
}

/// Handles `PUT /user/:user_id/resend` route
pub fn regenerate_token_and_send(req: &mut dyn RequestExt) -> EndpointResult {
    use diesel::dsl::sql;
    use diesel::update;

    let param_user_id = req.params()["user_id"]
        .parse::<i32>()
        .chain_error(|| bad_request("invalid user_id"))?;
    let authenticated_user = req.authenticate()?;
    let conn = req.db_conn()?;
    let user = authenticated_user.user();

    // need to check if current user matches user to be updated
    if user.id != param_user_id {
        return Err(bad_request("current user does not match requested user"));
    }

    conn.transaction(|| {
        let email: Email = update(Email::belonging_to(&user))
            .set(emails::token.eq(sql("DEFAULT")))
            .get_result(&*conn)
            .map_err(|_| bad_request("Email could not be found"))?;

        req.app()
            .emails
            .send_user_confirm(&email.email, &user.gh_login, &email.token)
    })?;

    ok_true()
}

/// Handles `PUT /me/email_notifications` route
pub fn update_email_notifications(req: &mut dyn RequestExt) -> EndpointResult {
    use self::crate_owners::dsl::*;
    use diesel::pg::upsert::excluded;

    #[derive(Deserialize)]
    struct CrateEmailNotifications {
        id: i32,
        email_notifications: bool,
    }

    let mut body = String::new();
    req.body().read_to_string(&mut body)?;
    let updates: HashMap<i32, bool> = serde_json::from_str::<Vec<CrateEmailNotifications>>(&body)
        .map_err(|_| bad_request("invalid json request"))?
        .iter()
        .map(|c| (c.id, c.email_notifications))
        .collect();

    let user_id = req.authenticate()?.user_id();
    let conn = req.db_conn()?;

    // Build inserts from existing crates belonging to the current user
    let to_insert = CrateOwner::by_owner_kind(OwnerKind::User)
        .filter(owner_id.eq(user_id))
        .select((crate_id, owner_id, owner_kind, email_notifications))
        .load(&*conn)?
        .into_iter()
        // Remove records whose `email_notifications` will not change from their current value
        .map(
            |(c_id, o_id, o_kind, e_notifications): (i32, i32, i32, bool)| {
                let current_e_notifications = *updates.get(&c_id).unwrap_or(&e_notifications);
                (
                    crate_id.eq(c_id),
                    owner_id.eq(o_id),
                    owner_kind.eq(o_kind),
                    email_notifications.eq(current_e_notifications),
                )
            },
        )
        .collect::<Vec<_>>();

    // Upsert crate owners; this should only actually exectute updates
    diesel::insert_into(crate_owners)
        .values(&to_insert)
        .on_conflict((crate_id, owner_id, owner_kind))
        .do_update()
        .set(email_notifications.eq(excluded(email_notifications)))
        .execute(&*conn)?;

    ok_true()
}
<|endoftext|>