<commit_before>//! Displays an image in a window created by sdl2.

use image::{imageops::resize, RgbaImage};
use sdl2::{
    event::{Event, WindowEvent},
    keyboard::Keycode,
    pixels::{Color, PixelFormatEnum},
    rect::Rect,
    render::{Canvas, TextureCreator, WindowCanvas},
    surface::Surface,
    video::{Window, WindowContext},
};

/// Displays the provided RGBA image in a new window.
///
/// The minimum window width or height is 150 pixels - input values less than this
/// will be rounded up to the minimum.
pub fn display_image(title: &str, image: &RgbaImage, window_width: u32, window_height: u32) {
    display_multiple_images(title, &vec![image], window_width, window_height);
}

/// Displays the provided RGBA images in new windows.
///
/// The minimum window width or height is 150 pixels - input values less than this
/// will be rounded up to the minimum.
pub fn display_multiple_images(
    title: &str,
    images: &[&RgbaImage],
    window_width: u32,
    window_height: u32,
) {
    if images.len() == 0 {
        return;
    }

    // Enforce minimum window size
    const MIN_WINDOW_DIMENSION: u32 = 150;
    let window_width = window_width.max(MIN_WINDOW_DIMENSION);
    let window_height = window_height.max(MIN_WINDOW_DIMENSION);

    // Initialise sdl2 window
    let sdl = sdl2::init().expect("couldn't create sdl2 context");
    let video_subsystem = sdl.video().expect("couldn't create video subsystem");

    let mut windows: Vec<Window> = Vec::with_capacity(images.len());
    let mut window_visibility: Vec<bool> = Vec::with_capacity(images.len());
    for _ in 0..images.len() {
        let mut window = video_subsystem
            .window(title, window_width, window_height)
            .resizable()
            .allow_highdpi()
            .build()
            .expect("couldn't create window");

        window
            .set_minimum_size(MIN_WINDOW_DIMENSION, MIN_WINDOW_DIMENSION)
            .expect("invalid minimum size for window");

        windows.push(window);
        window_visibility.push(true);
    }

    {
        use sdl2::video::WindowPos::Positioned;

        let (base_position_x, base_position_y) = windows[0].position();
        for (i, window) in windows.iter_mut().enumerate() {
            let multiplier = 1.0 + i as f32 / 20.0;
            window.set_position(
                Positioned((base_position_x as f32 * multiplier) as i32),
                Positioned(base_position_y),
            );

            let (window_pos_x, _window_pos_y) = window.position();
            let display_bounds = video_subsystem
                .display_bounds(0)
                .expect("No bounds found for that display.");
            let screen_width = display_bounds.w;
            if window_pos_x + window_width as i32 > screen_width {
                window.set_position(
                    Positioned(screen_width - window_width as i32),
                    Positioned(base_position_y),
                );
            }
        }
    }

    let mut canvases: Vec<WindowCanvas> = Vec::with_capacity(images.len());
    for window in windows.into_iter() {
        let canvas = window
            .into_canvas()
            .software()
            .build()
            .expect("couldn't create canvas");
        canvases.push(canvas);
    }

    let mut texture_creators: Vec<TextureCreator<WindowContext>> = Vec::with_capacity(images.len());
    for canvas in canvases.iter() {
        let texture_creator = canvas.texture_creator();
        texture_creators.push(texture_creator);
    }

    // Shrinks input image to fit if required and renders to the sdl canvas
    let render_image_to_canvas =
        |image,
         window_width,
         window_height,
         canvas: &mut Canvas<Window>,
         texture_creator: &TextureCreator<WindowContext>| {
            let scaled_image = resize_to_fit(image, window_width, window_height);

            let (image_width, image_height) = scaled_image.dimensions();
            let mut buffer = scaled_image.into_raw();
            const CHANNEL_COUNT: u32 = 4;
            let surface = Surface::from_data(
                &mut buffer,
                image_width,
                image_height,
                image_width * CHANNEL_COUNT,
                PixelFormatEnum::ABGR8888, // sdl2 expects bits from highest to lowest
            )
            .expect("couldn't create surface");

            let texture = texture_creator
                .create_texture_from_surface(surface)
                .expect("couldn't create texture from surface");

            canvas.set_draw_color(Color::RGB(255, 255, 255));
            canvas.clear();

            let left = ((window_width - image_width) as f32 / 2f32) as i32;
            let top = ((window_height - image_height) as f32 / 2f32) as i32;
            canvas
                .copy(
                    &texture,
                    None,
                    Rect::new(left, top, image_width, image_height),
                )
                .unwrap();
            canvas.present();
        };

    for (i, (canvas, texture_creator)) in
        canvases.iter_mut().zip(texture_creators.iter()).enumerate()
    {
        render_image_to_canvas(
            images[i],
            window_width,
            window_height,
            canvas,
            texture_creator,
        );
    }

    let mut hidden_count = 0;

    // Create and start event loop to keep window open until Esc
    let mut event_pump = sdl.event_pump().unwrap();
    event_pump.enable_event(sdl2::event::EventType::Window);
    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit { .. }
                | Event::KeyDown {
                    keycode: Some(Keycode::Escape),
                    ..
                } => break 'running,
                Event::KeyDown {
                    keycode: Some(Keycode::Q),
                    window_id,
                    ..
                } => {
                    for (i, canvas) in canvases.iter_mut().enumerate() {
                        if window_id == canvas.window().id() {
                            canvas.window_mut().hide();
                            window_visibility[i] = false;
                            hidden_count += 1;
                        }
                        if hidden_count == images.len() {
                            break 'running;
                        }
                    }
                }
                Event::Window {
                    win_event: WindowEvent::Close,
                    window_id,
                    ..
                } => {
                    for (i, canvas) in canvases.iter_mut().enumerate() {
                        if window_id == canvas.window().id() {
                            canvas.window_mut().hide();
                            window_visibility[i] = false;
                            hidden_count += 1;
                        }
                        if hidden_count == images.len() {
                            break 'running;
                        }
                    }
                }
                Event::Window {
                    win_event: WindowEvent::Resized(w, h),
                    window_id,
                    ..
                } => {
                    for (i, (canvas, texture_creator)) in
                        canvases.iter_mut().zip(texture_creators.iter()).enumerate()
                    {
                        if window_id == canvas.window().id() {
                            render_image_to_canvas(
                                images[i],
                                w as u32,
                                h as u32,
                                canvas,
                                texture_creator,
                            );
                        }
                    }
                }
                _ => {}
            }
        }
    }
}

// Scale input image down if required so that it fits within a window of the given dimensions
fn resize_to_fit(image: &RgbaImage, window_width: u32, window_height: u32) -> RgbaImage {
    if image.height() < window_height && image.width() < window_width {
        return image.clone();
    }

    let scale = {
        let width_scale = window_width as f32 / image.width() as f32;
        let height_scale = window_height as f32 / image.height() as f32;
        width_scale.min(height_scale)
    };

    let height = (scale * image.height() as f32) as u32;
    let width = (scale * image.width() as f32) as u32;

    resize(image, width, height, image::FilterType::Triangle)
}
<commit_msg>Make display_image() and display_multiple_images generic (#411)<commit_after>//! Displays an image in a window created by sdl2.

use image::{
    imageops::{resize, FilterType},
    ConvertBuffer, GenericImageView, RgbaImage,
};
use sdl2::{
    event::{Event, WindowEvent},
    keyboard::Keycode,
    pixels::{Color, PixelFormatEnum},
    rect::Rect,
    render::{Canvas, TextureCreator, WindowCanvas},
    surface::Surface,
    video::{Window, WindowContext},
};

/// Displays the provided RGBA image in a new window.
///
/// The minimum window width or height is 150 pixels - input values less than this
/// will be rounded up to the minimum.
pub fn display_image<I>(title: &str, image: &I, window_width: u32, window_height: u32)
where
    I: GenericImageView + ConvertBuffer<RgbaImage>,
{
    display_multiple_images(title, &vec![image], window_width, window_height);
}

/// Displays the provided RGBA images in new windows.
///
/// The minimum window width or height is 150 pixels - input values less than this
/// will be rounded up to the minimum.
pub fn display_multiple_images<I>(title: &str, images: &[&I], window_width: u32, window_height: u32)
where
    I: GenericImageView + ConvertBuffer<RgbaImage>,
{
    if images.len() == 0 {
        return;
    }

    // Enforce minimum window size
    const MIN_WINDOW_DIMENSION: u32 = 150;
    let window_width = window_width.max(MIN_WINDOW_DIMENSION);
    let window_height = window_height.max(MIN_WINDOW_DIMENSION);

    // Initialise sdl2 window
    let sdl = sdl2::init().expect("couldn't create sdl2 context");
    let video_subsystem = sdl.video().expect("couldn't create video subsystem");

    let mut windows: Vec<Window> = Vec::with_capacity(images.len());
    let mut window_visibility: Vec<bool> = Vec::with_capacity(images.len());
    for _ in 0..images.len() {
        let mut window = video_subsystem
            .window(title, window_width, window_height)
            .resizable()
            .allow_highdpi()
            .build()
            .expect("couldn't create window");

        window
            .set_minimum_size(MIN_WINDOW_DIMENSION, MIN_WINDOW_DIMENSION)
            .expect("invalid minimum size for window");

        windows.push(window);
        window_visibility.push(true);
    }

    {
        use sdl2::video::WindowPos::Positioned;

        let (base_position_x, base_position_y) = windows[0].position();
        for (i, window) in windows.iter_mut().enumerate() {
            let multiplier = 1.0 + i as f32 / 20.0;
            window.set_position(
                Positioned((base_position_x as f32 * multiplier) as i32),
                Positioned(base_position_y),
            );

            let (window_pos_x, _window_pos_y) = window.position();
            let display_bounds = video_subsystem
                .display_bounds(0)
                .expect("No bounds found for that display.");
            let screen_width = display_bounds.w;
            if window_pos_x + window_width as i32 > screen_width {
                window.set_position(
                    Positioned(screen_width - window_width as i32),
                    Positioned(base_position_y),
                );
            }
        }
    }

    let mut canvases: Vec<WindowCanvas> = Vec::with_capacity(images.len());
    for window in windows.into_iter() {
        let canvas = window
            .into_canvas()
            .software()
            .build()
            .expect("couldn't create canvas");
        canvases.push(canvas);
    }

    let mut texture_creators: Vec<TextureCreator<WindowContext>> = Vec::with_capacity(images.len());
    for canvas in canvases.iter() {
        let texture_creator = canvas.texture_creator();
        texture_creators.push(texture_creator);
    }

    // Shrinks input image to fit if required and renders to the sdl canvas

    for (i, (canvas, texture_creator)) in
        canvases.iter_mut().zip(texture_creators.iter()).enumerate()
    {
        render_image_to_canvas(
            images[i],
            window_width,
            window_height,
            canvas,
            texture_creator,
        );
    }

    let mut hidden_count = 0;

    // Create and start event loop to keep window open until Esc
    let mut event_pump = sdl.event_pump().unwrap();
    event_pump.enable_event(sdl2::event::EventType::Window);
    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit { .. }
                | Event::KeyDown {
                    keycode: Some(Keycode::Escape),
                    ..
                } => break 'running,
                Event::KeyDown {
                    keycode: Some(Keycode::Q),
                    window_id,
                    ..
                } => {
                    for (i, canvas) in canvases.iter_mut().enumerate() {
                        if window_id == canvas.window().id() {
                            canvas.window_mut().hide();
                            window_visibility[i] = false;
                            hidden_count += 1;
                        }
                        if hidden_count == images.len() {
                            break 'running;
                        }
                    }
                }
                Event::Window {
                    win_event: WindowEvent::Close,
                    window_id,
                    ..
                } => {
                    for (i, canvas) in canvases.iter_mut().enumerate() {
                        if window_id == canvas.window().id() {
                            canvas.window_mut().hide();
                            window_visibility[i] = false;
                            hidden_count += 1;
                        }
                        if hidden_count == images.len() {
                            break 'running;
                        }
                    }
                }
                Event::Window {
                    win_event: WindowEvent::Resized(w, h),
                    window_id,
                    ..
                } => {
                    for (i, (canvas, texture_creator)) in
                        canvases.iter_mut().zip(texture_creators.iter()).enumerate()
                    {
                        if window_id == canvas.window().id() {
                            render_image_to_canvas(
                                images[i],
                                w as u32,
                                h as u32,
                                canvas,
                                texture_creator,
                            );
                        }
                    }
                }
                _ => {}
            }
        }
    }
}

