<commit_before>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use glib::translate::*;
use glib::types;
use cursor::Cursor;
use display::Display;
use object::Object;
use screen::Screen;
use window::Window;
use ffi;

pub type Type = ffi::GdkDeviceType;

/// Object representing an input device
pub type Device = Object<ffi::GdkDevice>;

impl types::StaticType for Device {
    fn static_type() -> types::Type { unsafe { from_glib(ffi::gdk_device_get_type()) } }
}

impl Device {
    /// Determines the name of the device.
    pub fn get_name(&self) -> Option<String> {
        unsafe {
            from_glib_none(ffi::gdk_device_get_name(self.to_glib_none().0))
        }
    }

    /// Returns the vendor ID of this device, or NULL if this information couldn't be obtained. This
    /// ID is retrieved from the device, and is thus constant for it.
    ///
    /// This function, together with gdk_device_get_product_id(), can be used to eg. compose GSettings
    /// paths to store settings for this device.
    ///
    /// ```ignore
    /// fn get_device_settings(device: &Device) -> GSettings {
    ///     GSettings *settings;
    ///     GdkDevice *device;
    ///     gchar *path;
    ///
    ///     let vendor = device.get_vendor_id().unwrap();
    ///     let product = device.get_product_id().unwrap();
    ///
    ///     let path = format!("/org/example/app/devices/{}:{}/", vendor, product);
    ///     g_settings_new_with_path(DEVICE_SCHEMA, path);
    /// }
    /// ```
    #[cfg(gdk_3_16)]
    pub fn get_vendor_id(&self) -> Option<String> {
        unsafe {
            from_glib_none(ffi::gdk_device_get_vendor_id(self.to_glib_none().0))
        }
    }

    /// Returns the product ID of this device, or None if this information couldn't be obtained. This
    /// ID is retrieved from the device, and is thus constant for it. See Device::get_vendor_id() for
    /// more information.
    #[cfg(gdk_3_16)]
    pub fn get_vendor_id(&self) -> Option<String> {
        unsafe {
            from_glib_none(ffi::gdk_device_get_vendor_id(self.to_glib_none().0))
        }
    }

    /// Determines the type of the device.
    pub fn get_source(&self) -> ::InputSource {
        unsafe { ffi::gdk_device_get_source(self.to_glib_none().0) }
    }

    /// Sets a the mode of an input device. The mode controls if the device is active and whether the
    /// device’s range is mapped to the entire screen or to a single window.
    ///
    /// Note: This is only meaningful for floating devices, master devices (and slaves connected to
    /// these) drive the pointer cursor, which is not limited by the input mode.
    pub fn set_mode(&self, mode: ::InputMode) {
        unsafe { ffi::gdk_device_set_mode(self.to_glib_none().0, mode); }
    }

    /// Determines the mode of the device.
    pub fn get_mode(&self) -> ::InputMode {
        unsafe { ffi::gdk_device_get_mode(self.to_glib_none().0) }
    }

    /// Specifies the X key event to generate when a macro button of a device is pressed.
    pub fn set_key(&self, index_: u32, keyval: u32, modifiers: ::ModifierType) {
        unsafe { ffi::gdk_device_set_key(self.to_glib_none().0, index_, keyval, modifiers) }
    }

    /// If `index_` has a valid keyval, this function will return true and fill in `keyval` and
    /// `modifiers` with the keyval settings.
    pub fn get_key(&self, index_: u32, keyval: &mut u32, modifiers: &mut ::ModifierType) -> bool {
        unsafe { from_glib(ffi::gdk_device_get_key(self.to_glib_none().0, index_, keyval, modifiers)) }
    }

    /// Specifies how an axis of a device is used.
    pub fn set_axis_use(&self, index_: u32, use_: ::AxisUse) {
        unsafe { ffi::gdk_device_set_axis_use(self.to_glib_none().0, index_, use_) }
    }

    /// Returns the axis use for `index_`.
    pub fn get_axis_use(&self, index_: u32) -> ::AxisUse {
        unsafe { ffi::gdk_device_get_axis_use(self.to_glib_none().0, index_) }
    }

    /// Returns the associated `self` to `self` , if `self` is of type DeviceType::Master, it
    /// will return the paired pointer or keyboard.
    ///
    /// If `self` is of type DeviceType::Slave, it will return the master device to which `self`
    /// is attached to.
    ///
    /// If `self` is of type DeviceType::Floating, None will be returned, as there is no
    /// associated device.
    pub fn get_associated_device(&self) -> Option<Device> {
        unsafe { from_glib_none(ffi::gdk_device_get_associated_device(self.to_glib_none().0)) }
    }

    /// Returns the device type for `self`.
    pub fn get_device_type(&self) -> Type {
        unsafe { ffi::gdk_device_get_device_type(self.to_glib_none().0) }
    }

    /// Returns the Display to which `self` pertains.
    pub fn get_display(&self) -> Display {
        unsafe { from_glib_none(ffi::gdk_device_get_display(self.to_glib_none().0)) }
    }

    /// Determines whether the pointer follows device motion. This is not meaningful for
    /// keyboard devices, which don't have a pointer.
    pub fn get_has_cursor(&self) -> bool {
        unsafe { from_glib(ffi::gdk_device_get_has_cursor(self.to_glib_none().0)) }
    }

    /// Returns the number of axes the device currently has.
    pub fn get_n_axes(&self) -> i32 {
        unsafe { ffi::gdk_device_get_n_axes(self.to_glib_none().0) }
    }

    /// Returns the number of keys the device currently has.
    pub fn get_n_keys(&self) -> i32 {
        unsafe { ffi::gdk_device_get_n_keys(self.to_glib_none().0) }
    }

    /// Warps `self` in display to the point `x`, `y` on the screen `screen`, unless the device
    /// is confined to a window by a grab, in which case it will be moved as far as allowed by
    /// the grab. Warping the pointer creates events as if the user had moved the mouse
    /// instantaneously to the destination.
    ///
    /// Note that the pointer should normally be under the control of the user. This function
    /// was added to cover some rare use cases like keyboard navigation support for the color
    /// picker in the gtk::ColorSelectionDialog.
    pub fn warp(&self, screen: &Screen, x: i32, y: i32) {
        unsafe { ffi::gdk_device_warp(self.to_glib_none().0, screen.to_glib_none().0, x, y) }
    }

    /// Grabs the device so that all events coming from this device are passed to this
    /// application until the device is ungrabbed with Device::ungrab(), or the window becomes
    /// unviewable. This overrides any previous grab on the device by this client.
    ///
    /// Note that `self` and `window` need to be on the same display.
    ///
    /// Device grabs are used for operations which need complete control over the given device
    /// events (either pointer or keyboard). For example in GTK+ this is used for Drag and Drop
    /// operations, popup menus and such.
    ///
    /// Note that if the event mask of an X window has selected both button press and button
    /// release events, then a button press event will cause an automatic pointer grab until
    /// the button is released. X does this automatically since most applications expect to
    /// receive button press and release events in pairs. It is equivalent to a pointer grab
    /// on the window with `owner_events` set to true.
    ///
    /// If you set up anything at the time you take the grab that needs to be cleaned up when
    /// the grab ends, you should handle the GdkEventGrabBroken events that are emitted when
    /// the grab ends unvoluntarily.
    pub fn grab(&self, window: &Window, grab_ownership: ::GrabOwnership, owner_events: bool,
                event_mask: ::EventMask, cursor: &Cursor, time_: u32) -> ::GrabStatus {
        unsafe {
            ffi::gdk_device_grab(self.to_glib_none().0, window.to_glib_none().0, grab_ownership,
                owner_events.to_glib(), event_mask, cursor.to_glib_none().0, time_)
        }
    }

    /// Release any grab on `self`.
    pub fn ungrab(&self, time_: u32) {
        unsafe { ffi::gdk_device_ungrab(self.to_glib_none().0, time_) }
    }

    /*pub fn get_state(&self, window: &::Window, axes: &mut [f64], mask: &mut gdk;:ModifierType) {
        unsafe { ffi::gdk_device_get_state(self.to_glib_none().0, window.unwrap_pointer(), axes.as_mut_ptr(), mask) }
    }

    pub fn get_position(&self, x: &mut i32, y: &mut i32) -> Option<::Screen> {
        let mut ptr = ::std::ptr::null_mut();

        unsafe { ffi::gdk_device_get_position(self.to_glib_none().0, &mut ptr, x as *mut c_int, y as *mut c_int) };
        if ptr.is_null() {
            None
        } else {
            Some(::Screen::wrap_pointer(ptr))
        }
    }

    pub fn get_position_double(&self, x: &mut f64, y: &mut f64) -> Option<::Screen> {
        let mut ptr = ::std::ptr::null_mut();

        unsafe { ffi::gdk_device_get_position_double(self.to_glib_none().0, &mut ptr, x as *mut c_double, y as *mut c_double) };
        if ptr.is_null() {
            None
        } else {
            Some(::Screen::wrap_pointer(ptr))
        }
    }

    pub fn get_window_at_position(&self, x: &mut i32, y: &mut i32) -> Option<::Window> {
        let mut ptr = ::std::ptr::null_mut();

        unsafe { ffi::gdk_device_get_window_at_position(self.to_glib_none().0, &mut ptr, x as *mut c_int, y as *mut c_int) };
        if ptr.is_null() {
            None
        } else {
            Some(::Window::wrap_pointer(ptr))
        }
    }

    pub fn get_window_at_position_double(&self, x: &mut f64, y: &mut f64) -> Option<::Window> {
        let mut ptr = ::std::ptr::null_mut();

        unsafe { ffi::gdk_device_get_window_at_position_double(self.to_glib_none().0, &mut ptr, x as *mut c_double, y as *mut c_double) };
        if ptr.is_null() {
            None
        } else {
            Some(::Window::wrap_pointer(ptr))
        }
    }

    pub fn get_history(&self, window: &::Window, start: u32, stop: u32) -> Vec<::TimeCoord> {
        let mut ptr = ::std::ptr::null_mut();
        let mut n_events : c_int = 0;

        unsafe { ffi::gdk_device_get_history(self.to_glib_none().0, window.unwrap_pointer(), start, stop, &mut ptr, &mut n_events) };

        let mut ret = Vec::with_capacity(n_events as uint);

        for i in range(0, n_events) {
            ret.push(::TimeCoord::wrap_pointer(::std::ptr::read(ptr.offset(i))));
        }
        ret
    }

    pub fn free_history(events: &[::TimeCoord]) {
        let mut tmp = Vec::with_capacity(events.len());

        for i in range(0, events.len()) {
            tmp.push(events[i].unwrap_pointer());
        }
        unsafe { ffi::gdk_device_free_history(events.as_mut_ptr(), events.len()) }
    }*/

    /// Interprets an array of double as axis values for a given device, and locates the value
    /// in the array for a given axis use.
    pub fn get_axis(&self, axes: &mut [f64], use_: ::AxisUse, value: &mut f64) -> bool {
        unsafe { from_glib(ffi::gdk_device_get_axis(self.to_glib_none().0, axes.as_mut_ptr(), use_, value)) }
    }

    /*pub fn get_axis_value(&self, axes: &mut [f64], label: &mut ::Atom, value: &mut f64) -> bool {
        unsafe { from_glib(ffi::gdk_device_get_axis_value(self.to_glib_none().0, axes.as_mut_ptr(), label.unwrap_pointer(), value)) }
    }*/

    /*pub fn get_last_event_window(&self) -> Option<::Window> {
        let ptr = unsafe { ffi::gdk_device_get_last_event_window(self.to_glib_none().0) };

        if ptr.is_null() {
            None
        } else {
            Some(::Window::wrap_pointer(ptr))
        }
    }*/
}
<commit_msg>Fix invalid method<commit_after>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use glib::translate::*;
use glib::types;
use cursor::Cursor;
use display::Display;
use object::Object;
use screen::Screen;
use window::Window;
use ffi;

pub type Type = ffi::GdkDeviceType;

/// Object representing an input device
pub type Device = Object<ffi::GdkDevice>;

impl types::StaticType for Device {
    fn static_type() -> types::Type { unsafe { from_glib(ffi::gdk_device_get_type()) } }
}

impl Device {
    /// Determines the name of the device.
    pub fn get_name(&self) -> Option<String> {
        unsafe {
            from_glib_none(ffi::gdk_device_get_name(self.to_glib_none().0))
        }
    }

