<commit_before>extern crate piston_window;

extern crate turtleide;

use canvas::{TurtleCanvas, Command, Radians};

fn main() {
    let canvas = TurtleCanvas::new();

    let dashed = false;
    for i in 0..361 {
        if dashed {
            canvas.apply(Command::Pen {
                enabled: i % 2 == 0,
            });
        }
        canvas.apply(Command::Move {
            distance: 10.,
        });
        canvas.apply(Command::Rotate {
            angle: Radians(1f64.to_radians()),
            clockwise: true,
        });
    }
}

mod canvas {
    use std::thread;
    use std::process;
    use std::time::{Instant, Duration};
    use std::sync::mpsc::{self, TryRecvError};
    use std::ops::{Add, Mul};

    use piston_window::*;

    use turtleide::Speed;

    #[derive(Default, Clone, Copy, Debug, PartialOrd, PartialEq)]
    pub struct Radians(pub f64);

    impl Radians {
        pub fn cos(self) -> f64 {
            self.0.cos()
        }

        pub fn sin(self) -> f64 {
            self.0.sin()
        }
    }

    impl Add for Radians {
        type Output = Self;

        fn add(self, other: Self) -> Self {
            Radians(self.0 + other.0)
        }
    }

    impl Mul<f64> for Radians {
        type Output = Self;

        fn mul(self, other: f64) -> Self {
            Radians(self.0 * other)
        }
    }

    trait ToCanvasCoordinates : Copy {
        fn to_canvas_coords(self, center: [f64; 2]) -> Self;
    }

    impl ToCanvasCoordinates for [f64; 2] {
        /// Transforms the given local coordinate into a point that can be drawn on the canvas.
        ///
        /// Takes into account the direction of the axis and center when converting
        /// `local` from cartesian coordinates.
        ///
        /// Origin in window is the top left corner and the y-axis goes down instead of up.
        fn to_canvas_coords(self, center: [f64; 2]) -> [f64; 2] {
            [center[0] + self[0], center[1] - self[1]]
        }
    }

    trait AsMillis {
        fn as_millis(&self) -> u64;
    }

    impl AsMillis for Duration {
        fn as_millis(&self) -> u64 {
            self.as_secs() * 1000 + (self.subsec_nanos() / 1_000_000) as u64
        }
    }

    pub enum Command {
        Move {
            distance: f64,
        },
        Rotate {
            angle: Radians,
            clockwise: bool,
        },
        Pen {
            enabled: bool,
        },
    }

    #[derive(Debug, Clone, Copy)]
    pub enum Color {
        Black,
        Transparent,
    }

    impl From<Color> for types::Color {
        fn from(color: Color) -> Self {
            match color {
                Color::Black => [0., 0., 0., 255.],
                Color::Transparent => [0., 0., 0., 0.],
            }
        }
    }

    #[derive(Debug, Clone)]
    struct Path {
        start: [f64; 2],
        end: [f64; 2],
        pen: Pen,
    }

    type Response = Result<(), ()>;

    struct TurtleState {
        pub position: [f64; 2],
        pub heading: Radians,
        pub speed: Speed,
    }

    impl Default for TurtleState {
        fn default() -> TurtleState {
            TurtleState {
                position: Default::default(),
                heading: Radians(90f64.to_radians()),
                speed: Default::default(),
            }
        }
    }

    struct DrawingState {
        pen: Pen,
        //pub background: Color,
    }

    #[derive(Debug, Clone)]
    struct Pen {
        pub enabled: bool,
        pub thickness: f64,
        pub color: Color,
    }

    struct Animation {
        kind: AnimationKind,
        speed: Speed,
        start: Instant,
    }

    enum AnimationKind {
        Move {
            path: Path,
        },
        Rotation {
            target_angle: Radians,
            clockwise: bool,
        },
    }

    pub struct TurtleCanvas {
        thread_handle: Option<thread::JoinHandle<()>>,
        transmitter: mpsc::Sender<Command>,
        receiver: mpsc::Receiver<Response>,
    }

    impl TurtleCanvas {
        pub fn new() -> TurtleCanvas {
            let (drawing_tx, drawing_rx) = mpsc::channel();
            let (main_tx, main_rx) = mpsc::channel();

            let handle = thread::spawn(move || {
                let mut window: PistonWindow = WindowSettings::new(
                    "Turtle IDE", [800, 600]
                ).exit_on_esc(true).build().unwrap();
                let mut paths: Vec<Path> = Vec::new();
                let mut animation: Option<Animation> = None;
                let mut turtle = TurtleState::default();
                let mut drawing = DrawingState {
                    pen: Pen {
                        enabled: true,
                        thickness: 1.,
                        color: Color::Black,
                    },
                };

                while let Some(e) = window.next() {
                    match drawing_rx.try_recv() {
                        Ok(command) => {
                            if animation.is_some() {
                                unreachable!("The main thread did not wait for the animation to complete before sending another command")
                            }
                            match command {
                                Command::Move {distance} => {
                                    if distance != 0. {
                                        let start = turtle.position;
                                        let x = distance * turtle.heading.cos();
                                        let y = distance * turtle.heading.sin();
                                        let end = math::add(start, [x, y]);
                                        animation = Some(Animation {
                                            kind: AnimationKind::Move {
                                                path: Path {
                                                    start, end,
                                                    pen: drawing.pen.clone(),
                                                },
                                            },
                                            speed: turtle.speed,
                                            start: Instant::now(),
                                        });
                                    }
                                },
                                Command::Rotate {angle, clockwise} => {
                                    animation = Some(Animation {
                                        kind: AnimationKind::Rotation {
                                            target_angle: turtle.heading + angle,
                                            clockwise,
                                        },
                                        speed: turtle.speed,
                                        start: Instant::now(),
                                    });
                                },
                                Command::Pen {enabled} => {
                                    drawing.pen.enabled = enabled;
                                    main_tx.send(Ok(())).unwrap();
                                },
                            }
                        },
                        Err(TryRecvError::Empty) => {}, // Do nothing
                        Err(TryRecvError::Disconnected) => break, // Quit
                    }

                    window.draw_2d(&e, |c, g| {
                        clear([1.0; 4], g);

                        let view = c.get_view_size();
                        let width = view[0] as f64;
                        let height = view[1] as f64;
                        let center = [width * 0.5, height * 0.5];

                        let mut animation_complete = false;
                        if let Some(Animation {ref kind, ref speed, ref start}) = animation {
                            let elapsed = start.elapsed().as_millis() as f64;

                            match *kind {
                                AnimationKind::Move {ref path} => {
                                    // This code finds the point on the line between start and
                                    // end that we are supposed to be at right now using some
                                    // vector math.
                                    //
                                    // The basic idea is to find the vector that represents the
                                    // line between start and end, normalize it into a direction,
                                    // and then scale that vector to be the size that it should be
                                    // at the elapsed time based on the speed.
                                    let &Path {start, end, ref pen} = path;
                                    let speed = speed.to_absolute(); // px per second
                                    let path_line = math::sub(start, end);
                                    let path_length = math::square_len(path_line).sqrt();
                                    let direction = math::mul_scalar(path_line, path_length);
                                    // (px / sec) * (sec / 1000ms) * ms => px
                                    let offset = math::mul_scalar(direction, speed / 1000. * elapsed);
                                    let offset_length = math::square_len(offset).sqrt();

                                    let current = if offset_length >= path_length {
                                        paths.push(path.clone());
                                        animation_complete = true;
                                        end
                                    }
                                    else {
                                        math::add(start, offset)
                                    };

                                    turtle.position = current;

                                    let &Pen {thickness, color, enabled} = pen;
                                    if enabled {
                                        let start = start.to_canvas_coords(center);
                                        let current = current.to_canvas_coords(center);

                                        line(color.into(), thickness,
                                            [start[0], start[1], current[0], current[1]],
                                            c.transform, g);
                                    }
                                },
                                AnimationKind::Rotation {target_angle, clockwise} => {
                                    // TODO: Use the returned value in Radians and impl Div for Radians
                                    let speed = speed.to_rotation();
                                    animation_complete = true;
                                },
                            }
                        }
                        if animation_complete {
                            animation = None;
                            main_tx.send(Ok(())).unwrap();
                        }

                        for path in &paths {
                            if !path.pen.enabled {
                                continue;
                            }

                            let Path {start, end, ref pen} = *path;
                            let start = start.to_canvas_coords(center);
                            let end = end.to_canvas_coords(center);

                            line(pen.color.into(), pen.thickness,
                                [start[0], start[1], end[0], end[1]],
                                c.transform, g);
                        }

                        // TODO: Draw the turtle
                    });
                }
            });

            Self {
                thread_handle: Some(handle),
                transmitter: drawing_tx,
                receiver: main_rx,
            }
        }

        pub fn apply(&self, command: Command) {
            let result = self.transmitter.send(command).map_err(|_| ());
            let result = result.and_then(|_| {
                // Wait for the drawing animation to complete
                self.receiver.recv().map_err(|_| ())
            });
            match result {
                Ok(_) => {},
                Err(_) => {
                    // The connection has been closed so the window was closed
                    // or an error occurred on that thread
                    process::exit(0);
                },
            }
        }
    }

    impl Drop for TurtleCanvas {
        fn drop(&mut self) {
            if let Some(handle) = self.thread_handle.take() {
                handle.join().unwrap();
            }
        }
    }
}
<commit_msg>Started drawing the turtle's shell<commit_after>extern crate piston_window;

extern crate turtleide;

use canvas::{TurtleCanvas, Command, Radians};

fn main() {
    let canvas = TurtleCanvas::new();

    let dashed = false;
    for i in 0..361 {
        if dashed {
            canvas.apply(Command::Pen {
                enabled: i % 2 == 0,
            });
        }
        canvas.apply(Command::Move {
            distance: 10.,
        });
        canvas.apply(Command::Rotate {
            angle: Radians(1f64.to_radians()),
            clockwise: true,
        });
    }
}

mod canvas {
    use std::thread;
    use std::process;
    use std::time::{Instant, Duration};
    use std::sync::mpsc::{self, TryRecvError};
    use std::ops::{Add, Mul};

    use piston_window::*;

    use turtleide::Speed;

    #[derive(Default, Clone, Copy, Debug, PartialOrd, PartialEq)]
    pub struct Radians(pub f64);

    impl Radians {
        pub fn cos(self) -> f64 {
            self.0.cos()
        }

        pub fn sin(self) -> f64 {
            self.0.sin()
        }
    }

    impl Add for Radians {
        type Output = Self;

        fn add(self, other: Self) -> Self {
            Radians(self.0 + other.0)
        }
    }

    impl Mul<f64> for Radians {
        type Output = Self;

        fn mul(self, other: f64) -> Self {
            Radians(self.0 * other)
        }
    }

    trait ToCanvasCoordinates : Copy {
        fn to_canvas_coords(self, center: [f64; 2]) -> Self;
    }

    impl ToCanvasCoordinates for [f64; 2] {
        /// Transforms the given local coordinate into a point that can be drawn on the canvas.
        ///
        /// Takes into account the direction of the axis and center when converting
        /// `local` from cartesian coordinates.
        ///
        /// Origin in window is the top left corner and the y-axis goes down instead of up.
        fn to_canvas_coords(self, center: [f64; 2]) -> [f64; 2] {
            [center[0] + self[0], center[1] - self[1]]
        }
    }