// Scale input image down if required so that it fits within a window of the given dimensions
fn resize_to_fit<I>(image: &I, window_width: u32, window_height: u32) -> RgbaImage
where
    I: GenericImageView + ConvertBuffer<RgbaImage>,
{
    let image = image.convert();
    if image.height() < window_height && image.width() < window_width {
        return image;
    }

    let scale = {
        let width_scale = window_width as f32 / image.width() as f32;
        let height_scale = window_height as f32 / image.height() as f32;
        width_scale.min(height_scale)
    };

    let height = (scale * image.height() as f32) as u32;
    let width = (scale * image.width() as f32) as u32;

    resize(&image, width, height, FilterType::Triangle)
}

fn render_image_to_canvas<I>(
    image: &I,
    window_width: u32,
    window_height: u32,
    canvas: &mut Canvas<Window>,
    texture_creator: &TextureCreator<WindowContext>,
) where
    I: GenericImageView + ConvertBuffer<RgbaImage>,
{
    let scaled_image = resize_to_fit(image, window_width, window_height);

    let (image_width, image_height) = scaled_image.dimensions();
    let mut buffer = scaled_image.into_raw();
    const CHANNEL_COUNT: u32 = 4;
    let surface = Surface::from_data(
        &mut buffer,
        image_width,
        image_height,
        image_width * CHANNEL_COUNT,
        PixelFormatEnum::ABGR8888, // sdl2 expects bits from highest to lowest
    )
    .expect("couldn't create surface");

    let texture = texture_creator
        .create_texture_from_surface(surface)
        .expect("couldn't create texture from surface");

    canvas.set_draw_color(Color::RGB(255, 255, 255));
    canvas.clear();

    let left = ((window_width - image_width) as f32 / 2f32) as i32;
    let top = ((window_height - image_height) as f32 / 2f32) as i32;
    canvas
        .copy(
            &texture,
            None,
            Rect::new(left, top, image_width, image_height),
        )
        .unwrap();
    canvas.present();
}
<|endoftext|>


<commit_before>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::convert::From;
use std::fmt::{self, Display};
use std::ops::Deref;

use gl;
use glutin;

/// Default title for the window
const DEFAULT_TITLE: &'static str = "Alacritty";

/// Resize handling for Mac and maybe other platforms
///
/// This delegates to a statically referenced closure for convenience. The
/// C-style callback doesn't receive a pointer or anything, so we are forced to
/// use static storage.
///
/// This will fail horribly if more than one window is created. Don't do that :)
fn window_resize_handler(width: u32, height: u32) {
    unsafe {
        RESIZE_CALLBACK.as_ref().map(|func| func(width, height));
    }
}

/// The resize callback invoked by `window_resize_handler`
static mut RESIZE_CALLBACK: Option<Box<Fn(u32, u32)>> = None;

/// Window errors
#[derive(Debug)]
pub enum Error {
    /// Error creating the window
    Creation(glutin::CreationError),

    /// Error manipulating the rendering context
    Context(glutin::ContextError),
}

/// Result of fallible operations concerning a Window.
type Result<T> = ::std::result::Result<T, Error>;

/// A window which can be used for displaying the terminal
///
/// Wraps the underlying windowing library to provide a stable API in Alacritty
pub struct Window {
    glutin_window: glutin::Window,
}

/// Threadsafe APIs for the window
pub struct Proxy(glutin::WindowProxy);

/// Information about where the window is being displayed
///
/// Useful for subsystems like the font rasterized which depend on DPI and scale
/// factor.
pub struct DeviceProperties {
    /// Scale factor for pixels <-> points.
    ///
    /// This will be 1. on standard displays and may have a different value on
    /// hidpi displays.
    pub scale_factor: f32,
}

/// Size of the window
#[derive(Debug, Copy, Clone)]
pub struct Size<T> {
    pub width: T,
    pub height: T,
}

/// Strongly typed Pixels unit
#[derive(Debug, Copy, Clone)]
pub struct Pixels<T>(pub T);

/// Strongly typed Points unit
///
/// Points are like pixels but adjusted for DPI.
#[derive(Debug, Copy, Clone)]
pub struct Points<T>(pub T);

pub trait ToPoints {
    fn to_points(&self, scale: f32) -> Size<Points<u32>>;
}

impl ToPoints for Size<Points<u32>> {
    #[inline]
    fn to_points(&self, _scale: f32) -> Size<Points<u32>> {
        *self
    }
}

impl ToPoints for Size<Pixels<u32>> {
    fn to_points(&self, scale: f32) -> Size<Points<u32>> {
        let width_pts = (*self.width as f32 / scale) as u32;
        let height_pts = (*self.height as f32 / scale) as u32;

        Size {
            width: Points(width_pts),
            height: Points(height_pts)
        }
    }
}

impl<T: Display> Display for Size<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} × {}", self.width, self.height)
    }
}

macro_rules! deref_newtype {
    ($($src:ty),+) => {
        $(
        impl<T> Deref for $src {
            type Target = T;

            #[inline]
            fn deref(&self) -> &Self::Target {
                &self.0
            }
        }
        )+
    }
}

deref_newtype! { Points<T>, Pixels<T> }

impl<T: Display> Display for Pixels<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}px", self.0)
    }
}

impl ::std::error::Error for Error {
    fn cause(&self) -> Option<&::std::error::Error> {
        match *self {
            Error::Creation(ref err) => Some(err),
            Error::Context(ref err) => Some(err),
        }
    }

    fn description(&self) -> &str {
        match *self {
            Error::Creation(ref _err) => "Error creating glutin Window",
            Error::Context(ref _err) => "Error operating on render context",
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            Error::Creation(ref err) => {
                write!(f, "Error creating glutin::Window; {}", err)
            },
            Error::Context(ref err) => {
                write!(f, "Error operating on render context; {}", err)
            },
        }
    }
}

impl From<glutin::CreationError> for Error {
    fn from(val: glutin::CreationError) -> Error {
        Error::Creation(val)
    }
}

impl From<glutin::ContextError> for Error {
    fn from(val: glutin::ContextError) -> Error {
        Error::Context(val)
    }
}

impl Window {
    /// Create a new window
    ///
    /// This creates a window and fully initializes a window.
    pub fn new() -> Result<Window> {
        /// Create a glutin::Window
        let mut window = glutin::WindowBuilder::new()
            .with_vsync()
            .with_title(DEFAULT_TITLE)
            .build()?;

        /// Set the glutin window resize callback for *this* window. The
        /// function pointer must be a C-style callback. This sets such a
        /// callback which simply delegates to a statically referenced Rust
        /// closure.
        window.set_window_resize_callback(Some(window_resize_handler as fn(u32, u32)));

        /// Set OpenGL symbol loader
        gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);

        /// Make the window's context current so OpenGL operations can run
        unsafe {
            window.make_current()?;
        }

        Ok(Window {
            glutin_window: window,
        })
    }

    /// Get some properties about the device
    ///
    /// Some window properties are provided since subsystems like font
    /// rasterization depend on DPI and scale factor.
    pub fn device_properties(&self) -> DeviceProperties {
        DeviceProperties {
            scale_factor: self.glutin_window.hidpi_factor(),
        }
    }

    /// Set the window resize callback
    ///
    /// Pass a `move` closure which will be called with the new width and height
    /// when the window is resized. According to the glutin docs, this can be
    /// used to draw during resizing.
    ///
    /// This method takes self mutably to ensure there's no race condition
    /// setting the callback.
    pub fn set_resize_callback<F: Fn(u32, u32) + 'static>(&mut self, func: F) {
        unsafe {
            RESIZE_CALLBACK = Some(Box::new(func));
        }
    }

    pub fn inner_size_pixels(&self) -> Option<Size<Pixels<u32>>> {
        self.glutin_window
            .get_inner_size_pixels()
            .map(|(w, h)| Size { width: Pixels(w), height: Pixels(h) })
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
        self.glutin_window.hidpi_factor()
    }

    #[inline]
    pub fn create_window_proxy(&self) -> Proxy {
        Proxy(self.glutin_window.create_window_proxy())
    }

    #[inline]
    pub fn swap_buffers(&self) -> Result<()> {
        self.glutin_window
            .swap_buffers()
            .map_err(From::from)
    }

    /// Block waiting for events
    ///
    /// FIXME should return our own type
    #[inline]
    pub fn wait_events(&self) -> glutin::WaitEventsIterator {
        self.glutin_window.wait_events()
    }

    /// Block waiting for events
    ///
    /// FIXME should return our own type
    #[inline]
    pub fn poll_events(&self) -> glutin::PollEventsIterator {
        self.glutin_window.poll_events()
    }
}

impl Proxy {
    /// Wakes up the event loop of the window
    ///
    /// This is useful for triggering a draw when the renderer would otherwise
    /// be waiting on user input.
    pub fn wakeup_event_loop(&self) {
        self.0.wakeup_event_loop();
    }
}

pub trait SetInnerSize<T> {
    fn set_inner_size<S: ToPoints>(&mut self, size: S);
}

impl SetInnerSize<Pixels<u32>> for Window {
    fn set_inner_size<T: ToPoints>(&mut self, size: T) {
        let size = size.to_points(self.hidpi_factor());
        self.glutin_window.set_inner_size(*size.width as _, *size.height as _);
    }
}
<commit_msg>Add display impl for Points<T><commit_after>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::convert::From;
use std::fmt::{self, Display};
use std::ops::Deref;

use gl;
use glutin;

/// Default title for the window
const DEFAULT_TITLE: &'static str = "Alacritty";