    /// Returns the vendor ID of this device, or NULL if this information couldn't be obtained. This
    /// ID is retrieved from the device, and is thus constant for it.
    ///
    /// This function, together with gdk_device_get_product_id(), can be used to eg. compose GSettings
    /// paths to store settings for this device.
    ///
    /// ```ignore
    /// fn get_device_settings(device: &Device) -> GSettings {
    ///     GSettings *settings;
    ///     GdkDevice *device;
    ///     gchar *path;
    ///
    ///     let vendor = device.get_vendor_id().unwrap();
    ///     let product = device.get_product_id().unwrap();
    ///
    ///     let path = format!("/org/example/app/devices/{}:{}/", vendor, product);
    ///     g_settings_new_with_path(DEVICE_SCHEMA, path);
    /// }
    /// ```
    #[cfg(gdk_3_16)]
    pub fn get_vendor_id(&self) -> Option<String> {
        unsafe {
            from_glib_none(ffi::gdk_device_get_vendor_id(self.to_glib_none().0))
        }
    }

    /// Returns the product ID of this device, or None if this information couldn't be obtained. This
    /// ID is retrieved from the device, and is thus constant for it. See Device::get_vendor_id() for
    /// more information.
    #[cfg(gdk_3_16)]
    pub fn get_product_id(&self) -> Option<String> {
        unsafe {
            from_glib_none(ffi::gdk_device_get_product_id(self.to_glib_none().0))
        }
    }

    /// Determines the type of the device.
    pub fn get_source(&self) -> ::InputSource {
        unsafe { ffi::gdk_device_get_source(self.to_glib_none().0) }
    }

    /// Sets a the mode of an input device. The mode controls if the device is active and whether the
    /// device’s range is mapped to the entire screen or to a single window.
    ///
    /// Note: This is only meaningful for floating devices, master devices (and slaves connected to
    /// these) drive the pointer cursor, which is not limited by the input mode.
    pub fn set_mode(&self, mode: ::InputMode) {
        unsafe { ffi::gdk_device_set_mode(self.to_glib_none().0, mode); }
    }

    /// Determines the mode of the device.
    pub fn get_mode(&self) -> ::InputMode {
        unsafe { ffi::gdk_device_get_mode(self.to_glib_none().0) }
    }

    /// Specifies the X key event to generate when a macro button of a device is pressed.
    pub fn set_key(&self, index_: u32, keyval: u32, modifiers: ::ModifierType) {
        unsafe { ffi::gdk_device_set_key(self.to_glib_none().0, index_, keyval, modifiers) }
    }

    /// If `index_` has a valid keyval, this function will return true and fill in `keyval` and
    /// `modifiers` with the keyval settings.
    pub fn get_key(&self, index_: u32, keyval: &mut u32, modifiers: &mut ::ModifierType) -> bool {
        unsafe { from_glib(ffi::gdk_device_get_key(self.to_glib_none().0, index_, keyval, modifiers)) }
    }

    /// Specifies how an axis of a device is used.
    pub fn set_axis_use(&self, index_: u32, use_: ::AxisUse) {
        unsafe { ffi::gdk_device_set_axis_use(self.to_glib_none().0, index_, use_) }
    }

    /// Returns the axis use for `index_`.
    pub fn get_axis_use(&self, index_: u32) -> ::AxisUse {
        unsafe { ffi::gdk_device_get_axis_use(self.to_glib_none().0, index_) }
    }

    /// Returns the associated `self` to `self` , if `self` is of type DeviceType::Master, it
    /// will return the paired pointer or keyboard.
    ///
    /// If `self` is of type DeviceType::Slave, it will return the master device to which `self`
    /// is attached to.
    ///
    /// If `self` is of type DeviceType::Floating, None will be returned, as there is no
    /// associated device.
    pub fn get_associated_device(&self) -> Option<Device> {
        unsafe { from_glib_none(ffi::gdk_device_get_associated_device(self.to_glib_none().0)) }
    }

    /// Returns the device type for `self`.
    pub fn get_device_type(&self) -> Type {
        unsafe { ffi::gdk_device_get_device_type(self.to_glib_none().0) }
    }

    /// Returns the Display to which `self` pertains.
    pub fn get_display(&self) -> Display {
        unsafe { from_glib_none(ffi::gdk_device_get_display(self.to_glib_none().0)) }
    }

    /// Determines whether the pointer follows device motion. This is not meaningful for
    /// keyboard devices, which don't have a pointer.
    pub fn get_has_cursor(&self) -> bool {
        unsafe { from_glib(ffi::gdk_device_get_has_cursor(self.to_glib_none().0)) }
    }

    /// Returns the number of axes the device currently has.
    pub fn get_n_axes(&self) -> i32 {
        unsafe { ffi::gdk_device_get_n_axes(self.to_glib_none().0) }
    }

    /// Returns the number of keys the device currently has.
    pub fn get_n_keys(&self) -> i32 {
        unsafe { ffi::gdk_device_get_n_keys(self.to_glib_none().0) }
    }

    /// Warps `self` in display to the point `x`, `y` on the screen `screen`, unless the device
    /// is confined to a window by a grab, in which case it will be moved as far as allowed by
    /// the grab. Warping the pointer creates events as if the user had moved the mouse
    /// instantaneously to the destination.
    ///
    /// Note that the pointer should normally be under the control of the user. This function
    /// was added to cover some rare use cases like keyboard navigation support for the color
    /// picker in the gtk::ColorSelectionDialog.
    pub fn warp(&self, screen: &Screen, x: i32, y: i32) {
        unsafe { ffi::gdk_device_warp(self.to_glib_none().0, screen.to_glib_none().0, x, y) }
    }

    /// Grabs the device so that all events coming from this device are passed to this
    /// application until the device is ungrabbed with Device::ungrab(), or the window becomes
    /// unviewable. This overrides any previous grab on the device by this client.
    ///
    /// Note that `self` and `window` need to be on the same display.
    ///
    /// Device grabs are used for operations which need complete control over the given device
    /// events (either pointer or keyboard). For example in GTK+ this is used for Drag and Drop
    /// operations, popup menus and such.
    ///
    /// Note that if the event mask of an X window has selected both button press and button
    /// release events, then a button press event will cause an automatic pointer grab until
    /// the button is released. X does this automatically since most applications expect to
    /// receive button press and release events in pairs. It is equivalent to a pointer grab
    /// on the window with `owner_events` set to true.
    ///
    /// If you set up anything at the time you take the grab that needs to be cleaned up when
    /// the grab ends, you should handle the GdkEventGrabBroken events that are emitted when
    /// the grab ends unvoluntarily.
    pub fn grab(&self, window: &Window, grab_ownership: ::GrabOwnership, owner_events: bool,
                event_mask: ::EventMask, cursor: &Cursor, time_: u32) -> ::GrabStatus {
        unsafe {
            ffi::gdk_device_grab(self.to_glib_none().0, window.to_glib_none().0, grab_ownership,
                owner_events.to_glib(), event_mask, cursor.to_glib_none().0, time_)
        }
    }

    /// Release any grab on `self`.
    pub fn ungrab(&self, time_: u32) {
        unsafe { ffi::gdk_device_ungrab(self.to_glib_none().0, time_) }
    }

    /*pub fn get_state(&self, window: &::Window, axes: &mut [f64], mask: &mut gdk;:ModifierType) {
        unsafe { ffi::gdk_device_get_state(self.to_glib_none().0, window.unwrap_pointer(), axes.as_mut_ptr(), mask) }
    }

    pub fn get_position(&self, x: &mut i32, y: &mut i32) -> Option<::Screen> {
        let mut ptr = ::std::ptr::null_mut();

        unsafe { ffi::gdk_device_get_position(self.to_glib_none().0, &mut ptr, x as *mut c_int, y as *mut c_int) };
        if ptr.is_null() {
            None
        } else {
            Some(::Screen::wrap_pointer(ptr))
        }
    }

    pub fn get_position_double(&self, x: &mut f64, y: &mut f64) -> Option<::Screen> {
        let mut ptr = ::std::ptr::null_mut();

        unsafe { ffi::gdk_device_get_position_double(self.to_glib_none().0, &mut ptr, x as *mut c_double, y as *mut c_double) };
        if ptr.is_null() {
            None
        } else {
            Some(::Screen::wrap_pointer(ptr))
        }
    }

    pub fn get_window_at_position(&self, x: &mut i32, y: &mut i32) -> Option<::Window> {
        let mut ptr = ::std::ptr::null_mut();

        unsafe { ffi::gdk_device_get_window_at_position(self.to_glib_none().0, &mut ptr, x as *mut c_int, y as *mut c_int) };
        if ptr.is_null() {
            None
        } else {
            Some(::Window::wrap_pointer(ptr))
        }
    }

    pub fn get_window_at_position_double(&self, x: &mut f64, y: &mut f64) -> Option<::Window> {
        let mut ptr = ::std::ptr::null_mut();

        unsafe { ffi::gdk_device_get_window_at_position_double(self.to_glib_none().0, &mut ptr, x as *mut c_double, y as *mut c_double) };
        if ptr.is_null() {
            None
        } else {
            Some(::Window::wrap_pointer(ptr))
        }
    }

    pub fn get_history(&self, window: &::Window, start: u32, stop: u32) -> Vec<::TimeCoord> {
        let mut ptr = ::std::ptr::null_mut();
        let mut n_events : c_int = 0;

        unsafe { ffi::gdk_device_get_history(self.to_glib_none().0, window.unwrap_pointer(), start, stop, &mut ptr, &mut n_events) };

        let mut ret = Vec::with_capacity(n_events as uint);

        for i in range(0, n_events) {
            ret.push(::TimeCoord::wrap_pointer(::std::ptr::read(ptr.offset(i))));
        }
        ret
    }

    pub fn free_history(events: &[::TimeCoord]) {
        let mut tmp = Vec::with_capacity(events.len());

        for i in range(0, events.len()) {
            tmp.push(events[i].unwrap_pointer());
        }
        unsafe { ffi::gdk_device_free_history(events.as_mut_ptr(), events.len()) }
    }*/

    /// Interprets an array of double as axis values for a given device, and locates the value
    /// in the array for a given axis use.
    pub fn get_axis(&self, axes: &mut [f64], use_: ::AxisUse, value: &mut f64) -> bool {
        unsafe { from_glib(ffi::gdk_device_get_axis(self.to_glib_none().0, axes.as_mut_ptr(), use_, value)) }
    }

    /*pub fn get_axis_value(&self, axes: &mut [f64], label: &mut ::Atom, value: &mut f64) -> bool {
        unsafe { from_glib(ffi::gdk_device_get_axis_value(self.to_glib_none().0, axes.as_mut_ptr(), label.unwrap_pointer(), value)) }
    }*/

    /*pub fn get_last_event_window(&self) -> Option<::Window> {
        let ptr = unsafe { ffi::gdk_device_get_last_event_window(self.to_glib_none().0) };

        if ptr.is_null() {
            None
        } else {
            Some(::Window::wrap_pointer(ptr))
        }
    }*/
}
<|endoftext|>


<commit_before>use find_folder;
use conrod::{
    Button, Canvas, Colorable, Frameable, Positionable, Labelable, Sizeable, Theme,
    Ui, UiCell, Text, Widget, color
};
use piston_window::{G2d, Glyphs, Graphics, PistonWindow};

use game::{Rustris, GameState};
use stats::GameStats;
use settings::*;