    trait AsMillis {
        fn as_millis(&self) -> u64;
    }

    impl AsMillis for Duration {
        fn as_millis(&self) -> u64 {
            self.as_secs() * 1000 + (self.subsec_nanos() / 1_000_000) as u64
        }
    }

    pub enum Command {
        Move {
            distance: f64,
        },
        Rotate {
            angle: Radians,
            clockwise: bool,
        },
        Pen {
            enabled: bool,
        },
    }

    #[derive(Debug, Clone, Copy)]
    pub enum Color {
        Black,
        White,
        Transparent,
    }

    impl From<Color> for types::Color {
        fn from(color: Color) -> Self {
            match color {
                Color::Black => [0., 0., 0., 255.],
                Color::White => [255., 255., 255., 255.],
                Color::Transparent => [0., 0., 0., 0.],
            }
        }
    }

    #[derive(Debug, Clone)]
    struct Path {
        start: [f64; 2],
        end: [f64; 2],
        pen: Pen,
    }

    type Response = Result<(), ()>;

    struct TurtleState {
        pub position: [f64; 2],
        pub heading: Radians,
        pub speed: Speed,
    }

    impl Default for TurtleState {
        fn default() -> TurtleState {
            TurtleState {
                position: Default::default(),
                heading: Radians(90f64.to_radians()),
                speed: Default::default(),
            }
        }
    }

    struct DrawingState {
        pen: Pen,
        //pub background: Color,
    }

    #[derive(Debug, Clone)]
    struct Pen {
        pub enabled: bool,
        pub thickness: f64,
        pub color: Color,
    }

    struct Animation {
        kind: AnimationKind,
        speed: Speed,
        start: Instant,
    }

    enum AnimationKind {
        Move {
            path: Path,
        },
        Rotation {
            target_angle: Radians,
            clockwise: bool,
        },
    }

    pub struct TurtleCanvas {
        thread_handle: Option<thread::JoinHandle<()>>,
        transmitter: mpsc::Sender<Command>,
        receiver: mpsc::Receiver<Response>,
    }

    impl TurtleCanvas {
        pub fn new() -> TurtleCanvas {
            let (drawing_tx, drawing_rx) = mpsc::channel();
            let (main_tx, main_rx) = mpsc::channel();

            let handle = thread::spawn(move || {
                let mut window: PistonWindow = WindowSettings::new(
                    "Turtle IDE", [800, 600]
                ).exit_on_esc(true).build().unwrap();
                let mut paths: Vec<Path> = Vec::new();
                let mut animation: Option<Animation> = None;
                let mut turtle = TurtleState::default();
                let mut drawing = DrawingState {
                    pen: Pen {
                        enabled: true,
                        thickness: 1.,
                        color: Color::Black,
                    },
                };

                while let Some(e) = window.next() {
                    match drawing_rx.try_recv() {
                        Ok(command) => {
                            if animation.is_some() {
                                unreachable!("The main thread did not wait for the animation to complete before sending another command")
                            }
                            match command {
                                Command::Move {distance} => {
                                    if distance != 0. {
                                        let start = turtle.position;
                                        let x = distance * turtle.heading.cos();
                                        let y = distance * turtle.heading.sin();
                                        let end = math::add(start, [x, y]);
                                        animation = Some(Animation {
                                            kind: AnimationKind::Move {
                                                path: Path {
                                                    start, end,
                                                    pen: drawing.pen.clone(),
                                                },
                                            },
                                            speed: turtle.speed,
                                            start: Instant::now(),
                                        });
                                    }
                                },
                                Command::Rotate {angle, clockwise} => {
                                    animation = Some(Animation {
                                        kind: AnimationKind::Rotation {
                                            target_angle: turtle.heading + angle,
                                            clockwise,
                                        },
                                        speed: turtle.speed,
                                        start: Instant::now(),
                                    });
                                },
                                Command::Pen {enabled} => {
                                    drawing.pen.enabled = enabled;
                                    main_tx.send(Ok(())).unwrap();
                                },
                            }
                        },
                        Err(TryRecvError::Empty) => {}, // Do nothing
                        Err(TryRecvError::Disconnected) => break, // Quit
                    }

                    window.draw_2d(&e, |c, g| {
                        clear([1.0; 4], g);

                        let view = c.get_view_size();
                        let width = view[0] as f64;
                        let height = view[1] as f64;
                        let center = [width * 0.5, height * 0.5];

                        let mut animation_complete = false;
                        if let Some(Animation {ref kind, ref speed, ref start}) = animation {
                            let elapsed = start.elapsed().as_millis() as f64;

                            match *kind {
                                AnimationKind::Move {ref path} => {
                                    // This code finds the point on the line between start and
                                    // end that we are supposed to be at right now using some
                                    // vector math.
                                    //
                                    // The basic idea is to find the vector that represents the
                                    // line between start and end, normalize it into a direction,
                                    // and then scale that vector to be the size that it should be
                                    // at the elapsed time based on the speed.
                                    let &Path {start, end, ref pen} = path;
                                    let speed = speed.to_absolute(); // px per second
                                    let path_line = math::sub(start, end);
                                    let path_length = math::square_len(path_line).sqrt();
                                    let direction = math::mul_scalar(path_line, path_length);
                                    // (px / sec) * (sec / 1000ms) * ms => px
                                    let offset = math::mul_scalar(direction, speed / 1000. * elapsed);
                                    let offset_length = math::square_len(offset).sqrt();

                                    let current = if offset_length >= path_length {
                                        paths.push(path.clone());
                                        animation_complete = true;
                                        end
                                    }
                                    else {
                                        math::add(start, offset)
                                    };

                                    turtle.position = current;

                                    let &Pen {thickness, color, enabled} = pen;
                                    if enabled {
                                        let start = start.to_canvas_coords(center);
                                        let current = current.to_canvas_coords(center);

                                        line(color.into(), thickness,
                                            [start[0], start[1], current[0], current[1]],
                                            c.transform, g);
                                    }
                                },
                                AnimationKind::Rotation {target_angle, clockwise} => {
                                    // TODO: Use the returned value in Radians and impl Div for Radians
                                    let speed = speed.to_rotation();
                                    animation_complete = true;
                                },
                            }
                        }
                        if animation_complete {
                            animation = None;
                            main_tx.send(Ok(())).unwrap();
                        }

                        for path in &paths {
                            if !path.pen.enabled {
                                continue;
                            }

                            let Path {start, end, ref pen} = *path;
                            let start = start.to_canvas_coords(center);
                            let end = end.to_canvas_coords(center);

                            line(pen.color.into(), pen.thickness,
                                [start[0], start[1], end[0], end[1]],
                                c.transform, g);
                        }

                        // Draw the turtle's shell
                        let cos = turtle.heading.cos();
                        let sin = turtle.heading.sin();
                        let turtle_x = turtle.position[0];
                        let turtle_y = turtle.position[1];
                        let shell: Vec<_> = [
                            [0., 15.],
                            [10., 0.],
                            [0., -15.],
                        ].into_iter().map(|pt| {
                            // Rotate each point by the heading and add the current turtle position
                            let x = cos * pt[0] - sin * pt[1] + turtle_x;
                            let y = sin * pt[0] + cos * pt[1] + turtle_y;
                            [x, y].to_canvas_coords(center)
                        }).collect();

                        polygon(Color::White.into(), &shell, c.transform, g);
                        for i in 0..shell.len() {
                            let start = shell[i];
                            let end = shell[(i + 1) % shell.len()];

                            line(Color::Black.into(), 1.,
                                [start[0], start[1], end[0], end[1]],
                                c.transform, g);
                        }
                    });
                }
            });

            Self {
                thread_handle: Some(handle),
                transmitter: drawing_tx,
                receiver: main_rx,
            }
        }

        pub fn apply(&self, command: Command) {
            let result = self.transmitter.send(command).map_err(|_| ());
            let result = result.and_then(|_| {
                // Wait for the drawing animation to complete
                self.receiver.recv().map_err(|_| ())
            });
            match result {
                Ok(_) => {},
                Err(_) => {
                    // The connection has been closed so the window was closed
                    // or an error occurred on that thread
                    process::exit(0);
                },
            }
        }
    }

    impl Drop for TurtleCanvas {
        fn drop(&mut self) {
            if let Some(handle) = self.thread_handle.take() {
                handle.join().unwrap();
            }
        }
    }
}
<|endoftext|>


<commit_before>
// Allow dead code since this is an example app.
#![allow(dead_code)]

extern crate piston;
extern crate graphics;
extern crate sdl2_game_window;
extern crate opengl_graphics;

use opengl_graphics::{Gl};
use Window = sdl2_game_window::GameWindowSDL2;
use graphics::{
    Context,
    AddColor,
    AddLine,
    AddRoundBorder,
    RelativeColor,
    RelativeTransform2d,
    Draw,
};
use piston::{
    GameIterator,
    GameIteratorSettings,
    GameWindowSettings,
    Render,
};

fn render(c: &Context, gl: &mut Gl) {
    let line = c.line(0.0, 0.0, 0.5, 0.5);
    let line = line.round_border_radius(0.1);
    let line = line.rgb(1.0, 1.0, 0.0);
    let n = 200;
    let (start, end) = (-0.75, 0.5);
    for i in range(0u, n + 1) {
        let f = i as f64 / n as f64;
        line.trans(f * (end - start) + start, 0.0)
        .hue_deg(f as f32 * 360.0)
        .draw(gl);
    }
}

fn main() {
    let mut window = Window::new(
        GameWindowSettings {
            title: "Rust-Graphics-Lab: Line App".to_string(),
            size: [600, 300],
            fullscreen: false,
            exit_on_esc: true,
        }
    );

    let game_iter_settings = GameIteratorSettings {
        updates_per_second: 120,
        max_frames_per_second: 60,
    };
    let mut game_iter = GameIterator::new(&mut window, &game_iter_settings);
    let ref mut gl = Gl::new();
    loop {
        match game_iter.next() {
            None => break,
            Some(mut e) => match e {
                Render(ref mut args) => {
                    gl.viewport(0, 0, args.width as i32, args.height as i32);
                    let c = Context::abs(
                            args.width as f64,
                            args.height as f64
                        );
                    c.rgb(1.0, 1.0, 1.0).draw(gl);
                    render(&c, gl);
                },
                _ => {},
            },
        }
    }
}
<commit_msg>Fixed 'line_app.rs' to draw something<commit_after>
// Allow dead code since this is an example app.
#![allow(dead_code)]

extern crate piston;
extern crate graphics;
extern crate sdl2_game_window;
extern crate opengl_graphics;

use opengl_graphics::{Gl};
use Window = sdl2_game_window::GameWindowSDL2;
use graphics::{
    Context,
    AddColor,
    AddLine,
    AddRoundBorder,
    RelativeColor,
    RelativeTransform2d,
    Draw,
};
use piston::{
    GameIterator,
    GameIteratorSettings,
    GameWindowSettings,
    Render,
};