/// Resize handling for Mac and maybe other platforms
///
/// This delegates to a statically referenced closure for convenience. The
/// C-style callback doesn't receive a pointer or anything, so we are forced to
/// use static storage.
///
/// This will fail horribly if more than one window is created. Don't do that :)
fn window_resize_handler(width: u32, height: u32) {
    unsafe {
        RESIZE_CALLBACK.as_ref().map(|func| func(width, height));
    }
}

/// The resize callback invoked by `window_resize_handler`
static mut RESIZE_CALLBACK: Option<Box<Fn(u32, u32)>> = None;

/// Window errors
#[derive(Debug)]
pub enum Error {
    /// Error creating the window
    Creation(glutin::CreationError),

    /// Error manipulating the rendering context
    Context(glutin::ContextError),
}

/// Result of fallible operations concerning a Window.
type Result<T> = ::std::result::Result<T, Error>;

/// A window which can be used for displaying the terminal
///
/// Wraps the underlying windowing library to provide a stable API in Alacritty
pub struct Window {
    glutin_window: glutin::Window,
}

/// Threadsafe APIs for the window
pub struct Proxy(glutin::WindowProxy);

/// Information about where the window is being displayed
///
/// Useful for subsystems like the font rasterized which depend on DPI and scale
/// factor.
pub struct DeviceProperties {
    /// Scale factor for pixels <-> points.
    ///
    /// This will be 1. on standard displays and may have a different value on
    /// hidpi displays.
    pub scale_factor: f32,
}

/// Size of the window
#[derive(Debug, Copy, Clone)]
pub struct Size<T> {
    pub width: T,
    pub height: T,
}

/// Strongly typed Pixels unit
#[derive(Debug, Copy, Clone)]
pub struct Pixels<T>(pub T);

/// Strongly typed Points unit
///
/// Points are like pixels but adjusted for DPI.
#[derive(Debug, Copy, Clone)]
pub struct Points<T>(pub T);

pub trait ToPoints {
    fn to_points(&self, scale: f32) -> Size<Points<u32>>;
}

impl ToPoints for Size<Points<u32>> {
    #[inline]
    fn to_points(&self, _scale: f32) -> Size<Points<u32>> {
        *self
    }
}

impl ToPoints for Size<Pixels<u32>> {
    fn to_points(&self, scale: f32) -> Size<Points<u32>> {
        let width_pts = (*self.width as f32 / scale) as u32;
        let height_pts = (*self.height as f32 / scale) as u32;

        Size {
            width: Points(width_pts),
            height: Points(height_pts)
        }
    }
}

impl<T: Display> Display for Size<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} × {}", self.width, self.height)
    }
}

macro_rules! deref_newtype {
    ($($src:ty),+) => {
        $(
        impl<T> Deref for $src {
            type Target = T;

            #[inline]
            fn deref(&self) -> &Self::Target {
                &self.0
            }
        }
        )+
    }
}

deref_newtype! { Points<T>, Pixels<T> }

impl<T: Display> Display for Pixels<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}px", self.0)
    }
}

impl<T: Display> Display for Points<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}pts", self.0)
    }
}

impl ::std::error::Error for Error {
    fn cause(&self) -> Option<&::std::error::Error> {
        match *self {
            Error::Creation(ref err) => Some(err),
            Error::Context(ref err) => Some(err),
        }
    }

    fn description(&self) -> &str {
        match *self {
            Error::Creation(ref _err) => "Error creating glutin Window",
            Error::Context(ref _err) => "Error operating on render context",
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            Error::Creation(ref err) => {
                write!(f, "Error creating glutin::Window; {}", err)
            },
            Error::Context(ref err) => {
                write!(f, "Error operating on render context; {}", err)
            },
        }
    }
}

impl From<glutin::CreationError> for Error {
    fn from(val: glutin::CreationError) -> Error {
        Error::Creation(val)
    }
}

impl From<glutin::ContextError> for Error {
    fn from(val: glutin::ContextError) -> Error {
        Error::Context(val)
    }
}

impl Window {
    /// Create a new window
    ///
    /// This creates a window and fully initializes a window.
    pub fn new() -> Result<Window> {
        /// Create a glutin::Window
        let mut window = glutin::WindowBuilder::new()
            .with_vsync()
            .with_title(DEFAULT_TITLE)
            .build()?;

        /// Set the glutin window resize callback for *this* window. The
        /// function pointer must be a C-style callback. This sets such a
        /// callback which simply delegates to a statically referenced Rust
        /// closure.
        window.set_window_resize_callback(Some(window_resize_handler as fn(u32, u32)));

        /// Set OpenGL symbol loader
        gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);

        /// Make the window's context current so OpenGL operations can run
        unsafe {
            window.make_current()?;
        }

        Ok(Window {
            glutin_window: window,
        })
    }

    /// Get some properties about the device
    ///
    /// Some window properties are provided since subsystems like font
    /// rasterization depend on DPI and scale factor.
    pub fn device_properties(&self) -> DeviceProperties {
        DeviceProperties {
            scale_factor: self.glutin_window.hidpi_factor(),
        }
    }

    /// Set the window resize callback
    ///
    /// Pass a `move` closure which will be called with the new width and height
    /// when the window is resized. According to the glutin docs, this can be
    /// used to draw during resizing.
    ///
    /// This method takes self mutably to ensure there's no race condition
    /// setting the callback.
    pub fn set_resize_callback<F: Fn(u32, u32) + 'static>(&mut self, func: F) {
        unsafe {
            RESIZE_CALLBACK = Some(Box::new(func));
        }
    }

    pub fn inner_size_pixels(&self) -> Option<Size<Pixels<u32>>> {
        self.glutin_window
            .get_inner_size_pixels()
            .map(|(w, h)| Size { width: Pixels(w), height: Pixels(h) })
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
        self.glutin_window.hidpi_factor()
    }

    #[inline]
    pub fn create_window_proxy(&self) -> Proxy {
        Proxy(self.glutin_window.create_window_proxy())
    }

    #[inline]
    pub fn swap_buffers(&self) -> Result<()> {
        self.glutin_window
            .swap_buffers()
            .map_err(From::from)
    }

    /// Block waiting for events
    ///
    /// FIXME should return our own type
    #[inline]
    pub fn wait_events(&self) -> glutin::WaitEventsIterator {
        self.glutin_window.wait_events()
    }

    /// Block waiting for events
    ///
    /// FIXME should return our own type
    #[inline]
    pub fn poll_events(&self) -> glutin::PollEventsIterator {
        self.glutin_window.poll_events()
    }
}

impl Proxy {
    /// Wakes up the event loop of the window
    ///
    /// This is useful for triggering a draw when the renderer would otherwise
    /// be waiting on user input.
    pub fn wakeup_event_loop(&self) {
        self.0.wakeup_event_loop();
    }
}

pub trait SetInnerSize<T> {
    fn set_inner_size<S: ToPoints>(&mut self, size: S);
}

impl SetInnerSize<Pixels<u32>> for Window {
    fn set_inner_size<T: ToPoints>(&mut self, size: T) {
        let size = size.to_points(self.hidpi_factor());
        self.glutin_window.set_inner_size(*size.width as _, *size.height as _);
    }
}
<|endoftext|>


<commit_before>//! Window abstraction

use std::cell::RefCell;
use input::InputEvent;
use current::{ Get, Modifier, Set, Usage };

use GenericEvent;

/// Whether window should close or not.
pub struct ShouldClose(pub bool);

/// Work-around trait for `Get<ShouldClose>`.
/// Used to support generic constraints.
pub trait GetShouldClose: Get<ShouldClose> {
    /// Returns whether window should close.
    fn get_should_close(&self) -> ShouldClose {
        self.get()
    }
}

impl<T: Get<ShouldClose>> GetShouldClose for T {}

/// Work-around trait for `Set<ShouldClose>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetShouldClose: Set<ShouldClose> {
    /// Sets whether window should close.
    fn set_should_close(&mut self, val: ShouldClose);
}

/// The size of the window.
pub struct Size(pub [u32, ..2]);

/// Work-around trait for `Get<Size>`.
/// Used to support generic constraints.
pub trait GetSize: Get<Size> {
    /// Returns the size of window.
    fn get_size(&self) -> Size {
        self.get()
    }
}

impl<T: Get<Size>> GetSize for T {}

/// Work-around trait for `Set<Size>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetSize: Set<Size> {
    /// Sets size of window.
    fn set_size(&mut self, val: Size);
}

/// The title of the window.
pub struct Title(pub String);

/// Work-around trait for `Get<Title>`.
/// Used to support generic constraints.
pub trait GetTitle: Get<Title> {
    /// Returns the title of the window.
    fn get_title(&self) -> Title {
        self.get()
    }
}

impl<T: Get<Title>> GetTitle for T {}

/// Work-around trait for `Set<Title>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetTitle: Set<Title> {
    /// Sets title of window.
    fn set_title(&mut self, val: Title);
}

/// The anti-aliasing samples when rendering.
pub struct Samples(pub u8);

/// Work-around trait for `Get<Samples>`.
/// Used to support generic constraints.
pub trait GetSamples: Get<Samples> {
    /// Returns the antialiasing samples when rendering.
    fn get_samples(&self) -> Samples {
        self.get()
    }
}

impl<T: Get<Samples>> GetSamples for T {}

/// Work-around trait for `Set<Samples>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetSamples: Set<Samples> {
    /// Sets antialiasing samples of window.
    fn set_samples(&mut self, val: Samples);
}

/// Whether window is opened in full screen mode.
pub struct Fullscreen(pub bool);

/// Work-around trait for `Get<Fullscreen>`.
/// Used to support generic constraints.
pub trait GetFullscreen: Get<Fullscreen> {
    /// Returns whether window is in full screen mode.
    fn get_fullscreen(&self) -> Fullscreen {
        self.get()
    }
}

impl<T: Get<Fullscreen>> GetFullscreen for T {}

/// Work-around trait for `Set<Fullscreen>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetFullscreen: Set<Fullscreen> {
    /// Sets window to fullscreen mode.
    fn set_fullscreen(&mut self, val: Fullscreen);
}

/// Whether to exit when pressing the Esc keyboard button.
pub struct ExitOnEsc(pub bool);

/// Work-around trait for `Get<ExitOnEsc>`.
/// Used to support generic constraints.
pub trait GetExitOnEsc: Get<ExitOnEsc> {
    /// Returns whether window exits when pressing Esc.
    fn get_exit_on_esc(&self) -> ExitOnEsc {
        self.get()
    }
}

impl<T: Get<ExitOnEsc>> GetExitOnEsc for T {}

/// Work-around trait for `Set<ExitOnEsc>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetExitOnEsc: Set<ExitOnEsc> {
    /// Sets exit when pressing Esc.
    fn set_exit_on_esc(&mut self, val: ExitOnEsc);
}

/// Whether to capture the mouse cursor.
pub struct CaptureCursor(pub bool);