pub type Backend = (<G2d<'static> as Graphics>::Texture, Glyphs);
pub type UI = Ui<Backend>;
pub type UICell<'a> = UiCell<'a, Backend>;

pub fn create_ui(window: &PistonWindow) -> UI {
    let assets = find_folder::Search::KidsThenParents(3, 5)
        .for_folder("assets").unwrap();
    let font_path = assets.join("fonts/NotoSans/NotoSans-Regular.ttf");
    let theme = Theme::default();
    let glyph_cache = Glyphs::new(&font_path, window.factory.clone());
    UI::new(glyph_cache.unwrap(), theme)
}

pub fn set_ui(ref mut ui: UICell, game: &mut Rustris) {
    Canvas::new().flow_right(&[
        (LEFT_COLUMN, Canvas::new().color(color::DARK_CHARCOAL).pad(20.0)),
        (MIDDLE_COLUMN, Canvas::new().color(color::TRANSPARENT).length(300.0)),
        (RIGHT_COLUMN, Canvas::new().color(color::DARK_CHARCOAL).pad(20.0)),
    ]).set(MASTER, ui);
    set_scoreboard(ui, game.get_game_stats());
    set_next_piece(ui);

    if game.is_paused() {
        set_pause_menu(ui, game);
    } else if game.is_game_over() {
        set_game_over_menu(ui, game);
    }

}

fn set_pause_menu(ui: &mut UICell, game: &mut Rustris) {
    Canvas::new()
      .w_h(WINDOW_WIDTH as f64, WINDOW_HEIGHT as f64)
      .floating(true)
      .middle_of(MASTER)
      .rgba(0.0, 0.0, 0.0, 0.3)
      .set(PAUSE_OVERLAY, ui);

    Canvas::new().flow_down(&[
        (RESUME_CANVAS, Canvas::new()),
        (QUIT_CANVAS, Canvas::new())
    ]).label("Paused")
      .label_color(color::WHITE)
      .w_h(200.0, 200.0)
      .frame(1.0)
      .frame_color(color::WHITE)
      .pad(1.0)
      .middle_of(PAUSE_OVERLAY)
      .set(PAUSE_MENU, ui);

    Button::new()
        .label("Resume")
        .label_color(color::WHITE)
        .color(color::CHARCOAL)
        .middle_of(RESUME_CANVAS)
        .w_h(150.0, 30.0)
        .react(|| {
            game.set_game_state(GameState::Playing);
        })
        .set(RESUME_BUTTON, ui);

    Button::new()
        .label("Quit")
        .label_color(color::WHITE)
        .color(color::CHARCOAL)
        .middle_of(QUIT_CANVAS)
        .w_h(150.0, 30.0)
        .react(|| {})
        .set(QUIT_BUTTON, ui);
}

fn set_game_over_menu(ui: &mut UICell, game: &mut Rustris) {
    Canvas::new()
      .w_h(WINDOW_WIDTH as f64, WINDOW_HEIGHT as f64)
      .floating(true)
      .middle_of(MASTER)
      .rgba(0.0, 0.0, 0.0, 0.3)
      .set(GAME_OVER_OVERLAY, ui);

    Canvas::new().flow_down(&[
        (FINAL_SCORE_CANVAS, Canvas::new()),
        (RESTART_CANVAS, Canvas::new())
    ]).label("Game Over")
      .label_color(color::WHITE)
      .w_h(200.0, 200.0)
      .frame(1.0)
      .frame_color(color::WHITE)
      .pad(1.0)
      .middle_of(GAME_OVER_OVERLAY)
      .set(GAME_OVER_MENU, ui);

    {
        let stats = game.get_game_stats();
        Text::new(
            &format!("Final Score: {}", stats.get_score().to_string()))
            .color(color::WHITE)
            .middle_of(FINAL_SCORE_CANVAS)
            .set(FINAL_SCORE_TEXT, ui);
    }

    Button::new()
        .label("New Game?")
        .label_color(color::WHITE)
        .color(color::CHARCOAL)
        .middle_of(RESTART_CANVAS)
        .w_h(150.0, 30.0)
        .react(|| {
            game.reset();
        })
        .set(NEW_GAME_BUTTON, ui);
}

fn set_scoreboard(ui: &mut UICell, stats: &GameStats) {
    Canvas::new().flow_down(&[
        (SCORE_CANVAS, Canvas::new().label("Score").label_color(color::WHITE)),
        (LEVEL_CANVAS, Canvas::new().label("Level").label_color(color::WHITE)),
        (LINES_CANVAS, Canvas::new().label("Lines").label_color(color::WHITE))
    ]).w_h(150.0, 250.0)
      .frame(1.0)
      .frame_color(color::WHITE)
      .pad(1.0)
      .mid_bottom_of(LEFT_COLUMN)
      .set(SCOREBOARD, ui);

    Text::new(&stats.get_score().to_string())
        .color(color::WHITE)
        .middle_of(SCORE_CANVAS)
        .set(SCORE, ui);
    Text::new(&stats.get_level().to_string())
        .color(color::WHITE)
        .middle_of(LEVEL_CANVAS)
        .set(LEVEL, ui);
    Text::new(&stats.get_lines().to_string())
        .color(color::WHITE)
        .middle_of(LINES_CANVAS)
        .set(LINES, ui);
}

fn set_next_piece(ui: &mut UICell) {
    Canvas::new()
        .label("Next Piece")
        .label_color(color::WHITE)
        .w_h(NEXT_PIECE_WIDTH, NEXT_PIECE_HEIGHT)
        .frame(1.0)
        .frame_color(color::WHITE)
        .pad(1.0)
        .mid_top_of(RIGHT_COLUMN)
        .set(NEXT_PIECE, ui);
}

widget_ids! {
    // Canvas IDs
    MASTER,
    LEFT_COLUMN,
    MIDDLE_COLUMN,
    RIGHT_COLUMN,

    // Scoreboard IDs
    SCOREBOARD,
    SCORE_CANVAS,
    LEVEL_CANVAS,
    LINES_CANVAS,
    SCORE,
    LEVEL,
    LINES,

    // Pause Menu
    PAUSE_OVERLAY,
    PAUSE_MENU,
    RESUME_CANVAS,
    RESUME_BUTTON,
    QUIT_CANVAS,
    QUIT_BUTTON,

    // Game Over Menu
    GAME_OVER_OVERLAY,
    GAME_OVER_MENU,
    NEW_GAME_BUTTON,
    RESTART_CANVAS,
    FINAL_SCORE_CANVAS,
    FINAL_SCORE_TEXT,

    // Next Piece IDs
    NEXT_PIECE
}
<commit_msg>remove the quit button. Escape exits anyway<commit_after>use find_folder;
use conrod::{
    Button, Canvas, Colorable, Frameable, Positionable, Labelable, Sizeable, Theme,
    Ui, UiCell, Text, Widget, color
};
use piston_window::{G2d, Glyphs, Graphics, PistonWindow};

use game::{Rustris, GameState};
use stats::GameStats;
use settings::*;

pub type Backend = (<G2d<'static> as Graphics>::Texture, Glyphs);
pub type UI = Ui<Backend>;
pub type UICell<'a> = UiCell<'a, Backend>;

pub fn create_ui(window: &PistonWindow) -> UI {
    let assets = find_folder::Search::KidsThenParents(3, 5)
        .for_folder("assets").unwrap();
    let font_path = assets.join("fonts/NotoSans/NotoSans-Regular.ttf");
    let theme = Theme::default();
    let glyph_cache = Glyphs::new(&font_path, window.factory.clone());
    UI::new(glyph_cache.unwrap(), theme)
}

pub fn set_ui(ref mut ui: UICell, game: &mut Rustris) {
    Canvas::new().flow_right(&[
        (LEFT_COLUMN, Canvas::new().color(color::DARK_CHARCOAL).pad(20.0)),
        (MIDDLE_COLUMN, Canvas::new().color(color::TRANSPARENT).length(300.0)),
        (RIGHT_COLUMN, Canvas::new().color(color::DARK_CHARCOAL).pad(20.0)),
    ]).set(MASTER, ui);
    set_scoreboard(ui, game.get_game_stats());
    set_next_piece(ui);

    if game.is_paused() {
        set_pause_menu(ui, game);
    } else if game.is_game_over() {
        set_game_over_menu(ui, game);
    }

}

fn set_pause_menu(ui: &mut UICell, game: &mut Rustris) {
    Canvas::new()
      .w_h(WINDOW_WIDTH as f64, WINDOW_HEIGHT as f64)
      .floating(true)
      .middle_of(MASTER)
      .rgba(0.0, 0.0, 0.0, 0.3)
      .set(PAUSE_OVERLAY, ui);

    Canvas::new().flow_down(&[
        (RESUME_CANVAS, Canvas::new())
    ]).label("Paused")
      .label_color(color::WHITE)
      .w_h(200.0, 200.0)
      .frame(1.0)
      .frame_color(color::WHITE)
      .pad(1.0)
      .middle_of(PAUSE_OVERLAY)
      .set(PAUSE_MENU, ui);

    Button::new()
        .label("Resume")
        .label_color(color::WHITE)
        .color(color::CHARCOAL)
        .middle_of(RESUME_CANVAS)
        .w_h(150.0, 30.0)
        .react(|| {
            game.set_game_state(GameState::Playing);
        })
        .set(RESUME_BUTTON, ui);
}

fn set_game_over_menu(ui: &mut UICell, game: &mut Rustris) {
    Canvas::new()
      .w_h(WINDOW_WIDTH as f64, WINDOW_HEIGHT as f64)
      .floating(true)
      .middle_of(MASTER)
      .rgba(0.0, 0.0, 0.0, 0.3)
      .set(GAME_OVER_OVERLAY, ui);

    Canvas::new().flow_down(&[
        (FINAL_SCORE_CANVAS, Canvas::new()),
        (RESTART_CANVAS, Canvas::new())
    ]).label("Game Over")
      .label_color(color::WHITE)
      .w_h(200.0, 200.0)
      .frame(1.0)
      .frame_color(color::WHITE)
      .pad(1.0)
      .middle_of(GAME_OVER_OVERLAY)
      .set(GAME_OVER_MENU, ui);

    {
        let stats = game.get_game_stats();
        Text::new(
            &format!("Final Score: {}", stats.get_score().to_string()))
            .color(color::WHITE)
            .middle_of(FINAL_SCORE_CANVAS)
            .set(FINAL_SCORE_TEXT, ui);
    }

    Button::new()
        .label("New Game?")
        .label_color(color::WHITE)
        .color(color::CHARCOAL)
        .middle_of(RESTART_CANVAS)
        .w_h(150.0, 30.0)
        .react(|| {
            game.reset();
        })
        .set(NEW_GAME_BUTTON, ui);
}

fn set_scoreboard(ui: &mut UICell, stats: &GameStats) {
    Canvas::new().flow_down(&[
        (SCORE_CANVAS, Canvas::new().label("Score").label_color(color::WHITE)),
        (LEVEL_CANVAS, Canvas::new().label("Level").label_color(color::WHITE)),
        (LINES_CANVAS, Canvas::new().label("Lines").label_color(color::WHITE))
    ]).w_h(150.0, 250.0)
      .frame(1.0)
      .frame_color(color::WHITE)
      .pad(1.0)
      .mid_bottom_of(LEFT_COLUMN)
      .set(SCOREBOARD, ui);

    Text::new(&stats.get_score().to_string())
        .color(color::WHITE)
        .middle_of(SCORE_CANVAS)
        .set(SCORE, ui);
    Text::new(&stats.get_level().to_string())
        .color(color::WHITE)
        .middle_of(LEVEL_CANVAS)
        .set(LEVEL, ui);
    Text::new(&stats.get_lines().to_string())
        .color(color::WHITE)
        .middle_of(LINES_CANVAS)
        .set(LINES, ui);
}

fn set_next_piece(ui: &mut UICell) {
    Canvas::new()
        .label("Next Piece")
        .label_color(color::WHITE)
        .w_h(NEXT_PIECE_WIDTH, NEXT_PIECE_HEIGHT)
        .frame(1.0)
        .frame_color(color::WHITE)
        .pad(1.0)
        .mid_top_of(RIGHT_COLUMN)
        .set(NEXT_PIECE, ui);
}

widget_ids! {
    // Canvas IDs
    MASTER,
    LEFT_COLUMN,
    MIDDLE_COLUMN,
    RIGHT_COLUMN,

    // Scoreboard IDs
    SCOREBOARD,
    SCORE_CANVAS,
    LEVEL_CANVAS,
    LINES_CANVAS,
    SCORE,
    LEVEL,
    LINES,

    // Pause Menu
    PAUSE_OVERLAY,
    PAUSE_MENU,
    RESUME_CANVAS,
    RESUME_BUTTON,

    // Game Over Menu
    GAME_OVER_OVERLAY,
    GAME_OVER_MENU,
    NEW_GAME_BUTTON,
    RESTART_CANVAS,
    FINAL_SCORE_CANVAS,
    FINAL_SCORE_TEXT,

    // Next Piece IDs
    NEXT_PIECE
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![feature(rustc_private)]
#![feature(str_strip)]

// FIXME: switch to something more ergonomic here, once available.
// (Currently there is no way to opt into sysroot crates without `extern crate`.)
#[allow(unused_extern_crates)]
extern crate rustc;
#[allow(unused_extern_crates)]
extern crate rustc_driver;
#[allow(unused_extern_crates)]
extern crate rustc_errors;
#[allow(unused_extern_crates)]
extern crate rustc_interface;

use rustc::ty::TyCtxt;
use rustc_interface::interface;
use rustc_tools_util::*;

use lazy_static::lazy_static;
use std::borrow::Cow;
use std::env;
use std::ops::Deref;
use std::panic;
use std::path::{Path, PathBuf};
use std::process::{exit, Command};

mod lintlist;

/// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
/// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`.
fn arg_value<'a, T: Deref<Target = str>>(
    args: &'a [T],
    find_arg: &str,
    pred: impl Fn(&str) -> bool,
) -> Option<&'a str> {
    let mut args = args.iter().map(Deref::deref);
    while let Some(arg) = args.next() {
        let mut arg = arg.splitn(2, '=');
        if arg.next() != Some(find_arg) {
            continue;
        }

        match arg.next().or_else(|| args.next()) {
            Some(v) if pred(v) => return Some(v),
            _ => {},
        }
    }
    None
}

#[test]
fn test_arg_value() {
    let args = &["--bar=bar", "--foobar", "123", "--foo"];

    assert_eq!(arg_value(&[] as &[&str], "--foobar", |_| true), None);
    assert_eq!(arg_value(args, "--bar", |_| false), None);
    assert_eq!(arg_value(args, "--bar", |_| true), Some("bar"));
    assert_eq!(arg_value(args, "--bar", |p| p == "bar"), Some("bar"));
    assert_eq!(arg_value(args, "--bar", |p| p == "foo"), None);
    assert_eq!(arg_value(args, "--foobar", |p| p == "foo"), None);
    assert_eq!(arg_value(args, "--foobar", |p| p == "123"), Some("123"));
    assert_eq!(arg_value(args, "--foo", |_| true), None);
}

#[allow(clippy::too_many_lines)]

struct ClippyCallbacks;

impl rustc_driver::Callbacks for ClippyCallbacks {
    fn config(&mut self, config: &mut interface::Config) {
        let previous = config.register_lints.take();
        config.register_lints = Some(Box::new(move |sess, mut lint_store| {
            // technically we're ~guaranteed that this is none but might as well call anything that
            // is there already. Certainly it can't hurt.
            if let Some(previous) = &previous {
                (previous)(sess, lint_store);
            }

            let conf = clippy_lints::read_conf(&[], &sess);
            clippy_lints::register_plugins(&mut lint_store, &sess, &conf);
            clippy_lints::register_pre_expansion_lints(&mut lint_store, &conf);
            clippy_lints::register_renamed(&mut lint_store);
        }));

        // FIXME: #4825; This is required, because Clippy lints that are based on MIR have to be
        // run on the unoptimized MIR. On the other hand this results in some false negatives. If
        // MIR passes can be enabled / disabled separately, we should figure out, what passes to
        // use for Clippy.
        config.opts.debugging_opts.mir_opt_level = 0;
    }
}

#[allow(clippy::find_map, clippy::filter_map)]
fn describe_lints() {
    use lintlist::*;
    use std::collections::HashSet;

    println!(
        "
Available lint options:
    -W <foo>           Warn about <foo>
    -A <foo>           Allow <foo>
    -D <foo>           Deny <foo>
    -F <foo>           Forbid <foo> (deny <foo> and all attempts to override)

"
    );

    let lint_level = |lint: &Lint| {
        LINT_LEVELS
            .iter()
            .find(|level_mapping| level_mapping.0 == lint.group)
            .map(|(_, level)| match level {
                Level::Allow => "allow",
                Level::Warn => "warn",
                Level::Deny => "deny",
            })
            .unwrap()
    };

    let mut lints: Vec<_> = ALL_LINTS.iter().collect();
    // The sort doesn't case-fold but it's doubtful we care.
    lints.sort_by_cached_key(|x: &&Lint| (lint_level(x), x.name));

    let max_lint_name_len = lints
        .iter()
        .map(|lint| lint.name.len())
        .map(|len| len + "clippy::".len())
        .max()
        .unwrap_or(0);

    let padded = |x: &str| {
        let mut s = " ".repeat(max_lint_name_len - x.chars().count());
        s.push_str(x);
        s
    };

    let scoped = |x: &str| format!("clippy::{}", x);

    let lint_groups: HashSet<_> = lints.iter().map(|lint| lint.group).collect();

    println!("Lint checks provided by clippy:\n");
    println!("    {}  {:7.7}  meaning", padded("name"), "default");
    println!("    {}  {:7.7}  -------", padded("----"), "-------");

    let print_lints = |lints: &[&Lint]| {
        for lint in lints {
            let name = lint.name.replace("_", "-");
            println!(
                "    {}  {:7.7}  {}",
                padded(&scoped(&name)),
                lint_level(lint),
                lint.desc
            );
        }
        println!("\n");
    };

    print_lints(&lints);

    let max_group_name_len = std::cmp::max(
        "clippy::all".len(),
        lint_groups
            .iter()
            .map(|group| group.len())
            .map(|len| len + "clippy::".len())
            .max()
            .unwrap_or(0),
    );

    let padded_group = |x: &str| {
        let mut s = " ".repeat(max_group_name_len - x.chars().count());
        s.push_str(x);
        s
    };

    println!("Lint groups provided by clippy:\n");
    println!("    {}  sub-lints", padded_group("name"));
    println!("    {}  ---------", padded_group("----"));
    println!("    {}  the set of all clippy lints", padded_group("clippy::all"));

    let print_lint_groups = || {
        for group in lint_groups {
            let name = group.to_lowercase().replace("_", "-");
            let desc = lints
                .iter()
                .filter(|&lint| lint.group == group)
                .map(|lint| lint.name)
                .map(|name| name.replace("_", "-"))
                .collect::<Vec<String>>()
                .join(", ");
            println!("    {}  {}", padded_group(&scoped(&name)), desc);
        }
        println!("\n");
    };

    print_lint_groups();
}

fn display_help() {
    println!(
        "\
Checks a package to catch common mistakes and improve your Rust code.

Usage:
    cargo clippy [options] [--] [<opts>...]

Common options:
    -h, --help               Print this message
    -V, --version            Print version info and exit

Other options are the same as `cargo check`.

To allow or deny a lint from the command line you can use `cargo clippy --`
with:

    -W --warn OPT       Set lint warnings
    -A --allow OPT      Set lint allowed
    -D --deny OPT       Set lint denied
    -F --forbid OPT     Set lint forbidden

You can use tool lints to allow or deny lints from your code, eg.:

    #[allow(clippy::needless_lifetimes)]
"
    );
}

const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new";

lazy_static! {
    static ref ICE_HOOK: Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static> = {
        let hook = panic::take_hook();
        panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL)));
        hook
    };
}

fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
    // Invoke our ICE handler, which prints the actual panic message and optionally a backtrace
    (*ICE_HOOK)(info);

    // Separate the output with an empty line
    eprintln!();

    let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
        rustc_errors::ColorConfig::Auto,
        None,
        false,
        false,
        None,
        false,
    ));
    let handler = rustc_errors::Handler::with_emitter(true, None, emitter);

    // a .span_bug or .bug call has already printed what
    // it wants to print.
    if !info.payload().is::<rustc_errors::ExplicitBug>() {
        let d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic");
        handler.emit_diagnostic(&d);
    }

    let version_info = rustc_tools_util::get_version_info!();

    let xs: Vec<Cow<'static, str>> = vec![
        "the compiler unexpectedly panicked. this is a bug.".into(),
        format!("we would appreciate a bug report: {}", bug_report_url).into(),
        format!("Clippy version: {}", version_info).into(),
    ];

    for note in &xs {
        handler.note_without_error(&note);
    }

    // If backtraces are enabled, also print the query stack
    let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0");

    if backtrace {
        TyCtxt::try_print_query_stack(&handler);
    }
}

pub fn main() {
    rustc_driver::init_rustc_env_logger();
    lazy_static::initialize(&ICE_HOOK);
    exit(
        rustc_driver::catch_fatal_errors(move || {
            let mut orig_args: Vec<String> = env::args().collect();

            if orig_args.iter().any(|a| a == "--version" || a == "-V") {
                let version_info = rustc_tools_util::get_version_info!();
                println!("{}", version_info);
                exit(0);
            }

            // Get the sysroot, looking from most specific to this invocation to the least:
            // - command line
            // - runtime environment
            //    - SYSROOT
            //    - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN
            // - sysroot from rustc in the path
            // - compile-time environment
            let sys_root_arg = arg_value(&orig_args, "--sysroot", |_| true);
            let have_sys_root_arg = sys_root_arg.is_some();
            let sys_root = sys_root_arg
                .map(PathBuf::from)
                .or_else(|| std::env::var("SYSROOT").ok().map(PathBuf::from))
                .or_else(|| {
                    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
                    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
                    home.and_then(|home| {
                        toolchain.map(|toolchain| {
                            let mut path = PathBuf::from(home);
                            path.push("toolchains");
                            path.push(toolchain);
                            path
                        })
                    })
                })
                .or_else(|| {
                    Command::new("rustc")
                        .arg("--print")
                        .arg("sysroot")
                        .output()
                        .ok()
                        .and_then(|out| String::from_utf8(out.stdout).ok())
                        .map(|s| PathBuf::from(s.trim()))
                })
                .or_else(|| option_env!("SYSROOT").map(PathBuf::from))
                .map(|pb| pb.to_string_lossy().to_string())
                .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust");

            // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
            // We're invoking the compiler programmatically, so we ignore this/
            let wrapper_mode = orig_args.get(1).map(Path::new).and_then(Path::file_stem) == Some("rustc".as_ref());

            if wrapper_mode {
                // we still want to be able to invoke it normally though
                orig_args.remove(1);
            }

            if !wrapper_mode && (orig_args.iter().any(|a| a == "--help" || a == "-h") || orig_args.len() == 1) {
                display_help();
                exit(0);
            }

            let should_describe_lints = || {
                let args: Vec<_> = env::args().collect();
                args.windows(2).any(|args| {
                    args[1] == "help"
                        && match args[0].as_str() {
                            "-W" | "-A" | "-D" | "-F" => true,
                            _ => false,
                        }
                })
            };

            if !wrapper_mode && should_describe_lints() {
                describe_lints();
                exit(0);
            }

            // this conditional check for the --sysroot flag is there so users can call
            // `clippy_driver` directly
            // without having to pass --sysroot or anything
            let mut args: Vec<String> = orig_args.clone();
            if !have_sys_root_arg {
                args.extend(vec!["--sysroot".into(), sys_root]);
            };

            // this check ensures that dependencies are built but not linted and the final
            // crate is linted but not built
            let clippy_enabled = env::var("CLIPPY_TESTS").map_or(false, |val| val == "true")
                || arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_none();

            if clippy_enabled {
                args.extend(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]);
                if let Ok(extra_args) = env::var("CLIPPY_ARGS") {
                    args.extend(extra_args.split("__CLIPPY_HACKERY__").filter_map(|s| {
                        if s.is_empty() {
                            None
                        } else {
                            Some(s.to_string())
                        }
                    }));
                }
            }
            let mut clippy = ClippyCallbacks;
            let mut default = rustc_driver::DefaultCallbacks;
            let callbacks: &mut (dyn rustc_driver::Callbacks + Send) =
                if clippy_enabled { &mut clippy } else { &mut default };
            rustc_driver::run_compiler(&args, callbacks, None, None)
        })
        .and_then(|result| result)
        .is_err() as i32,
    )
}
<commit_msg>Impl DefaultCallbacks on our side<commit_after>#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![feature(rustc_private)]
#![feature(str_strip)]

// FIXME: switch to something more ergonomic here, once available.
// (Currently there is no way to opt into sysroot crates without `extern crate`.)
#[allow(unused_extern_crates)]
extern crate rustc;
#[allow(unused_extern_crates)]
extern crate rustc_driver;
#[allow(unused_extern_crates)]
extern crate rustc_errors;
#[allow(unused_extern_crates)]
extern crate rustc_interface;

use rustc::ty::TyCtxt;
use rustc_interface::interface;
use rustc_tools_util::*;

use lazy_static::lazy_static;
use std::borrow::Cow;
use std::env;
use std::ops::Deref;
use std::panic;
use std::path::{Path, PathBuf};
use std::process::{exit, Command};

mod lintlist;

/// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
/// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`.
fn arg_value<'a, T: Deref<Target = str>>(
    args: &'a [T],
    find_arg: &str,
    pred: impl Fn(&str) -> bool,
) -> Option<&'a str> {
    let mut args = args.iter().map(Deref::deref);
    while let Some(arg) = args.next() {
        let mut arg = arg.splitn(2, '=');
        if arg.next() != Some(find_arg) {
            continue;
        }

        match arg.next().or_else(|| args.next()) {
            Some(v) if pred(v) => return Some(v),
            _ => {},
        }
    }
    None
}