fn render(c: &Context, gl: &mut Gl) {
    // Create a line.
    let line = c.line(0.0, 0.0, 0.0, 100.0)
        .round_border_radius(3.0)
        .rgb(1.0, 1.0, 0.0);

    // Draw ten lines beside each other with hue transformed color.
    let n = 10;
    let (start, end) = (0.0, 400.0);
    for i in range(0u, n + 1) {
        let f = i as f64 / n as f64;
        line.trans(f * (end - start) + start, 0.0)
        .hue_deg(f as f32 * 360.0)
        .draw(gl);
    }
}

fn main() {
    let mut window = Window::new(
        GameWindowSettings {
            title: "Rust-Graphics-Lab: Line App".to_string(),
            size: [600, 300],
            fullscreen: false,
            exit_on_esc: true,
        }
    );

    let game_iter_settings = GameIteratorSettings {
        updates_per_second: 120,
        max_frames_per_second: 60,
    };
    let mut game_iter = GameIterator::new(&mut window, &game_iter_settings);
    let ref mut gl = Gl::new();
    loop {
        match game_iter.next() {
            None => break,
            Some(mut e) => match e {
                Render(ref mut args) => {
                    gl.viewport(0, 0, args.width as i32, args.height as i32);
                    let c = Context::abs(
                            args.width as f64,
                            args.height as f64
                        );
                    c.rgb(1.0, 1.0, 1.0).draw(gl);
                    render(&c, gl);
                },
                _ => {},
            },
        }
    }
}
<|endoftext|>


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

// ignore-pretty issue #37201

// This test is ensuring that parameters are indeed dropped after
// temporaries in a fn body.

use std::cell::RefCell;

use self::d::D;

pub fn main() {
    let log = RefCell::new(vec![]);
    d::println("created empty log");
    test(&log);

    assert_eq!(&log.borrow()[..],
               [
                   //                                    created empty log
                   //    +-- Make D(da_0, 0)
                   //    | +-- Make D(de_1, 1)
                   //    | |                             calling foo
                   //    | |                             entered foo
                   //    | | +-- Make D(de_2, 2)
                   //    | | | +-- Make D(da_1, 3)
                   //    | | | | +-- Make D(de_3, 4)
                   //    | | | | | +-- Make D(de_4, 5)
                   3, // | | | +-- Drop D(da_1, 3)
                   //    | | |   | |
                   4, // | | |   +-- Drop D(de_3, 4)
                   //    | | |     |
                   //    | | |     |                     eval tail of foo
                   //    | | | +-- Make D(de_5, 6)
                   //    | | | | +-- Make D(de_6, 7)
                   5, // | | | | | +-- Drop D(de_4, 5)
                   //    | | | | |
                   2, // | | +-- Drop D(de_2, 2)
                   //    | |   | |
                   6, // | |   +-- Drop D(de_5, 6)
                   //    | |     |
                   1, // | +-- Drop D(de_1, 1)
                   //    |       |
                   0, // +-- Drop D(da_0, 0)
                   //            |
                   //            |                       result D(de_6, 7)
                   7 //          +-- Drop D(de_6, 7)

                       ]);
}

fn test<'a>(log: d::Log<'a>) {
    let da = D::new("da", 0, log);
    let de = D::new("de", 1, log);
    d::println("calling foo");
    let result = foo(da, de);
    d::println(&format!("result {}", result));
}

// FIXME(#33490) Remove the double braces when old trans is gone.
fn foo<'a>(da0: D<'a>, de1: D<'a>) -> D<'a> {{
    d::println("entered foo");
    let de2 = de1.incr();      // creates D(de_2, 2)
    let de4 = {
        let _da1 = da0.incr(); // creates D(da_1, 3)
        de2.incr().incr()      // creates D(de_3, 4) and D(de_4, 5)
    };
    d::println("eval tail of foo");
    de4.incr().incr()          // creates D(de_5, 6) and D(de_6, 7)
}}

// This module provides simultaneous printouts of the dynamic extents
// of all of the D values, in addition to logging the order that each
// is dropped.

const PREF_INDENT: u32 = 16;

pub mod d {
    #![allow(unused_parens)]
    use std::fmt;
    use std::mem;
    use std::cell::RefCell;

    static mut counter: u32 = 0;
    static mut trails: u64 = 0;

    pub type Log<'a> = &'a RefCell<Vec<u32>>;

    pub fn current_width() -> u32 {
        unsafe { max_width() - trails.leading_zeros() }
    }

    pub fn max_width() -> u32 {
        unsafe {
            (mem::size_of_val(&trails)*8) as u32
        }
    }

    pub fn indent_println(my_trails: u32, s: &str) {
        let mut indent: String = String::new();
        for i in 0..my_trails {
            unsafe {
                if trails & (1 << i) != 0 {
                    indent = indent + "| ";
                } else {
                    indent = indent + "  ";
                }
            }
        }
        println!("{}{}", indent, s);
    }

    pub fn println(s: &str) {
        indent_println(super::PREF_INDENT, s);
    }

    fn first_avail() -> u32 {
        unsafe {
            for i in 0..64 {
                if trails & (1 << i) == 0 {
                    return i;
                }
            }
        }
        panic!("exhausted trails");
    }

    pub struct D<'a> {
        name: &'static str, i: u32, uid: u32, trail: u32, log: Log<'a>
    }

    impl<'a> fmt::Display for D<'a> {
        fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
            write!(w, "D({}_{}, {})", self.name, self.i, self.uid)
        }
    }

    impl<'a> D<'a> {
        pub fn new(name: &'static str, i: u32, log: Log<'a>) -> D<'a> {
            unsafe {
                let trail = first_avail();
                let ctr = counter;
                counter += 1;
                trails |= (1 << trail);
                let ret = D {
                    name: name, i: i, log: log, uid: ctr, trail: trail
                };
                indent_println(trail, &format!("+-- Make {}", ret));
                ret
            }
        }
        pub fn incr(&self) -> D<'a> {
            D::new(self.name, self.i + 1, self.log)
        }
    }

    impl<'a> Drop for D<'a> {
        fn drop(&mut self) {
            unsafe { trails &= !(1 << self.trail); };
            self.log.borrow_mut().push(self.uid);
            indent_println(self.trail, &format!("+-- Drop {}", self));
            indent_println(::PREF_INDENT, "");
        }
    }
}
<commit_msg>#33490 is closed remove the FIXME<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-pretty issue #37201

// This test is ensuring that parameters are indeed dropped after
// temporaries in a fn body.

use std::cell::RefCell;

use self::d::D;

pub fn main() {
    let log = RefCell::new(vec![]);
    d::println("created empty log");
    test(&log);

    assert_eq!(&log.borrow()[..],
               [
                   //                                    created empty log
                   //    +-- Make D(da_0, 0)
                   //    | +-- Make D(de_1, 1)
                   //    | |                             calling foo
                   //    | |                             entered foo
                   //    | | +-- Make D(de_2, 2)
                   //    | | | +-- Make D(da_1, 3)
                   //    | | | | +-- Make D(de_3, 4)
                   //    | | | | | +-- Make D(de_4, 5)
                   3, // | | | +-- Drop D(da_1, 3)
                   //    | | |   | |
                   4, // | | |   +-- Drop D(de_3, 4)
                   //    | | |     |
                   //    | | |     |                     eval tail of foo
                   //    | | | +-- Make D(de_5, 6)
                   //    | | | | +-- Make D(de_6, 7)
                   5, // | | | | | +-- Drop D(de_4, 5)
                   //    | | | | |
                   2, // | | +-- Drop D(de_2, 2)
                   //    | |   | |
                   6, // | |   +-- Drop D(de_5, 6)
                   //    | |     |
                   1, // | +-- Drop D(de_1, 1)
                   //    |       |
                   0, // +-- Drop D(da_0, 0)
                   //            |
                   //            |                       result D(de_6, 7)
                   7 //          +-- Drop D(de_6, 7)

                       ]);
}

fn test<'a>(log: d::Log<'a>) {
    let da = D::new("da", 0, log);
    let de = D::new("de", 1, log);
    d::println("calling foo");
    let result = foo(da, de);
    d::println(&format!("result {}", result));
}

fn foo<'a>(da0: D<'a>, de1: D<'a>) -> D<'a> {
    d::println("entered foo");
    let de2 = de1.incr();      // creates D(de_2, 2)
    let de4 = {
        let _da1 = da0.incr(); // creates D(da_1, 3)
        de2.incr().incr()      // creates D(de_3, 4) and D(de_4, 5)
    };
    d::println("eval tail of foo");
    de4.incr().incr()          // creates D(de_5, 6) and D(de_6, 7)
}

// This module provides simultaneous printouts of the dynamic extents
// of all of the D values, in addition to logging the order that each
// is dropped.

const PREF_INDENT: u32 = 16;

pub mod d {
    #![allow(unused_parens)]
    use std::fmt;
    use std::mem;
    use std::cell::RefCell;

    static mut counter: u32 = 0;
    static mut trails: u64 = 0;

    pub type Log<'a> = &'a RefCell<Vec<u32>>;

    pub fn current_width() -> u32 {
        unsafe { max_width() - trails.leading_zeros() }
    }

    pub fn max_width() -> u32 {
        unsafe {
            (mem::size_of_val(&trails)*8) as u32
        }
    }

    pub fn indent_println(my_trails: u32, s: &str) {
        let mut indent: String = String::new();
        for i in 0..my_trails {
            unsafe {
                if trails & (1 << i) != 0 {
                    indent = indent + "| ";
                } else {
                    indent = indent + "  ";
                }
            }
        }
        println!("{}{}", indent, s);
    }

    pub fn println(s: &str) {
        indent_println(super::PREF_INDENT, s);
    }

    fn first_avail() -> u32 {
        unsafe {
            for i in 0..64 {
                if trails & (1 << i) == 0 {
                    return i;
                }
            }
        }
        panic!("exhausted trails");
    }

    pub struct D<'a> {
        name: &'static str, i: u32, uid: u32, trail: u32, log: Log<'a>
    }

    impl<'a> fmt::Display for D<'a> {
        fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
            write!(w, "D({}_{}, {})", self.name, self.i, self.uid)
        }
    }

    impl<'a> D<'a> {
        pub fn new(name: &'static str, i: u32, log: Log<'a>) -> D<'a> {
            unsafe {
                let trail = first_avail();
                let ctr = counter;
                counter += 1;
                trails |= (1 << trail);
                let ret = D {
                    name: name, i: i, log: log, uid: ctr, trail: trail
                };
                indent_println(trail, &format!("+-- Make {}", ret));
                ret
            }
        }
        pub fn incr(&self) -> D<'a> {
            D::new(self.name, self.i + 1, self.log)
        }
    }

    impl<'a> Drop for D<'a> {
        fn drop(&mut self) {
            unsafe { trails &= !(1 << self.trail); };
            self.log.borrow_mut().push(self.uid);
            indent_println(self.trail, &format!("+-- Drop {}", self));
            indent_println(::PREF_INDENT, "");
        }
    }
}
<|endoftext|>


<commit_before>use hyper;
use std::convert::From;
use serde_json;
use std::num::ParseIntError;