/// Work-around trait for `Get<CaptureCursor>`.
/// Used to support generic constraints.
pub trait GetCaptureCursor: Get<CaptureCursor> {
    /// Returns whether window captures cursor.
    fn get_capture_cursor(&self) -> CaptureCursor {
        self.get()
    }
}

impl<T: Get<CaptureCursor>> GetCaptureCursor for T {}

/// Work-around trait for `Set<CaptureCursor>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetCaptureCursor: Set<CaptureCursor> {
    /// Sets capture cursor.
    fn set_capture_cursor(&mut self, val: CaptureCursor);
}

/// The draw size of the window.
pub struct DrawSize(pub [u32, ..2]);

/// Work-around trait for `Get<DrawSize>`.
/// Used to support generic constraints.
pub trait GetDrawSize: Get<DrawSize> {
    /// Returns the draw size of window.
    fn get_draw_size(&self) -> DrawSize {
        self.get()
    }
}

impl<T: Get<DrawSize>> GetDrawSize for T {}

/// Work-around trait for `Set<DrawSize>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetDrawSize: Set<DrawSize> {
    /// Sets draw size.
    fn set_draw_size(&mut self, val: DrawSize);
}

#[test]
fn test_methods() {
    use current::Modifier;

    struct Obj;

    impl Get<ShouldClose> for Obj {
        fn get(&self) -> ShouldClose { ShouldClose(false) }
    }

    impl Modifier<Obj> for ShouldClose {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetShouldClose for Obj {
        fn set_should_close(&mut self, val: ShouldClose) {
            self.set_mut(val);
        }
    }

    impl Get<Size> for Obj {
        fn get(&self) -> Size { Size([0, 0]) }
    }

    impl Modifier<Obj> for Size {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetSize for Obj {
        fn set_size(&mut self, val: Size) {
            self.set_mut(val);
        }
    }

    impl Get<Title> for Obj {
        fn get(&self) -> Title { Title("hello".to_string()) }
    }

    impl Modifier<Obj> for Title {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetTitle for Obj {
        fn set_title(&mut self, val: Title) {
            self.set_mut(val);
        }
    }

    impl Get<Samples> for Obj {
        fn get(&self) -> Samples { Samples(0) }
    }

    impl Modifier<Obj> for Samples {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetSamples for Obj {
        fn set_samples(&mut self, val: Samples) {
            self.set_mut(val);
        }
    }

    impl Get<Fullscreen> for Obj {
        fn get(&self) -> Fullscreen { Fullscreen(false) }
    }

    impl Modifier<Obj> for Fullscreen {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetFullscreen for Obj {
        fn set_fullscreen(&mut self, val: Fullscreen) {
            self.set_mut(val);
        }
    }

    impl Get<ExitOnEsc> for Obj {
        fn get(&self) -> ExitOnEsc { ExitOnEsc(true) }
    }

    impl Modifier<Obj> for ExitOnEsc {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetExitOnEsc for Obj {
        fn set_exit_on_esc(&mut self, val: ExitOnEsc) {
            self.set_mut(val);
        }
    }

    impl Get<CaptureCursor> for Obj {
        fn get(&self) -> CaptureCursor { CaptureCursor(false) }
    }

    impl Modifier<Obj> for CaptureCursor {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetCaptureCursor for Obj {
        fn set_capture_cursor(&mut self, val: CaptureCursor) {
            self.set_mut(val);
        }
    }

    impl Get<DrawSize> for Obj {
        fn get(&self) -> DrawSize { DrawSize([0, 0]) }
    }

    impl Modifier<Obj> for DrawSize {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetDrawSize for Obj {
        fn set_draw_size(&mut self, val: DrawSize) {
            self.set_mut(val);
        }
    }

    fn foo<T: GetShouldClose + SetShouldClose
            + GetSize + SetSize
            + GetTitle + SetTitle
            + GetSamples + SetSamples
            + GetFullscreen + SetFullscreen
            + GetExitOnEsc + SetExitOnEsc
            + GetCaptureCursor + SetCaptureCursor
            + GetDrawSize + SetDrawSize>(_obj: T) {}

    foo(Obj);
}

/// Implemented by windows that can swap buffers.
pub trait SwapBuffers {
    /// Swaps the buffers.
    fn swap_buffers(&mut self);
}

impl<'a, W: 'a + SwapBuffers> SwapBuffers for Usage<'a, W> {
    #[inline(always)]
    fn swap_buffers(&mut self) {
        self.with_unwrap(|window: &RefCell<W>| {
            window.borrow_mut().deref_mut().swap_buffers()
        })
    }
}

impl<'a, W: 'a + SwapBuffers> SwapBuffers for &'a RefCell<W> {
    #[inline(always)]
    fn swap_buffers(&mut self) {
        self.borrow_mut().deref_mut().swap_buffers()
    }
}

/// Implemented by windows that can pull events.
pub trait PollEvent<E: GenericEvent> {
    /// Polls event from window.
    fn poll_event(&mut self) -> Option<E>;
}

impl<'a, W: 'a + PollEvent<I>, I: GenericEvent> PollEvent<I> for Usage<'a, W> {
    #[inline(always)]
    fn poll_event(&mut self) -> Option<I> {
        self.with_unwrap(|window: &RefCell<W>| {
            window.borrow_mut().deref_mut().poll_event()
        })
    }
}

impl<'a, W: 'a + PollEvent<I>, I: GenericEvent> PollEvent<I> for &'a RefCell<W> {
    #[inline(always)]
    fn poll_event(&mut self) -> Option<I> {
        self.borrow_mut().deref_mut().poll_event()
    }
}

/// Settings for window behavior.
pub struct WindowSettings {
    /// Title of the window.
    pub title: String,
    /// The size of the window.
    pub size: [u32, ..2],
    /// Number samples per pixel (anti-aliasing).
    pub samples: u8,
    /// If true, the window is fullscreen.
    pub fullscreen: bool,
    /// If true, exit when pressing Esc.
    pub exit_on_esc: bool,
}

impl WindowSettings {
    /// Gets default settings.
    ///
    /// This exits the window when pressing `Esc`.
    /// The background color is set to black.
    pub fn default() -> WindowSettings {
        WindowSettings {
            title: "Piston".to_string(),
            size: [640, 480],
            samples: 0,
            fullscreen: false,
            exit_on_esc: true,
        }
    }
}

/// Implemented by window back-end.
pub trait Window<E: GenericEvent = InputEvent>:
    SwapBuffers
  + PollEvent<E>
  + GetShouldClose + SetShouldClose
  + GetSize
  + SetCaptureCursor
  + GetDrawSize
  + GetTitle + SetTitle
  + GetExitOnEsc + SetExitOnEsc {}

/// An implementation of Window that runs without a window at all.
pub struct NoWindow {
    should_close: bool,
    title: String,
}

impl NoWindow {
    /// Returns a new `NoWindow`.
    pub fn new(settings: WindowSettings) -> NoWindow {
        let title = settings.title.clone();
        NoWindow {
            should_close: false,
            title: title,
        }
    }
}

impl SwapBuffers for NoWindow {
    fn swap_buffers(&mut self) {}
}

impl PollEvent<InputEvent> for NoWindow {
    fn poll_event(&mut self) -> Option<InputEvent> { None }
}

impl Get<ShouldClose> for NoWindow {
    fn get(&self) -> ShouldClose {
        ShouldClose(self.should_close)
    }
}

impl Get<Size> for NoWindow {
    fn get(&self) -> Size {
        Size([0, 0])
    }
}

impl Modifier<NoWindow> for CaptureCursor {
    fn modify(self, _window: &mut NoWindow) {}
}

impl SetCaptureCursor for NoWindow {
    fn set_capture_cursor(&mut self, val: CaptureCursor) {
        self.set_mut(val);
    }
}

impl Modifier<NoWindow> for ShouldClose {
    fn modify(self, window: &mut NoWindow) {
        let ShouldClose(val) = self;
        window.should_close = val;
    }
}

impl SetShouldClose for NoWindow {
    fn set_should_close(&mut self, val: ShouldClose) {
        self.set_mut(val);
    }
}

impl Get<DrawSize> for NoWindow {
    fn get(&self) -> DrawSize {
        let Size(val) = self.get();
        DrawSize(val)
    }
}

impl Window<InputEvent> for NoWindow {}

impl Get<Title> for NoWindow {
    fn get(&self) -> Title {
        Title(self.title.clone())
    }
}

impl Modifier<NoWindow> for Title {
    fn modify(self, window: &mut NoWindow) {
        let Title(val) = self;
        window.title = val;
    }
}

impl SetTitle for NoWindow {
    fn set_title(&mut self, val: Title) {
        self.set_mut(val);
    }
}

impl Get<ExitOnEsc> for NoWindow {
    fn get(&self) -> ExitOnEsc {
        ExitOnEsc(false)
    }
}

impl Modifier<NoWindow> for ExitOnEsc {
    // Ignore attempt to exit by pressing Esc.
    fn modify(self, _window: &mut NoWindow) {}
}

impl SetExitOnEsc for NoWindow {
    fn set_exit_on_esc(&mut self, val: ExitOnEsc) {
        self.set_mut(val);
    }
}

<commit_msg>Added blanket impls for Set wrapper traits<commit_after>//! Window abstraction

use std::cell::RefCell;
use input::InputEvent;
use current::{ Get, Modifier, Set, Usage };

use GenericEvent;

/// Whether window should close or not.
pub struct ShouldClose(pub bool);

/// Work-around trait for `Get<ShouldClose>`.
/// Used to support generic constraints.
pub trait GetShouldClose: Get<ShouldClose> {
    /// Returns whether window should close.
    fn get_should_close(&self) -> ShouldClose {
        self.get()
    }
}

impl<T: Get<ShouldClose>> GetShouldClose for T {}

/// Work-around trait for `Set<ShouldClose>`.
/// Used to support generic constraints.
pub trait SetShouldClose: Set<ShouldClose> {
    /// Sets whether window should close.
    fn set_should_close(&mut self, val: ShouldClose) {
        self.set_mut(val);
    }
}

impl<T: Set<ShouldClose>> SetShouldClose for T {}

/// The size of the window.
pub struct Size(pub [u32, ..2]);

/// Work-around trait for `Get<Size>`.
/// Used to support generic constraints.
pub trait GetSize: Get<Size> {
    /// Returns the size of window.
    fn get_size(&self) -> Size {
        self.get()
    }
}

impl<T: Get<Size>> GetSize for T {}

/// Work-around trait for `Set<Size>`.
/// Used to support generic constraints.
pub trait SetSize: Set<Size> {
    /// Sets size of window.
    fn set_size(&mut self, val: Size) {
        self.set_mut(val);
    }
}

impl<T: Set<Size>> SetSize for T {}

/// The title of the window.
pub struct Title(pub String);

/// Work-around trait for `Get<Title>`.
/// Used to support generic constraints.
pub trait GetTitle: Get<Title> {
    /// Returns the title of the window.
    fn get_title(&self) -> Title {
        self.get()
    }
}

impl<T: Get<Title>> GetTitle for T {}

/// Work-around trait for `Set<Title>`.
/// Used to support generic constraints.
pub trait SetTitle: Set<Title> {
    /// Sets title of window.
    fn set_title(&mut self, val: Title) {
        self.set_mut(val);
    }
}

impl<T: Set<Title>> SetTitle for T {}

/// The anti-aliasing samples when rendering.
pub struct Samples(pub u8);

/// Work-around trait for `Get<Samples>`.
/// Used to support generic constraints.
pub trait GetSamples: Get<Samples> {
    /// Returns the antialiasing samples when rendering.
    fn get_samples(&self) -> Samples {
        self.get()
    }
}

impl<T: Get<Samples>> GetSamples for T {}

/// Work-around trait for `Set<Samples>`.
/// Used to support generic constraints.
pub trait SetSamples: Set<Samples> {
    /// Sets antialiasing samples of window.
    fn set_samples(&mut self, val: Samples) {
        self.set_mut(val);
    }
}

impl<T: Set<Samples>> SetSamples for T {}

/// Whether window is opened in full screen mode.
pub struct Fullscreen(pub bool);

/// Work-around trait for `Get<Fullscreen>`.
/// Used to support generic constraints.
pub trait GetFullscreen: Get<Fullscreen> {
    /// Returns whether window is in full screen mode.
    fn get_fullscreen(&self) -> Fullscreen {
        self.get()
    }
}

impl<T: Get<Fullscreen>> GetFullscreen for T {}

/// Work-around trait for `Set<Fullscreen>`.
/// Used to support generic constraints.
pub trait SetFullscreen: Set<Fullscreen> {
    /// Sets window to fullscreen mode.
    fn set_fullscreen(&mut self, val: Fullscreen) {
        self.set_mut(val);
    }
}

impl<T: Set<Fullscreen>> SetFullscreen for T {}

/// Whether to exit when pressing the Esc keyboard button.
pub struct ExitOnEsc(pub bool);

/// Work-around trait for `Get<ExitOnEsc>`.
/// Used to support generic constraints.
pub trait GetExitOnEsc: Get<ExitOnEsc> {
    /// Returns whether window exits when pressing Esc.
    fn get_exit_on_esc(&self) -> ExitOnEsc {
        self.get()
    }
}

impl<T: Get<ExitOnEsc>> GetExitOnEsc for T {}

/// Work-around trait for `Set<ExitOnEsc>`.
/// Used to support generic constraints.
pub trait SetExitOnEsc: Set<ExitOnEsc> {
    /// Sets exit when pressing Esc.
    fn set_exit_on_esc(&mut self, val: ExitOnEsc) {
        self.set_mut(val);
    }
}

impl<T: Set<ExitOnEsc>> SetExitOnEsc for T {}

/// Whether to capture the mouse cursor.
pub struct CaptureCursor(pub bool);

/// Work-around trait for `Get<CaptureCursor>`.
/// Used to support generic constraints.
pub trait GetCaptureCursor: Get<CaptureCursor> {
    /// Returns whether window captures cursor.
    fn get_capture_cursor(&self) -> CaptureCursor {
        self.get()
    }
}

impl<T: Get<CaptureCursor>> GetCaptureCursor for T {}

/// Work-around trait for `Set<CaptureCursor>`.
/// Used to support generic constraints.
pub trait SetCaptureCursor: Set<CaptureCursor> {
    /// Sets capture cursor.
    fn set_capture_cursor(&mut self, val: CaptureCursor) {
        self.set_mut(val);
    }
}

impl<T: Set<CaptureCursor>> SetCaptureCursor for T {}

/// The draw size of the window.
pub struct DrawSize(pub [u32, ..2]);

/// Work-around trait for `Get<DrawSize>`.
/// Used to support generic constraints.
pub trait GetDrawSize: Get<DrawSize> {
    /// Returns the draw size of window.
    fn get_draw_size(&self) -> DrawSize {
        self.get()
    }
}

impl<T: Get<DrawSize>> GetDrawSize for T {}

/// Work-around trait for `Set<DrawSize>`.
/// Used to support generic constraints.
pub trait SetDrawSize: Set<DrawSize> {
    /// Sets draw size.
    fn set_draw_size(&mut self, val: DrawSize) {
        self.set_mut(val);
    }
}

impl<T: Set<DrawSize>> SetDrawSize for T {}

#[test]
fn test_methods() {
    use current::Modifier;

    struct Obj;

    impl Get<ShouldClose> for Obj {
        fn get(&self) -> ShouldClose { ShouldClose(false) }
    }

    impl Modifier<Obj> for ShouldClose {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl Get<Size> for Obj {
        fn get(&self) -> Size { Size([0, 0]) }
    }

    impl Modifier<Obj> for Size {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl Get<Title> for Obj {
        fn get(&self) -> Title { Title("hello".to_string()) }
    }

    impl Modifier<Obj> for Title {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl Get<Samples> for Obj {
        fn get(&self) -> Samples { Samples(0) }
    }

    impl Modifier<Obj> for Samples {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl Get<Fullscreen> for Obj {
        fn get(&self) -> Fullscreen { Fullscreen(false) }
    }

    impl Modifier<Obj> for Fullscreen {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl Get<ExitOnEsc> for Obj {
        fn get(&self) -> ExitOnEsc { ExitOnEsc(true) }
    }

    impl Modifier<Obj> for ExitOnEsc {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl Get<CaptureCursor> for Obj {
        fn get(&self) -> CaptureCursor { CaptureCursor(false) }
    }

    impl Modifier<Obj> for CaptureCursor {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl Get<DrawSize> for Obj {
        fn get(&self) -> DrawSize { DrawSize([0, 0]) }
    }

    impl Modifier<Obj> for DrawSize {
        fn modify(self, _obj: &mut Obj) {}
    }

    fn foo<T: GetShouldClose + SetShouldClose
            + GetSize + SetSize
            + GetTitle + SetTitle
            + GetSamples + SetSamples
            + GetFullscreen + SetFullscreen
            + GetExitOnEsc + SetExitOnEsc
            + GetCaptureCursor + SetCaptureCursor
            + GetDrawSize + SetDrawSize>(_obj: T) {}

    foo(Obj);
}

/// Implemented by windows that can swap buffers.
pub trait SwapBuffers {
    /// Swaps the buffers.
    fn swap_buffers(&mut self);
}

impl<'a, W: 'a + SwapBuffers> SwapBuffers for Usage<'a, W> {
    #[inline(always)]
    fn swap_buffers(&mut self) {
        self.with_unwrap(|window: &RefCell<W>| {
            window.borrow_mut().deref_mut().swap_buffers()
        })
    }
}

impl<'a, W: 'a + SwapBuffers> SwapBuffers for &'a RefCell<W> {
    #[inline(always)]
    fn swap_buffers(&mut self) {
        self.borrow_mut().deref_mut().swap_buffers()
    }
}

/// Implemented by windows that can pull events.
pub trait PollEvent<E: GenericEvent> {
    /// Polls event from window.
    fn poll_event(&mut self) -> Option<E>;
}

impl<'a, W: 'a + PollEvent<I>, I: GenericEvent> PollEvent<I> for Usage<'a, W> {
    #[inline(always)]
    fn poll_event(&mut self) -> Option<I> {
        self.with_unwrap(|window: &RefCell<W>| {
            window.borrow_mut().deref_mut().poll_event()
        })
    }
}

impl<'a, W: 'a + PollEvent<I>, I: GenericEvent> PollEvent<I> for &'a RefCell<W> {
    #[inline(always)]
    fn poll_event(&mut self) -> Option<I> {
        self.borrow_mut().deref_mut().poll_event()
    }
}

/// Settings for window behavior.
pub struct WindowSettings {
    /// Title of the window.
    pub title: String,
    /// The size of the window.
    pub size: [u32, ..2],
    /// Number samples per pixel (anti-aliasing).
    pub samples: u8,
    /// If true, the window is fullscreen.
    pub fullscreen: bool,
    /// If true, exit when pressing Esc.
    pub exit_on_esc: bool,
}

impl WindowSettings {
    /// Gets default settings.
    ///
    /// This exits the window when pressing `Esc`.
    /// The background color is set to black.
    pub fn default() -> WindowSettings {
        WindowSettings {
            title: "Piston".to_string(),
            size: [640, 480],
            samples: 0,
            fullscreen: false,
            exit_on_esc: true,
        }
    }
}

/// Implemented by window back-end.
pub trait Window<E: GenericEvent = InputEvent>:
    SwapBuffers
  + PollEvent<E>
  + GetShouldClose + SetShouldClose
  + GetSize
  + SetCaptureCursor
  + GetDrawSize
  + GetTitle + SetTitle
  + GetExitOnEsc + SetExitOnEsc {}

/// An implementation of Window that runs without a window at all.
pub struct NoWindow {
    should_close: bool,
    title: String,
}

impl NoWindow {
    /// Returns a new `NoWindow`.
    pub fn new(settings: WindowSettings) -> NoWindow {
        let title = settings.title.clone();
        NoWindow {
            should_close: false,
            title: title,
        }
    }
}

impl SwapBuffers for NoWindow {
    fn swap_buffers(&mut self) {}
}

impl PollEvent<InputEvent> for NoWindow {
    fn poll_event(&mut self) -> Option<InputEvent> { None }
}

impl Get<ShouldClose> for NoWindow {
    fn get(&self) -> ShouldClose {
        ShouldClose(self.should_close)
    }
}

impl Get<Size> for NoWindow {
    fn get(&self) -> Size {
        Size([0, 0])
    }
}

impl Modifier<NoWindow> for CaptureCursor {
    fn modify(self, _window: &mut NoWindow) {}
}

impl Modifier<NoWindow> for ShouldClose {
    fn modify(self, window: &mut NoWindow) {
        let ShouldClose(val) = self;
        window.should_close = val;
    }
}

impl Get<DrawSize> for NoWindow {
    fn get(&self) -> DrawSize {
        let Size(val) = self.get();
        DrawSize(val)
    }
}

impl Window<InputEvent> for NoWindow {}

impl Get<Title> for NoWindow {
    fn get(&self) -> Title {
        Title(self.title.clone())
    }
}

impl Modifier<NoWindow> for Title {
    fn modify(self, window: &mut NoWindow) {
        let Title(val) = self;
        window.title = val;
    }
}

impl Get<ExitOnEsc> for NoWindow {
    fn get(&self) -> ExitOnEsc {
        ExitOnEsc(false)
    }
}

impl Modifier<NoWindow> for ExitOnEsc {
    // Ignore attempt to exit by pressing Esc.
    fn modify(self, _window: &mut NoWindow) {}
}

<|endoftext|>


<commit_before>use alloc::arc::Arc;
use alloc::boxed::FnBox;
use alloc::heap;
use arch::cpu;
use arch::thread;
use collections::vec_deque::VecDeque;
use core::mem;
use core::slice;
use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use libc::{self,jmp_buf};
use mutex::{Mutex,MutexGuard};
use prelude::*;
use process::Process;
use singleton::Singleton;

static SCHEDULER: Singleton<Mutex<SchedulerState>> = Singleton::new();

fn setjmp() -> Option<jmp_buf> {
    unsafe {
        let mut jmp_buf = mem::uninitialized();
        if libc::setjmp(&mut jmp_buf) == 0 {
            Some(jmp_buf)
        } else {
            None
        }
    }
}

fn drop_write_guard<'a, T>(guard: MutexGuard<'a, T>) {
    mem::drop(guard);
}

fn forget_write_guard<'a, T>(guard: MutexGuard<'a, T>) {
    mem::forget(guard);
}

fn assert_no_lock() {
    assert!(cpu::interrupts_enabled());
}

struct Thread {
    id: usize,
    stack: &'static mut [u8],
    process: Arc<Process>,
    exited: Deferred<i32>
}

impl Thread {
    pub fn new(process: Arc<Process>, stack: &'static mut [u8]) -> Thread {
        static NEXT_THREAD_ID: AtomicUsize = ATOMIC_USIZE_INIT;
        Thread {
            id: NEXT_THREAD_ID.fetch_add(1, Ordering::Relaxed),
            stack: stack,
            process: process,
            exited: Deferred::new()
        }
    }
}

struct DeferredState<A> {
    result: Option<A>,
    waiters: VecDeque<(jmp_buf, Thread)>
}

struct SchedulerState {
    current: Thread,
    threads: VecDeque<(jmp_buf, Thread)>,
    garbage_stacks: Vec<&'static mut [u8]>
}

impl Drop for SchedulerState {
    fn drop(&mut self) {
        let garbage_stacks = mem::replace(&mut self.garbage_stacks, Vec::new());

        for stack in garbage_stacks {
            unsafe { heap::deallocate(stack.as_mut_ptr(), stack.len(), 16) };
        }
    }
}

pub struct Deferred<A> {
    state: Arc<Mutex<DeferredState<A>>>
}

#[inline(never)] // hmm?
pub fn with_scheduler<F: FnOnce()>(idle_process: Arc<Process>, f: F) {
    let state = SchedulerState {
        current: Thread::new(idle_process.clone(), &mut []),
        threads: VecDeque::new(),
        garbage_stacks: Vec::new()
    };

    let _d = SCHEDULER.register(Mutex::new(state));
    unsafe { idle_process.switch() };
    f()
}

fn current_sched() -> &'static Mutex<SchedulerState> {
    SCHEDULER.get().expect("no Scheduler registered")
}

macro_rules! lock_sched {
    () => (lock!(current_sched()))
}

pub fn current_process() -> Arc<Process> {
    lock_sched!().current.process.clone()
}

pub fn schedule() {
    assert_no_lock();

    let mut state = lock_sched!();
    match state.threads.pop_front() {
        Some((new_jmp_buf, new_current)) => {
            let new_process = new_current.process.clone();
            let old_current = mem::replace(&mut state.current, new_current);

            match setjmp() {
                Some(old_jmp_buf) => {
                    state.threads.push_back((old_jmp_buf, old_current));
                    drop_write_guard(state);

                    unsafe {
                        new_process.switch();
                        mem::drop(new_process);
                        libc::longjmp(&new_jmp_buf, 1);
                    }
                },

                None => {
                    forget_write_guard(state);
                }
            }
        },

        None => { }
    };
}

pub fn exit(code: i32) -> ! {
    let exited = lock_sched!().current.exited.clone();
    exited.resolve(code);

    let new_jmp_buf = {
        assert_no_lock();

        let mut state = lock_sched!();
        let (new_jmp_buf, new_current) =
            match state.threads.pop_front() {
                Some(front) => front,
                None => panic!("exit({}): no more threads", state.current.id)
            };

        let new_process = new_current.process.clone();
        let old_current = mem::replace(&mut state.current, new_current);
        state.garbage_stacks.push(old_current.stack);
        unsafe { new_process.switch() };
        new_jmp_buf
    };

    unsafe {
        libc::longjmp(&new_jmp_buf, 1);
    }
}

fn spawn_inner<'a>(process: Arc<Process>, start: Box<FnBox() + 'a>) -> Deferred<i32> {
    let stack_len = 4096;
    let stack_base_ptr = unsafe { heap::allocate(stack_len, 16) };
    let b: Box<FnBox() + 'a> = Box::new(start);
    let jmp_buf = thread::new_jmp_buf(b, unsafe { stack_base_ptr.offset(stack_len as isize) });
    let thread = Thread::new(process, unsafe { slice::from_raw_parts_mut(stack_base_ptr, stack_len) });
    let exited = thread.exited.clone();

    {
        let mut state = lock_sched!();
        state.threads.push_back((jmp_buf, thread));
    }

    exited
}

pub fn spawn_user_mode(pc: *const u8, stack: &mut [u8]) -> Deferred<i32> {
    let stack_ptr = stack.as_mut_ptr();
    let stack_len = stack.len();

    let start = move || {
        unsafe {
            thread::jmp_user_mode(pc, stack_ptr.offset(stack_len as isize))
        }
        // TODO: free stack
    };

    let process = lock_sched!().current.process.clone();
    spawn_inner(process, Box::new(start))
}

pub fn spawn_remote<T>(process: Arc<Process>, start: T) -> Deferred<i32> where T : FnOnce() -> i32 {
    let start = || { exit(start()) };
    spawn_inner(process, Box::new(start))
}

pub fn spawn<T>(start: T) -> Deferred<i32> where T : FnOnce() -> i32 {
    let process = lock_sched!().current.process.clone();
    spawn_remote(process, start)
}

impl<A> Clone for Deferred<A> {
    fn clone(&self) -> Self {
        Deferred { state: self.state.clone() }
    }
}

impl<A> Deferred<A> {
    pub fn new() -> Self {
        let dstate = Arc::new(Mutex::new(DeferredState {
            result: None,
            waiters: VecDeque::new()
        }));

        Deferred { state: dstate }
    }

    pub fn resolve(&self, result: A) {
        let mut dstate = lock!(self.state);
        match dstate.result {
            Some(_) => panic!("promise is already resolved"),
            None => { }
        }

        dstate.result = Some(result);

        let mut waiters = mem::replace(&mut dstate.waiters, VecDeque::new());
        if waiters.len() > 0 {
            let mut state = lock_sched!();
            state.threads.append(&mut waiters);
        }
    }

    pub fn get(self) -> A {
        loop {
            assert_no_lock();

            let mut dstate = lock!(self.state);
            match mem::replace(&mut dstate.result, None) {
                Some(result) => { return result; },
                None => { }
            }

            let mut state = lock_sched!();
            let (new_jmp_buf, new_current) =
                match state.threads.pop_front() {
                    Some(front) => front,
                    None => panic!("block({}): no more threads", state.current.id)
                };

            let new_process = new_current.process.clone();
            let old_current = mem::replace(&mut state.current, new_current);

            match setjmp() {
                Some(old_jmp_buf) => {
                    dstate.waiters.push_back((old_jmp_buf, old_current));
                    drop_write_guard(state);
                    drop_write_guard(dstate);

                    unsafe {
                        new_process.switch();
                        mem::drop(new_process);
                        libc::longjmp(&new_jmp_buf, 1);
                    }
                },

                None => {
                    forget_write_guard(state);
                    forget_write_guard(dstate);
                }
            }
        }
    }

    pub fn try_get(self) -> Result<A, Self> {
        let opt = {
            let mut state = lock!(self.state);
            mem::replace(&mut state.result, None)
        };

        opt.ok_or(self)
    }
}

#[cfg(feature = "test")]
pub mod test {
    use alloc::arc::Arc;
    use phys_mem::PhysicalBitmap;
    use prelude::*;
    use process::Process;
    use super::*;
    use virt_mem::VirtualTree;

    test! {
        fn can_spawn_exit_thread() {
            let phys = Arc::new(PhysicalBitmap::parse_multiboot());
            let kernel_virt = Arc::new(VirtualTree::new());
            let p = Arc::new(Process::new(phys, kernel_virt).unwrap());
            with_scheduler(p, || {
                let d = spawn(|| 123);
                assert_eq!(123, d.get());
            });
        }

        fn can_spawn_exit_two_threads() {
            let phys = Arc::new(PhysicalBitmap::parse_multiboot());
            let kernel_virt = Arc::new(VirtualTree::new());
            let p = Arc::new(Process::new(phys, kernel_virt).unwrap());
            with_scheduler(p, || {
                let d1 = spawn(|| 456);
                let d2 = spawn(|| 789);
                assert_eq!(456, d1.get());
                assert_eq!(789, d2.get());
            });
        }

        fn can_closure() {
            let phys = Arc::new(PhysicalBitmap::parse_multiboot());
            let kernel_virt = Arc::new(VirtualTree::new());
            let p = Arc::new(Process::new(phys, kernel_virt).unwrap());
            with_scheduler(p, || {
                let s = String::from("hello");
                let d = spawn(move || (s + &" world").len() as i32);
                assert_eq!(11, d.get());
            });
        }

        fn threads_can_spawn_more_threads() {
            let phys = Arc::new(PhysicalBitmap::parse_multiboot());
            let kernel_virt = Arc::new(VirtualTree::new());
            let p = Arc::new(Process::new(phys, kernel_virt).unwrap());
            with_scheduler(p, || {
                let thread2_fn = || 1234;

                let thread1_fn = {
                    || {
                        let d = spawn(thread2_fn);
                        d.get() * 2
                    }
                };

                let d = spawn(thread1_fn);
                assert_eq!(1234 * 2, d.get());
            });
        }
    }
}
<commit_msg>Didn't need #[inline(never)]<commit_after>use alloc::arc::Arc;
use alloc::boxed::FnBox;
use alloc::heap;
use arch::cpu;
use arch::thread;
use collections::vec_deque::VecDeque;
use core::mem;
use core::slice;
use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use libc::{self,jmp_buf};
use mutex::{Mutex,MutexGuard};
use prelude::*;
use process::Process;
use singleton::Singleton;

static SCHEDULER: Singleton<Mutex<SchedulerState>> = Singleton::new();

fn setjmp() -> Option<jmp_buf> {
    unsafe {
        let mut jmp_buf = mem::uninitialized();
        if libc::setjmp(&mut jmp_buf) == 0 {
            Some(jmp_buf)
        } else {
            None
        }
    }
}

fn drop_write_guard<'a, T>(guard: MutexGuard<'a, T>) {
    mem::drop(guard);
}

fn forget_write_guard<'a, T>(guard: MutexGuard<'a, T>) {
    mem::forget(guard);
}

fn assert_no_lock() {
    assert!(cpu::interrupts_enabled());
}

struct Thread {
    id: usize,
    stack: &'static mut [u8],
    process: Arc<Process>,
    exited: Deferred<i32>
}

impl Thread {
    pub fn new(process: Arc<Process>, stack: &'static mut [u8]) -> Thread {
        static NEXT_THREAD_ID: AtomicUsize = ATOMIC_USIZE_INIT;
        Thread {
            id: NEXT_THREAD_ID.fetch_add(1, Ordering::Relaxed),
            stack: stack,
            process: process,
            exited: Deferred::new()
        }
    }
}

struct DeferredState<A> {
    result: Option<A>,
    waiters: VecDeque<(jmp_buf, Thread)>
}

struct SchedulerState {
    current: Thread,
    threads: VecDeque<(jmp_buf, Thread)>,
    garbage_stacks: Vec<&'static mut [u8]>
}

impl Drop for SchedulerState {
    fn drop(&mut self) {
        let garbage_stacks = mem::replace(&mut self.garbage_stacks, Vec::new());

        for stack in garbage_stacks {
            unsafe { heap::deallocate(stack.as_mut_ptr(), stack.len(), 16) };
        }
    }
}

pub struct Deferred<A> {
    state: Arc<Mutex<DeferredState<A>>>
}

pub fn with_scheduler<F: FnOnce()>(idle_process: Arc<Process>, f: F) {
    let state = SchedulerState {
        current: Thread::new(idle_process.clone(), &mut []),
        threads: VecDeque::new(),
        garbage_stacks: Vec::new()
    };

    let _d = SCHEDULER.register(Mutex::new(state));
    unsafe { idle_process.switch() };
    f()
}

fn current_sched() -> &'static Mutex<SchedulerState> {
    SCHEDULER.get().expect("no Scheduler registered")
}