#[test]
fn test_arg_value() {
    let args = &["--bar=bar", "--foobar", "123", "--foo"];

    assert_eq!(arg_value(&[] as &[&str], "--foobar", |_| true), None);
    assert_eq!(arg_value(args, "--bar", |_| false), None);
    assert_eq!(arg_value(args, "--bar", |_| true), Some("bar"));
    assert_eq!(arg_value(args, "--bar", |p| p == "bar"), Some("bar"));
    assert_eq!(arg_value(args, "--bar", |p| p == "foo"), None);
    assert_eq!(arg_value(args, "--foobar", |p| p == "foo"), None);
    assert_eq!(arg_value(args, "--foobar", |p| p == "123"), Some("123"));
    assert_eq!(arg_value(args, "--foo", |_| true), None);
}

struct DefaultCallbacks;
impl rustc_driver::Callbacks for DefaultCallbacks {}

struct ClippyCallbacks;
impl rustc_driver::Callbacks for ClippyCallbacks {
    fn config(&mut self, config: &mut interface::Config) {
        let previous = config.register_lints.take();
        config.register_lints = Some(Box::new(move |sess, mut lint_store| {
            // technically we're ~guaranteed that this is none but might as well call anything that
            // is there already. Certainly it can't hurt.
            if let Some(previous) = &previous {
                (previous)(sess, lint_store);
            }

            let conf = clippy_lints::read_conf(&[], &sess);
            clippy_lints::register_plugins(&mut lint_store, &sess, &conf);
            clippy_lints::register_pre_expansion_lints(&mut lint_store, &conf);
            clippy_lints::register_renamed(&mut lint_store);
        }));

        // FIXME: #4825; This is required, because Clippy lints that are based on MIR have to be
        // run on the unoptimized MIR. On the other hand this results in some false negatives. If
        // MIR passes can be enabled / disabled separately, we should figure out, what passes to
        // use for Clippy.
        config.opts.debugging_opts.mir_opt_level = 0;
    }
}

#[allow(clippy::find_map, clippy::filter_map)]
fn describe_lints() {
    use lintlist::*;
    use std::collections::HashSet;

    println!(
        "
Available lint options:
    -W <foo>           Warn about <foo>
    -A <foo>           Allow <foo>
    -D <foo>           Deny <foo>
    -F <foo>           Forbid <foo> (deny <foo> and all attempts to override)

"
    );

    let lint_level = |lint: &Lint| {
        LINT_LEVELS
            .iter()
            .find(|level_mapping| level_mapping.0 == lint.group)
            .map(|(_, level)| match level {
                Level::Allow => "allow",
                Level::Warn => "warn",
                Level::Deny => "deny",
            })
            .unwrap()
    };

    let mut lints: Vec<_> = ALL_LINTS.iter().collect();
    // The sort doesn't case-fold but it's doubtful we care.
    lints.sort_by_cached_key(|x: &&Lint| (lint_level(x), x.name));

    let max_lint_name_len = lints
        .iter()
        .map(|lint| lint.name.len())
        .map(|len| len + "clippy::".len())
        .max()
        .unwrap_or(0);

    let padded = |x: &str| {
        let mut s = " ".repeat(max_lint_name_len - x.chars().count());
        s.push_str(x);
        s
    };

    let scoped = |x: &str| format!("clippy::{}", x);

    let lint_groups: HashSet<_> = lints.iter().map(|lint| lint.group).collect();

    println!("Lint checks provided by clippy:\n");
    println!("    {}  {:7.7}  meaning", padded("name"), "default");
    println!("    {}  {:7.7}  -------", padded("----"), "-------");

    let print_lints = |lints: &[&Lint]| {
        for lint in lints {
            let name = lint.name.replace("_", "-");
            println!(
                "    {}  {:7.7}  {}",
                padded(&scoped(&name)),
                lint_level(lint),
                lint.desc
            );
        }
        println!("\n");
    };

    print_lints(&lints);

    let max_group_name_len = std::cmp::max(
        "clippy::all".len(),
        lint_groups
            .iter()
            .map(|group| group.len())
            .map(|len| len + "clippy::".len())
            .max()
            .unwrap_or(0),
    );

    let padded_group = |x: &str| {
        let mut s = " ".repeat(max_group_name_len - x.chars().count());
        s.push_str(x);
        s
    };

    println!("Lint groups provided by clippy:\n");
    println!("    {}  sub-lints", padded_group("name"));
    println!("    {}  ---------", padded_group("----"));
    println!("    {}  the set of all clippy lints", padded_group("clippy::all"));

    let print_lint_groups = || {
        for group in lint_groups {
            let name = group.to_lowercase().replace("_", "-");
            let desc = lints
                .iter()
                .filter(|&lint| lint.group == group)
                .map(|lint| lint.name)
                .map(|name| name.replace("_", "-"))
                .collect::<Vec<String>>()
                .join(", ");
            println!("    {}  {}", padded_group(&scoped(&name)), desc);
        }
        println!("\n");
    };

    print_lint_groups();
}

fn display_help() {
    println!(
        "\
Checks a package to catch common mistakes and improve your Rust code.

Usage:
    cargo clippy [options] [--] [<opts>...]

Common options:
    -h, --help               Print this message
    -V, --version            Print version info and exit

Other options are the same as `cargo check`.

To allow or deny a lint from the command line you can use `cargo clippy --`
with:

    -W --warn OPT       Set lint warnings
    -A --allow OPT      Set lint allowed
    -D --deny OPT       Set lint denied
    -F --forbid OPT     Set lint forbidden

You can use tool lints to allow or deny lints from your code, eg.:

    #[allow(clippy::needless_lifetimes)]
"
    );
}

const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new";

lazy_static! {
    static ref ICE_HOOK: Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static> = {
        let hook = panic::take_hook();
        panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL)));
        hook
    };
}

fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
    // Invoke our ICE handler, which prints the actual panic message and optionally a backtrace
    (*ICE_HOOK)(info);

    // Separate the output with an empty line
    eprintln!();

    let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
        rustc_errors::ColorConfig::Auto,
        None,
        false,
        false,
        None,
        false,
    ));
    let handler = rustc_errors::Handler::with_emitter(true, None, emitter);

    // a .span_bug or .bug call has already printed what
    // it wants to print.
    if !info.payload().is::<rustc_errors::ExplicitBug>() {
        let d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic");
        handler.emit_diagnostic(&d);
    }

    let version_info = rustc_tools_util::get_version_info!();

    let xs: Vec<Cow<'static, str>> = vec![
        "the compiler unexpectedly panicked. this is a bug.".into(),
        format!("we would appreciate a bug report: {}", bug_report_url).into(),
        format!("Clippy version: {}", version_info).into(),
    ];

    for note in &xs {
        handler.note_without_error(&note);
    }

    // If backtraces are enabled, also print the query stack
    let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0");

    if backtrace {
        TyCtxt::try_print_query_stack(&handler);
    }
}

pub fn main() {
    rustc_driver::init_rustc_env_logger();
    lazy_static::initialize(&ICE_HOOK);
    exit(
        rustc_driver::catch_fatal_errors(move || {
            let mut orig_args: Vec<String> = env::args().collect();

            if orig_args.iter().any(|a| a == "--version" || a == "-V") {
                let version_info = rustc_tools_util::get_version_info!();
                println!("{}", version_info);
                exit(0);
            }

            // Get the sysroot, looking from most specific to this invocation to the least:
            // - command line
            // - runtime environment
            //    - SYSROOT
            //    - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN
            // - sysroot from rustc in the path
            // - compile-time environment
            let sys_root_arg = arg_value(&orig_args, "--sysroot", |_| true);
            let have_sys_root_arg = sys_root_arg.is_some();
            let sys_root = sys_root_arg
                .map(PathBuf::from)
                .or_else(|| std::env::var("SYSROOT").ok().map(PathBuf::from))
                .or_else(|| {
                    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
                    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
                    home.and_then(|home| {
                        toolchain.map(|toolchain| {
                            let mut path = PathBuf::from(home);
                            path.push("toolchains");
                            path.push(toolchain);
                            path
                        })
                    })
                })
                .or_else(|| {
                    Command::new("rustc")
                        .arg("--print")
                        .arg("sysroot")
                        .output()
                        .ok()
                        .and_then(|out| String::from_utf8(out.stdout).ok())
                        .map(|s| PathBuf::from(s.trim()))
                })
                .or_else(|| option_env!("SYSROOT").map(PathBuf::from))
                .map(|pb| pb.to_string_lossy().to_string())
                .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust");

            // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
            // We're invoking the compiler programmatically, so we ignore this/
            let wrapper_mode = orig_args.get(1).map(Path::new).and_then(Path::file_stem) == Some("rustc".as_ref());

            if wrapper_mode {
                // we still want to be able to invoke it normally though
                orig_args.remove(1);
            }

            if !wrapper_mode && (orig_args.iter().any(|a| a == "--help" || a == "-h") || orig_args.len() == 1) {
                display_help();
                exit(0);
            }

            let should_describe_lints = || {
                let args: Vec<_> = env::args().collect();
                args.windows(2).any(|args| {
                    args[1] == "help"
                        && match args[0].as_str() {
                            "-W" | "-A" | "-D" | "-F" => true,
                            _ => false,
                        }
                })
            };

            if !wrapper_mode && should_describe_lints() {
                describe_lints();
                exit(0);
            }

            // this conditional check for the --sysroot flag is there so users can call
            // `clippy_driver` directly
            // without having to pass --sysroot or anything
            let mut args: Vec<String> = orig_args.clone();
            if !have_sys_root_arg {
                args.extend(vec!["--sysroot".into(), sys_root]);
            };

            // this check ensures that dependencies are built but not linted and the final
            // crate is linted but not built
            let clippy_enabled = env::var("CLIPPY_TESTS").map_or(false, |val| val == "true")
                || arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_none();

            if clippy_enabled {
                args.extend(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]);
                if let Ok(extra_args) = env::var("CLIPPY_ARGS") {
                    args.extend(extra_args.split("__CLIPPY_HACKERY__").filter_map(|s| {
                        if s.is_empty() {
                            None
                        } else {
                            Some(s.to_string())
                        }
                    }));
                }
            }
            let mut clippy = ClippyCallbacks;
            let mut default = DefaultCallbacks;
            let callbacks: &mut (dyn rustc_driver::Callbacks + Send) =
                if clippy_enabled { &mut clippy } else { &mut default };
            rustc_driver::run_compiler(&args, callbacks, None, None)
        })
        .and_then(|result| result)
        .is_err() as i32,
    )
}
<|endoftext|>


<commit_before>use reflector::Reflector;
use rotor::Rotor;

#[derive(Clone, Debug)]
pub struct Enigma {
    slow: Rotor,
    mid: Rotor,
    fast: Rotor,
    reflector: Reflector,
}

impl Enigma {
    /// Creates a new `Enigma`.
    pub fn new(slow: usize, mid: usize, fast: usize, reflector: char) -> Enigma {
        let reflector = (reflector as usize) - 65;

        Enigma {
            slow: ROTORS[slow - 1].clone(),
            mid: ROTORS[mid - 1].clone(),
            fast: ROTORS[fast - 1].clone(),
            reflector: REFLECTORS[reflector - 1].clone(),
        }
    }

    /// Advances the `fast` rotor of the `Enigma`, and also advances
    /// the `mid` and `slow` rotors if appropriate.
    pub fn advance(&mut self) {
        if self.fast.advance() {
            if self.mid.advance() {
                self.slow.advance();
            }
        }
    }
}

lazy_static! {
    static ref ROTORS: Vec<Rotor> = vec![
        Rotor::new("EKMFLGDQVZNTOWYHXUSPAIBRCJ", "Q"),
        Rotor::new("AJDKSIRUXBLHWTMCQGZNPYFVOE", "E"),
        Rotor::new("BDFHJLCPRTXVZNYEIWGAKMUSQO", "V"),
        Rotor::new("ESOVPZJAYQUIRHXLNFTGKDCMWB", "J"),
        Rotor::new("VZBRGITYUPSDNHLXAWMJQOFECK", "Z"),
        Rotor::new("JPGVOUMFYQBENHZRDKASXLICTW", "ZM"),
        Rotor::new("NZJHGRCXMYSWBOUFAIVLPEKQDT", "ZM"),
        Rotor::new("FKQHTLXOCBJSPDZRAMEWNIUYGV", "ZM"),
    ];

    static ref REFLECTORS: Vec<Reflector> = vec![
        Reflector::new("EJMZALYXVBWFCRQUONTSPIKHGD"),
        Reflector::new("YRUHQSLDPXNGOKMIEBFZCWVJAT"),
        Reflector::new("FVPJIAOYEDRZXWGCTKUQSBNMHL"),
    ];
}

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

    #[test]
    fn advance_enigma() {
        let mut enigma = Enigma::new(1, 2, 3, 'B');
        enigma.advance();
    }
}
<commit_msg>Choose correct reflector in Enigma::new()<commit_after>use reflector::Reflector;
use rotor::Rotor;

