<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use platform::{Application, Window};

use windowing::{ApplicationMethods, WindowEvent, WindowMethods};
use windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass};
use windowing::{ScrollWindowEvent, ZoomWindowEvent, NavigationWindowEvent, FinishedWindowEvent};
use windowing::{QuitWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};

use servo_msg::constellation_msg::{ConstellationChan, NavigateMsg, ResizedWindowMsg, LoadUrlMsg};
use servo_msg::constellation_msg;

use azure::azure_hl::SourceSurfaceMethods;
use azure::azure_hl;
use std::comm::Port;
use std::num::Orderable;
use std::vec;
use std::path::Path;
use std::rt::io::timer::Timer;
use geom::matrix::identity;
use geom::point::Point2D;
use geom::size::Size2D;
use geom::rect::Rect;
use layers::layers::{ContainerLayer, ContainerLayerKind};
use layers::rendergl;
use layers::scene::Scene;
use opengles::gl2;
use png;
use servo_util::{time, url};
use servo_util::time::profile;

use extra::future::Future;
use extra::time::precise_time_s;

use compositing::compositor_layer::CompositorLayer;

use compositing::*;

/// Starts the compositor, which listens for messages on the specified port.
pub fn run_compositor(compositor: &CompositorTask) {
    let app: Application = ApplicationMethods::new();
    let window: @mut Window = WindowMethods::new(&app);

    // Create an initial layer tree.
    //
    // TODO: There should be no initial layer tree until the renderer creates one from the display
    // list. This is only here because we don't have that logic in the renderer yet.
    let context = rendergl::init_render_context();
    let root_layer = @mut ContainerLayer();
    let window_size = window.size();
    let mut scene = Scene(ContainerLayerKind(root_layer), window_size, identity());
    let mut window_size = Size2D(window_size.width as uint, window_size.height as uint);
    let mut done = false;
    let mut recomposite = false;
    let graphics_context = CompositorTask::create_graphics_context();

    // Keeps track of the current zoom factor
    let mut world_zoom = 1f32;
    let mut zoom_action = false;
    let mut zoom_time = 0f64;

    // The root CompositorLayer
    let mut compositor_layer: Option<CompositorLayer> = None;
    let mut constellation_chan: Option<ConstellationChan> = None;

    // Get BufferRequests from each layer.
    let ask_for_tiles = || {
        let window_size_page = Size2D(window_size.width as f32 / world_zoom,
                                      window_size.height as f32 / world_zoom);
        for layer in compositor_layer.mut_iter() {
            if !layer.hidden {
                let rect = Rect(Point2D(0f32, 0f32), window_size_page);
                recomposite = layer.get_buffer_request(&graphics_context, rect, world_zoom) ||
                    recomposite;
            } else {
                debug!("Compositor: root layer is hidden!");
            }
        }
    };

    let check_for_messages: &fn(&Port<Msg>) = |port: &Port<Msg>| {
        // Handle messages
        while port.peek() {
            match port.recv() {
                Exit => done = true,

                ChangeReadyState(ready_state) => window.set_ready_state(ready_state),
                ChangeRenderState(render_state) => window.set_render_state(render_state),

                SetIds(frame_tree, response_chan, new_constellation_chan) => {
                    response_chan.send(());

                    // This assumes there is at most one child, which should be the case.
                    match root_layer.first_child {
                        Some(old_layer) => root_layer.remove_child(old_layer),
                        None => {}
                    }

                    let layer = CompositorLayer::from_frame_tree(frame_tree,
                                                                 compositor.opts.tile_size,
                                                                 Some(10000000u),
                                                                 compositor.opts.cpu_painting);
                    root_layer.add_child_start(ContainerLayerKind(layer.root_layer));

                    // If there's already a root layer, destroy it cleanly.
                    match compositor_layer {
                        None => {}
                        Some(ref mut compositor_layer) => compositor_layer.clear_all(),
                    }

                    compositor_layer = Some(layer);
                    constellation_chan = Some(new_constellation_chan);
                }

                GetSize(chan) => {
                    let size = window.size();
                    chan.send(Size2D(size.width as int, size.height as int));
                }

                GetGraphicsMetadata(chan) => chan.send(azure_hl::current_graphics_metadata()),

                NewLayer(_id, new_size) => {
                    // FIXME: This should create an additional layer instead of replacing the current one.
                    // Once ResizeLayer messages are set up, we can switch to the new functionality.

                    let p = match compositor_layer {
                        Some(ref compositor_layer) => compositor_layer.pipeline.clone(),
                        None => fail!("Compositor: Received new layer without initialized pipeline"),
                    };
                    let page_size = Size2D(new_size.width as f32, new_size.height as f32);
                    let new_layer = CompositorLayer::new(p,
                                                         Some(page_size),
                                                         compositor.opts.tile_size,
                                                         Some(10000000u),
                                                         compositor.opts.cpu_painting);

                    let current_child = root_layer.first_child;
                    // This assumes there is at most one child, which should be the case.
                    match current_child {
                        Some(old_layer) => root_layer.remove_child(old_layer),
                        None => {}
                    }
                    root_layer.add_child_start(ContainerLayerKind(new_layer.root_layer));
                    compositor_layer = Some(new_layer);

                    ask_for_tiles();
                }

                SetLayerPageSize(id, new_size, epoch) => {
                    match compositor_layer {
                        Some(ref mut layer) => {
                            let page_window = Size2D(window_size.width as f32 / world_zoom,
                                                     window_size.height as f32 / world_zoom);
                            assert!(layer.resize(id, new_size, page_window, epoch));
                            ask_for_tiles();
                        }
                        None => {}
                    }
                }

                SetLayerClipRect(id, new_rect) => {
                    match compositor_layer {
                        Some(ref mut layer) => {
                            assert!(layer.set_clipping_rect(id, new_rect));
                            ask_for_tiles();
                        }
                        None => {}
                    }
                }

                DeleteLayer(id) => {
                    match compositor_layer {
                        Some(ref mut layer) => {
                            assert!(layer.delete(&graphics_context, id));
                            ask_for_tiles();
                        }
                        None => {}
                    }
                }

                Paint(id, new_layer_buffer_set, epoch) => {
                    debug!("osmain: received new frame");

                    // From now on, if we destroy the buffers, they will leak.
                    let mut new_layer_buffer_set = new_layer_buffer_set;
                    new_layer_buffer_set.mark_will_leak();

                    match compositor_layer {
                        Some(ref mut layer) => {
                            assert!(layer.add_buffers(&graphics_context,
                                                      id,
                                                      new_layer_buffer_set,
                                                      epoch).is_none());
                            recomposite = true;
                        }
                        None => {
                            fail!("Compositor: given paint command with no CompositorLayer initialized");
                        }
                    }
                    // TODO: Recycle the old buffers; send them back to the renderer to reuse if
                    // it wishes.
                }

                InvalidateRect(id, rect) => {
                    match compositor_layer {
                        Some(ref mut layer) => {
                            layer.invalidate_rect(id, Rect(Point2D(rect.origin.x as f32,
                                                                   rect.origin.y as f32),
                                                           Size2D(rect.size.width as f32,
                                                                  rect.size.height as f32)));
                            ask_for_tiles();
                        }
                        None => {} // Nothing to do
                    }
                }
            }
        }
    };

    let check_for_window_messages: &fn(WindowEvent) = |event| {
        match event {
            IdleWindowEvent => {}

            ResizeWindowEvent(width, height) => {
                let new_size = Size2D(width, height);
                if window_size != new_size {
                    debug!("osmain: window resized to %ux%u", width, height);
                    window_size = new_size;
                    match constellation_chan {
                        Some(ref chan) => chan.send(ResizedWindowMsg(new_size)),
                        None => error!("Compositor: Recieved resize event without initialized layout chan"),
                    }
                } else {
                    debug!("osmain: dropping window resize since size is still %ux%u", width, height);
                }
            }

            LoadUrlWindowEvent(url_string) => {
                debug!("osmain: loading URL `%s`", url_string);
                let root_pipeline_id = match compositor_layer {
                    Some(ref layer) => layer.pipeline.id.clone(),
                    None => fail!("Compositor: Received LoadUrlWindowEvent without initialized compositor layers"),
                };
                match constellation_chan {
                    Some(ref chan) => chan.send(LoadUrlMsg(root_pipeline_id,
                                                           url::make_url(url_string.to_str(), None),
                                                           Future::from_value(window_size))),
                    None => error!("Compositor: Recieved loadurl event without initialized layout chan"),
                }
            }

            MouseWindowEventClass(mouse_window_event) => {
                let point = match mouse_window_event {
                    MouseWindowClickEvent(_, p) => Point2D(p.x / world_zoom, p.y / world_zoom),
                    MouseWindowMouseDownEvent(_, p) => Point2D(p.x / world_zoom, p.y / world_zoom),
                    MouseWindowMouseUpEvent(_, p) => Point2D(p.x / world_zoom, p.y / world_zoom),
                };
                for layer in compositor_layer.iter() {
                    layer.send_mouse_event(mouse_window_event, point);
                }
            }

            ScrollWindowEvent(delta, cursor) => {
                // TODO: modify delta to snap scroll to pixels.
                let page_delta = Point2D(delta.x as f32 / world_zoom, delta.y as f32 / world_zoom);
                let page_cursor: Point2D<f32> = Point2D(cursor.x as f32 / world_zoom,
                                                        cursor.y as f32 / world_zoom);
                let page_window = Size2D(window_size.width as f32 / world_zoom,
                                         window_size.height as f32 / world_zoom);
                for layer in compositor_layer.mut_iter() {
                    recomposite = layer.scroll(page_delta, page_cursor, page_window) || recomposite;
                }
                ask_for_tiles();
            }

            ZoomWindowEvent(magnification) => {
                zoom_action = true;
                zoom_time = precise_time_s();
                let old_world_zoom = world_zoom;

                // Determine zoom amount
                world_zoom = (world_zoom * magnification).max(&1.0);
                root_layer.common.set_transform(identity().scale(world_zoom, world_zoom, 1f32));

                // Scroll as needed
                let page_delta = Point2D(window_size.width as f32 * (1.0 / world_zoom - 1.0 / old_world_zoom) * 0.5,
                                         window_size.height as f32 * (1.0 / world_zoom - 1.0 / old_world_zoom) * 0.5);
                // TODO: modify delta to snap scroll to pixels.
                let page_cursor = Point2D(-1f32, -1f32); // Make sure this hits the base layer
                let page_window = Size2D(window_size.width as f32 / world_zoom,
                                         window_size.height as f32 / world_zoom);
                for layer in compositor_layer.mut_iter() {
                    layer.scroll(page_delta, page_cursor, page_window);
                }

                recomposite = true;
            }

            NavigationWindowEvent(direction) => {
                let direction = match direction {
                    windowing::Forward => constellation_msg::Forward,
                    windowing::Back => constellation_msg::Back,
                };
                match constellation_chan {
                    Some(ref chan) => chan.send(NavigateMsg(direction)),
                    None => error!("Compositor: Recieved navigation event without initialized layout chan"),
                }
            }

            FinishedWindowEvent => {
                if compositor.opts.exit_after_load {
                    done = true;
                }
            }

            QuitWindowEvent => {
                done = true;
            }
        }
    };

    let profiler_chan = compositor.profiler_chan.clone();
    let write_png = compositor.opts.output_file.is_some();
    let exit = compositor.opts.exit_after_load;
    let composite = || {
        do profile(time::CompositingCategory, profiler_chan.clone()) {
            debug!("compositor: compositing");
            // Adjust the layer dimensions as necessary to correspond to the size of the window.
            scene.size = window.size();

            // Render the scene.
            rendergl::render_scene(context, &scene);
        }

        // Render to PNG. We must read from the back buffer (ie, before
        // window.present()) as OpenGL ES 2 does not have glReadBuffer().
        if write_png {
            let (width, height) = (window_size.width as uint, window_size.height as uint);
            let path = from_str::<Path>(*compositor.opts.output_file.get_ref()).unwrap();
            let mut pixels = gl2::read_pixels(0, 0,
                                              width as gl2::GLsizei,
                                              height as gl2::GLsizei,
                                              gl2::RGB, gl2::UNSIGNED_BYTE);
            // flip image vertically (texture is upside down)
            let orig_pixels = pixels.clone();
            let stride = width * 3;
            for y in range(0, height) {
                let dst_start = y * stride;
                let src_start = (height - y - 1) * stride;
                vec::bytes::copy_memory(pixels.mut_slice(dst_start, dst_start + stride),
                                        orig_pixels.slice(src_start, src_start + stride),
                                        stride);
            }
            let img = png::Image {
                width: width as u32,
                height: height as u32,
                color_type: png::RGB8,
                pixels: pixels,
            };
            let res = png::store_png(&img, &path);
            assert!(res.is_ok());

            done = true;
        }

        window.present();

        if exit { done = true; }
    };

    // Enter the main event loop.
    let mut tm = Timer::new().unwrap();
    while !done {
        // Check for new messages coming from the rendering task.
        check_for_messages(&compositor.port);

        // Check for messages coming from the windowing system.
        check_for_window_messages(window.recv());

        if recomposite {
            recomposite = false;
            composite();
        }

        tm.sleep(10);

        // If a pinch-zoom happened recently, ask for tiles at the new resolution
        if zoom_action && precise_time_s() - zoom_time > 0.3 {
            zoom_action = false;
            ask_for_tiles();
        }

    }

    compositor.shutdown_chan.send(());

    // Clear out the compositor layers so that painting tasks can destroy the buffers.
    match compositor_layer {
        None => {}
        Some(ref mut layer) => layer.forget_all_tiles(),
    }
}
<commit_msg>auto merge of #1151 : guersam/servo/patch-1, r=metajack<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use platform::{Application, Window};