impl From<::json::Error> for HueError {
    fn from(e: ::json::Error) -> HueError {
        HueErrorKind::BridgeError {
            address:e.address,
            description:e.description,
            error:From::from(e.code)
        }.into()
    }
}

error_chain! {

    types {
        HueError, HueErrorKind, ResultExt, Result;
    }

    errors {
        /// this does not happen in practice
        MalformedResponse { }
        /// An error that occured in the bridge
        BridgeError {
            address:String,
            description:String,
            error:BridgeError
        } {
            description("bridge error")
            display("Bridge error: {:?} address: {} description: {}", error, address, description)
        }
    }

    foreign_links {
        JsonError(serde_json::Error);
        HyperError(hyper::Error);
        ParseIntError(ParseIntError);
    }

}

macro_rules! error_enum {
    (
        $(#[$meta:meta])*
        pub enum $name:ident{
            $($err:ident = $n:expr),+;
            $other:ident
        }
    ) => (
        $(#[$meta])*
        pub enum $name{
            $($err = $n,)+
            $other
        }
        impl From<u16> for $name{
            fn from(n: u16) -> Self{
                match n {
                    $($n => $name::$err,)+
                    _ => $name::$other
                }
            }
        }
    );
}

error_enum!{
    /// All errors defined in http://www.developers.meethue.com/documentation/error-messages
    #[repr(u16)]
    #[allow(missing_docs)]
    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
    pub enum BridgeError {
        // Generic Errors
        UnauthorizedUser = 1,
        BodyContainsInvalidJson = 2,
        ResourceNotAvailable = 3,
        MethodNotAvailableForResource = 4,
        MissingParametersInBody = 5,
        ParameterNotAvailable = 6,
        InvalidValueForParameter = 7,
        ParameterIsNotModifiable = 8,
        TooManyItemsInList = 11,
        ProtalConnectionRequired = 12,
        InternalError = 901,

        // Command Specific Errors
        LinkButtonNotPressed = 101,
        DHCPCannotBeDisabled = 110,
        InvalidUpdateState = 111,
        DeviceIsSetToOff = 201,
        GroupCouldNotBeCreatedGroupFull = 301,
        DeviceCouldNotBeAddedGroupFull = 302,
        DeviceIsUnreachable = 304,
        UpdateOrDeleteGroupOfThisTypeNotAllowed = 305,
        LightAlreadyUsed = 306,
        SceneCouldNotBeCreated = 401,
        SceneCouldNotBeCreatedBufferFull = 402,
        SceneCouldNotBeRemoved = 403,
        NotAllowedToCreateSensorType = 501,
        SensorListIsFull = 502,
        RuleEngineFull = 601,
        ConditionError = 607,
        ActionError = 608,
        UnableToActivae = 609,
        ScheduleListIsFull = 701,
        ScheduleTimezoneNotValid = 702,
        ScheduleCannotSetTimeAndLocalTime = 703,
        CannotCreateSchedule = 704,
        CannotEnableScheduleTimeInPast = 705,
        CommandError = 706,
        SourceModelInvalid = 801,
        SourceFactoryNew = 802,
        InvalidState = 803;
        Other
    }
}

#[test]
fn bridge_errors() {
    use self::BridgeError::*;

    assert_eq!(BridgeError::from(101), LinkButtonNotPressed);
    assert_eq!(BridgeError::from(0), Other);
    assert_eq!(BridgeError::from(51234), Other);
    assert_eq!(BridgeError::from(4), MethodNotAvailableForResource);
    assert_eq!(SceneCouldNotBeRemoved as u16, 403);
    assert_eq!(InternalError as u16, 901);
}
<commit_msg>document foreign links<commit_after>use hyper;
use std::convert::From;
use serde_json;
use std::num::ParseIntError;

impl From<::json::Error> for HueError {
    fn from(e: ::json::Error) -> HueError {
        HueErrorKind::BridgeError {
            address:e.address,
            description:e.description,
            error:From::from(e.code)
        }.into()
    }
}

error_chain! {

    types {
        HueError, HueErrorKind, ResultExt, Result;
    }

    errors {
        /// this does not happen in practice
        MalformedResponse { }
        /// An error that occured in the bridge
        BridgeError {
            address:String,
            description:String,
            error:BridgeError
        } {
            description("bridge error")
            display("Bridge error: {:?} address: {} description: {}", error, address, description)
        }
    }

    foreign_links {
        JsonError(serde_json::Error) #[doc = "Json Error"];
        HyperError(hyper::Error)     #[doc = "Hyper Error"];
        ParseIntError(ParseIntError) #[doc = "Parser Error"];
    }

}

macro_rules! error_enum {
    (
        $(#[$meta:meta])*
        pub enum $name:ident{
            $($err:ident = $n:expr),+;
            $other:ident
        }
    ) => (
        $(#[$meta])*
        pub enum $name{
            $($err = $n,)+
            $other
        }
        impl From<u16> for $name{
            fn from(n: u16) -> Self{
                match n {
                    $($n => $name::$err,)+
                    _ => $name::$other
                }
            }
        }
    );
}

error_enum!{
    /// All errors defined in http://www.developers.meethue.com/documentation/error-messages
    #[repr(u16)]
    #[allow(missing_docs)]
    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
    pub enum BridgeError {
        // Generic Errors
        UnauthorizedUser = 1,
        BodyContainsInvalidJson = 2,
        ResourceNotAvailable = 3,
        MethodNotAvailableForResource = 4,
        MissingParametersInBody = 5,
        ParameterNotAvailable = 6,
        InvalidValueForParameter = 7,
        ParameterIsNotModifiable = 8,
        TooManyItemsInList = 11,
        ProtalConnectionRequired = 12,
        InternalError = 901,

        // Command Specific Errors
        LinkButtonNotPressed = 101,
        DHCPCannotBeDisabled = 110,
        InvalidUpdateState = 111,
        DeviceIsSetToOff = 201,
        GroupCouldNotBeCreatedGroupFull = 301,
        DeviceCouldNotBeAddedGroupFull = 302,
        DeviceIsUnreachable = 304,
        UpdateOrDeleteGroupOfThisTypeNotAllowed = 305,
        LightAlreadyUsed = 306,
        SceneCouldNotBeCreated = 401,
        SceneCouldNotBeCreatedBufferFull = 402,
        SceneCouldNotBeRemoved = 403,
        NotAllowedToCreateSensorType = 501,
        SensorListIsFull = 502,
        RuleEngineFull = 601,
        ConditionError = 607,
        ActionError = 608,
        UnableToActivae = 609,
        ScheduleListIsFull = 701,
        ScheduleTimezoneNotValid = 702,
        ScheduleCannotSetTimeAndLocalTime = 703,
        CannotCreateSchedule = 704,
        CannotEnableScheduleTimeInPast = 705,
        CommandError = 706,
        SourceModelInvalid = 801,
        SourceFactoryNew = 802,
        InvalidState = 803;
        Other
    }
}

#[test]
fn bridge_errors() {
    use self::BridgeError::*;

    assert_eq!(BridgeError::from(101), LinkButtonNotPressed);
    assert_eq!(BridgeError::from(0), Other);
    assert_eq!(BridgeError::from(51234), Other);
    assert_eq!(BridgeError::from(4), MethodNotAvailableForResource);
    assert_eq!(SceneCouldNotBeRemoved as u16, 403);
    assert_eq!(InternalError as u16, 901);
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (eliza@elizas.website)
//
//  Copyright (c) 2015-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Macros to make our custom address types require a lot less repetitive code.
#[macro_export]
macro_rules! Addr {
    (($size:ty) $(pub)* enum $name:ident $($tail:tt)*) => {
        Addr! { @impl $name, $size }
    };
    (($size:ty) $(pub)* struct $name:ident $($tail:tt)*) => {
        Addr! { @impl $name, $size }
    };
    (@impl $ty:ident, $size:ty) => {

        impl ::core::fmt::Debug for $ty {
            fn fmt(&self, f: &mut ::core::fmt::Formatter)
                  -> ::core::fmt::Result {
                write!(f, "{}({:#x})", stringify!($ty), self.0)
            }
        }

        impl ::core::fmt::Pointer for $ty {
            fn fmt(&self, f: &mut ::core::fmt::Formatter)
                  -> ::core::fmt::Result {
                write!(f, "{:#x}", self.0)
            }
        }

        impl ::core::convert::Into<$size> for $ty {
            #[inline] fn into(self) -> $size { self.0 }
        }

        impl ::core::convert::From<$size> for $ty {
            #[inline] fn from(n: $size) -> Self { $ty(n) }
        }

        impl<T> ::core::convert::From<*mut T> for $ty {
            #[inline] fn from(ptr: *mut T) -> Self { $ty(ptr as $size) }
        }

        impl<T> ::core::convert::From<*const T> for $ty {
            #[inline] fn from(ptr: *const T) -> Self { $ty(ptr as $size) }
        }

        impl ::core::ops::Deref for $ty {
            type Target = $size;
            #[inline] fn deref(&self) -> &Self::Target { &self.0 }
        }

        impl $ty {
            #[inline(always)]
            pub const fn as_mut_ptr<T>(&self) -> *mut T { self.0 as *mut _ }

            #[inline(always)]
            pub const fn as_ptr<T>(&self) -> *const T { self.0 as *const _ }

            #[inline(always)]
            pub const fn new(value: $size) -> Self { $ty(value) }

        }

        impl_ops! {
            Add, add, + for $ty, $size
            Sub, sub, - for $ty, $size
            Div, div, / for $ty, $size
            Mul, mul, * for $ty, $size
            Shl, shl, >> for $ty, $size
            Shr, shr, << for $ty, $size
            Rem, rem, % for $ty, $size
            BitAnd, bitand, & for $ty, $size
            BitOr, bitor, | for $ty, $size
            BitXor, bitxor, ^ for $ty, $size

        }

        impl_assign_ops! {
            AddAssign, add_assign, += for $ty, $size
            SubAssign, sub_assign, -= for $ty, $size
            DivAssign, div_assign, /= for $ty, $size
            MulAssign, mul_assign, *= for $ty, $size
            ShlAssign, shl_assign, >>= for $ty, $size
            ShrAssign, shr_assign, <<= for $ty, $size
            RemAssign, rem_assign, %= for $ty, $size
            BitAndAssign, bitand_assign, &= for $ty, $size
            BitOrAssign, bitor_assign, |= for $ty, $size
            BitXorAssign, bitxor_assign, ^= for $ty, $size
        }

        impl_fmt! {
            Binary for $ty
            Display for $ty
            Octal for $ty
            LowerHex for $ty
            UpperHex for $ty
        }

        impl Addr for $ty {
            type Repr = $size;

            #[inline] fn align_down(&self, align: Self::Repr) -> Self {
                use util::Align;
                $ty ( self.0.align_down(align) )
            }

            #[inline] fn align_up(&self, align: Self::Repr) -> Self {
                use util::Align;
                // assert!(align.is_page_aligned());
                $ty ( self.0.align_up(align) )
            }

            #[inline] fn is_page_aligned(&self) -> bool {
                **self % PAGE_SIZE as <Self as Addr>::Repr == 0 as <Self as Addr>::Repr
            }
        }

    }
}

macro_rules! impl_page_ops {
    ($($name:ident, $fun:ident, $op:tt for $ty:ident, $size:ty)*) => {$(
        impl ::core::ops::$name<$ty> for $ty {
            type Output = Self;

            #[inline] fn $fun(self, rhs: $ty) -> Self {
                expr!( $ty { number: expr!(self.number $op rhs.number) })
            }
        }
        impl ::core::ops::$name<$size> for $ty {
            type Output = $ty;

            #[inline] fn $fun(self, rhs: $size) -> Self {
                expr!($ty{ number: expr!(self.number $op rhs) })
            }
        }

        forward_ref_binop! {
            $name, $fun for $ty, $ty
        }
        forward_ref_binop! {
            $name, $fun for $ty, $size
        }
    )*}
}