#[derive(Clone, Debug)]
pub struct Enigma {
    slow: Rotor,
    mid: Rotor,
    fast: Rotor,
    reflector: Reflector,
}

impl Enigma {
    /// Creates a new `Enigma`.
    pub fn new(slow: usize, mid: usize, fast: usize, reflector: char) -> Enigma {
        let reflector = (reflector as usize) - 65;

        Enigma {
            slow: ROTORS[slow - 1].clone(),
            mid: ROTORS[mid - 1].clone(),
            fast: ROTORS[fast - 1].clone(),
            reflector: REFLECTORS[reflector].clone(),
        }
    }

    /// Advances the `fast` rotor of the `Enigma`, and also advances
    /// the `mid` and `slow` rotors if appropriate.
    pub fn advance(&mut self) {
        if self.fast.advance() {
            if self.mid.advance() {
                self.slow.advance();
            }
        }
    }
}

lazy_static! {
    static ref ROTORS: Vec<Rotor> = vec![
        Rotor::new("EKMFLGDQVZNTOWYHXUSPAIBRCJ", "Q"),
        Rotor::new("AJDKSIRUXBLHWTMCQGZNPYFVOE", "E"),
        Rotor::new("BDFHJLCPRTXVZNYEIWGAKMUSQO", "V"),
        Rotor::new("ESOVPZJAYQUIRHXLNFTGKDCMWB", "J"),
        Rotor::new("VZBRGITYUPSDNHLXAWMJQOFECK", "Z"),
        Rotor::new("JPGVOUMFYQBENHZRDKASXLICTW", "ZM"),
        Rotor::new("NZJHGRCXMYSWBOUFAIVLPEKQDT", "ZM"),
        Rotor::new("FKQHTLXOCBJSPDZRAMEWNIUYGV", "ZM"),
    ];

    static ref REFLECTORS: Vec<Reflector> = vec![
        Reflector::new("EJMZALYXVBWFCRQUONTSPIKHGD"),
        Reflector::new("YRUHQSLDPXNGOKMIEBFZCWVJAT"),
        Reflector::new("FVPJIAOYEDRZXWGCTKUQSBNMHL"),
    ];
}

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

    #[test]
    fn advance_enigma() {
        let mut enigma = Enigma::new(1, 2, 3, 'B');
        enigma.advance();
    }
}
<|endoftext|>


<commit_before>use std;
use bincode;
use std::path::PathBuf;

static ISSUE_TEMPLATE: &'static str = r#"
=> If this is a bug please file an issue at: https://git.io/v96U6"#;

error_chain! {
    errors {
        BookmarkNotFound(name: String) {
            description("Bookmark not found")
            display("There is no entry for the bookmark {}", name)
        }

        InfoFlagRequiresName {
            description("--info requires <name>")
            display("For example: to -i foo")
        }

        DeleteFlagRequiresName {
            description("--delete requires <name>")
            display("For example: to -d foo")
        }

        ToRequiresName {
            description("requires <name>")
            display("For example: to foo")
        }

        DBOpenError(path: PathBuf) {
            description("Failed to open bookmark DB.")
            display("Failed to open db file: {:?}.{}", path, ISSUE_TEMPLATE)
        }

        DBCloseError(path: PathBuf) {
            description("Failed to close DB file")
            display("Could not close: \n\"{:?}\"\n\n{}", path, ISSUE_TEMPLATE)
        }

        ResolveError(path: PathBuf) {
            description("Failed to resolve path.")
            display("Failed to resolve {:?}.{}", path, ISSUE_TEMPLATE)
        }

        PathDoesNotExistError(path: PathBuf) {
            description("Path does not exist.")
            display("Path does not exist {:?}.{}", path, ISSUE_TEMPLATE)
        }

        CurrentDirectoryError(path: PathBuf) {
            description("Failed to derive current directory.")
            display("Failed to get current dir when resolving {:?}.{}", path, ISSUE_TEMPLATE)
        }

        ConfigError {
            description("Unable to derive config")
            display("{}", ISSUE_TEMPLATE)
        }

        BasenameError(path: PathBuf) {
            description("Failed to derive basename")
            display("Could not derive basename from {:?}.{}", path, ISSUE_TEMPLATE)
        }

        CreateDirError(path: PathBuf) {
            description("Failed to create dir")
            display("Failed to create {:?}.{}", path, ISSUE_TEMPLATE)
        }
    }

    foreign_links {
        IOError(std::io::Error) #[doc = "Error during IO"];
        BincodeError(std::boxed::Box<bincode::ErrorKind>);
    }
}
<commit_msg>Testing out error tests<commit_after>use bincode;
use std;
use std::path::PathBuf;

static ISSUE_TEMPLATE: &'static str = r#"
=> If this is a bug please file an issue at: https://git.io/v96U6"#;

error_chain! {
    errors {
        BookmarkNotFound(name: String) {
            description("Bookmark not found")
            display("The bookmark \"{}\" was not found", name)
        }

        InfoFlagRequiresName {
            description("--info requires <name>")
            display("For example: to -i foo")
        }

        DeleteFlagRequiresName {
            description("--delete requires <name>")
            display("For example: to -d foo")
        }

        ToRequiresName {
            description("requires <name>")
            display("For example: to foo")
        }

        DBOpenError(path: PathBuf) {
            description("Failed to open bookmark DB.")
            display("Failed to open db file: {:?}.{}", path, ISSUE_TEMPLATE)
        }

        DBCloseError(path: PathBuf) {
            description("Failed to close DB file")
            display("Could not close: \n\"{:?}\"\n\n{}", path, ISSUE_TEMPLATE)
        }

        ResolveError(path: PathBuf) {
            description("Failed to resolve path.")
            display("Failed to resolve {:?}.{}", path, ISSUE_TEMPLATE)
        }

        PathDoesNotExistError(path: PathBuf) {
            description("Path does not exist.")
            display("Path does not exist {:?}.{}", path, ISSUE_TEMPLATE)
        }

        CurrentDirectoryError(path: PathBuf) {
            description("Failed to derive current directory.")
            display("Failed to get current dir when resolving {:?}.{}", path, ISSUE_TEMPLATE)
        }

        ConfigError {
            description("Unable to derive config")
            display("{}", ISSUE_TEMPLATE)
        }

        BasenameError(path: PathBuf) {
            description("Failed to derive basename")
            display("Could not derive basename from {:?}.{}", path, ISSUE_TEMPLATE)
        }

        CreateDirError(path: PathBuf) {
            description("Failed to create dir")
            display("Failed to create {:?}.{}", path, ISSUE_TEMPLATE)
        }
    }

    foreign_links {
        IOError(std::io::Error) #[doc = "Error during IO"];
        BincodeError(std::boxed::Box<bincode::ErrorKind>);
    }
}

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

    #[test]
    fn bookmark_not_found() {
        let name = String::from("nope");
        let err = ErrorKind::BookmarkNotFound(name);
        assert_eq!(err.description(), "Bookmark not found");
        assert_eq!(err.to_string(), "The bookmark \"nope\" was not found");
    }
}
<|endoftext|>


<commit_before>
use std::io::Read;  // Trait providing read_to_string()

use std::env;

use hyper;
use rustc_serialize;

use projects;
use groups;

pub const API_VERSION: u16 = 3;

#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct Version {
    pub version: String,
    pub revision: String,
}

#[derive(Debug)]
pub struct Pagination {
    pub page: u16,
    pub per_page: u16,
}

#[derive(Debug)]
pub struct GitLab {
    scheme: String,
    domain: String,
    port: u16,
    private_token: String,
    client: hyper::Client,
    pagination: Pagination,
}

impl GitLab {

    pub fn new(scheme: &str, domain: &str, port: u16, private_token: &str) -> GitLab {
        GitLab {
            scheme: scheme.to_string(),
            domain: domain.to_string(),
            port:   port,
            private_token: private_token.to_string(),
            client: match env::var("HTTP_PROXY") {
                Ok(proxy) => {
                    println!("proxy: {:?}", proxy);
                    let proxy: Vec<&str> = proxy.trim_left_matches("http://").split(':').collect();
                    let hostname = proxy[0].to_string();
                    let port = proxy[1];

                    hyper::Client::with_http_proxy(hostname, port.parse().unwrap())
                },
                Err(_) => hyper::Client::new(),
            },
            pagination: Pagination {page: 1, per_page: 20},
        }
    }

    pub fn new_http(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("http", &domain, 80, &private_token)
    }

    pub fn new_https(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("https", &domain, 443, &private_token)
    }

    pub fn build_url(&self, command: &str) -> String {
        format!("{}://{}:{}/api/v{}/{}?private_token={}&page={}&per_page={}",
                                self.scheme,
                                self.domain,
                                self.port,
                                API_VERSION,
                                command,
                                self.private_token,
                                self.pagination.page,
                                self.pagination.per_page)
    }

    pub fn attempt_connection(&self) -> Result<hyper::client::Response, hyper::Error> {
        // self.get("version")
        let url = self.build_url("version");
        // Close connections after each GET.
        let res = self.client.get(&url).header(hyper::header::Connection::close()).send();

        res
    }

    pub fn set_pagination(&mut self, pagination: Pagination) {
        self.pagination = pagination;
    }

    pub fn get<T>(&self, command: &str) -> Result<T, rustc_serialize::json::DecoderError>
            where T: rustc_serialize::Decodable {

        let url = self.build_url(command);
        let mut res: hyper::client::Response =
                        self.client
                        .get(&url)
                        .header(hyper::header::Connection::close())
                        .send()
                        .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        rustc_serialize::json::decode(body.as_str())
    }

    pub fn version(&self) -> Result<Version, rustc_serialize::json::DecoderError> {
        self.get("version")
    }

    pub fn groups(&self) -> Result<groups::Groups, rustc_serialize::json::DecoderError> {
        self.get("groups")
    }

    pub fn projects(&self) -> Result<projects::Projects, rustc_serialize::json::DecoderError> {
        self.get("projects")
    }
}

#[cfg(test)]
mod tests {
    use std::env;
    use gitlab::GitLab;
    use gitlab::Pagination;

    #[test]
    fn list_groups() {
        let token = match env::var("GITLAB_TOKEN") {
            Ok(val) => val,
            Err(_)  => panic!("Please set environment variable 'GITLAB_TOKEN'"),
        };

        let mut gl = GitLab::new_https("gitlab.com", &token);
        gl.set_pagination(Pagination{page: 1, per_page: 100});
        println!("gl: {:?}", gl);

        let groups = gl.groups().unwrap();
        println!("groups: {:?}", groups);
    }

    #[test]
    fn list_projects() {
        let token = match env::var("GITLAB_TOKEN") {
            Ok(val) => val,
            Err(_)  => panic!("Please set environment variable 'GITLAB_TOKEN'"),
        };

        let mut gl = GitLab::new_https("gitlab.com", &token);
        // for i in 1..82 {
        //     gl.set_pagination(Pagination{page: i, per_page: 1});
        //     println!("projects: {:?}", gl.projects().unwrap());
        // }
        //     println!("projects: {:?}", gl.projects().unwrap());
        gl.set_pagination(Pagination{page: 1, per_page: 100});
        let projects = gl.projects().unwrap();

        // assert_eq!(gl.attempt_connection().unwrap().status, hyper::Ok);

    }
}
<commit_msg>Cleanup debug print<commit_after>
use std::io::Read;  // Trait providing read_to_string()

use std::env;

use hyper;
use rustc_serialize;

use projects;
use groups;

pub const API_VERSION: u16 = 3;

#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct Version {
    pub version: String,
    pub revision: String,
}

#[derive(Debug)]
pub struct Pagination {
    pub page: u16,
    pub per_page: u16,
}

#[derive(Debug)]
pub struct GitLab {
    scheme: String,
    domain: String,
    port: u16,
    private_token: String,
    client: hyper::Client,
    pagination: Pagination,
}

impl GitLab {

    pub fn new(scheme: &str, domain: &str, port: u16, private_token: &str) -> GitLab {
        GitLab {
            scheme: scheme.to_string(),
            domain: domain.to_string(),
            port:   port,
            private_token: private_token.to_string(),
            client: match env::var("HTTP_PROXY") {
                Ok(proxy) => {
                    let proxy: Vec<&str> = proxy.trim_left_matches("http://").split(':').collect();
                    let hostname = proxy[0].to_string();
                    let port = proxy[1];

                    hyper::Client::with_http_proxy(hostname, port.parse().unwrap())
                },
                Err(_) => hyper::Client::new(),
            },
            pagination: Pagination {page: 1, per_page: 20},
        }
    }