use windowing::{ApplicationMethods, WindowEvent, WindowMethods};
use windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass};
use windowing::{ScrollWindowEvent, ZoomWindowEvent, NavigationWindowEvent, FinishedWindowEvent};
use windowing::{QuitWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};

use servo_msg::constellation_msg::{ConstellationChan, NavigateMsg, ResizedWindowMsg, LoadUrlMsg};
use servo_msg::constellation_msg;

use azure::azure_hl::SourceSurfaceMethods;
use azure::azure_hl;
use std::comm::Port;
use std::num::Orderable;
use std::vec;
use std::path::Path;
use std::rt::io::timer::Timer;
use geom::matrix::identity;
use geom::point::Point2D;
use geom::size::Size2D;
use geom::rect::Rect;
use layers::layers::{ContainerLayer, ContainerLayerKind};
use layers::rendergl;
use layers::scene::Scene;
use opengles::gl2;
use png;
use servo_util::{time, url};
use servo_util::time::profile;

use extra::future::Future;
use extra::time::precise_time_s;

use compositing::compositor_layer::CompositorLayer;

use compositing::*;

/// Starts the compositor, which listens for messages on the specified port.
pub fn run_compositor(compositor: &CompositorTask) {
    let app: Application = ApplicationMethods::new();
    let window: @mut Window = WindowMethods::new(&app);

    // Create an initial layer tree.
    //
    // TODO: There should be no initial layer tree until the renderer creates one from the display
    // list. This is only here because we don't have that logic in the renderer yet.
    let context = rendergl::init_render_context();
    let root_layer = @mut ContainerLayer();
    let window_size = window.size();
    let mut scene = Scene(ContainerLayerKind(root_layer), window_size, identity());
    let mut window_size = Size2D(window_size.width as uint, window_size.height as uint);
    let mut done = false;
    let mut recomposite = false;
    let graphics_context = CompositorTask::create_graphics_context();

    // Keeps track of the current zoom factor
    let mut world_zoom = 1f32;
    let mut zoom_action = false;
    let mut zoom_time = 0f64;

    // The root CompositorLayer
    let mut compositor_layer: Option<CompositorLayer> = None;
    let mut constellation_chan: Option<ConstellationChan> = None;

    // Get BufferRequests from each layer.
    let ask_for_tiles = || {
        let window_size_page = Size2D(window_size.width as f32 / world_zoom,
                                      window_size.height as f32 / world_zoom);
        for layer in compositor_layer.mut_iter() {
            if !layer.hidden {
                let rect = Rect(Point2D(0f32, 0f32), window_size_page);
                recomposite = layer.get_buffer_request(&graphics_context, rect, world_zoom) ||
                    recomposite;
            } else {
                debug!("Compositor: root layer is hidden!");
            }
        }
    };

    let check_for_messages: &fn(&Port<Msg>) = |port: &Port<Msg>| {
        // Handle messages
        while port.peek() {
            match port.recv() {
                Exit => done = true,

                ChangeReadyState(ready_state) => window.set_ready_state(ready_state),
                ChangeRenderState(render_state) => window.set_render_state(render_state),

                SetIds(frame_tree, response_chan, new_constellation_chan) => {
                    response_chan.send(());

                    // This assumes there is at most one child, which should be the case.
                    match root_layer.first_child {
                        Some(old_layer) => root_layer.remove_child(old_layer),
                        None => {}
                    }

                    let layer = CompositorLayer::from_frame_tree(frame_tree,
                                                                 compositor.opts.tile_size,
                                                                 Some(10000000u),
                                                                 compositor.opts.cpu_painting);
                    root_layer.add_child_start(ContainerLayerKind(layer.root_layer));

                    // If there's already a root layer, destroy it cleanly.
                    match compositor_layer {
                        None => {}
                        Some(ref mut compositor_layer) => compositor_layer.clear_all(),
                    }

                    compositor_layer = Some(layer);
                    constellation_chan = Some(new_constellation_chan);
                }

                GetSize(chan) => {
                    let size = window.size();
                    chan.send(Size2D(size.width as int, size.height as int));
                }

                GetGraphicsMetadata(chan) => chan.send(azure_hl::current_graphics_metadata()),

                NewLayer(_id, new_size) => {
                    // FIXME: This should create an additional layer instead of replacing the current one.
                    // Once ResizeLayer messages are set up, we can switch to the new functionality.

                    let p = match compositor_layer {
                        Some(ref compositor_layer) => compositor_layer.pipeline.clone(),
                        None => fail!("Compositor: Received new layer without initialized pipeline"),
                    };
                    let page_size = Size2D(new_size.width as f32, new_size.height as f32);
                    let new_layer = CompositorLayer::new(p,
                                                         Some(page_size),
                                                         compositor.opts.tile_size,
                                                         Some(10000000u),
                                                         compositor.opts.cpu_painting);

                    let current_child = root_layer.first_child;
                    // This assumes there is at most one child, which should be the case.
                    match current_child {
                        Some(old_layer) => root_layer.remove_child(old_layer),
                        None => {}
                    }
                    root_layer.add_child_start(ContainerLayerKind(new_layer.root_layer));
                    compositor_layer = Some(new_layer);

                    ask_for_tiles();
                }

                SetLayerPageSize(id, new_size, epoch) => {
                    match compositor_layer {
                        Some(ref mut layer) => {
                            let page_window = Size2D(window_size.width as f32 / world_zoom,
                                                     window_size.height as f32 / world_zoom);
                            assert!(layer.resize(id, new_size, page_window, epoch));
                            ask_for_tiles();
                        }
                        None => {}
                    }
                }

                SetLayerClipRect(id, new_rect) => {
                    match compositor_layer {
                        Some(ref mut layer) => {
                            assert!(layer.set_clipping_rect(id, new_rect));
                            ask_for_tiles();
                        }
                        None => {}
                    }
                }

                DeleteLayer(id) => {
                    match compositor_layer {
                        Some(ref mut layer) => {
                            assert!(layer.delete(&graphics_context, id));
                            ask_for_tiles();
                        }
                        None => {}
                    }
                }

                Paint(id, new_layer_buffer_set, epoch) => {
                    debug!("osmain: received new frame");

                    // From now on, if we destroy the buffers, they will leak.
                    let mut new_layer_buffer_set = new_layer_buffer_set;
                    new_layer_buffer_set.mark_will_leak();

                    match compositor_layer {
                        Some(ref mut layer) => {
                            assert!(layer.add_buffers(&graphics_context,
                                                      id,
                                                      new_layer_buffer_set,
                                                      epoch).is_none());
                            recomposite = true;
                        }
                        None => {
                            fail!("Compositor: given paint command with no CompositorLayer initialized");
                        }
                    }
                    // TODO: Recycle the old buffers; send them back to the renderer to reuse if
                    // it wishes.
                }

                InvalidateRect(id, rect) => {
                    match compositor_layer {
                        Some(ref mut layer) => {
                            layer.invalidate_rect(id, Rect(Point2D(rect.origin.x as f32,
                                                                   rect.origin.y as f32),
                                                           Size2D(rect.size.width as f32,
                                                                  rect.size.height as f32)));
                            ask_for_tiles();
                        }
                        None => {} // Nothing to do
                    }
                }
            }
        }
    };

    let check_for_window_messages: &fn(WindowEvent) = |event| {
        match event {
            IdleWindowEvent => {}

            ResizeWindowEvent(width, height) => {
                let new_size = Size2D(width, height);
                if window_size != new_size {
                    debug!("osmain: window resized to %ux%u", width, height);
                    window_size = new_size;
                    match constellation_chan {
                        Some(ref chan) => chan.send(ResizedWindowMsg(new_size)),
                        None => error!("Compositor: Received resize event without initialized layout chan"),
                    }
                } else {
                    debug!("osmain: dropping window resize since size is still %ux%u", width, height);
                }
            }

            LoadUrlWindowEvent(url_string) => {
                debug!("osmain: loading URL `%s`", url_string);
                let root_pipeline_id = match compositor_layer {
                    Some(ref layer) => layer.pipeline.id.clone(),
                    None => fail!("Compositor: Received LoadUrlWindowEvent without initialized compositor layers"),
                };
                match constellation_chan {
                    Some(ref chan) => chan.send(LoadUrlMsg(root_pipeline_id,
                                                           url::make_url(url_string.to_str(), None),
                                                           Future::from_value(window_size))),
                    None => error!("Compositor: Received loadurl event without initialized layout chan"),
                }
            }

            MouseWindowEventClass(mouse_window_event) => {
                let point = match mouse_window_event {
                    MouseWindowClickEvent(_, p) => Point2D(p.x / world_zoom, p.y / world_zoom),
                    MouseWindowMouseDownEvent(_, p) => Point2D(p.x / world_zoom, p.y / world_zoom),
                    MouseWindowMouseUpEvent(_, p) => Point2D(p.x / world_zoom, p.y / world_zoom),
                };
                for layer in compositor_layer.iter() {
                    layer.send_mouse_event(mouse_window_event, point);
                }
            }

            ScrollWindowEvent(delta, cursor) => {
                // TODO: modify delta to snap scroll to pixels.
                let page_delta = Point2D(delta.x as f32 / world_zoom, delta.y as f32 / world_zoom);
                let page_cursor: Point2D<f32> = Point2D(cursor.x as f32 / world_zoom,
                                                        cursor.y as f32 / world_zoom);
                let page_window = Size2D(window_size.width as f32 / world_zoom,
                                         window_size.height as f32 / world_zoom);
                for layer in compositor_layer.mut_iter() {
                    recomposite = layer.scroll(page_delta, page_cursor, page_window) || recomposite;
                }
                ask_for_tiles();
            }

            ZoomWindowEvent(magnification) => {
                zoom_action = true;
                zoom_time = precise_time_s();
                let old_world_zoom = world_zoom;

                // Determine zoom amount
                world_zoom = (world_zoom * magnification).max(&1.0);
                root_layer.common.set_transform(identity().scale(world_zoom, world_zoom, 1f32));

                // Scroll as needed
                let page_delta = Point2D(window_size.width as f32 * (1.0 / world_zoom - 1.0 / old_world_zoom) * 0.5,
                                         window_size.height as f32 * (1.0 / world_zoom - 1.0 / old_world_zoom) * 0.5);
                // TODO: modify delta to snap scroll to pixels.
                let page_cursor = Point2D(-1f32, -1f32); // Make sure this hits the base layer
                let page_window = Size2D(window_size.width as f32 / world_zoom,
                                         window_size.height as f32 / world_zoom);
                for layer in compositor_layer.mut_iter() {
                    layer.scroll(page_delta, page_cursor, page_window);
                }

                recomposite = true;
            }

            NavigationWindowEvent(direction) => {
                let direction = match direction {
                    windowing::Forward => constellation_msg::Forward,
                    windowing::Back => constellation_msg::Back,
                };
                match constellation_chan {
                    Some(ref chan) => chan.send(NavigateMsg(direction)),
                    None => error!("Compositor: Received navigation event without initialized layout chan"),
                }
            }

            FinishedWindowEvent => {
                if compositor.opts.exit_after_load {
                    done = true;
                }
            }

            QuitWindowEvent => {
                done = true;
            }
        }
    };

    let profiler_chan = compositor.profiler_chan.clone();
    let write_png = compositor.opts.output_file.is_some();
    let exit = compositor.opts.exit_after_load;
    let composite = || {
        do profile(time::CompositingCategory, profiler_chan.clone()) {
            debug!("compositor: compositing");
            // Adjust the layer dimensions as necessary to correspond to the size of the window.
            scene.size = window.size();

            // Render the scene.
            rendergl::render_scene(context, &scene);
        }

        // Render to PNG. We must read from the back buffer (ie, before
        // window.present()) as OpenGL ES 2 does not have glReadBuffer().
        if write_png {
            let (width, height) = (window_size.width as uint, window_size.height as uint);
            let path = from_str::<Path>(*compositor.opts.output_file.get_ref()).unwrap();
            let mut pixels = gl2::read_pixels(0, 0,
                                              width as gl2::GLsizei,
                                              height as gl2::GLsizei,
                                              gl2::RGB, gl2::UNSIGNED_BYTE);
            // flip image vertically (texture is upside down)
            let orig_pixels = pixels.clone();
            let stride = width * 3;
            for y in range(0, height) {
                let dst_start = y * stride;
                let src_start = (height - y - 1) * stride;
                vec::bytes::copy_memory(pixels.mut_slice(dst_start, dst_start + stride),
                                        orig_pixels.slice(src_start, src_start + stride),
                                        stride);
            }
            let img = png::Image {
                width: width as u32,
                height: height as u32,
                color_type: png::RGB8,
                pixels: pixels,
            };
            let res = png::store_png(&img, &path);
            assert!(res.is_ok());

            done = true;
        }

        window.present();

        if exit { done = true; }
    };

    // Enter the main event loop.
    let mut tm = Timer::new().unwrap();
    while !done {
        // Check for new messages coming from the rendering task.
        check_for_messages(&compositor.port);

        // Check for messages coming from the windowing system.
        check_for_window_messages(window.recv());

        if recomposite {
            recomposite = false;
            composite();
        }

        tm.sleep(10);

        // If a pinch-zoom happened recently, ask for tiles at the new resolution
        if zoom_action && precise_time_s() - zoom_time > 0.3 {
            zoom_action = false;
            ask_for_tiles();
        }

    }

    compositor.shutdown_chan.send(());

    // Clear out the compositor layers so that painting tasks can destroy the buffers.
    match compositor_layer {
        None => {}
        Some(ref mut layer) => layer.forget_all_tiles(),
    }
}
<|endoftext|>