macro_rules! impl_page_assign_ops {
    ($($name:ident, $fun:ident, $op:tt for $ty:ident, $size:ty)*) => {$(
        impl ::core::ops::$name<$ty> for $ty {

            #[inline] fn $fun(&mut self, rhs: $ty) {
                expr!(self.number $op rhs.number);
            }
        }
        impl ::core::ops::$name<$size> for $ty {

            #[inline] fn $fun(&mut self, rhs: $size) {
                expr!(self.number $op rhs);
            }
        }
    )*}
}

macro_rules! Page {
    (($addr:ty) $(pub)* struct $name:ident $($tail:tt)*) => {
        Page! { @impl $name, $addr }
    };
    (@impl $ty:ident, $addr:ty) => {

        impl Page for $ty {
            type Address = $addr;

            /// Create a new `Page` containing the given address.
            //  TODO: rewrite this as `up`/`down` using the page shift, instead.
            fn containing(addr: $addr) -> Self {
                use ::PAGE_SHIFT;
                assert!( *addr < 0x0000_8000_0000_0000 ||
                         *addr >= 0xffff_8000_0000_0000
                       , "invalid address: 0x{:x}", addr );
                $ty { number: *addr >> PAGE_SHIFT as <Self::Address as Addr>::Repr }
            }

            /// Return the start address of this page
            #[inline]
            fn base(&self) -> $addr {
                Self::Address::from(
                    self.number << PAGE_SHIFT as <Self::Address as Addr>::Repr )
            }

            /// Return the end address of this page
            #[inline]
            fn end_address(&self) -> $addr {
                self.base() + PAGE_SIZE as <Self::Address as Addr>::Repr
            }

            #[inline] fn number(&self) -> usize {
                self.number as usize
            }
        }

        // impl ::core::num::One for $ty {
        //     #[inline] fn one() -> Self {
        //         $ty { number:
        //             <<$addr as Addr>::Repr as ::core::num::One>::one()
        //         }
        //     }
        // }

        impl ::core::iter::Step for $ty {
            #[inline]
            fn step(&self, by: &Self) -> Option<Self> {
                self.number
                    .step(&by.number)
                    .map(|s| $ty { number: s})
            }

            #[inline]
            #[allow(trivial_numeric_casts)]
            fn steps_between(start: &$ty, end: &$ty, by: &$ty)
                            -> Option<usize> {
                use ::core::iter::Step;
                <<$addr as Addr>::Repr as Step>::steps_between( &start.number
                                                              , &end.number
                                                              , &by.number
                                                              )
            }

            #[inline]
            fn steps_between_by_one(start: &$ty, end: &$ty) -> Option<usize> {
                use ::core::iter::Step;
                <<$addr as Addr>::Repr as Step>::steps_between( &start.number
                                                              , &end.number
                                                              , &1
                                                              )
            }

            #[inline] fn sub_one(&self) -> Self { self - 1 }

            #[inline] fn add_one(&self) -> Self { self + 1 }

            #[inline] fn replace_one(&mut self) -> Self { unimplemented!() }

            #[inline] fn replace_zero(&mut self) -> Self { unimplemented!() }

            #[inline] fn is_negative(&self) -> bool { unimplemented!(); }

        }

        impl<A> ::core::convert::From<A> for $ty
        where <Self as Page>::Address: ::core::convert::From<A> {
            #[inline] fn from(addr: A) -> Self {
                $ty::containing(<Self as Page>::Address::from(addr))
            }
        }

        impl_page_ops! {
            Add, add, + for $ty, <<$ty as Page>::Address as Addr>::Repr
            Sub, sub, - for $ty, <<$ty as Page>::Address as Addr>::Repr
            Div, div, / for $ty, <<$ty as Page>::Address as Addr>::Repr
            Mul, mul, * for $ty, <<$ty as Page>::Address as Addr>::Repr
            Shl, shl, >> for $ty,<<$ty as Page>::Address as Addr>::Repr
            Shr, shr, << for $ty, <<$ty as Page>::Address as Addr>::Repr
            Rem, rem, % for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitAnd, bitand, & for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitOr, bitor, | for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitXor, bitxor, ^ for $ty, <<$ty as Page>::Address as Addr>::Repr

        }

        impl_page_assign_ops! {
            AddAssign, add_assign, += for $ty, <<$ty as Page>::Address as Addr>::Repr
            SubAssign, sub_assign, -= for $ty, <<$ty as Page>::Address as Addr>::Repr
            DivAssign, div_assign, /= for $ty, <<$ty as Page>::Address as Addr>::Repr
            MulAssign, mul_assign, *= for $ty, <<$ty as Page>::Address as Addr>::Repr
            ShlAssign, shl_assign, >>= for $ty, <<$ty as Page>::Address as Addr>::Repr
            ShrAssign, shr_assign, <<= for $ty, <<$ty as Page>::Address as Addr>::Repr
            RemAssign, rem_assign, %= for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitAndAssign, bitand_assign, &= for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitOrAssign, bitor_assign, |= for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitXorAssign, bitxor_assign, ^= for $ty, <<$ty as Page>::Address as Addr>::Repr
        }
    }
}
<commit_msg>feat(memory::macros): add PartialEq/PartialOrd<Repr> instances to Addrs<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (eliza@elizas.website)
//
//  Copyright (c) 2015-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Macros to make our custom address types require a lot less repetitive code.
#[macro_export]
macro_rules! Addr {
    (($size:ty) $(pub)* enum $name:ident $($tail:tt)*) => {
        Addr! { @impl $name, $size }
    };
    (($size:ty) $(pub)* struct $name:ident $($tail:tt)*) => {
        Addr! { @impl $name, $size }
    };
    (@impl $ty:ident, $size:ty) => {

        impl ::core::fmt::Debug for $ty {
            fn fmt(&self, f: &mut ::core::fmt::Formatter)
                  -> ::core::fmt::Result {
                write!(f, "{}({:#x})", stringify!($ty), self.0)
            }
        }

        impl ::core::fmt::Pointer for $ty {
            fn fmt(&self, f: &mut ::core::fmt::Formatter)
                  -> ::core::fmt::Result {
                write!(f, "{:#x}", self.0)
            }
        }

        impl ::core::convert::Into<$size> for $ty {
            #[inline] fn into(self) -> $size { self.0 }
        }

        impl ::core::convert::From<$size> for $ty {
            #[inline] fn from(n: $size) -> Self { $ty(n) }
        }

        impl<T> ::core::convert::From<*mut T> for $ty {
            #[inline] fn from(ptr: *mut T) -> Self { $ty(ptr as $size) }
        }

        impl<T> ::core::convert::From<*const T> for $ty {
            #[inline] fn from(ptr: *const T) -> Self { $ty(ptr as $size) }
        }

        impl ::core::ops::Deref for $ty {
            type Target = $size;
            #[inline] fn deref(&self) -> &Self::Target { &self.0 }
        }

        impl $ty {
            #[inline(always)]
            pub const fn as_mut_ptr<T>(&self) -> *mut T { self.0 as *mut _ }

            #[inline(always)]
            pub const fn as_ptr<T>(&self) -> *const T { self.0 as *const _ }

            #[inline(always)]
            pub const fn new(value: $size) -> Self { $ty(value) }

        }

        impl_ops! {
            Add, add, + for $ty, $size
            Sub, sub, - for $ty, $size
            Div, div, / for $ty, $size
            Mul, mul, * for $ty, $size
            Shl, shl, >> for $ty, $size
            Shr, shr, << for $ty, $size
            Rem, rem, % for $ty, $size
            BitAnd, bitand, & for $ty, $size
            BitOr, bitor, | for $ty, $size
            BitXor, bitxor, ^ for $ty, $size

        }

        impl_assign_ops! {
            AddAssign, add_assign, += for $ty, $size
            SubAssign, sub_assign, -= for $ty, $size
            DivAssign, div_assign, /= for $ty, $size
            MulAssign, mul_assign, *= for $ty, $size
            ShlAssign, shl_assign, >>= for $ty, $size
            ShrAssign, shr_assign, <<= for $ty, $size
            RemAssign, rem_assign, %= for $ty, $size
            BitAndAssign, bitand_assign, &= for $ty, $size
            BitOrAssign, bitor_assign, |= for $ty, $size
            BitXorAssign, bitxor_assign, ^= for $ty, $size
        }

        impl_fmt! {
            Binary for $ty
            Display for $ty
            Octal for $ty
            LowerHex for $ty
            UpperHex for $ty
        }

        impl ::core::cmp::PartialEq<$size> for $ty {
            #[inline] fn eq(&self, rhs: &$size) -> bool {
                self.0 == *rhs
            }
        }

        impl ::core::cmp::PartialOrd<$size> for $ty {
            #[inline]
            fn partial_cmp(&self, rhs: &$size) -> Option<::core::cmp::Ordering> {
                self.0.partial_cmp(rhs)
            }
        }

        impl Addr for $ty {
            type Repr = $size;

            #[inline] fn align_down(&self, align: Self::Repr) -> Self {
                use util::Align;
                $ty ( self.0.align_down(align) )
            }

            #[inline] fn align_up(&self, align: Self::Repr) -> Self {
                use util::Align;
                // assert!(align.is_page_aligned());
                $ty ( self.0.align_up(align) )
            }

            #[inline] fn is_page_aligned(&self) -> bool {
                **self % PAGE_SIZE as <Self as Addr>::Repr == 0 as <Self as Addr>::Repr
            }
        }

    }
}

macro_rules! impl_page_ops {
    ($($name:ident, $fun:ident, $op:tt for $ty:ident, $size:ty)*) => {$(
        impl ::core::ops::$name<$ty> for $ty {
            type Output = Self;

            #[inline] fn $fun(self, rhs: $ty) -> Self {
                expr!( $ty { number: expr!(self.number $op rhs.number) })
            }
        }
        impl ::core::ops::$name<$size> for $ty {
            type Output = $ty;

            #[inline] fn $fun(self, rhs: $size) -> Self {
                expr!($ty{ number: expr!(self.number $op rhs) })
            }
        }

        forward_ref_binop! {
            $name, $fun for $ty, $ty
        }
        forward_ref_binop! {
            $name, $fun for $ty, $size
        }
    )*}
}