    pub fn new_http(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("http", &domain, 80, &private_token)
    }

    pub fn new_https(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("https", &domain, 443, &private_token)
    }

    pub fn build_url(&self, command: &str) -> String {
        format!("{}://{}:{}/api/v{}/{}?private_token={}&page={}&per_page={}",
                                self.scheme,
                                self.domain,
                                self.port,
                                API_VERSION,
                                command,
                                self.private_token,
                                self.pagination.page,
                                self.pagination.per_page)
    }

    pub fn attempt_connection(&self) -> Result<hyper::client::Response, hyper::Error> {
        // self.get("version")
        let url = self.build_url("version");
        // Close connections after each GET.
        let res = self.client.get(&url).header(hyper::header::Connection::close()).send();

        res
    }

    pub fn set_pagination(&mut self, pagination: Pagination) {
        self.pagination = pagination;
    }

    pub fn get<T>(&self, command: &str) -> Result<T, rustc_serialize::json::DecoderError>
            where T: rustc_serialize::Decodable {

        let url = self.build_url(command);
        let mut res: hyper::client::Response =
                        self.client
                        .get(&url)
                        .header(hyper::header::Connection::close())
                        .send()
                        .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        rustc_serialize::json::decode(body.as_str())
    }

    pub fn version(&self) -> Result<Version, rustc_serialize::json::DecoderError> {
        self.get("version")
    }

    pub fn groups(&self) -> Result<groups::Groups, rustc_serialize::json::DecoderError> {
        self.get("groups")
    }

    pub fn projects(&self) -> Result<projects::Projects, rustc_serialize::json::DecoderError> {
        self.get("projects")
    }
}

#[cfg(test)]
mod tests {
    use std::env;
    use gitlab::GitLab;
    use gitlab::Pagination;

    #[test]
    fn list_groups() {
        let token = match env::var("GITLAB_TOKEN") {
            Ok(val) => val,
            Err(_)  => panic!("Please set environment variable 'GITLAB_TOKEN'"),
        };

        let mut gl = GitLab::new_https("gitlab.com", &token);
        gl.set_pagination(Pagination{page: 1, per_page: 100});
        println!("gl: {:?}", gl);

        let groups = gl.groups().unwrap();
        println!("groups: {:?}", groups);
    }

    #[test]
    fn list_projects() {
        let token = match env::var("GITLAB_TOKEN") {
            Ok(val) => val,
            Err(_)  => panic!("Please set environment variable 'GITLAB_TOKEN'"),
        };

        let mut gl = GitLab::new_https("gitlab.com", &token);
        // for i in 1..82 {
        //     gl.set_pagination(Pagination{page: i, per_page: 1});
        //     println!("projects: {:?}", gl.projects().unwrap());
        // }
        //     println!("projects: {:?}", gl.projects().unwrap());
        gl.set_pagination(Pagination{page: 1, per_page: 100});
        let projects = gl.projects().unwrap();

        // assert_eq!(gl.attempt_connection().unwrap().status, hyper::Ok);

    }
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

// Marauder is grid-less turn-based strategy game.

extern mod glfw;
extern mod gl;
extern mod cgmath;

use gl::types::{
  GLenum,
  GLuint,
  GLint,
  GLchar,
  GLfloat,
  GLsizeiptr,
  GLboolean
};
use cgmath::matrix::{Matrix, Mat4, Mat3, ToMat4};
use cgmath::projection;
use cgmath::angle;
use cgmath::vector::{Vec3, Vec2};

#[link(name = "glfw")]
#[link(name = "m")]
extern {}

/// usage: let s = mvp_matrix; println(type_of(&s));
fn type_of<T>(_: &T) -> &'static str {
  unsafe {
    (*std::unstable::intrinsics::get_tydesc::<T>()).name
  }
}

fn print_mat4(name: &str, mat: Mat4<f32>) {
  println!("{}:", name);
  for i in range(0u, 4) {
    for j in range(0u, 4) {
      print!("{} ", *mat.cr(i, j));
    }
    println("");
  }
  println("");
}

static mut MOUSE_POS: Vec2<f32> = Vec2{x: 0.0f32, y: 0.0};
static mut CAMERA_POS: Vec3<f32> = Vec3{x: 0.0f32, y: 0.0, z: 0.0};

static WIN_SIZE: Vec2<uint> = Vec2{x: 640, y: 480};
static VERTICES_COUNT: i32 = 3 * 2;

static VERTEX_DATA: [GLfloat, ..VERTICES_COUNT * 3] = [
   0.0,  1.0, 0.0,
   2.0, -1.0, 0.0,
  -2.0, -1.0, 0.0,

  0.0,  1.0,  0.0,
  0.0, -1.0,  2.0,
  0.0, -1.0, -2.0
];

static VERTEX_SHADER_SRC: &'static str = "
  #version 130
  in vec3 position;
  uniform mat4 model_view_proj_matrix;
  void main() {
    vec4 v = vec4(position, 1);
    gl_Position = model_view_proj_matrix * v;
  }
";

static FRAGMENT_SHADER_SRC: &'static str = "
  #version 130
  out vec4 out_color;
  void main() {
    out_color = vec4(1.0, 1.0, 1.0, 1.0);
  }
";

#[start]
fn start(argc: int, argv: **u8) -> int {
  std::rt::start_on_main_thread(argc, argv, main)
}

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
  let shader = gl::CreateShader(ty);
  unsafe {
    // Attempt to compile the shader
    gl::ShaderSource(shader, 1, &src.to_c_str().unwrap(), std::ptr::null());
    gl::CompileShader(shader);

    // Get the compile status
    let mut status = gl::FALSE as GLint;
    gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len = 0;
      gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
      // subtract 1 to skip the trailing null character
      let mut buf = std::vec::from_elem(len as uint - 1, 0u8);
      gl::GetShaderInfoLog(shader, len, std::ptr::mut_null(),
        std::vec::raw::to_mut_ptr(buf) as *mut GLchar
      );
      fail!("compile_shader(): " + std::str::raw::from_utf8(buf));
    }
  }
  shader
}

fn link_program(vertex_shader: GLuint, fragment_shader: GLuint) -> GLuint {
  let program = gl::CreateProgram();
  gl::AttachShader(program, vertex_shader);
  gl::AttachShader(program, fragment_shader);
  gl::LinkProgram(program);
  unsafe {
    // Get the link status
    let mut status = gl::FALSE as GLint;
    gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len: GLint = 0;
      gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
      // subtract 1 to skip the trailing null character
      let mut buf = std::vec::from_elem(len as uint - 1, 0u8);
      gl::GetProgramInfoLog(program, len, std::ptr::mut_null(),
        std::vec::raw::to_mut_ptr(buf) as *mut GLchar
      );
      fail!("link_program(): " + std::str::raw::from_utf8(buf));
    }
  }
  program
}

fn tr(m: Mat4<f32>, v: Vec3<f32>) -> Mat4<f32> {
  let mut t = Mat4::<f32>::identity();
  *t.mut_cr(3, 0) = v.x;
  *t.mut_cr(3, 1) = v.y;
  *t.mut_cr(3, 2) = v.z;
  m.mul_m(&t)
}

fn rot_x(m: Mat4<f32>, angle: f32) -> Mat4<f32> {
  let r = Mat3::from_angle_x(angle::rad(angle)).to_mat4();
  m.mul_m(&r)
}

fn rot_y(m: Mat4<f32>, angle: f32) -> Mat4<f32> {
  let r = Mat3::from_angle_y(angle::rad(angle)).to_mat4();
  m.mul_m(&r)
}

// change matrices
fn upd(programId: GLuint) {
  let fov = angle::deg(45.0f32);
  let ratio = 4.0 / 3.0;
  let display_range_min = 0.1;
  let display_range_max = 100.0;
  let projection_matrix = projection::perspective(
    fov, ratio, display_range_min, display_range_max
  );

  let mut mvp_matrix = projection_matrix;
  unsafe {
    mvp_matrix = tr(mvp_matrix, Vec3{x: 0.0f32, y: 0.0, z: -10.0f32});
    mvp_matrix = rot_x(mvp_matrix, MOUSE_POS.y / 100.0);
    mvp_matrix = rot_y(mvp_matrix, MOUSE_POS.x / 100.0);
    mvp_matrix = tr(mvp_matrix, CAMERA_POS);
  }

  unsafe {
    // Get a handle for our "model_view_proj_matrix" uniform.
    // Only at initialisation time.
    let matrixId = gl::GetUniformLocation(
      programId, "model_view_proj_matrix".to_c_str().unwrap());

    // Send our transformation to the currently bound shader,
    // in the "model_view_proj_matrix" uniform.
    // For each model you render, since the model_view_proj_matrix
    // will be different (at least the M part).
    gl::UniformMatrix4fv(matrixId, 1, gl::FALSE, mvp_matrix.cr(0, 0));
  }
}

struct Win {
  vertex_shader: GLuint,
  fragment_shader: GLuint,
  program: GLuint,
  vertex_array_obj: GLuint,
  vertex_buffer_obj: GLuint,
  window: glfw::Window
}

impl Win {
  fn new() -> Win {
    let mut win =  Win{
      vertex_shader: 0,
      fragment_shader: 0,
      program: 0,
      vertex_array_obj: 0,
      vertex_buffer_obj: 0,
      window: glfw::Window::create(
        WIN_SIZE.x,
        WIN_SIZE.y,
        "OpenGL",
        glfw::Windowed
      ).unwrap()
    };

    win.window.make_context_current();
    win.window.set_cursor_pos_callback(~CursorPosContext);
    win.window.set_key_callback(~KeyContext);

    // Load the OpenGL function pointers
    gl::load_with(glfw::get_proc_address);

    // Create GLSL shaders
    win.vertex_shader = compile_shader(
      VERTEX_SHADER_SRC, gl::VERTEX_SHADER);
    win.fragment_shader = compile_shader(
      FRAGMENT_SHADER_SRC, gl::FRAGMENT_SHADER);
    win.program = link_program(win.vertex_shader, win.fragment_shader);

    unsafe {
      // Create Vertex Array Object
      gl::GenVertexArrays(1, &mut win.vertex_array_obj);
      gl::BindVertexArray(win.vertex_array_obj);

      // Create a Vertex Buffer Object and copy the vertex data to it
      gl::GenBuffers(1, &mut win.vertex_buffer_obj);
      gl::BindBuffer(gl::ARRAY_BUFFER, win.vertex_buffer_obj);
      let float_size = std::mem::size_of::<GLfloat>();
      let vertices_ptr = (VERTEX_DATA.len() * float_size) as GLsizeiptr;
      gl::BufferData(
        gl::ARRAY_BUFFER,
        vertices_ptr,
        std::cast::transmute(&VERTEX_DATA[0]),
        gl::STATIC_DRAW
      );

      gl::UseProgram(win.program);
      gl::BindFragDataLocation(win.program, 0, "out_color".to_c_str().unwrap());

      // Specify the layout of the vertex data
      let pos_attr = gl::GetAttribLocation(
        win.program, "position".to_c_str().unwrap()) as GLuint;
      gl::EnableVertexAttribArray(pos_attr);
      let size = 3;
      let normalized = gl::FALSE as GLboolean;
      let stride = 0;
      gl::VertexAttribPointer(
        pos_attr,
        size,
        gl::FLOAT,
        normalized,
        stride,
        std::ptr::null()
      );
    }

    win
  }

  fn cleanup(&self) {
    // Cleanup
    gl::DeleteProgram(self.program);
    gl::DeleteShader(self.fragment_shader);
    gl::DeleteShader(self.vertex_shader);
    unsafe {
      gl::DeleteBuffers(1, &self.vertex_buffer_obj);
      gl::DeleteVertexArrays(1, &self.vertex_array_obj);
    }
  }

  fn draw(&self) {
    upd(self.program);

    // Clear the screen to black
    gl::ClearColor(0.3, 0.3, 0.3, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT);

    // Draw a triangle from the 3 vertices
    gl::DrawArrays(gl::TRIANGLES, 0, VERTICES_COUNT);

    self.window.swap_buffers();
  }
}

fn main() {
  glfw::set_error_callback(~ErrorContext);

  do glfw::start {
    // glfw::window_hint::context_version(3, 2);

    let win =  Win::new();

    while !win.window.should_close() {
      glfw::poll_events();
      win.draw();
    }

    win.cleanup();
  }
}