<commit_before>use std::io::{self, Read, Error, ErrorKind};
use std::borrow::Cow;

use hyper;
use hyper::{client, Client, Url };
use hyper::net::HttpsConnector;
use hyper_native_tls::NativeTlsClient;

use std::time::Duration;
use rustc_serialize::json::Json;
use product;
use configs::{Configs, ApiConfigs, ProxyConfigs};

const HOST_URL: &'static str = "https://www.versioneye.com";

fn to_product_url(lang: &str, prod_key: &str, version: &str) -> String {
    format!("{}/{}/{}/{}", HOST_URL, lang, prod_key, version)
}

fn configs_to_url(api_confs: &ApiConfigs, resource_path: &str)
    -> Result<hyper::Url, hyper::error::ParseError> {
    let url_str = match api_confs.port {
        None => {
            format!(
                "{}://{}/{}/{}",
                api_confs.scheme.clone().unwrap(), api_confs.host.clone().unwrap(),
                api_confs.path.clone().unwrap(), resource_path,
            )

        },
        Some(port) => format!(
            "{}://{}:{}/{}/{}",
            api_confs.scheme.clone().unwrap(), api_confs.host.clone().unwrap(),
            port, api_confs.path.clone().unwrap(), resource_path
        )
    };

    Url::parse(url_str.as_str())
}

fn request_json<'a>(uri: &Url, proxy_confs: &'a ProxyConfigs) -> Option<String> {
    let ssl = NativeTlsClient::new().unwrap();
    let connector = HttpsConnector::new(ssl);

    //use proxy only iff user has defined proxy host and port
    let mut client = if proxy_confs.is_complete() {
        let host = Cow::from(proxy_confs.host.clone().unwrap());
        let port = proxy_confs.port.clone().unwrap();
        let scheme = proxy_confs.scheme.clone().unwrap_or("http".to_string());

        let ssl_proxy = NativeTlsClient::new().unwrap();
        let proxy = client::ProxyConfig::new (
            scheme.as_str(), host, port, connector, ssl_proxy
        );

        Client::with_proxy_config(proxy)
    } else {
        Client::with_connector(connector)
    };

    client.set_read_timeout(Some(Duration::new(5,0)));

    let mut res = client.get(uri.as_str()).send().expect("Failed to fetch results from the url");
    let mut body = String::new();
    res.read_to_string(&mut body).expect("Failed to read response body");

    Some(body)
}

pub fn fetch_product_details_by_sha(confs: &Configs, file_sha: &str)
    -> Result<product::ProductMatch, Error> {

    let sha_res = fetch_product_by_sha(&confs, &file_sha);
    match sha_res {
        Ok(m) => {
            let sha = m.sha.expect("No product sha from SHA result");
            let product = m.product.expect("No product info from SHA result");
            match fetch_product( &confs, &product.language, &product.prod_key, &product.version ) {
                Ok(mut m) => {
                    m.sha = Some(sha);
                    Ok(m)
                },
                Err(e) => {
                    println!("Failed to fetch product details for sha: {}", file_sha);
                    Err(e)
                }
            }

        },
        Err(e) => Err(e)
    }
}

pub fn fetch_product_by_sha(confs: &Configs, sha: &str)
    -> Result<product::ProductMatch, io::Error> {
    let api_confs = confs.api.clone();
    let resource_path = format!("products/sha/{}", sha.clone() );
    let mut resource_url = match configs_to_url(&api_confs, resource_path.as_str()) {
        Ok(the_url) => the_url,
        Err(_)      => {
            return Err(
                Error::new(
                    ErrorKind::InvalidData,
                    "The values of API configs make up non-valid URL"
                )
            )
        }
    };

    //attach query params
    resource_url
        .query_pairs_mut()
        .clear()
        .append_pair("api_key", api_confs.key.clone().unwrap().as_str());

    let json_txt = request_json( &resource_url, &confs.proxy );
    process_sha_response(json_txt)
}

pub fn encode_prod_key<'b>(prod_key: &'b str) -> String {
    let encoded_prod_key = prod_key.to_string();
    encoded_prod_key
        .replace(".", "~")
        .replace("/", ":")
        .trim().to_string()

}

pub fn encode_language<'b>(lang: &'b str) -> String {
    let encoded_lang = lang.to_string();
    encoded_lang.replace(".", "").trim().to_lowercase().to_string()
}

pub fn fetch_product<'a>(
    confs: &Configs, lang: &str, prod_key: &str, version: &str
) -> Result<product::ProductMatch, io::Error> {

    let api_confs = confs.api.clone();
    let encoded_prod_key = encode_prod_key(&prod_key);
    let encoded_lang = encode_language(lang);
    let resource_path = format!("products/{}/{}", encoded_lang.clone(), encoded_prod_key.clone());
    let prod_url = to_product_url(encoded_lang.clone().as_str(), encoded_prod_key.clone().as_str(), version);

    let mut resource_url = match configs_to_url(&api_confs, resource_path.as_str()) {
        Ok(the_url) => the_url,
        Err(_)      => {
            return Err(
                Error::new(
                    ErrorKind::InvalidData,
                    "The values of API configs make up non-valid URL"
                )
            )
        }
    };

    //attach query params
    resource_url
        .query_pairs_mut()
        .clear()
        .append_pair("prod_version", version)
        .append_pair("api_key", api_confs.key.clone().unwrap().as_str());

    let json_txt = request_json( &resource_url, &confs.proxy );
    process_product_response(json_txt, Some(prod_url))
}