macro_rules! lock_sched {
    () => (lock!(current_sched()))
}

pub fn current_process() -> Arc<Process> {
    lock_sched!().current.process.clone()
}

pub fn schedule() {
    assert_no_lock();

    let mut state = lock_sched!();
    match state.threads.pop_front() {
        Some((new_jmp_buf, new_current)) => {
            let new_process = new_current.process.clone();
            let old_current = mem::replace(&mut state.current, new_current);

            match setjmp() {
                Some(old_jmp_buf) => {
                    state.threads.push_back((old_jmp_buf, old_current));
                    drop_write_guard(state);

                    unsafe {
                        new_process.switch();
                        mem::drop(new_process);
                        libc::longjmp(&new_jmp_buf, 1);
                    }
                },

                None => {
                    forget_write_guard(state);
                }
            }
        },

        None => { }
    };
}

pub fn exit(code: i32) -> ! {
    let exited = lock_sched!().current.exited.clone();
    exited.resolve(code);

    let new_jmp_buf = {
        assert_no_lock();

        let mut state = lock_sched!();
        let (new_jmp_buf, new_current) =
            match state.threads.pop_front() {
                Some(front) => front,
                None => panic!("exit({}): no more threads", state.current.id)
            };

        let new_process = new_current.process.clone();
        let old_current = mem::replace(&mut state.current, new_current);
        state.garbage_stacks.push(old_current.stack);
        unsafe { new_process.switch() };
        new_jmp_buf
    };

    unsafe {
        libc::longjmp(&new_jmp_buf, 1);
    }
}