macro_rules! impl_page_assign_ops {
    ($($name:ident, $fun:ident, $op:tt for $ty:ident, $size:ty)*) => {$(
        impl ::core::ops::$name<$ty> for $ty {

            #[inline] fn $fun(&mut self, rhs: $ty) {
                expr!(self.number $op rhs.number);
            }
        }
        impl ::core::ops::$name<$size> for $ty {

            #[inline] fn $fun(&mut self, rhs: $size) {
                expr!(self.number $op rhs);
            }
        }
    )*}
}

macro_rules! Page {
    (($addr:ty) $(pub)* struct $name:ident $($tail:tt)*) => {
        Page! { @impl $name, $addr }
    };
    (@impl $ty:ident, $addr:ty) => {

        impl Page for $ty {
            type Address = $addr;

            /// Create a new `Page` containing the given address.
            //  TODO: rewrite this as `up`/`down` using the page shift, instead.
            fn containing(addr: $addr) -> Self {
                use ::PAGE_SHIFT;
                assert!( *addr < 0x0000_8000_0000_0000 ||
                         *addr >= 0xffff_8000_0000_0000
                       , "invalid address: 0x{:x}", addr );
                $ty { number: *addr >> PAGE_SHIFT as <Self::Address as Addr>::Repr }
            }

            /// Return the start address of this page
            #[inline]
            fn base(&self) -> $addr {
                Self::Address::from(
                    self.number << PAGE_SHIFT as <Self::Address as Addr>::Repr )
            }

            /// Return the end address of this page
            #[inline]
            fn end_address(&self) -> $addr {
                self.base() + PAGE_SIZE as <Self::Address as Addr>::Repr
            }

            #[inline] fn number(&self) -> usize {
                self.number as usize
            }
        }

        // impl ::core::num::One for $ty {
        //     #[inline] fn one() -> Self {
        //         $ty { number:
        //             <<$addr as Addr>::Repr as ::core::num::One>::one()
        //         }
        //     }
        // }

        impl ::core::iter::Step for $ty {
            #[inline]
            fn step(&self, by: &Self) -> Option<Self> {
                self.number
                    .step(&by.number)
                    .map(|s| $ty { number: s})
            }

            #[inline]
            #[allow(trivial_numeric_casts)]
            fn steps_between(start: &$ty, end: &$ty, by: &$ty)
                            -> Option<usize> {
                use ::core::iter::Step;
                <<$addr as Addr>::Repr as Step>::steps_between( &start.number
                                                              , &end.number
                                                              , &by.number
                                                              )
            }

            #[inline]
            fn steps_between_by_one(start: &$ty, end: &$ty) -> Option<usize> {
                use ::core::iter::Step;
                <<$addr as Addr>::Repr as Step>::steps_between( &start.number
                                                              , &end.number
                                                              , &1
                                                              )
            }

            #[inline] fn sub_one(&self) -> Self { self - 1 }

            #[inline] fn add_one(&self) -> Self { self + 1 }

            #[inline] fn replace_one(&mut self) -> Self { unimplemented!() }

            #[inline] fn replace_zero(&mut self) -> Self { unimplemented!() }

            #[inline] fn is_negative(&self) -> bool { unimplemented!(); }

        }

        impl<A> ::core::convert::From<A> for $ty
        where <Self as Page>::Address: ::core::convert::From<A> {
            #[inline] fn from(addr: A) -> Self {
                $ty::containing(<Self as Page>::Address::from(addr))
            }
        }

        impl_page_ops! {
            Add, add, + for $ty, <<$ty as Page>::Address as Addr>::Repr
            Sub, sub, - for $ty, <<$ty as Page>::Address as Addr>::Repr
            Div, div, / for $ty, <<$ty as Page>::Address as Addr>::Repr
            Mul, mul, * for $ty, <<$ty as Page>::Address as Addr>::Repr
            Shl, shl, >> for $ty,<<$ty as Page>::Address as Addr>::Repr
            Shr, shr, << for $ty, <<$ty as Page>::Address as Addr>::Repr
            Rem, rem, % for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitAnd, bitand, & for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitOr, bitor, | for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitXor, bitxor, ^ for $ty, <<$ty as Page>::Address as Addr>::Repr

        }

        impl_page_assign_ops! {
            AddAssign, add_assign, += for $ty, <<$ty as Page>::Address as Addr>::Repr
            SubAssign, sub_assign, -= for $ty, <<$ty as Page>::Address as Addr>::Repr
            DivAssign, div_assign, /= for $ty, <<$ty as Page>::Address as Addr>::Repr
            MulAssign, mul_assign, *= for $ty, <<$ty as Page>::Address as Addr>::Repr
            ShlAssign, shl_assign, >>= for $ty, <<$ty as Page>::Address as Addr>::Repr
            ShrAssign, shr_assign, <<= for $ty, <<$ty as Page>::Address as Addr>::Repr
            RemAssign, rem_assign, %= for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitAndAssign, bitand_assign, &= for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitOrAssign, bitor_assign, |= for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitXorAssign, bitxor_assign, ^= for $ty, <<$ty as Page>::Address as Addr>::Repr
        }
    }
}
<|endoftext|>


<commit_before>/// Eases forming of QVariantLists ([`QVariant`](struct.QVariant.html) of array).
///
/// # Examples
/// ```
/// # #[macro_use] extern crate qml;
/// # use qml::*;
/// # fn main() {
/// let shortcut: QVariant = qvarlist![["John", [2, 2]], ["Ivan", [10, 0]], ["Mary", [0, 1]]];
/// # }
/// ```
#[macro_export]
macro_rules! qvarlist{
    (__ $v:ident, [$($inside:tt)*], $($rest:tt)*) => {
        $v.push(qvarlist!($($inside)*).into());
        qvarlist!(__ $v, $($rest)*);
    };
    (__ $v:ident, [$($inside:tt)*]) => {
        $v.push(qvarlist!($($inside)*).into());
    };
    (__ $v:ident, $varname:expr, $($rest:tt)*) => {
        $v.push($varname.into());
        qvarlist!(__ $v, $($rest)*);
    };
    (__ $v:ident, $varname:expr) => {
        $v.push($varname.into());
    };
    ($($rest:tt)*) => {{
        let mut v: Vec<QVariant> = Vec::new();
        qvarlist!(__ v, $($rest)*);
        v
    }};
}

/// Marks the structure to be able to be used in Qt meta-object system.
///
/// # Examples
///
/// ```
/// #[macro_use] extern crate qml;
/// use qml::*;
/// pub struct Example;
///
/// impl Example {
///     pub fn simple_receiver(&mut self) {
///         // This is a function that also will be a slot
///     }
/// }
///
/// Q_OBJECT!(
/// pub Example as QExample{
///     signals:
///         fn simple_signal(s: String);
///     slots:
///         fn simple_receiver();
/// });
///
/// fn main() {
///    let mut qqae = QmlEngine::new();
///    let mut qobject = QExample::new(Example);
///    qobject.simple_signal("Hi from Rust!".into());
/// }
/// ```
#[macro_export]
macro_rules! Q_OBJECT{
    (
        pub $obj:ty as $wrapper:ident{
            signals:
            $(fn $signalname:ident ( $( $signalvar:ident : $signalqtype:ident ),* );)*

            slots:
            $(fn $slotname:ident ( $( $slotvar:ident : $slotqtype:ident ),* );)*

// properties
        }) =>{
            pub struct $wrapper{
                origin: Box<$obj>,
                ptr: QObject,
            }

            impl ::std::ops::Deref for $wrapper {
                type Target = $obj;

                fn deref(&self) -> &$obj {
                    let ref b: Box<$obj> = self.origin;
                    b.as_ref()
                }
            }

            impl ::std::ops::DerefMut for $wrapper {
                fn deref_mut<'a>(&'a mut self) -> &'a mut $obj {
                    self.origin.as_mut()
                }
            }

            impl $wrapper{
                $(pub fn $signalname(&self, $( $signalvar: $signalqtype ),*){
                    let mut vec: Vec<QVariant> = Vec::new();
                    $(
                        let $signalvar: $signalqtype = $signalvar;
                        vec.push($signalvar.into());
                    )*
                    emit_signal(self, stringify!($signalname), vec);
                    ::std::mem::forget(vec);
                })*

                pub fn new(origin: $obj) -> Box<Self>{
                    unsafe{
                        let mut local = $wrapper{
                            origin: Box::new(origin),
                            ptr: ::std::mem::uninitialized()
                        };
                        let mut local = Box::new(local);
                        let qobj = QObject::new(&mut *local);
                        local.ptr = qobj;
                        local
                    }
                }
            }

            impl QObjectMacro for $wrapper{
                fn qslot_call(&mut self, name: &str, args: Vec<QVariant>) {
                    println!("SWEET CALLBACK");
                    fn next_or_panic(qt: Option<QVariant>) -> QVariant{
                        if let Some(o) = qt {
                            o
                        }else {
                            panic!("Not enough parameters to call a slot")
                        }
                    }
                    match name {
                        $(stringify!($slotname) => {
                            let mut iter = args.into_iter();
                            $(
                                let next = next_or_panic (iter.next());
                                let $slotvar: $slotqtype = next.into();
                            )*
                            self.$slotname ($($slotvar),*);
                        },)*
                        _ => panic!("Unrecognized slot call: {}", name)
                    }
                }

                fn qmeta(&self) -> (Vec<(&str, i32, Vec<i32>)>, Vec<(&str, i32, i32, Vec<i32>)>, &'static str){
                    use qml::qtypes::*;
                    let mut signals = Vec::new();
                    $(
                        let mut argc = 0;
                        let mut mttypes = Vec::new();
                        $(
                            argc += 1;
                            mttypes.push($signalqtype::metatype() as i32);
                        )*
                        signals.push((stringify!($signalname), argc, mttypes));
                    )*
                    let mut slots = Vec::new();
                    $(
                        let $slotname = ();
                        let mut argc = 0;
                        let mut mttypes = Vec::new();
                        $(
                            argc += 1;
                            mttypes.push($slotqtype::metatype() as i32);
                        )*
                        slots.push((stringify!($slotname), 43, argc, mttypes));
                    )*
                    (signals, slots, stringify!($obj))
                }

                fn get_qobj(&self) -> &QObject{
                    &self.ptr
                }
            }
        };
    }
<commit_msg>Fixed a macro<commit_after>/// Eases forming of QVariantLists ([`QVariant`](struct.QVariant.html) of array).
///
/// # Examples
/// ```
/// # #[macro_use] extern crate qml;
/// # use qml::*;
/// # fn main() {
/// let shortcut: QVariant = qvarlist![["John", [2, 2]], ["Ivan", [10, 0]], ["Mary", [0, 1]]];
/// # }
/// ```
#[macro_export]
macro_rules! qvarlist{
    (__ $v:ident, [$($inside:tt)*], $($rest:tt)*) => {
        $v.push(qvarlist!($($inside)*).into());
        qvarlist!(__ $v, $($rest)*);
    };
    (__ $v:ident, [$($inside:tt)*]) => {
        $v.push(qvarlist!($($inside)*).into());
    };
    (__ $v:ident, $varname:expr, $($rest:tt)*) => {
        $v.push($varname.into());
        qvarlist!(__ $v, $($rest)*);
    };
    (__ $v:ident, $varname:expr) => {
        $v.push($varname.into());
    };
    ($($rest:tt)*) => {{
        let mut v: Vec<QVariant> = Vec::new();
        qvarlist!(__ v, $($rest)*);
        v
    }};
}