//TODO: log all error details
//-- helper functions
pub fn process_sha_response(json_text: Option<String> ) -> Result<product::ProductMatch, io::Error> {
    if json_text.is_none() {
        return Err(
            Error::new(ErrorKind::Other, "No response from API")
        )
    }

    let json_res = Json::from_str( &json_text.clone().unwrap());
    if json_res.is_err() {
        return Err(
            Error::new(
                ErrorKind::Other,
                "Failed to parse response from SHA endpoint - server failed to process request"
            )
        )
    }

    let json_obj = json_res.unwrap();
    //if response includes error field in HTTP200 response
    if let Some(_) = json_obj.find("error") {
        return Err(
            Error::new(
                ErrorKind::Other,
                "API rate limit reached. Go to https://www.versioneye.com and upgrade your subscription to a higher plan."
            )
        )
    }

    if !json_obj.is_array() {
        return Err(Error::new( ErrorKind::Other, "The structure of SHA response has been changed"));
    }

    let product_doc = match json_obj.as_array() {
        Some(products) if products.len() > 0 => products[0].clone(),
        _ => return Err(Error::new(ErrorKind::Other, "Empty response - API may be not responding"))
    };

    let the_prod = product::Product {
        name: "".to_string(),
        language: product_doc["language"].as_string().expect("No field `language`").to_string(),
        prod_key: product_doc["prod_key"].as_string().expect("No field `prod_key`").to_string(),
        version: product_doc["version"].as_string().expect("No field `version`").to_string(),
        prod_type: Some( product_doc["prod_type"].as_string().expect("No field `prod_types`").to_string() )
    };

    let the_sha = product::ProductSHA {
        packaging: product_doc["packaging"].as_string().unwrap_or("unknown").to_string(),
        method: product_doc["sha_method"].as_string().expect("No field `sha_method`").to_string(),
        value: product_doc["sha_value"].as_string().expect("No field `sha_value`").to_string(),
        filepath: None
    };

    Ok(product::ProductMatch::new(the_prod, the_sha))
}

// converts the response of product endpoint into ProductMatch struct
pub fn process_product_response(
    json_text: Option<String>, prod_url: Option<String>
) -> Result<product::ProductMatch, io::Error> {

    if json_text.is_none() {
        return Err(
            Error::new(
                ErrorKind::Other,
                "API returned empty response string - server may not responding"
            )
        )
    }

    let json_res = Json::from_str( &json_text.clone().unwrap());
    if json_res.is_err() {
        return Err(
            Error::new(
                ErrorKind::Other,
                "Failed to parse response from the Product endpoint - server failed to process request"
            )
        )
    }

    let json_obj = json_res.unwrap();
    if !json_obj.is_object() {
        return Err(Error::new(ErrorKind::Other, "Response had no product details"));
    }

    //if response includes error field in HTTP200 response
    // NB! it may include other errors than limit, but @Rob asked to see custom Limit error message
    if let Some(_) = json_obj.find("error") {
        return Err(
            Error::new(
                ErrorKind::Other,
                "Hit API request limit - upgrade your subscription"
            )
        )
    }

    let product_doc = json_obj.as_object().expect("Failed to fetch product document");
    let the_prod = product::Product {
        name: product_doc["name"].as_string().unwrap().to_string(),
        language: product_doc["language"].as_string().unwrap().to_string(),
        prod_key: product_doc["prod_key"].as_string().unwrap().to_string(),
        version: product_doc["version"].as_string().unwrap().to_string(),
        prod_type: Some( product_doc["prod_type"].as_string().unwrap_or("").to_string() )
    };

    let licenses = match product_doc["licenses"].as_array() {
        Some(arr) => arr.iter().fold(vec![], |mut acc, ref x| {
            acc.push(product::ProductLicense {
                name: x["name"].as_string().unwrap().to_string(),
                url: x["url"].as_string().unwrap_or("").to_string()
            });

            acc
        }),
        None      => vec![]
    };

    let n_vulns = match product_doc["security_vulnerabilities"].as_array() {
        Some(arr) => arr.len() as u32,
        None      => 0 as u32
    };

    let the_match = product::ProductMatch {
        sha: None,
        product: Some(the_prod),
        url: prod_url,
        licenses : licenses,
        n_vulns : n_vulns,
        error: None
    };

    Ok(the_match)
}
<commit_msg>Update error message.<commit_after>use std::io::{self, Read, Error, ErrorKind};
use std::borrow::Cow;

use hyper;
use hyper::{client, Client, Url };
use hyper::net::HttpsConnector;
use hyper_native_tls::NativeTlsClient;

use std::time::Duration;
use rustc_serialize::json::Json;
use product;
use configs::{Configs, ApiConfigs, ProxyConfigs};

const HOST_URL: &'static str = "https://www.versioneye.com";

fn to_product_url(lang: &str, prod_key: &str, version: &str) -> String {
    format!("{}/{}/{}/{}", HOST_URL, lang, prod_key, version)
}

fn configs_to_url(api_confs: &ApiConfigs, resource_path: &str)
    -> Result<hyper::Url, hyper::error::ParseError> {
    let url_str = match api_confs.port {
        None => {
            format!(
                "{}://{}/{}/{}",
                api_confs.scheme.clone().unwrap(), api_confs.host.clone().unwrap(),
                api_confs.path.clone().unwrap(), resource_path,
            )

        },
        Some(port) => format!(
            "{}://{}:{}/{}/{}",
            api_confs.scheme.clone().unwrap(), api_confs.host.clone().unwrap(),
            port, api_confs.path.clone().unwrap(), resource_path
        )
    };

    Url::parse(url_str.as_str())
}

fn request_json<'a>(uri: &Url, proxy_confs: &'a ProxyConfigs) -> Option<String> {
    let ssl = NativeTlsClient::new().unwrap();
    let connector = HttpsConnector::new(ssl);

    //use proxy only iff user has defined proxy host and port
    let mut client = if proxy_confs.is_complete() {
        let host = Cow::from(proxy_confs.host.clone().unwrap());
        let port = proxy_confs.port.clone().unwrap();
        let scheme = proxy_confs.scheme.clone().unwrap_or("http".to_string());

        let ssl_proxy = NativeTlsClient::new().unwrap();
        let proxy = client::ProxyConfig::new (
            scheme.as_str(), host, port, connector, ssl_proxy
        );

        Client::with_proxy_config(proxy)
    } else {
        Client::with_connector(connector)
    };

    client.set_read_timeout(Some(Duration::new(5,0)));

    let mut res = client.get(uri.as_str()).send().expect("Failed to fetch results from the url");
    let mut body = String::new();
    res.read_to_string(&mut body).expect("Failed to read response body");

    Some(body)
}

pub fn fetch_product_details_by_sha(confs: &Configs, file_sha: &str)
    -> Result<product::ProductMatch, Error> {

    let sha_res = fetch_product_by_sha(&confs, &file_sha);
    match sha_res {
        Ok(m) => {
            let sha = m.sha.expect("No product sha from SHA result");
            let product = m.product.expect("No product info from SHA result");
            match fetch_product( &confs, &product.language, &product.prod_key, &product.version ) {
                Ok(mut m) => {
                    m.sha = Some(sha);
                    Ok(m)
                },
                Err(e) => {
                    println!("Failed to fetch product details for sha: {}", file_sha);
                    Err(e)
                }
            }

        },
        Err(e) => Err(e)
    }
}

pub fn fetch_product_by_sha(confs: &Configs, sha: &str)
    -> Result<product::ProductMatch, io::Error> {
    let api_confs = confs.api.clone();
    let resource_path = format!("products/sha/{}", sha.clone() );
    let mut resource_url = match configs_to_url(&api_confs, resource_path.as_str()) {
        Ok(the_url) => the_url,
        Err(_)      => {
            return Err(
                Error::new(
                    ErrorKind::InvalidData,
                    "The values of API configs make up non-valid URL"
                )
            )
        }
    };

    //attach query params
    resource_url
        .query_pairs_mut()
        .clear()
        .append_pair("api_key", api_confs.key.clone().unwrap().as_str());

    let json_txt = request_json( &resource_url, &confs.proxy );
    process_sha_response(json_txt)
}

pub fn encode_prod_key<'b>(prod_key: &'b str) -> String {
    let encoded_prod_key = prod_key.to_string();
    encoded_prod_key
        .replace(".", "~")
        .replace("/", ":")
        .trim().to_string()

}

pub fn encode_language<'b>(lang: &'b str) -> String {
    let encoded_lang = lang.to_string();
    encoded_lang.replace(".", "").trim().to_lowercase().to_string()
}

pub fn fetch_product<'a>(
    confs: &Configs, lang: &str, prod_key: &str, version: &str
) -> Result<product::ProductMatch, io::Error> {

    let api_confs = confs.api.clone();
    let encoded_prod_key = encode_prod_key(&prod_key);
    let encoded_lang = encode_language(lang);
    let resource_path = format!("products/{}/{}", encoded_lang.clone(), encoded_prod_key.clone());
    let prod_url = to_product_url(encoded_lang.clone().as_str(), encoded_prod_key.clone().as_str(), version);

    let mut resource_url = match configs_to_url(&api_confs, resource_path.as_str()) {
        Ok(the_url) => the_url,
        Err(_)      => {
            return Err(
                Error::new(
                    ErrorKind::InvalidData,
                    "The values of API configs make up non-valid URL"
                )
            )
        }
    };

    //attach query params
    resource_url
        .query_pairs_mut()
        .clear()
        .append_pair("prod_version", version)
        .append_pair("api_key", api_confs.key.clone().unwrap().as_str());

    let json_txt = request_json( &resource_url, &confs.proxy );
    process_product_response(json_txt, Some(prod_url))
}

//TODO: log all error details
//-- helper functions
pub fn process_sha_response(json_text: Option<String> ) -> Result<product::ProductMatch, io::Error> {
    if json_text.is_none() {
        return Err(
            Error::new(ErrorKind::Other, "No response from API")
        )
    }

    let json_res = Json::from_str( &json_text.clone().unwrap());
    if json_res.is_err() {
        return Err(
            Error::new(
                ErrorKind::Other,
                "Failed to parse response from SHA endpoint - server failed to process request"
            )
        )
    }

    let json_obj = json_res.unwrap();
    //if response includes error field in HTTP200 response
    if let Some(_) = json_obj.find("error") {
        return Err(
            Error::new(
                ErrorKind::Other,
                "API rate limit reached. Go to https://www.versioneye.com and upgrade your subscription to a higher plan."
            )
        )
    }

    if !json_obj.is_array() {
        return Err(Error::new( ErrorKind::Other, "The structure of SHA response has been changed"));
    }

    let product_doc = match json_obj.as_array() {
        Some(products) if products.len() > 0 => products[0].clone(),
        _ => return Err(Error::new(ErrorKind::Other, "Empty response"))
    };

    let the_prod = product::Product {
        name: "".to_string(),
        language: product_doc["language"].as_string().expect("No field `language`").to_string(),
        prod_key: product_doc["prod_key"].as_string().expect("No field `prod_key`").to_string(),
        version: product_doc["version"].as_string().expect("No field `version`").to_string(),
        prod_type: Some( product_doc["prod_type"].as_string().expect("No field `prod_types`").to_string() )
    };

    let the_sha = product::ProductSHA {
        packaging: product_doc["packaging"].as_string().unwrap_or("unknown").to_string(),
        method: product_doc["sha_method"].as_string().expect("No field `sha_method`").to_string(),
        value: product_doc["sha_value"].as_string().expect("No field `sha_value`").to_string(),
        filepath: None
    };

    Ok(product::ProductMatch::new(the_prod, the_sha))
}