fn spawn_inner<'a>(process: Arc<Process>, start: Box<FnBox() + 'a>) -> Deferred<i32> {
    let stack_len = 4096;
    let stack_base_ptr = unsafe { heap::allocate(stack_len, 16) };
    let b: Box<FnBox() + 'a> = Box::new(start);
    let jmp_buf = thread::new_jmp_buf(b, unsafe { stack_base_ptr.offset(stack_len as isize) });
    let thread = Thread::new(process, unsafe { slice::from_raw_parts_mut(stack_base_ptr, stack_len) });
    let exited = thread.exited.clone();

    {
        let mut state = lock_sched!();
        state.threads.push_back((jmp_buf, thread));
    }

    exited
}

pub fn spawn_user_mode(pc: *const u8, stack: &mut [u8]) -> Deferred<i32> {
    let stack_ptr = stack.as_mut_ptr();
    let stack_len = stack.len();

    let start = move || {
        unsafe {
            thread::jmp_user_mode(pc, stack_ptr.offset(stack_len as isize))
        }
        // TODO: free stack
    };

    let process = lock_sched!().current.process.clone();
    spawn_inner(process, Box::new(start))
}

pub fn spawn_remote<T>(process: Arc<Process>, start: T) -> Deferred<i32> where T : FnOnce() -> i32 {
    let start = || { exit(start()) };
    spawn_inner(process, Box::new(start))
}