struct CursorPosContext;
impl glfw::CursorPosCallback for CursorPosContext {
  fn call(&self, w: &glfw::Window, xpos: f64, ypos: f64) {
    if w.get_mouse_button(glfw::MouseButtonRight) == glfw::Press {
      // println!("Cursor position: ({}, {})", xpos, ypos);
      unsafe {
        MOUSE_POS.x = xpos as f32;
        MOUSE_POS.y = ypos as f32;
      }
    }
  }
}

struct ErrorContext;
impl glfw::ErrorCallback for ErrorContext {
  fn call(&self, _: glfw::Error, description: ~str) {
    println!("GLFW Error: {:s}", description);
  }
}

struct KeyContext;
impl glfw::KeyCallback for KeyContext {
  fn call(
    &self,
    window: &glfw::Window,
    key:    glfw::Key,
    _:      std::libc::c_int,
    action: glfw::Action,
    _:      glfw::Modifiers
  ) {
    match (action, key) {
      (glfw::Press, glfw::KeyEscape) => {
        window.set_should_close(true)
      }
      (glfw::Press, glfw::KeySpace) => {
        println!("space")
      }
      (glfw::Press, glfw::KeyUp) => unsafe { CAMERA_POS.y -= 1.0f32 },
      (glfw::Press, glfw::KeyDown) => unsafe { CAMERA_POS.y += 1.0f32 },
      (glfw::Press, glfw::KeyRight) => unsafe { CAMERA_POS.x -= 1.0f32 },
      (glfw::Press, glfw::KeyLeft) => unsafe { CAMERA_POS.x += 1.0f32 },
      _ => {}
    }
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<commit_msg>Win::is_running() -> bool<commit_after>// See LICENSE file for copyright and license details.

// Marauder is grid-less turn-based strategy game.

extern mod glfw;
extern mod gl;
extern mod cgmath;

use gl::types::{
  GLenum,
  GLuint,
  GLint,
  GLchar,
  GLfloat,
  GLsizeiptr,
  GLboolean
};
use cgmath::matrix::{Matrix, Mat4, Mat3, ToMat4};
use cgmath::projection;
use cgmath::angle;
use cgmath::vector::{Vec3, Vec2};

#[link(name = "glfw")]
#[link(name = "m")]
extern {}

/// usage: let s = mvp_matrix; println(type_of(&s));
fn type_of<T>(_: &T) -> &'static str {
  unsafe {
    (*std::unstable::intrinsics::get_tydesc::<T>()).name
  }
}

fn print_mat4(name: &str, mat: Mat4<f32>) {
  println!("{}:", name);
  for i in range(0u, 4) {
    for j in range(0u, 4) {
      print!("{} ", *mat.cr(i, j));
    }
    println("");
  }
  println("");
}

static mut MOUSE_POS: Vec2<f32> = Vec2{x: 0.0f32, y: 0.0};
static mut CAMERA_POS: Vec3<f32> = Vec3{x: 0.0f32, y: 0.0, z: 0.0};

static WIN_SIZE: Vec2<uint> = Vec2{x: 640, y: 480};
static VERTICES_COUNT: i32 = 3 * 2;

static VERTEX_DATA: [GLfloat, ..VERTICES_COUNT * 3] = [
   0.0,  1.0, 0.0,
   2.0, -1.0, 0.0,
  -2.0, -1.0, 0.0,

  0.0,  1.0,  0.0,
  0.0, -1.0,  2.0,
  0.0, -1.0, -2.0
];

static VERTEX_SHADER_SRC: &'static str = "
  #version 130
  in vec3 position;
  uniform mat4 model_view_proj_matrix;
  void main() {
    vec4 v = vec4(position, 1);
    gl_Position = model_view_proj_matrix * v;
  }
";

static FRAGMENT_SHADER_SRC: &'static str = "
  #version 130
  out vec4 out_color;
  void main() {
    out_color = vec4(1.0, 1.0, 1.0, 1.0);
  }
";

#[start]
fn start(argc: int, argv: **u8) -> int {
  std::rt::start_on_main_thread(argc, argv, main)
}

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
  let shader = gl::CreateShader(ty);
  unsafe {
    // Attempt to compile the shader
    gl::ShaderSource(shader, 1, &src.to_c_str().unwrap(), std::ptr::null());
    gl::CompileShader(shader);

    // Get the compile status
    let mut status = gl::FALSE as GLint;
    gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len = 0;
      gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
      // subtract 1 to skip the trailing null character
      let mut buf = std::vec::from_elem(len as uint - 1, 0u8);
      gl::GetShaderInfoLog(shader, len, std::ptr::mut_null(),
        std::vec::raw::to_mut_ptr(buf) as *mut GLchar
      );
      fail!("compile_shader(): " + std::str::raw::from_utf8(buf));
    }
  }
  shader
}

fn link_program(vertex_shader: GLuint, fragment_shader: GLuint) -> GLuint {
  let program = gl::CreateProgram();
  gl::AttachShader(program, vertex_shader);
  gl::AttachShader(program, fragment_shader);
  gl::LinkProgram(program);
  unsafe {
    // Get the link status
    let mut status = gl::FALSE as GLint;
    gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len: GLint = 0;
      gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
      // subtract 1 to skip the trailing null character
      let mut buf = std::vec::from_elem(len as uint - 1, 0u8);
      gl::GetProgramInfoLog(program, len, std::ptr::mut_null(),
        std::vec::raw::to_mut_ptr(buf) as *mut GLchar
      );
      fail!("link_program(): " + std::str::raw::from_utf8(buf));
    }
  }
  program
}

fn tr(m: Mat4<f32>, v: Vec3<f32>) -> Mat4<f32> {
  let mut t = Mat4::<f32>::identity();
  *t.mut_cr(3, 0) = v.x;
  *t.mut_cr(3, 1) = v.y;
  *t.mut_cr(3, 2) = v.z;
  m.mul_m(&t)
}

fn rot_x(m: Mat4<f32>, angle: f32) -> Mat4<f32> {
  let r = Mat3::from_angle_x(angle::rad(angle)).to_mat4();
  m.mul_m(&r)
}

fn rot_y(m: Mat4<f32>, angle: f32) -> Mat4<f32> {
  let r = Mat3::from_angle_y(angle::rad(angle)).to_mat4();
  m.mul_m(&r)
}

// change matrices
fn upd(programId: GLuint) {
  let fov = angle::deg(45.0f32);
  let ratio = 4.0 / 3.0;
  let display_range_min = 0.1;
  let display_range_max = 100.0;
  let projection_matrix = projection::perspective(
    fov, ratio, display_range_min, display_range_max
  );

  let mut mvp_matrix = projection_matrix;
  unsafe {
    mvp_matrix = tr(mvp_matrix, Vec3{x: 0.0f32, y: 0.0, z: -10.0f32});
    mvp_matrix = rot_x(mvp_matrix, MOUSE_POS.y / 100.0);
    mvp_matrix = rot_y(mvp_matrix, MOUSE_POS.x / 100.0);
    mvp_matrix = tr(mvp_matrix, CAMERA_POS);
  }

  unsafe {
    // Get a handle for our "model_view_proj_matrix" uniform.
    // Only at initialisation time.
    let matrixId = gl::GetUniformLocation(
      programId, "model_view_proj_matrix".to_c_str().unwrap());

    // Send our transformation to the currently bound shader,
    // in the "model_view_proj_matrix" uniform.
    // For each model you render, since the model_view_proj_matrix
    // will be different (at least the M part).
    gl::UniformMatrix4fv(matrixId, 1, gl::FALSE, mvp_matrix.cr(0, 0));
  }
}

struct Win {
  vertex_shader: GLuint,
  fragment_shader: GLuint,
  program: GLuint,
  vertex_array_obj: GLuint,
  vertex_buffer_obj: GLuint,
  window: glfw::Window
}

impl Win {
  fn new() -> Win {
    let mut win =  Win{
      vertex_shader: 0,
      fragment_shader: 0,
      program: 0,
      vertex_array_obj: 0,
      vertex_buffer_obj: 0,
      window: glfw::Window::create(
        WIN_SIZE.x,
        WIN_SIZE.y,
        "OpenGL",
        glfw::Windowed
      ).unwrap()
    };

    win.window.make_context_current();
    win.window.set_cursor_pos_callback(~CursorPosContext);
    win.window.set_key_callback(~KeyContext);

    // Load the OpenGL function pointers
    gl::load_with(glfw::get_proc_address);

    // Create GLSL shaders
    win.vertex_shader = compile_shader(
      VERTEX_SHADER_SRC, gl::VERTEX_SHADER);
    win.fragment_shader = compile_shader(
      FRAGMENT_SHADER_SRC, gl::FRAGMENT_SHADER);
    win.program = link_program(win.vertex_shader, win.fragment_shader);

    unsafe {
      // Create Vertex Array Object
      gl::GenVertexArrays(1, &mut win.vertex_array_obj);
      gl::BindVertexArray(win.vertex_array_obj);

      // Create a Vertex Buffer Object and copy the vertex data to it
      gl::GenBuffers(1, &mut win.vertex_buffer_obj);
      gl::BindBuffer(gl::ARRAY_BUFFER, win.vertex_buffer_obj);
      let float_size = std::mem::size_of::<GLfloat>();
      let vertices_ptr = (VERTEX_DATA.len() * float_size) as GLsizeiptr;
      gl::BufferData(
        gl::ARRAY_BUFFER,
        vertices_ptr,
        std::cast::transmute(&VERTEX_DATA[0]),
        gl::STATIC_DRAW
      );

      gl::UseProgram(win.program);
      gl::BindFragDataLocation(win.program, 0, "out_color".to_c_str().unwrap());

      // Specify the layout of the vertex data
      let pos_attr = gl::GetAttribLocation(
        win.program, "position".to_c_str().unwrap()) as GLuint;
      gl::EnableVertexAttribArray(pos_attr);
      let size = 3;
      let normalized = gl::FALSE as GLboolean;
      let stride = 0;
      gl::VertexAttribPointer(
        pos_attr,
        size,
        gl::FLOAT,
        normalized,
        stride,
        std::ptr::null()
      );
    }

    win
  }

  fn cleanup(&self) {
    // Cleanup
    gl::DeleteProgram(self.program);
    gl::DeleteShader(self.fragment_shader);
    gl::DeleteShader(self.vertex_shader);
    unsafe {
      gl::DeleteBuffers(1, &self.vertex_buffer_obj);
      gl::DeleteVertexArrays(1, &self.vertex_array_obj);
    }
  }

  fn draw(&self) {
    upd(self.program);

    // Clear the screen to black
    gl::ClearColor(0.3, 0.3, 0.3, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT);

    // Draw a triangle from the 3 vertices
    gl::DrawArrays(gl::TRIANGLES, 0, VERTICES_COUNT);

    self.window.swap_buffers();
  }

  fn is_running(&self) -> bool {
    return !self.window.should_close()
  }
}

fn main() {
  glfw::set_error_callback(~ErrorContext);

  do glfw::start {
    // glfw::window_hint::context_version(3, 2);

    let win =  Win::new();

    while win.is_running() {
      glfw::poll_events();
      win.draw();
    }

    win.cleanup();
  }
}

struct CursorPosContext;
impl glfw::CursorPosCallback for CursorPosContext {
  fn call(&self, w: &glfw::Window, xpos: f64, ypos: f64) {
    if w.get_mouse_button(glfw::MouseButtonRight) == glfw::Press {
      // println!("Cursor position: ({}, {})", xpos, ypos);
      unsafe {
        MOUSE_POS.x = xpos as f32;
        MOUSE_POS.y = ypos as f32;
      }
    }
  }
}

struct ErrorContext;
impl glfw::ErrorCallback for ErrorContext {
  fn call(&self, _: glfw::Error, description: ~str) {
    println!("GLFW Error: {:s}", description);
  }
}

struct KeyContext;
impl glfw::KeyCallback for KeyContext {
  fn call(
    &self,
    window: &glfw::Window,
    key:    glfw::Key,
    _:      std::libc::c_int,
    action: glfw::Action,
    _:      glfw::Modifiers
  ) {
    match (action, key) {
      (glfw::Press, glfw::KeyEscape) => {
        window.set_should_close(true)
      }
      (glfw::Press, glfw::KeySpace) => {
        println!("space")
      }
      (glfw::Press, glfw::KeyUp) => unsafe { CAMERA_POS.y -= 1.0f32 },
      (glfw::Press, glfw::KeyDown) => unsafe { CAMERA_POS.y += 1.0f32 },
      (glfw::Press, glfw::KeyRight) => unsafe { CAMERA_POS.x -= 1.0f32 },
      (glfw::Press, glfw::KeyLeft) => unsafe { CAMERA_POS.x += 1.0f32 },
      _ => {}
    }
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<|endoftext|>