// converts the response of product endpoint into ProductMatch struct
pub fn process_product_response(
    json_text: Option<String>, prod_url: Option<String>
) -> Result<product::ProductMatch, io::Error> {

    if json_text.is_none() {
        return Err(
            Error::new(
                ErrorKind::Other,
                "API returned empty response string - server may not responding"
            )
        )
    }

    let json_res = Json::from_str( &json_text.clone().unwrap());
    if json_res.is_err() {
        return Err(
            Error::new(
                ErrorKind::Other,
                "Failed to parse response from the Product endpoint - server failed to process request"
            )
        )
    }

    let json_obj = json_res.unwrap();
    if !json_obj.is_object() {
        return Err(Error::new(ErrorKind::Other, "Response had no product details"));
    }

    //if response includes error field in HTTP200 response
    // NB! it may include other errors than limit, but @Rob asked to see custom Limit error message
    if let Some(_) = json_obj.find("error") {
        return Err(
            Error::new(
                ErrorKind::Other,
                "Hit API request limit - upgrade your subscription"
            )
        )
    }

    let product_doc = json_obj.as_object().expect("Failed to fetch product document");
    let the_prod = product::Product {
        name: product_doc["name"].as_string().unwrap().to_string(),
        language: product_doc["language"].as_string().unwrap().to_string(),
        prod_key: product_doc["prod_key"].as_string().unwrap().to_string(),
        version: product_doc["version"].as_string().unwrap().to_string(),
        prod_type: Some( product_doc["prod_type"].as_string().unwrap_or("").to_string() )
    };

    let licenses = match product_doc["licenses"].as_array() {
        Some(arr) => arr.iter().fold(vec![], |mut acc, ref x| {
            acc.push(product::ProductLicense {
                name: x["name"].as_string().unwrap().to_string(),
                url: x["url"].as_string().unwrap_or("").to_string()
            });

            acc
        }),
        None      => vec![]
    };

    let n_vulns = match product_doc["security_vulnerabilities"].as_array() {
        Some(arr) => arr.len() as u32,
        None      => 0 as u32
    };

    let the_match = product::ProductMatch {
        sha: None,
        product: Some(the_prod),
        url: prod_url,
        licenses : licenses,
        n_vulns : n_vulns,
        error: None
    };

    Ok(the_match)
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt;
use std::ffi;
use std::io;
use std::sync::mpsc;
use std::convert;
use kbindings;
use kbindings::{K, KVal, KData, kvoid, KOwned, deserial};

#[derive(Debug)]
pub struct KError {
    desc: String,
    pub kind: KErr
}

pub type KResult<T> = Result<T, KError>;

impl Error for KError {
    fn description(&self) -> &str {
        &self.desc
    }
}

impl fmt::Display for KError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Kind: {:?}, Desc: {}", self.kind, self.description())
    }
}

impl KError {
    pub fn new(s: String, kind: KErr) -> Self {
        KError {
            desc: s,
            kind: kind
        }
    }
}

impl convert::From<io::Error> for KError {
    fn from(err: io::Error) -> KError {
        KError {
            desc: err.description().to_string(),
            kind: KErr::IOErr
        }
    }
}

impl convert::From<mpsc::RecvError> for KError {
    fn from(err: mpsc::RecvError) -> KError {
        KError {
            desc: err.description().to_string(),
            kind: KErr::RecvErr
        }
    }
}

#[derive(Debug)]
pub enum KErr {
    ConnectionFailed,
    AuthenticationFailed,
    QueryFailed,
    SocketClosed,
    IOErr,
    RecvErr,
    SendErr,
    EncodeFailed,
    DecodeFailed,
    CorruptData,
    BadConfig,
    Generic,
    WrongType
}

pub struct Handle {
    host: String,
    port: i32,
    username: String,
    handle: i32
}

impl Handle {
    pub fn connect(host: &str, port: i32, username: &str) -> Result<Handle, Box<Error>> {
        let chost = try!(ffi::CString::new(host)).as_ptr();
        let cuser = try!(ffi::CString::new(username)).as_ptr();
        let handle = match unsafe { kbindings::khpu(chost, port, cuser) } {
            h if h < 0 => return Err(Box::new(KError::new("Could not connect".to_string(), KErr::ConnectionFailed))),
            0 => return Err(Box::new(KError::new("Wrong credentials".to_string(), KErr::AuthenticationFailed))),
            h => h
        };
        Ok(Handle {
            host: host.to_string(),
            username: username.to_string(),
            port: port,
            handle: handle
        })
    }

    pub fn query(&self, query: &str) -> Result<KOwned, Box<Error>> {
        let cquery = try!(ffi::CString::new(query)).as_ptr();
        let kptr = unsafe { kbindings::k(self.handle, cquery, kvoid()) };
        if kptr.is_null() {
            return Err(Box::new(KError::new("Query failed".to_string(), KErr::QueryFailed)))
        }
        Ok(unsafe { KOwned(&*kptr)} )
    }

    pub fn close(&self) {
        unsafe { kbindings::kclose(self.handle) };
    }
}

pub fn serialize(k: &KOwned) -> KResult<KOwned> {
    let ser = unsafe { &*kbindings::b9(3, k.0) };
    if kbindings::valid_stream(ser) {
        Ok(KOwned(ser))
    } else {
        Err(KError::new("Invalid serialization".to_string(), KErr::EncodeFailed))
    }
}

pub fn deserialize(ser: &KOwned) -> KResult<KOwned> {
    if kbindings::valid_stream(ser.0) {
        Ok(KOwned(kbindings::deserial(ser.0)))
    } else {
        Err(KError::new("Invalid deserialization".to_string(), KErr::DecodeFailed))
    }
}

<commit_msg>add sockettimeout error<commit_after>use std::error::Error;
use std::fmt;
use std::ffi;
use std::io;
use std::sync::mpsc;
use std::convert;
use kbindings;
use kbindings::{K, KVal, KData, kvoid, KOwned, deserial};

#[derive(Debug)]
pub struct KError {
    desc: String,
    pub kind: KErr
}

pub type KResult<T> = Result<T, KError>;

impl Error for KError {
    fn description(&self) -> &str {
        &self.desc
    }
}

impl fmt::Display for KError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Kind: {:?}, Desc: {}", self.kind, self.description())
    }
}

impl KError {
    pub fn new(s: String, kind: KErr) -> Self {
        KError {
            desc: s,
            kind: kind
        }
    }
}

impl convert::From<io::Error> for KError {
    fn from(err: io::Error) -> KError {
        KError {
            desc: err.description().to_string(),
            kind: KErr::IOErr
        }
    }
}

impl convert::From<mpsc::RecvError> for KError {
    fn from(err: mpsc::RecvError) -> KError {
        KError {
            desc: err.description().to_string(),
            kind: KErr::RecvErr
        }
    }
}

#[derive(Debug)]
pub enum KErr {
    ConnectionFailed,
    AuthenticationFailed,
    QueryFailed,
    SocketClosed,
    SocketTimeout,
    IOErr,
    RecvErr,
    SendErr,
    EncodeFailed,
    DecodeFailed,
    CorruptData,
    BadConfig,
    Generic,
    WrongType
}

pub struct Handle {
    host: String,
    port: i32,
    username: String,
    handle: i32
}

impl Handle {
    pub fn connect(host: &str, port: i32, username: &str) -> Result<Handle, Box<Error>> {
        let chost = try!(ffi::CString::new(host)).as_ptr();
        let cuser = try!(ffi::CString::new(username)).as_ptr();
        let handle = match unsafe { kbindings::khpu(chost, port, cuser) } {
            h if h < 0 => return Err(Box::new(KError::new("Could not connect".to_string(), KErr::ConnectionFailed))),
            0 => return Err(Box::new(KError::new("Wrong credentials".to_string(), KErr::AuthenticationFailed))),
            h => h
        };
        Ok(Handle {
            host: host.to_string(),
            username: username.to_string(),
            port: port,
            handle: handle
        })
    }

    pub fn query(&self, query: &str) -> Result<KOwned, Box<Error>> {
        let cquery = try!(ffi::CString::new(query)).as_ptr();
        let kptr = unsafe { kbindings::k(self.handle, cquery, kvoid()) };
        if kptr.is_null() {
            return Err(Box::new(KError::new("Query failed".to_string(), KErr::QueryFailed)))
        }
        Ok(unsafe { KOwned(&*kptr)} )
    }

    pub fn close(&self) {
        unsafe { kbindings::kclose(self.handle) };
    }
}

pub fn serialize(k: &KOwned) -> KResult<KOwned> {
    let ser = unsafe { &*kbindings::b9(3, k.0) };
    if kbindings::valid_stream(ser) {
        Ok(KOwned(ser))
    } else {
        Err(KError::new("Invalid serialization".to_string(), KErr::EncodeFailed))
    }
}

pub fn deserialize(ser: &KOwned) -> KResult<KOwned> {
    if kbindings::valid_stream(ser.0) {
        Ok(KOwned(kbindings::deserial(ser.0)))
    } else {
        Err(KError::new("Invalid deserialization".to_string(), KErr::DecodeFailed))
    }
}

<|endoftext|>


<commit_before>use lexer::*;
use errors::*;
use items::*;

#[derive(Debug, Clone)]
pub struct Parser<I>
	where I: Iterator<Item=char>
{
	input: ValidLexer<I>
}

impl<I> Parser<I>
	where I: Iterator<Item=char>
{
	pub fn from(input: I) -> Parser<I> {
		Parser{
			input: ValidLexer::from(input)
		}
	}

	fn parse_header(&mut self) -> Result<Problem> {
		Ok(Problem::cnf(0, 0)) // TODO!
	}

	fn parse_clauses(&mut self) -> Result<Vec<Clause>> {
		Ok(vec![]) // TODO!
	}

	fn parse_formula(&mut self) -> Result<Formula> {
		Ok(Formula::Lit(Lit::from_i64(0))) // TODO!
	}

	pub fn parse_dimacs(&mut self) -> Result<Instance> {
		let _ = self.parse_header();
		let _ = self.parse_clauses();
		let _ = self.parse_formula();
		Ok(Instance::cnf(0, vec![]))
	}
}

pub fn parse_dimacs(input: &str) -> Result<Instance> {
	Parser::from(input.chars()).parse_dimacs()
}

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

	#[test]
	fn simple_cnf() {
		let sample = r"
			c Sample DIMACS .cnf file
			c holding some information
			c and trying to be some
			c kind of a test.
			p cnf 42 1337
			1 2 0
			-3 4 0
			5 -6 7 0
			-7 -8 -9 0";
		let parsed = parse_dimacs(sample).expect("valid .cnf");
		let expected = Instance::cnf(42, vec![
			Clause::from_vec(vec![Lit::from_i64( 1), Lit::from_i64( 2)]),
			Clause::from_vec(vec![Lit::from_i64(-3), Lit::from_i64( 4)]),
			Clause::from_vec(vec![Lit::from_i64( 5), Lit::from_i64(-6), Lit::from_i64( 7)]),
			Clause::from_vec(vec![Lit::from_i64(-7), Lit::from_i64(-8), Lit::from_i64(-9)])
		]);
		assert_eq!(parsed, expected);
	}

	#[test]
	fn simple_sat() {
		let sample = r"
			c Sample DIMACS .sat file
			p sat 42
			(*(+(1 3 -4)
			+(4)
			+(2 3)))";
		let parsed = parse_dimacs(sample).expect("valid .sat");
		let expected = Instance::sat(42,
			Formula::paren(
				Formula::and(vec![
					Formula::or(vec![
						Formula::lit(Lit::from_i64(1)), Formula::lit(Lit::from_i64(3)), Formula::lit(Lit::from_i64(-4))
					]),
					Formula::or(vec![
						Formula::lit(Lit::from_i64(4))
					]),
					Formula::or(vec![
						Formula::lit(Lit::from_i64(2)), Formula::lit(Lit::from_i64(3))
					])
				])
			)
		);
		assert_eq!(parsed, expected);
	}
}
<commit_msg>added further structure for parser<commit_after>use lexer::*;
use errors::*;
use items::*;