pub fn spawn<T>(start: T) -> Deferred<i32> where T : FnOnce() -> i32 {
    let process = lock_sched!().current.process.clone();
    spawn_remote(process, start)
}

impl<A> Clone for Deferred<A> {
    fn clone(&self) -> Self {
        Deferred { state: self.state.clone() }
    }
}

impl<A> Deferred<A> {
    pub fn new() -> Self {
        let dstate = Arc::new(Mutex::new(DeferredState {
            result: None,
            waiters: VecDeque::new()
        }));

        Deferred { state: dstate }
    }

    pub fn resolve(&self, result: A) {
        let mut dstate = lock!(self.state);
        match dstate.result {
            Some(_) => panic!("promise is already resolved"),
            None => { }
        }

        dstate.result = Some(result);

        let mut waiters = mem::replace(&mut dstate.waiters, VecDeque::new());
        if waiters.len() > 0 {
            let mut state = lock_sched!();
            state.threads.append(&mut waiters);
        }
    }

    pub fn get(self) -> A {
        loop {
            assert_no_lock();

            let mut dstate = lock!(self.state);
            match mem::replace(&mut dstate.result, None) {
                Some(result) => { return result; },
                None => { }
            }

            let mut state = lock_sched!();
            let (new_jmp_buf, new_current) =
                match state.threads.pop_front() {
                    Some(front) => front,
                    None => panic!("block({}): no more threads", state.current.id)
                };

            let new_process = new_current.process.clone();
            let old_current = mem::replace(&mut state.current, new_current);

            match setjmp() {
                Some(old_jmp_buf) => {
                    dstate.waiters.push_back((old_jmp_buf, old_current));
                    drop_write_guard(state);
                    drop_write_guard(dstate);

                    unsafe {
                        new_process.switch();
                        mem::drop(new_process);
                        libc::longjmp(&new_jmp_buf, 1);
                    }
                },

                None => {
                    forget_write_guard(state);
                    forget_write_guard(dstate);
                }
            }
        }
    }

    pub fn try_get(self) -> Result<A, Self> {
        let opt = {
            let mut state = lock!(self.state);
            mem::replace(&mut state.result, None)
        };

        opt.ok_or(self)
    }
}

#[cfg(feature = "test")]
pub mod test {
    use alloc::arc::Arc;
    use phys_mem::PhysicalBitmap;
    use prelude::*;
    use process::Process;
    use super::*;
    use virt_mem::VirtualTree;

    test! {
        fn can_spawn_exit_thread() {
            let phys = Arc::new(PhysicalBitmap::parse_multiboot());
            let kernel_virt = Arc::new(VirtualTree::new());
            let p = Arc::new(Process::new(phys, kernel_virt).unwrap());
            with_scheduler(p, || {
                let d = spawn(|| 123);
                assert_eq!(123, d.get());
            });
        }

        fn can_spawn_exit_two_threads() {
            let phys = Arc::new(PhysicalBitmap::parse_multiboot());
            let kernel_virt = Arc::new(VirtualTree::new());
            let p = Arc::new(Process::new(phys, kernel_virt).unwrap());
            with_scheduler(p, || {
                let d1 = spawn(|| 456);
                let d2 = spawn(|| 789);
                assert_eq!(456, d1.get());
                assert_eq!(789, d2.get());
            });
        }

        fn can_closure() {
            let phys = Arc::new(PhysicalBitmap::parse_multiboot());
            let kernel_virt = Arc::new(VirtualTree::new());
            let p = Arc::new(Process::new(phys, kernel_virt).unwrap());
            with_scheduler(p, || {
                let s = String::from("hello");
                let d = spawn(move || (s + &" world").len() as i32);
                assert_eq!(11, d.get());
            });
        }

        fn threads_can_spawn_more_threads() {
            let phys = Arc::new(PhysicalBitmap::parse_multiboot());
            let kernel_virt = Arc::new(VirtualTree::new());
            let p = Arc::new(Process::new(phys, kernel_virt).unwrap());
            with_scheduler(p, || {
                let thread2_fn = || 1234;

                let thread1_fn = {
                    || {
                        let d = spawn(thread2_fn);
                        d.get() * 2
                    }
                };

                let d = spawn(thread1_fn);
                assert_eq!(1234 * 2, d.get());
            });
        }
    }
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use data_type::AsBytes;

/// Compute hash value for `data`, with a seed value `seed`.
/// The data type `T` must implement the `AsBytes` trait.
/// TODO: implement more efficient hash, such as Crc32, using SSE4 instructions.
pub fn hash<T: AsBytes>(data: T, seed: u64) -> u64 {
  murmur_hash2_64a(data, seed)
}

static MURMUR_PRIME: u64 = 0xc6a4a7935bd1e995;
static MURMUR_R: i32 = 47;

/// Rust implementation of MurmurHash2, 64-bit version for 64-bit platforms
fn murmur_hash2_64a<T: AsBytes>(data: T, seed: u64) -> u64 {
  let data_bytes = data.as_bytes();
  let len = data_bytes.len();
  let len_64 = (len / 8) * 8;
  let data_bytes_64 = unsafe {
    ::std::slice::from_raw_parts(&data_bytes[0..len_64] as *const [u8] as *const u64, len / 8)
  };

  let mut h = seed ^ (MURMUR_PRIME.wrapping_mul(data_bytes.len() as u64));
  for v in data_bytes_64 {
    let mut k = *v;
    k = k.wrapping_mul(MURMUR_PRIME);
    k ^= k >> MURMUR_R;
    k = k.wrapping_mul(MURMUR_PRIME);
    h ^= k;
    h = h.wrapping_mul(MURMUR_PRIME);
  }

  let data2 = &data_bytes[len_64..];

  // TODO: no pattern matching w/ fallthrough in Rust makes this very awkward
  match len & 7 {
    1 => {
      h ^= data2[0] as u64;
      h = h.wrapping_mul(MURMUR_PRIME)
    },
    2 => {
      h ^= (data2[1] as u64) << 8;
      h ^= data2[0] as u64;
      h = h.wrapping_mul(MURMUR_PRIME)
    },
    3 => {
      h ^= (data2[2] as u64) << 16;
      h ^= (data2[1] as u64) << 8;
      h ^= data2[0] as u64;
      h = h.wrapping_mul(MURMUR_PRIME)
    },
    4 => {
      h ^= (data2[3] as u64) << 24;
      h ^= (data2[2] as u64) << 16;
      h ^= (data2[1] as u64) << 8;
      h ^= data2[0] as u64;
      h = h.wrapping_mul(MURMUR_PRIME)
    },
    5 => {
      h ^= (data2[4] as u64) << 32;
      h ^= (data2[3] as u64) << 24;
      h ^= (data2[2] as u64) << 16;
      h ^= (data2[1] as u64) << 8;
      h ^= data2[0] as u64;
      h = h.wrapping_mul(MURMUR_PRIME)
    },
    6 => {
      h ^= (data2[5] as u64) << 40;
      h ^= (data2[4] as u64) << 32;
      h ^= (data2[3] as u64) << 24;
      h ^= (data2[2] as u64) << 16;
      h ^= (data2[1] as u64) << 8;
      h ^= data2[0] as u64;
      h = h.wrapping_mul(MURMUR_PRIME)
    },
    7 => {
      h ^= (data2[6] as u64) << 48;
      h ^= (data2[5] as u64) << 40;
      h ^= (data2[4] as u64) << 32;
      h ^= (data2[3] as u64) << 24;
      h ^= (data2[2] as u64) << 16;
      h ^= (data2[1] as u64) << 8;
      h ^= data2[0] as u64;
      h = h.wrapping_mul(MURMUR_PRIME)
    },
    _ => panic!("Impossible!")
  }

  h ^= h >> MURMUR_R;
  h = h.wrapping_mul(MURMUR_PRIME);
  h ^= h >> MURMUR_R;
  h
}

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