/// Marks the structure to be able to be used in Qt meta-object system.
///
/// # Examples
///
/// ```
/// #[macro_use] extern crate qml;
/// use qml::*;
/// pub struct Example;
///
/// impl Example {
///     pub fn simple_receiver(&mut self) {
///         // This is a function that also will be a slot
///     }
/// }
///
/// Q_OBJECT!(
/// pub Example as QExample{
///     signals:
///         fn simple_signal(s: String);
///     slots:
///         fn simple_receiver();
/// });
///
/// fn main() {
///    let mut qqae = QmlEngine::new();
///    let mut qobject = QExample::new(Example);
///    qobject.simple_signal("Hi from Rust!".into());
/// }
/// ```
#[macro_export]
macro_rules! Q_OBJECT{
    (
        pub $obj:ty as $wrapper:ident{
            signals:
            $(fn $signalname:ident ( $( $signalvar:ident : $signalqtype:ident ),* );)*

            slots:
            $(fn $slotname:ident ( $( $slotvar:ident : $slotqtype:ident ),* );)*

// properties
        }) =>{
            pub struct $wrapper{
                origin: Box<$obj>,
                ptr: QObject,
            }

            impl ::std::ops::Deref for $wrapper {
                type Target = $obj;

                fn deref(&self) -> &$obj {
                    let ref b: Box<$obj> = self.origin;
                    b.as_ref()
                }
            }

            impl ::std::ops::DerefMut for $wrapper {
                fn deref_mut<'a>(&'a mut self) -> &'a mut $obj {
                    self.origin.as_mut()
                }
            }

            impl $wrapper{
                $(pub fn $signalname(&self, $( $signalvar: $signalqtype ),*){
                    let mut vec: Vec<QVariant> = Vec::new();
                    $(
                        let $signalvar: $signalqtype = $signalvar;
                        vec.push($signalvar.into());
                    )*
                    emit_signal(self, stringify!($signalname), vec);
                })*

                pub fn new(origin: $obj) -> Box<Self>{
                    unsafe{
                        let mut local = $wrapper{
                            origin: Box::new(origin),
                            ptr: ::std::mem::uninitialized()
                        };
                        let mut local = Box::new(local);
                        let qobj = QObject::new(&mut *local);
                        local.ptr = qobj;
                        local
                    }
                }
            }

            impl QObjectMacro for $wrapper{
                fn qslot_call(&mut self, name: &str, args: Vec<QVariant>) {
                    println!("SWEET CALLBACK");
                    fn next_or_panic(qt: Option<QVariant>) -> QVariant{
                        if let Some(o) = qt {
                            o
                        }else {
                            panic!("Not enough parameters to call a slot")
                        }
                    }
                    match name {
                        $(stringify!($slotname) => {
                            let mut iter = args.into_iter();
                            $(
                                let next = next_or_panic (iter.next());
                                let $slotvar: $slotqtype = next.into();
                            )*
                            self.$slotname ($($slotvar),*);
                        },)*
                        _ => panic!("Unrecognized slot call: {}", name)
                    }
                }

                fn qmeta(&self) -> (Vec<(&str, i32, Vec<i32>)>, Vec<(&str, i32, i32, Vec<i32>)>, &'static str){
                    use qml::qtypes::*;
                    let mut signals = Vec::new();
                    $(
                        let mut argc = 0;
                        let mut mttypes = Vec::new();
                        $(
                            argc += 1;
                            mttypes.push($signalqtype::metatype() as i32);
                        )*
                        signals.push((stringify!($signalname), argc, mttypes));
                    )*
                    let mut slots = Vec::new();
                    $(
                        let $slotname = ();
                        let mut argc = 0;
                        let mut mttypes = Vec::new();
                        $(
                            argc += 1;
                            mttypes.push($slotqtype::metatype() as i32);
                        )*
                        slots.push((stringify!($slotname), 43, argc, mttypes));
                    )*
                    (signals, slots, stringify!($obj))
                }

                fn get_qobj(&self) -> &QObject{
                    &self.ptr
                }
            }
        };
    }
<|endoftext|>


<commit_before>extern crate hyper;
extern crate rustc_serialize;
extern crate rusqlite;
extern crate jmap;
extern crate time;

#[macro_use]
extern crate log;

mod logger;
mod db;
mod util;
mod record;

use std::default::Default;
use std::io::{Read, Write, ErrorKind};

use std::fs::File;

use hyper::server::{Request, Response};
use hyper::method::Method;
use hyper::method::Method::{Post, Get, Head};
use hyper::status::StatusCode;
use hyper::uri::RequestUri::AbsolutePath;
use hyper::header;

use rustc_serialize::json::{Json,ToJson};

use jmap::parse::FromJson;
use jmap::method::{RequestBatch, ResponseBatch, ResponseMethod};
use jmap::method::RequestMethod::*;
use jmap::method::ResponseMethod::*;

use util::RequestContext;
use record::RecordHandler;
use db::Db;

struct StatusBody {
    code: StatusCode,
    body: Option<Vec<u8>>
}
impl StatusBody {
    fn new(code: StatusCode, body: Option<Vec<u8>>) -> StatusBody {
        StatusBody { code: code, body: body }
    }
}

macro_rules! make_crud_method_dispatcher {
    ($method: expr, $rmethods: expr, $r: expr,
     $($ty: ty { $get: ident => $rget: ident, $set: ident => $rset: ident, $getup: ident => $rgetup: ident }),*) => {
        $rmethods = match $method {
            $(
                $get(args, id)
                    => vec!($r.get_records(&args).map(|a| $rget(a, id.clone())).unwrap_or_else(|e| ResponseError(e, id.clone()))),
                $set(args, id)
                    => vec!($r.set_records(&args).map(|a| $rset(a, id.clone())).unwrap_or_else(|e| ResponseError(e, id.clone()))),
                $getup(args, id) => $r.get_record_updates(&args).map(|a| {
                    match a {
                        (a, Some(b)) => vec!($rgetup(a, id.clone()), $rget(b, id.clone())),
                        (a, _)       => vec!($rgetup(a, id.clone())),
                    }
                }).unwrap_or_else(|e| vec!(ResponseError(e, id.clone()))),
            )*
            RequestError(args, id) => vec!(ResponseError(args, id)),
        };
    }
}

fn jmap_handler(mut req: Request) -> StatusBody {

    match Json::from_reader(&mut req) {
        Ok(j) => match RequestBatch::from_json(&j) {
            Ok(b) => {
                let mut rbatch: ResponseBatch = ResponseBatch::default();

                let r = RequestContext {
                    userid: 1, // XXX get userid from auth
                    db: Db::open().unwrap(),
                };

                for method in b.0.into_iter() {
                    let rmethods: Vec<ResponseMethod>;
                    make_crud_method_dispatcher!(method, rmethods, r,
                        Calendar {
                            GetCalendars       => Calendars,
                            SetCalendars       => CalendarsSet,
                            GetCalendarUpdates => CalendarUpdates
                        },
                        CalendarEvent {
                            GetCalendarEvents       => CalendarEvents,
                            SetCalendarEvents       => CalendarEventsSet,
                            GetCalendarEventUpdates => CalendarEventUpdates
                        },
                        Contact {
                            GetContacts       => Contacts,
                            SetContacts       => ContactsSet,
                            GetContactUpdates => ContactUpdates
                        },
                        ContactGroup {
                            GetContactGroups       => ContactGroups,
                            SetContactGroups       => ContactGroupsSet,
                            GetContactGroupUpdates => ContactGroupUpdates
                        },
                        Mailbox {
                            GetMailboxes      => Mailboxes,
                            SetMailboxes      => MailboxesSet,
                            GetMailboxUpdates => MailboxUpdates
                        }
                    );

                    rbatch.0.extend(rmethods.into_iter());
                }

                StatusBody::new(StatusCode::Ok, Some(rbatch.to_json().to_string().into_bytes()))
            },
            Err(e) =>
                StatusBody::new(StatusCode::BadRequest, Some(e.to_string().into_bytes())),
        },
        Err(e) => StatusBody::new(StatusCode::BadRequest, Some(e.to_string().into_bytes())),
    }
}

fn file_handler(path: &String, include_body: bool) -> StatusBody {
    match File::open(String::from("client") + if path == "/" { "/index.html" } else { path }) {
        Err(ref e) => match e.kind() {
            ErrorKind::NotFound => StatusBody::new(StatusCode::NotFound, None),
            // XXX others
            _ => StatusBody::new(StatusCode::InternalServerError, Some(format!("{}", e).into_bytes())),
        },
        Ok(ref mut f) => {
            match include_body {
                false => StatusBody::new(StatusCode::Ok, None),
                true  => {
                    let mut buf: Vec<u8> = vec!();
                    match f.read_to_end(&mut buf) {
                        Err(ref e) =>
                            StatusBody::new(StatusCode::InternalServerError, Some(format!("{}", e).into_bytes())),
                        _ =>
                            StatusBody::new(StatusCode::Ok, Some(buf)),
                    }
                },
            }
        },
    }
}

fn finish_response(method: Method, path: &String, mut res: Response, out: StatusBody) {
    *res.status_mut() = out.code;

    info!("HTTP: {} {} => {}", method, path, out.code);

    match res.start()
        .and_then(|mut res|
                  match out.body {
                      Some(ref b) => {
                          try!(res.write_all(b));
                          Ok(res)
                      }
                      None => {
                          Ok(res)
                      }
                  })
        .and_then(|res| res.end()) {
            Err(e) => error!("response error: {}", e),
            _      => (),
        };
}

fn http_handler(mut req: Request, mut res: Response) {
    res.headers_mut().set(header::Server("salada/0.0.5".to_string()));

    let method = req.method.clone();
    let uri = req.uri.clone();

    match (method, uri) {
        (Post, AbsolutePath(ref path)) if path == "/jmap/" =>
            finish_response(Post, path, res, jmap_handler(req)),

        (Get, AbsolutePath(ref path)) =>
            finish_response(Get, path, res, file_handler(path, true)),

        (Head, AbsolutePath(ref path)) =>
            finish_response(Head, path, res, file_handler(path, false)),

        (_, ref ap) => {
            let s = match ap {
                &AbsolutePath(ref u) => u,
                _ => panic!("RequestUri not AbsolutePath?"),
            };
            let mut drain: Vec<u8> = vec!();
            req.read_to_end(&mut drain).ok();
            finish_response(req.method, &s, res, StatusBody::new(StatusCode::MethodNotAllowed, None))
        },
    };
}

fn main() {
    logger::init().unwrap();

    info!("Listening on http://127.0.0.1:3000/jmap");
    hyper::Server::http("127.0.0.1:3000").unwrap().handle(http_handler).unwrap();
}
<commit_msg>Ignore URL query and fragment parts when finding file to serve<commit_after>extern crate hyper;
extern crate rustc_serialize;
extern crate rusqlite;
extern crate jmap;
extern crate time;