#[derive(Debug, Clone)]
pub struct Parser<I>
	where I: Iterator<Item=char>
{
	input: ValidLexer<I>
}

impl<I> Parser<I>
	where I: Iterator<Item=char>
{
	pub fn from(input: I) -> Parser<I> {
		Parser{
			input: ValidLexer::from(input)
		}
	}

	fn parse_header(&mut self) -> Result<Problem> {
		Ok(Problem::cnf(0, 0)) // TODO!
	}

	fn parse_clauses(&mut self, num_clauses: u64) -> Result<Vec<Clause>> {
		let clauses: Vec<Clause> = Vec::with_capacity(num_clauses as usize);
		Ok(clauses) // TODO!
	}

	fn parse_cnf(&mut self, num_vars: u64, num_clauses: u64) -> Result<Instance> {
		Ok(Instance::cnf(num_vars, self.parse_clauses(num_clauses)?))
	}

	fn parse_formula(&mut self) -> Result<Formula> {
		Ok(Formula::Lit(Lit::from_i64(0))) // TODO!
	}

	fn parse_sat(&mut self, num_vars: u64, extensions: Box<[Extension]>) -> Result<Instance> {
		Ok(Instance::sat_with_ext(num_vars, extensions.to_vec(), self.parse_formula()?))
	}

	pub fn parse_dimacs(&mut self) -> Result<Instance> {
		match self.parse_header()? {
			Problem::Cnf{num_vars, num_clauses} => self.parse_cnf(num_vars, num_clauses),
			Problem::Sat{num_vars, extensions } => self.parse_sat(num_vars, extensions)
		}
	}
}

pub fn parse_dimacs(input: &str) -> Result<Instance> {
	Parser::from(input.chars()).parse_dimacs()
}

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

	#[test]
	fn simple_cnf() {
		let sample = r"
			c Sample DIMACS .cnf file
			c holding some information
			c and trying to be some
			c kind of a test.
			p cnf 42 1337
			1 2 0
			-3 4 0
			5 -6 7 0
			-7 -8 -9 0";
		let parsed = parse_dimacs(sample).expect("valid .cnf");
		let expected = Instance::cnf(42, vec![
			Clause::from_vec(vec![Lit::from_i64( 1), Lit::from_i64( 2)]),
			Clause::from_vec(vec![Lit::from_i64(-3), Lit::from_i64( 4)]),
			Clause::from_vec(vec![Lit::from_i64( 5), Lit::from_i64(-6), Lit::from_i64( 7)]),
			Clause::from_vec(vec![Lit::from_i64(-7), Lit::from_i64(-8), Lit::from_i64(-9)])
		]);
		assert_eq!(parsed, expected);
	}

	#[test]
	fn simple_sat() {
		let sample = r"
			c Sample DIMACS .sat file
			p sat 42
			(*(+(1 3 -4)
			+(4)
			+(2 3)))";
		let parsed = parse_dimacs(sample).expect("valid .sat");
		let expected = Instance::sat(42,
			Formula::paren(
				Formula::and(vec![
					Formula::or(vec![
						Formula::lit(Lit::from_i64(1)), Formula::lit(Lit::from_i64(3)), Formula::lit(Lit::from_i64(-4))
					]),
					Formula::or(vec![
						Formula::lit(Lit::from_i64(4))
					]),
					Formula::or(vec![
						Formula::lit(Lit::from_i64(2)), Formula::lit(Lit::from_i64(3))
					])
				])
			)
		);
		assert_eq!(parsed, expected);
	}
}
<|endoftext|>


<commit_before>// #![deny(missing_docs)]

use std::collections::HashMap;

use std::marker::PhantomData;

use combine::{Parser, ParseResult, Stream};
use combine::char::{tab, char, crlf, string, letter, alpha_num};
use combine::combinator::{between, many, none_of, or, optional, value};

pub type Name = String;
pub type SelectionSet = Vec<Selection>;

#[derive(Debug,PartialEq,Clone)]
pub struct Document {
  definitions: Vec<Definition>,
}

#[derive(Debug,PartialEq,Clone)]
pub enum Definition {
  Operation(Operation),
  SelectionSet(SelectionSet),
  Fragment(Fragment),
}

#[derive(Debug,PartialEq,Clone)]
pub struct Operation {
  op_type: OperationType,
  name: Option<Name>,
  variable_definitions: Vec<VariableDefinition>,
  directives: Vec<Directive>,
}

impl Operation {
  fn new(op_type: OperationType,
         name: Option<Name>,
         variable_definitions: Vec<VariableDefinition>,
         directives: Vec<Directive>)
         -> Operation {
    Operation {
      op_type: op_type,
      name: name,
      variable_definitions: variable_definitions,
      directives: directives,
    }
  }
}

#[derive(Debug,PartialEq,Clone)]
pub enum OperationType {
  Query,
  Mutation,
}

#[derive(Debug,PartialEq,Clone)]
pub struct VariableDefinition {
  variable: Variable,
  var_type: Type,
  default_value: Option<Value>,
}

impl VariableDefinition {
  fn new(variable: Variable, var_type: Type, default_value: Option<Value>) -> VariableDefinition {
    VariableDefinition {
      variable: variable,
      var_type: var_type,
      default_value: default_value,
    }
  }
}

pub type Variable = String;

#[derive(Debug,PartialEq,Clone)]
pub enum Type {
  Named(Name),
  List(Box<Type>),
  NonNull(Box<Type>),
}

#[derive(Debug,PartialEq,Clone)]
pub enum Value {
  Variable(Variable),
  Int(i32),
  Float(f32),
  String(String),
  Boolean(bool),
  Null,
  Enum(String),
  List(Vec<Value>),
  Object(HashMap<String, Value>),
}

#[derive(Debug,PartialEq,Clone)]
pub struct Directive {
  name: Name,
  arguments: Vec<Argument>,
}

#[derive(Debug,PartialEq,Clone)]
pub struct Argument {
  name: Name,
  value: Value,
}

#[derive(Debug,PartialEq,Clone)]
pub enum Selection {
  Field(Field),
  FragmentSpread(Name, Vec<Directive>),
  InlineFragment(Option<Type>, Vec<Directive>, SelectionSet),
}

#[derive(Debug,PartialEq,Clone)]
pub struct Field {
  alias: Option<Name>,
  name: Name,
  arguments: Vec<Argument>,
  directives: Vec<Directive>,
  selection_set: SelectionSet,
}

impl Field {
  fn new(alias: Option<Name>,
         name: Name,
         arguments: Vec<Argument>,
         directives: Vec<Directive>,
         selection_set: SelectionSet)
         -> Field {
    Field {
      alias: alias,
      name: name,
      arguments: arguments,
      directives: directives,
      selection_set: selection_set,
    }
  }
}

#[derive(Debug,PartialEq,Clone)]
pub struct Fragment {
  name: Name,
  type_condition: Type,
  directives: Vec<Directive>,
  selection_set: SelectionSet,
}