  #[test]
  fn test_murmur2_64a() {
    let result = murmur_hash2_64a("hello", 123);
    assert_eq!(result, 2597646618390559622);

    let result = murmur_hash2_64a("helloworld", 123);
    assert_eq!(result, 4934371746140206573);

    let result = murmur_hash2_64a("helloworldparquet", 123);
    assert_eq!(result, 2392198230801491746);
  }

  #[test]
  fn test_hash() {
    let result = hash("hello", 123);
    assert_eq!(result, 2597646618390559622);

    let result = hash("helloworld", 123);
    assert_eq!(result, 4934371746140206573);

    let result = hash("helloworldparquet", 123);
    assert_eq!(result, 2392198230801491746);
  }
}
<commit_msg>hash() should take reference<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use data_type::AsBytes;

/// Compute hash value for `data`, with a seed value `seed`.
/// The data type `T` must implement the `AsBytes` trait.
/// TODO: implement more efficient hash, such as Crc32, using SSE4 instructions.
pub fn hash<T: AsBytes>(data: &T, seed: u64) -> u64 {
  murmur_hash2_64a(data, seed)
}

static MURMUR_PRIME: u64 = 0xc6a4a7935bd1e995;
static MURMUR_R: i32 = 47;

/// Rust implementation of MurmurHash2, 64-bit version for 64-bit platforms
fn murmur_hash2_64a<T: AsBytes>(data: &T, seed: u64) -> u64 {
  let data_bytes = data.as_bytes();
  let len = data_bytes.len();
  let len_64 = (len / 8) * 8;
  let data_bytes_64 = unsafe {
    ::std::slice::from_raw_parts(&data_bytes[0..len_64] as *const [u8] as *const u64, len / 8)
  };

  let mut h = seed ^ (MURMUR_PRIME.wrapping_mul(data_bytes.len() as u64));
  for v in data_bytes_64 {
    let mut k = *v;
    k = k.wrapping_mul(MURMUR_PRIME);
    k ^= k >> MURMUR_R;
    k = k.wrapping_mul(MURMUR_PRIME);
    h ^= k;
    h = h.wrapping_mul(MURMUR_PRIME);
  }

  let data2 = &data_bytes[len_64..];

  // TODO: no pattern matching w/ fallthrough in Rust makes this very awkward
  match len & 7 {
    1 => {
      h ^= data2[0] as u64;
      h = h.wrapping_mul(MURMUR_PRIME)
    },
    2 => {
      h ^= (data2[1] as u64) << 8;
      h ^= data2[0] as u64;
      h = h.wrapping_mul(MURMUR_PRIME)
    },
    3 => {
      h ^= (data2[2] as u64) << 16;
      h ^= (data2[1] as u64) << 8;
      h ^= data2[0] as u64;
      h = h.wrapping_mul(MURMUR_PRIME)
    },
    4 => {
      h ^= (data2[3] as u64) << 24;
      h ^= (data2[2] as u64) << 16;
      h ^= (data2[1] as u64) << 8;
      h ^= data2[0] as u64;
      h = h.wrapping_mul(MURMUR_PRIME)
    },
    5 => {
      h ^= (data2[4] as u64) << 32;
      h ^= (data2[3] as u64) << 24;
      h ^= (data2[2] as u64) << 16;
      h ^= (data2[1] as u64) << 8;
      h ^= data2[0] as u64;
      h = h.wrapping_mul(MURMUR_PRIME)
    },
    6 => {
      h ^= (data2[5] as u64) << 40;
      h ^= (data2[4] as u64) << 32;
      h ^= (data2[3] as u64) << 24;
      h ^= (data2[2] as u64) << 16;
      h ^= (data2[1] as u64) << 8;
      h ^= data2[0] as u64;
      h = h.wrapping_mul(MURMUR_PRIME)
    },
    7 => {
      h ^= (data2[6] as u64) << 48;
      h ^= (data2[5] as u64) << 40;
      h ^= (data2[4] as u64) << 32;
      h ^= (data2[3] as u64) << 24;
      h ^= (data2[2] as u64) << 16;
      h ^= (data2[1] as u64) << 8;
      h ^= data2[0] as u64;
      h = h.wrapping_mul(MURMUR_PRIME)
    },
    _ => panic!("Impossible!")
  }

  h ^= h >> MURMUR_R;
  h = h.wrapping_mul(MURMUR_PRIME);
  h ^= h >> MURMUR_R;
  h
}

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

  #[test]
  fn test_murmur2_64a() {
    let result = murmur_hash2_64a(&"hello", 123);
    assert_eq!(result, 2597646618390559622);

    let result = murmur_hash2_64a(&"helloworld", 123);
    assert_eq!(result, 4934371746140206573);

    let result = murmur_hash2_64a(&"helloworldparquet", 123);
    assert_eq!(result, 2392198230801491746);
  }

  #[test]
  fn test_hash() {
    let result = hash(&"hello", 123);
    assert_eq!(result, 2597646618390559622);

    let result = hash(&"helloworld", 123);
    assert_eq!(result, 4934371746140206573);

    let result = hash(&"helloworldparquet", 123);
    assert_eq!(result, 2392198230801491746);
  }
}
<|endoftext|>


<commit_before>use std::fs;
use std::env;
use std::path::Path;

use utils::vcs;
use utils::xcode::{InfoPlist, XcodeProjectInfo};

use prelude::*;

fn get_xcode_project_info(path: &Path) -> Result<Option<XcodeProjectInfo>> {
    if_chain! {
        if let Some(filename_os) = path.file_name();
        if let Some(filename) = filename_os.to_str();
        if filename.ends_with(".xcodeproj");
        then {
            return Ok(Some(XcodeProjectInfo::from_path(path)?));
        }
    }

    let mut projects = vec![];
    for entry_rv in fs::read_dir(path)? {
        if let Ok(entry) = entry_rv {
            if let Some(filename) = entry.file_name().to_str() {
                if filename.ends_with(".xcodeproj") {
                    projects.push(entry.path().to_path_buf());
                }
            }
        }
    }
    if projects.len() == 1 {
        Ok(Some(XcodeProjectInfo::from_path(&projects[0])?))
    } else {
        Ok(None)
    }
}

fn get_xcode_release_name() -> Result<Option<String>>
{
    // if we are executed from within xcode, then we can use the environment
    // based discovery to get a release name without any interpolation.
    if let Some(plist) = InfoPlist::discover_from_env()? {
        return Ok(Some(format!("{}-{}", plist.bundle_id(), plist.version())));
    }

    // Otherwise look upwards for the most likely root of the project.  In
    // that case because we lack information to actually assemble the real
    // release name we will try to determin it from some well known folder names.
    if let Ok(mut here) = env::current_dir() {
        loop {
            if_chain! {
                if let Some(pi) = get_xcode_project_info(&here)?;
                if let Some(config) = pi.get_configuration("release")
                    .or_else(|| pi.get_configuration("debug"));
                if let Some(target) = pi.get_first_target();
                then {
                    return Ok(Some(pi.get_release_name(target, config, None)?));
                }
            }
            if !here.pop() {
                break;
            }
        }
    }

    Ok(None)
}

/// Detects the release name for the current working directory.
pub fn detect_release_name() -> Result<String>
{
    // for now only execute this on macs.  The reason is that this uses
    // xcodebuild which does not exist anywhere but there.
    if_chain! {
        if cfg!(target_os="macos");
        if let Some(release) = get_xcode_release_name()?;
        then {
            return Ok(release)
        }
    }

    Ok(vcs::find_head()?)
}
<commit_msg>Add better error message if the release name cannot be determined<commit_after>use std::fs;
use std::env;
use std::path::Path;

use utils::vcs;
use utils::xcode::{InfoPlist, XcodeProjectInfo};

use prelude::*;

fn get_xcode_project_info(path: &Path) -> Result<Option<XcodeProjectInfo>> {
    if_chain! {
        if let Some(filename_os) = path.file_name();
        if let Some(filename) = filename_os.to_str();
        if filename.ends_with(".xcodeproj");
        then {
            return Ok(Some(XcodeProjectInfo::from_path(path)?));
        }
    }

    let mut projects = vec![];
    for entry_rv in fs::read_dir(path)? {
        if let Ok(entry) = entry_rv {
            if let Some(filename) = entry.file_name().to_str() {
                if filename.ends_with(".xcodeproj") {
                    projects.push(entry.path().to_path_buf());
                }
            }
        }
    }
    if projects.len() == 1 {
        Ok(Some(XcodeProjectInfo::from_path(&projects[0])?))
    } else {
        Ok(None)
    }
}

fn get_xcode_release_name() -> Result<Option<String>>
{
    // if we are executed from within xcode, then we can use the environment
    // based discovery to get a release name without any interpolation.
    if let Some(plist) = InfoPlist::discover_from_env()? {
        return Ok(Some(format!("{}-{}", plist.bundle_id(), plist.version())));
    }

    // Otherwise look upwards for the most likely root of the project.  In
    // that case because we lack information to actually assemble the real
    // release name we will try to determin it from some well known folder names.
    if let Ok(mut here) = env::current_dir() {
        loop {
            if_chain! {
                if let Some(pi) = get_xcode_project_info(&here)?;
                if let Some(config) = pi.get_configuration("release")
                    .or_else(|| pi.get_configuration("debug"));
                if let Some(target) = pi.get_first_target();
                then {
                    return Ok(Some(pi.get_release_name(target, config, None)?));
                }
            }
            if !here.pop() {
                break;
            }
        }
    }

    Ok(None)
}

/// Detects the release name for the current working directory.
pub fn detect_release_name() -> Result<String>
{
    // for now only execute this on macs.  The reason is that this uses
    // xcodebuild which does not exist anywhere but there.
    if_chain! {
        if cfg!(target_os="macos");
        if let Some(release) = get_xcode_release_name()?;
        then {
            return Ok(release)
        }
    }

    if let Ok(head) = vcs::find_head() {
        Ok(head)
    } else {
        Err("Could not automatically determine release name".into())
    }
}
<|endoftext|>