#[macro_use]
extern crate log;

mod logger;
mod db;
mod util;
mod record;

use std::default::Default;
use std::io::{Read, Write, ErrorKind};

use std::fs::File;

use hyper::server::{Request, Response};
use hyper::method::Method;
use hyper::method::Method::{Post, Get, Head};
use hyper::status::StatusCode;
use hyper::uri::RequestUri::AbsolutePath;
use hyper::header;

use rustc_serialize::json::{Json,ToJson};

use jmap::parse::FromJson;
use jmap::method::{RequestBatch, ResponseBatch, ResponseMethod};
use jmap::method::RequestMethod::*;
use jmap::method::ResponseMethod::*;

use util::RequestContext;
use record::RecordHandler;
use db::Db;

struct StatusBody {
    code: StatusCode,
    body: Option<Vec<u8>>
}
impl StatusBody {
    fn new(code: StatusCode, body: Option<Vec<u8>>) -> StatusBody {
        StatusBody { code: code, body: body }
    }
}

macro_rules! make_crud_method_dispatcher {
    ($method: expr, $rmethods: expr, $r: expr,
     $($ty: ty { $get: ident => $rget: ident, $set: ident => $rset: ident, $getup: ident => $rgetup: ident }),*) => {
        $rmethods = match $method {
            $(
                $get(args, id)
                    => vec!($r.get_records(&args).map(|a| $rget(a, id.clone())).unwrap_or_else(|e| ResponseError(e, id.clone()))),
                $set(args, id)
                    => vec!($r.set_records(&args).map(|a| $rset(a, id.clone())).unwrap_or_else(|e| ResponseError(e, id.clone()))),
                $getup(args, id) => $r.get_record_updates(&args).map(|a| {
                    match a {
                        (a, Some(b)) => vec!($rgetup(a, id.clone()), $rget(b, id.clone())),
                        (a, _)       => vec!($rgetup(a, id.clone())),
                    }
                }).unwrap_or_else(|e| vec!(ResponseError(e, id.clone()))),
            )*
            RequestError(args, id) => vec!(ResponseError(args, id)),
        };
    }
}

fn jmap_handler(mut req: Request) -> StatusBody {

    match Json::from_reader(&mut req) {
        Ok(j) => match RequestBatch::from_json(&j) {
            Ok(b) => {
                let mut rbatch: ResponseBatch = ResponseBatch::default();

                let r = RequestContext {
                    userid: 1, // XXX get userid from auth
                    db: Db::open().unwrap(),
                };

                for method in b.0.into_iter() {
                    let rmethods: Vec<ResponseMethod>;
                    make_crud_method_dispatcher!(method, rmethods, r,
                        Calendar {
                            GetCalendars       => Calendars,
                            SetCalendars       => CalendarsSet,
                            GetCalendarUpdates => CalendarUpdates
                        },
                        CalendarEvent {
                            GetCalendarEvents       => CalendarEvents,
                            SetCalendarEvents       => CalendarEventsSet,
                            GetCalendarEventUpdates => CalendarEventUpdates
                        },
                        Contact {
                            GetContacts       => Contacts,
                            SetContacts       => ContactsSet,
                            GetContactUpdates => ContactUpdates
                        },
                        ContactGroup {
                            GetContactGroups       => ContactGroups,
                            SetContactGroups       => ContactGroupsSet,
                            GetContactGroupUpdates => ContactGroupUpdates
                        },
                        Mailbox {
                            GetMailboxes      => Mailboxes,
                            SetMailboxes      => MailboxesSet,
                            GetMailboxUpdates => MailboxUpdates
                        }
                    );

                    rbatch.0.extend(rmethods.into_iter());
                }

                StatusBody::new(StatusCode::Ok, Some(rbatch.to_json().to_string().into_bytes()))
            },
            Err(e) =>
                StatusBody::new(StatusCode::BadRequest, Some(e.to_string().into_bytes())),
        },
        Err(e) => StatusBody::new(StatusCode::BadRequest, Some(e.to_string().into_bytes())),
    }
}

fn file_handler(path: &String, include_body: bool) -> StatusBody {
    let mut filepath: String = (*path).clone();
    if let Some(n) = filepath.find(|c| c == '?' || c == '#') {
        filepath.truncate(n);
    }

    match File::open(String::from("client") + if filepath == "/" { "/index.html" } else { filepath.as_ref() }) {
        Err(ref e) => match e.kind() {
            ErrorKind::NotFound => StatusBody::new(StatusCode::NotFound, None),
            // XXX others
            _ => StatusBody::new(StatusCode::InternalServerError, Some(format!("{}", e).into_bytes())),
        },
        Ok(ref mut f) => {
            match include_body {
                false => StatusBody::new(StatusCode::Ok, None),
                true  => {
                    let mut buf: Vec<u8> = vec!();
                    match f.read_to_end(&mut buf) {
                        Err(ref e) =>
                            StatusBody::new(StatusCode::InternalServerError, Some(format!("{}", e).into_bytes())),
                        _ =>
                            StatusBody::new(StatusCode::Ok, Some(buf)),
                    }
                },
            }
        },
    }
}

fn finish_response(method: Method, path: &String, mut res: Response, out: StatusBody) {
    *res.status_mut() = out.code;

    info!("HTTP: {} {} => {}", method, path, out.code);

    match res.start()
        .and_then(|mut res|
                  match out.body {
                      Some(ref b) => {
                          try!(res.write_all(b));
                          Ok(res)
                      }
                      None => {
                          Ok(res)
                      }
                  })
        .and_then(|res| res.end()) {
            Err(e) => error!("response error: {}", e),
            _      => (),
        };
}

fn http_handler(mut req: Request, mut res: Response) {
    res.headers_mut().set(header::Server("salada/0.0.5".to_string()));

    let method = req.method.clone();
    let uri = req.uri.clone();

    match (method, uri) {
        (Post, AbsolutePath(ref path)) if path == "/jmap/" =>
            finish_response(Post, path, res, jmap_handler(req)),

        (Get, AbsolutePath(ref path)) =>
            finish_response(Get, path, res, file_handler(path, true)),

        (Head, AbsolutePath(ref path)) =>
            finish_response(Head, path, res, file_handler(path, false)),

        (_, ref ap) => {
            let s = match ap {
                &AbsolutePath(ref u) => u,
                _ => panic!("RequestUri not AbsolutePath?"),
            };
            let mut drain: Vec<u8> = vec!();
            req.read_to_end(&mut drain).ok();
            finish_response(req.method, &s, res, StatusBody::new(StatusCode::MethodNotAllowed, None))
        },
    };
}

fn main() {
    logger::init().unwrap();

    info!("Listening on http://127.0.0.1:3000/jmap");
    hyper::Server::http("127.0.0.1:3000").unwrap().handle(http_handler).unwrap();
}
<|endoftext|>


<commit_before>
use wca::*;
use maplit::hashmap;

//

#[test]
fn basic()
{

  let command = CommandOptions::default()
  .hint( "hint" )
  .long_hint( "long_hint" )
  .phrase( "phrase" )
  .subject_hint( "subject_hint" )
  .property_hint( "prop1", "hint of prop1" )
  .property_hint( "prop2", "hint of prop2" )
  .property_alias( "property_alias", "a1" )
  .property_alias( "property_alias", "a2" )
  .routine( &|| { println!( "hello" ) } )
  .form()
  ;

  dbg!( &command );

  assert_eq!( command.hint, "hint".to_string() );
  assert_eq!( command.long_hint, "long_hint".to_string() );
  assert_eq!( command.phrase, "phrase".to_string() );
  assert_eq!( command.subject_hint, "subject_hint".to_string() );

  let properties_hints = hashmap!
  {
    "prop1".to_string() => "hint of prop1".to_string(),
    "prop2".to_string() => "hint of prop2".to_string(),
  };
  assert_eq!( command.properties_hints, properties_hints );

  let properties_aliases = hashmap!
  {
    "property_alias".to_string() => vec![ "a1".to_string(), "a2".to_string() ],
  };
  assert_eq!( command.properties_aliases, properties_aliases );

}

//

#[test]
fn shortcut()
{

  let command = CommandOptions::default()
  .h( "hint2" )
  .lh( "long_hint2" )
  .ro( &|| { println!( "hello" ) } )
  .form()
  ;

  dbg!( &command );

  assert_eq!( command.hint, "hint2".to_string() );
  assert_eq!( command.long_hint, "long_hint2".to_string() );
  assert_eq!( command.phrase, "".to_string() );
  assert_eq!( command.subject_hint, "".to_string() );

}
<commit_msg>Write test routine `callback_trivial`<commit_after>
use wca::*;
use maplit::hashmap;
use wtest_basic::*;

//

fn _basic()
{
  let command = CommandOptions::default()
  .hint( "hint" )
  .long_hint( "long_hint" )
  .phrase( "phrase" )
  .subject_hint( "subject_hint" )
  .property_hint( "prop1", "hint of prop1" )
  .property_hint( "prop2", "hint of prop2" )
  .property_alias( "property_alias", "a1" )
  .property_alias( "property_alias", "a2" )
  .routine( &| _i : &instruction::Instruction | { println!( "hello" ); Ok( () ) } )
  .form();

  dbg!( &command );

  assert_eq!( command.hint, "hint".to_string() );
  assert_eq!( command.long_hint, "long_hint".to_string() );
  assert_eq!( command.phrase, "phrase".to_string() );
  assert_eq!( command.subject_hint, "subject_hint".to_string() );

  let properties_hints = hashmap!
  {
    "prop1".to_string() => "hint of prop1".to_string(),
    "prop2".to_string() => "hint of prop2".to_string(),
  };
  assert_eq!( command.properties_hints, properties_hints );

  let properties_aliases = hashmap!
  {
    "property_alias".to_string() => vec![ "a1".to_string(), "a2".to_string() ],
  };
  assert_eq!( command.properties_aliases, properties_aliases );
}

//

fn _shortcut()
{
  let command = CommandOptions::default()
  .h( "hint2" )
  .lh( "long_hint2" )
  .ro( &| _i : &instruction::Instruction | { println!( "hello" ); Ok( () ) } )
  .form();

  dbg!( &command );

  assert_eq!( command.hint, "hint2".to_string() );
  assert_eq!( command.long_hint, "long_hint2".to_string() );
  assert_eq!( command.phrase, "".to_string() );
  assert_eq!( command.subject_hint, "".to_string() );
}

//

fn _callback_trivial()
{
  let command = CommandOptions::default()
  .hint( "hint" )
  .long_hint( "long_hint" )
  .phrase( "phrase" )
  .subject_hint( "subject_hint" )
  .property_hint( "prop1", "hint of prop1" )
  .property_hint( "prop2", "hint of prop2" )
  .property_alias( "property_alias", "a1" )
  .property_alias( "property_alias", "a2" )
  .routine( &| _i : &instruction::Instruction | { println!( "hello" ); Ok( () ) } )
  .form();

  let perform = command.perform( &instruction::Instruction::default() );
  assert!( perform.is_ok() );
}

//

test_suite!
{
  basic,
  shortcut,
  callback_trivial,
}

<|endoftext|>