macro_rules! make_parser {

    // base case
    () => {};

    ($name:ident ($input_var:ident : $input_item_type:ty) -> $output_type:ty { $($tmpl:tt)* } $($rest:tt)*) => {

      #[derive(Clone)]
      #[allow(missing_docs)]
      pub struct $name<T: Clone> {
        _phantom: PhantomData<T>,
      }

      impl<T: Clone> $name<T> {
          #[allow(missing_docs)]
          pub fn new() -> Self {
              $name {
                _phantom: PhantomData
              }
          }
      }

      impl<I> Parser for $name<I> where I: Stream<Item=$input_item_type> {
        type Input = I;
        type Output = $output_type;

        fn parse_stream(&mut self, $input_var: I) -> ParseResult<Self::Output, Self::Input> {
          $($tmpl)*
        }
      }

      make_parser!($($rest)*);
    };

    ($name:ident ($input_var:ident : $input_item_type:ty , $($field:ident : &$typ:ty),*)
      -> $output_type:ty { $($tmpl:tt)* } $($rest:tt)*) => {

        #[derive(Clone)]
        #[allow(missing_docs)]
        pub struct $name<'a, T: Clone> {
          _phantom: PhantomData<T>,
          $( $field: &'a $typ),*
        }

        impl<'a, T: Clone> $name<'a, T> {
          #[allow(missing_docs)]
          pub fn new($($field: &'a $typ),*) -> Self {
            $name {
              _phantom: PhantomData,
              $( $field: $field),*
            }
          }
        }

        impl<'a, I> Parser for $name<'a, I> where I: Stream<Item=$input_item_type> {
          type Input = I;
          type Output = $output_type;

          fn parse_stream(&mut self, $input_var: I) -> ParseResult<Self::Output, Self::Input> {
            let &mut $name { _phantom, $($field),* } = self;

            $($tmpl)*
          }
        }

        make_parser!($($rest)*);
    };
}

// TODO graphql and char have a very differing set of code points
// graphql :: [0009,000A,000D, [0020,FFFF] ]
// char :: [0,D7FF] u [E000,10FFFF]
// somehow we need to wrangle char to match the graphql types :)

make_parser!(
  WhiteSpace(input: char) -> char {
    char(' ').or(tab())
      .parse_stream(input)
  }
);

make_parser!(
  LineTerminator(input: char, is_clr: &bool) -> char {

    if !is_clr {
      char('\r')
        .or(char('\n'))
        .parse_stream(input)
    } else {
      crlf()
        .or(char('\r'))
        .or(char('\n'))
        .parse_stream(input)
    }
  }
);

make_parser!(
  LineComment(input: char) -> () {
    value(())
      .skip(char('#'))
      .skip(many::<Vec<_>,_>(none_of("\r\n".chars())))
      .skip(LineTerminator::new(&true))
      .parse_stream(input)
  }
);

make_parser!(
  OperationDefinition(input: char) -> Operation {
    OperationTypeParserarser::new()
      .and(optional(NameParser::new()))
      .and(optional(VariableDefinitions::new()))
      .map(|((op_type,name),defns)| {
        let variable_definitions = match defns {
          Some(ds) => ds,
          None => Vec::new()
        };

        Operation::new(op_type, name, variable_definitions, Vec::new())
      })
      .parse_stream(input)
  }
);

make_parser!(
  OperationTypeParserarser(input: char) -> OperationType {
    string("query").map(|_| OperationType::Query)
      .or(string("mutation").map(|_| OperationType::Mutation))
      .skip(many::<Vec<_>,_>(or(WhiteSpace::new(), LineTerminator::new(&true))))
      .parse_stream(input)
  }
);

make_parser!(
  NameParser(input: char) -> Name {
    or(letter(),char('_'))
      .map(|c| {
        let mut result = String::new();
        result.push(c);
        result
      })
      .and(many::<String,_>(alpha_num().or(char('_'))))
      .map(|(mut f,r)| {
        f.push_str(&r);
        f
      })
      .skip(many::<Vec<_>,_>(or(WhiteSpace::new(), LineTerminator::new(&true))))
      .parse_stream(input)
  }
);

make_parser!(
  VariableDefinitions(input: char) -> Vec<VariableDefinition> {
    between(char('('), char(')'), many(VariableDefinitionP::new()))
      .parse_stream(input)
  }
);

make_parser!(
  VariableDefinitionP(input: char) -> VariableDefinition {
    VariableParser::new()
      .and(TypeParser::new())
      .map(|(variable,var_type)| {
        VariableDefinition::new(variable, var_type, None)
      })
      .parse_stream(input)
  }
);

make_parser!(
  VariableParser(input: char) -> Variable {
    char('$')
      .with(NameParser::new()) // skip the $
      .parse_stream(input)
  }
);

make_parser!(
  TypeParser(input: char) -> Type {
    let named_type = NameParser::new().map(Type::Named);
    let list_type = between(char('['),char(']'), TypeParser::new()).map(|t| Type::List(Box::new(t)));

// i can't clone for some reason -.-
    let non_null_type = char('!')
      .with(or(
        NameParser::new().map(Type::Named),
        between(char('['),char(']'), TypeParser::new()).map(|t| Type::List(Box::new(t)))
      ))
      .map(|t| Type::NonNull(Box::new(t)));

    non_null_type.or(named_type).or(list_type)
      .skip(many::<Vec<_>,_>(or(WhiteSpace::new(), LineTerminator::new(&true))))
      .parse_stream(input)
  }
);

make_parser!(
  Alias(input: char) -> Name {
    NameParser::new()
      .skip(many::<Vec<_>,_>(or(WhiteSpace::new(), LineTerminator::new(&true))))
      .skip(char(':'))
      .parse_stream(input)
  }
);

#[cfg(test)]
mod tests {
  use super::*;
  use combine::{State, Parser};

  macro_rules! assert_successful_parse {
    ($parser:ident,$input:expr,$result:expr) => {
      assert_eq!($parser::new().parse(State::new($input)).map(|x| x.0), Ok($result));
    }
  }

  #[test]
  fn test_parse_comment() {
    assert_successful_parse!(LineComment, "#hello world\r\n", ());
  }

  #[test]
  fn test_parse_operationtype() {
    assert_successful_parse!(OperationTypeParserarser, "query", OperationType::Query);
    assert_successful_parse!(OperationTypeParserarser,
                             "mutation",
                             OperationType::Mutation);
  }

  #[test]
  fn test_parse_name() {
    assert_successful_parse!(NameParser, "_asd", String::from("_asd"));
    assert_successful_parse!(NameParser, "aasd", String::from("aasd"));
    assert_successful_parse!(NameParser, "zasd", String::from("zasd"));
    assert_successful_parse!(NameParser, "Aasd", String::from("Aasd"));
    assert_successful_parse!(NameParser, "Zasd", String::from("Zasd"));
  }

  #[test]
  fn test_parse_alias() {
    assert_successful_parse!(Alias, "asd:", String::from("asd"));
    assert_successful_parse!(Alias, "asd :", String::from("asd"));
    assert_successful_parse!(Alias, "asd \r\n:", String::from("asd"));
  }

  #[test]
  fn test_parse_operation() {
    // named operation
    {
      let result = Operation::new(OperationType::Mutation,
                                  Some(String::from("test")),
                                  Vec::new(),
                                  Vec::new());
      assert_successful_parse!(OperationDefinition, "mutation test", result);
    }

    // non named
    {
      let result = Operation::new(OperationType::Mutation, None, Vec::new(), Vec::new());
      assert_successful_parse!(OperationDefinition, "mutation", result);
    }
  }

  #[test]
  fn test_parse_type() {
    assert_successful_parse!(TypeParser, "User", Type::Named(String::from("User")));
    assert_successful_parse!(TypeParser,
                             "[User]",
                             Type::List(Box::new(Type::Named(String::from("User")))));
  }

  #[test]
  fn test_parse_nonnull_type() {
    assert_successful_parse!(TypeParser,
                             "!User",
                             Type::NonNull(Box::new(Type::Named(String::from("User")))));
    assert_successful_parse!(TypeParser,
                             "![User]",
                             Type::NonNull(Box::new(Type::List(Box::new(Type::Named(String::from("User")))))));
  }
}
<commit_msg>added variable definition parse test<commit_after>// #![deny(missing_docs)]

use std::collections::HashMap;

use std::marker::PhantomData;

use combine::{Parser, ParseResult, Stream};
use combine::char::{tab, char, crlf, string, letter, alpha_num};
use combine::combinator::{between, many, none_of, or, optional, value};

pub type Name = String;
pub type SelectionSet = Vec<Selection>;

#[derive(Debug,PartialEq,Clone)]
pub struct Document {
  definitions: Vec<Definition>,
}

#[derive(Debug,PartialEq,Clone)]
pub enum Definition {
  Operation(Operation),
  SelectionSet(SelectionSet),
  Fragment(Fragment),
}

#[derive(Debug,PartialEq,Clone)]
pub struct Operation {
  op_type: OperationType,
  name: Option<Name>,
  variable_definitions: Vec<VariableDefinition>,
  directives: Vec<Directive>,
}

impl Operation {
  fn new(op_type: OperationType,
         name: Option<Name>,
         variable_definitions: Vec<VariableDefinition>,
         directives: Vec<Directive>)
         -> Operation {
    Operation {
      op_type: op_type,
      name: name,
      variable_definitions: variable_definitions,
      directives: directives,
    }
  }
}

#[derive(Debug,PartialEq,Clone)]
pub enum OperationType {
  Query,
  Mutation,
}

#[derive(Debug,PartialEq,Clone)]
pub struct VariableDefinition {
  variable: Variable,
  var_type: Type,
  default_value: Option<Value>,
}

impl VariableDefinition {
  fn new(variable: Variable, var_type: Type, default_value: Option<Value>) -> VariableDefinition {
    VariableDefinition {
      variable: variable,
      var_type: var_type,
      default_value: default_value,
    }
  }
}

pub type Variable = String;

#[derive(Debug,PartialEq,Clone)]
pub enum Type {
  Named(Name),
  List(Box<Type>),
  NonNull(Box<Type>),
}

#[derive(Debug,PartialEq,Clone)]
pub enum Value {
  Variable(Variable),
  Int(i32),
  Float(f32),
  String(String),
  Boolean(bool),
  Null,
  Enum(String),
  List(Vec<Value>),
  Object(HashMap<String, Value>),
}

#[derive(Debug,PartialEq,Clone)]
pub struct Directive {
  name: Name,
  arguments: Vec<Argument>,
}

#[derive(Debug,PartialEq,Clone)]
pub struct Argument {
  name: Name,
  value: Value,
}

#[derive(Debug,PartialEq,Clone)]
pub enum Selection {
  Field(Field),
  FragmentSpread(Name, Vec<Directive>),
  InlineFragment(Option<Type>, Vec<Directive>, SelectionSet),
}

#[derive(Debug,PartialEq,Clone)]
pub struct Field {
  alias: Option<Name>,
  name: Name,
  arguments: Vec<Argument>,
  directives: Vec<Directive>,
  selection_set: SelectionSet,
}

impl Field {
  fn new(alias: Option<Name>,
         name: Name,
         arguments: Vec<Argument>,
         directives: Vec<Directive>,
         selection_set: SelectionSet)
         -> Field {
    Field {
      alias: alias,
      name: name,
      arguments: arguments,
      directives: directives,
      selection_set: selection_set,
    }
  }
}

#[derive(Debug,PartialEq,Clone)]
pub struct Fragment {
  name: Name,
  type_condition: Type,
  directives: Vec<Directive>,
  selection_set: SelectionSet,
}

macro_rules! make_parser {

    // base case
    () => {};

    ($name:ident ($input_var:ident : $input_item_type:ty) -> $output_type:ty { $($tmpl:tt)* } $($rest:tt)*) => {

      #[derive(Clone)]
      #[allow(missing_docs)]
      pub struct $name<T: Clone> {
        _phantom: PhantomData<T>,
      }

      impl<T: Clone> $name<T> {
          #[allow(missing_docs)]
          pub fn new() -> Self {
              $name {
                _phantom: PhantomData
              }
          }
      }

      impl<I> Parser for $name<I> where I: Stream<Item=$input_item_type> {
        type Input = I;
        type Output = $output_type;

        fn parse_stream(&mut self, $input_var: I) -> ParseResult<Self::Output, Self::Input> {
          $($tmpl)*
        }
      }

      make_parser!($($rest)*);
    };

    ($name:ident ($input_var:ident : $input_item_type:ty , $($field:ident : &$typ:ty),*)
      -> $output_type:ty { $($tmpl:tt)* } $($rest:tt)*) => {

        #[derive(Clone)]
        #[allow(missing_docs)]
        pub struct $name<'a, T: Clone> {
          _phantom: PhantomData<T>,
          $( $field: &'a $typ),*
        }

        impl<'a, T: Clone> $name<'a, T> {
          #[allow(missing_docs)]
          pub fn new($($field: &'a $typ),*) -> Self {
            $name {
              _phantom: PhantomData,
              $( $field: $field),*
            }
          }
        }

        impl<'a, I> Parser for $name<'a, I> where I: Stream<Item=$input_item_type> {
          type Input = I;
          type Output = $output_type;

          fn parse_stream(&mut self, $input_var: I) -> ParseResult<Self::Output, Self::Input> {
            let &mut $name { _phantom, $($field),* } = self;

            $($tmpl)*
          }
        }

        make_parser!($($rest)*);
    };
}

// TODO graphql and char have a very differing set of code points
// graphql :: [0009,000A,000D, [0020,FFFF] ]
// char :: [0,D7FF] u [E000,10FFFF]
// somehow we need to wrangle char to match the graphql types :)

make_parser!(
  WhiteSpace(input: char) -> char {
    char(' ').or(tab())
      .parse_stream(input)
  }
);

make_parser!(
  LineTerminator(input: char, is_clr: &bool) -> char {

    if !is_clr {
      char('\r')
        .or(char('\n'))
        .parse_stream(input)
    } else {
      crlf()
        .or(char('\r'))
        .or(char('\n'))
        .parse_stream(input)
    }
  }
);

make_parser!(
  LineComment(input: char) -> () {
    value(())
      .skip(char('#'))
      .skip(many::<Vec<_>,_>(none_of("\r\n".chars())))
      .skip(LineTerminator::new(&true))
      .parse_stream(input)
  }
);

make_parser!(
  OperationDefinition(input: char) -> Operation {
    OperationTypeParser::new()
      .and(optional(NameParser::new()))
      .and(optional(VariableDefinitions::new()))
      .map(|((op_type,name),defns)| {
        let variable_definitions = match defns {
          Some(ds) => ds,
          None => Vec::new()
        };

        Operation::new(op_type, name, variable_definitions, Vec::new())
      })
      .skip(many::<Vec<_>,_>(or(WhiteSpace::new(), LineTerminator::new(&true))))
      .parse_stream(input)
  }
);

make_parser!(
  OperationTypeParser(input: char) -> OperationType {
    string("query").map(|_| OperationType::Query)
      .or(string("mutation").map(|_| OperationType::Mutation))
      .skip(many::<Vec<_>,_>(or(WhiteSpace::new(), LineTerminator::new(&true))))
      .parse_stream(input)
  }
);

make_parser!(
  NameParser(input: char) -> Name {
    or(letter(),char('_'))
      .map(|c| {
        let mut result = String::new();
        result.push(c);
        result
      })
      .and(many::<String,_>(alpha_num().or(char('_'))))
      .map(|(mut f,r)| {
        f.push_str(&r);
        f
      })
      .skip(many::<Vec<_>,_>(or(WhiteSpace::new(), LineTerminator::new(&true))))
      .parse_stream(input)
  }
);

make_parser!(
  VariableDefinitions(input: char) -> Vec<VariableDefinition> {
    between(char('('), char(')'), many(VariableDefinitionParser::new()))
      .parse_stream(input)
  }
);

make_parser!(
  VariableDefinitionParser(input: char) -> VariableDefinition {
    VariableParser::new()
      .skip(char(':'))
      .skip(many::<Vec<_>,_>(or(WhiteSpace::new(), LineTerminator::new(&true))))
      .and(TypeParser::new())
      .map(|(variable,var_type)| {
        VariableDefinition::new(variable, var_type, None)
      })
      .skip(many::<Vec<_>,_>(or(WhiteSpace::new(), LineTerminator::new(&true))))
      .parse_stream(input)
  }
);

make_parser!(
  VariableParser(input: char) -> Variable {
    char('$')
      .with(NameParser::new()) // skip the $
      .parse_stream(input)
  }
);

make_parser!(
  TypeParser(input: char) -> Type {
    let named_type = NameParser::new().map(Type::Named);
    let list_type = between(char('['),char(']'), TypeParser::new()).map(|t| Type::List(Box::new(t)));

// i can't clone for some reason -.-
    let non_null_type = char('!')
      .with(or(
        NameParser::new().map(Type::Named),
        between(char('['),char(']'), TypeParser::new()).map(|t| Type::List(Box::new(t)))
      ))
      .map(|t| Type::NonNull(Box::new(t)));

    non_null_type.or(named_type).or(list_type)
      .skip(many::<Vec<_>,_>(or(WhiteSpace::new(), LineTerminator::new(&true))))
      .parse_stream(input)
  }
);

make_parser!(
  Alias(input: char) -> Name {
    NameParser::new()
      .skip(char(':'))
      .skip(many::<Vec<_>,_>(or(WhiteSpace::new(), LineTerminator::new(&true))))
      .parse_stream(input)
  }
);

#[cfg(test)]
mod tests {
  use super::*;
  use combine::{State, Parser};

  macro_rules! assert_successful_parse {
    ($parser:ident,$input:expr,$result:expr) => {
      assert_eq!($parser::new().parse(State::new($input)).map(|x| x.0), Ok($result));
    }
  }

  #[test]
  fn test_parse_comment() {
    assert_successful_parse!(LineComment, "#hello world\r\n", ());
  }

  #[test]
  fn test_parse_operationtype() {
    assert_successful_parse!(OperationTypeParser, "query", OperationType::Query);
    assert_successful_parse!(OperationTypeParser, "mutation", OperationType::Mutation);
  }

  #[test]
  fn test_parse_name() {
    assert_successful_parse!(NameParser, "_asd", String::from("_asd"));
    assert_successful_parse!(NameParser, "aasd", String::from("aasd"));
    assert_successful_parse!(NameParser, "zasd", String::from("zasd"));
    assert_successful_parse!(NameParser, "Aasd", String::from("Aasd"));
    assert_successful_parse!(NameParser, "Zasd", String::from("Zasd"));
  }

  #[test]
  fn test_parse_alias() {
    assert_successful_parse!(Alias, "asd:", String::from("asd"));
    assert_successful_parse!(Alias, "asd :", String::from("asd"));
    assert_successful_parse!(Alias, "asd \r\n:", String::from("asd"));
  }

  #[test]
  fn test_parse_operation() {
    // named operation
    {
      let result = Operation::new(OperationType::Mutation,
                                  Some(String::from("test")),
                                  Vec::new(),
                                  Vec::new());
      assert_successful_parse!(OperationDefinition, "mutation test", result);
    }

    // non named
    {
      let result = Operation::new(OperationType::Mutation, None, Vec::new(), Vec::new());
      assert_successful_parse!(OperationDefinition, "mutation", result);
    }
  }

  #[test]
  fn test_parse_type() {
    assert_successful_parse!(TypeParser, "User", Type::Named(String::from("User")));
    assert_successful_parse!(TypeParser,
                             "[User]",
                             Type::List(Box::new(Type::Named(String::from("User")))));
  }

  #[test]
  fn test_parse_nonnull_type() {
    assert_successful_parse!(TypeParser,
                             "!User",
                             Type::NonNull(Box::new(Type::Named(String::from("User")))));
    assert_successful_parse!(TypeParser,
                             "![User]",
                             Type::NonNull(Box::new(Type::List(Box::new(Type::Named(String::from("User")))))));
  }

  #[test]
  fn test_parse_variabledefinition_nodefaultvalue() {
    assert_successful_parse!(VariableDefinitionParser,
                             "$devicePicSize: Int",
                             VariableDefinition::new(String::from("devicePicSize"), Type::Named(String::from("Int")), None));
  }
}
<|endoftext|>


<commit_before>use crate::iter::{FusedIterator, TrustedLen};

/// Creates a new iterator that endlessly repeats a single element.
///
/// The `repeat()` function repeats a single value over and over again.
///
/// Infinite iterators like `repeat()` are often used with adapters like
/// [`Iterator::take()`], in order to make them finite.
///
/// If the element type of the iterator you need does not implement `Clone`,
/// or if you do not want to keep the repeated element in memory, you can
/// instead use the [`repeat_with()`] function.
///
/// [`repeat_with()`]: crate::iter::repeat_with
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// use std::iter;
///
/// // the number four 4ever:
/// let mut fours = iter::repeat(4);
///
/// assert_eq!(Some(4), fours.next());
/// assert_eq!(Some(4), fours.next());
/// assert_eq!(Some(4), fours.next());
/// assert_eq!(Some(4), fours.next());
/// assert_eq!(Some(4), fours.next());
///
/// // yup, still four
/// assert_eq!(Some(4), fours.next());
/// ```
///
/// Going finite with [`Iterator::take()`]:
///
/// ```
/// use std::iter;
///
/// // that last example was too many fours. Let's only have four fours.
/// let mut four_fours = iter::repeat(4).take(4);
///
/// assert_eq!(Some(4), four_fours.next());
/// assert_eq!(Some(4), four_fours.next());
/// assert_eq!(Some(4), four_fours.next());
/// assert_eq!(Some(4), four_fours.next());
///
/// // ... and now we're done
/// assert_eq!(None, four_fours.next());
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn repeat<T: Clone>(elt: T) -> Repeat<T> {
    Repeat { element: elt }
}

/// An iterator that repeats an element endlessly.
///
/// This `struct` is created by the [`repeat()`] function. See its documentation for more.
#[derive(Clone, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Repeat<A> {
    element: A,
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A: Clone> Iterator for Repeat<A> {
    type Item = A;

    #[inline]
    fn next(&mut self) -> Option<A> {
        Some(self.element.clone())
    }
    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        (usize::MAX, None)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A: Clone> DoubleEndedIterator for Repeat<A> {
    #[inline]
    fn next_back(&mut self) -> Option<A> {
        Some(self.element.clone())
    }
}

#[stable(feature = "fused", since = "1.26.0")]
impl<A: Clone> FusedIterator for Repeat<A> {}

#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<A: Clone> TrustedLen for Repeat<A> {}
<commit_msg>Implement more Iterator methods on core::iter::Repeat<commit_after>use crate::iter::{FusedIterator, TrustedLen};

/// Creates a new iterator that endlessly repeats a single element.
///
/// The `repeat()` function repeats a single value over and over again.
///
/// Infinite iterators like `repeat()` are often used with adapters like
/// [`Iterator::take()`], in order to make them finite.
///
/// If the element type of the iterator you need does not implement `Clone`,
/// or if you do not want to keep the repeated element in memory, you can
/// instead use the [`repeat_with()`] function.
///
/// [`repeat_with()`]: crate::iter::repeat_with
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// use std::iter;
///
/// // the number four 4ever:
/// let mut fours = iter::repeat(4);
///
/// assert_eq!(Some(4), fours.next());
/// assert_eq!(Some(4), fours.next());
/// assert_eq!(Some(4), fours.next());
/// assert_eq!(Some(4), fours.next());
/// assert_eq!(Some(4), fours.next());
///
/// // yup, still four
/// assert_eq!(Some(4), fours.next());
/// ```
///
/// Going finite with [`Iterator::take()`]:
///
/// ```
/// use std::iter;
///
/// // that last example was too many fours. Let's only have four fours.
/// let mut four_fours = iter::repeat(4).take(4);
///
/// assert_eq!(Some(4), four_fours.next());
/// assert_eq!(Some(4), four_fours.next());
/// assert_eq!(Some(4), four_fours.next());
/// assert_eq!(Some(4), four_fours.next());
///
/// // ... and now we're done
/// assert_eq!(None, four_fours.next());
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn repeat<T: Clone>(elt: T) -> Repeat<T> {
    Repeat { element: elt }
}

/// An iterator that repeats an element endlessly.
///
/// This `struct` is created by the [`repeat()`] function. See its documentation for more.
#[derive(Clone, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Repeat<A> {
    element: A,
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A: Clone> Iterator for Repeat<A> {
    type Item = A;

    #[inline]
    fn next(&mut self) -> Option<A> {
        Some(self.element.clone())
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        (usize::MAX, None)
    }

    #[inline]
    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
        // Advancing an infinite iterator of a single element is a no-op.
        let _ = n;
        Ok(())
    }

    #[inline]
    fn nth(&mut self, n: usize) -> Option<A> {
        let _ = n;
        Some(self.element.clone())
    }

    fn last(self) -> Option<A> {
        loop {}
    }

    fn count(self) -> usize {
        loop {}
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A: Clone> DoubleEndedIterator for Repeat<A> {
    #[inline]
    fn next_back(&mut self) -> Option<A> {
        Some(self.element.clone())
    }

    #[inline]
    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
        // Advancing an infinite iterator of a single element is a no-op.
        let _ = n;
        Ok(())
    }

    #[inline]
    fn nth_back(&mut self, n: usize) -> Option<A> {
        let _ = n;
        Some(self.element.clone())
    }
}

#[stable(feature = "fused", since = "1.26.0")]
impl<A: Clone> FusedIterator for Repeat<A> {}

#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<A: Clone> TrustedLen for Repeat<A> {}
<|endoftext|>