<commit_before>use itertools::Itertools;
use std::collections::{HashMap, HashSet};
use std::fmt;
use rand::random;

type Point = (isize, isize);

#[derive(Debug, Clone)]
pub struct World {
    width: isize,
    height: isize,
    generation: HashSet<Point>,
    neighbours: HashMap<Point, usize>,
    age: usize,
}

impl World {
    pub fn new(width: isize, height: isize)  -> World {
        World { width: width, height: height, age: 0, generation: HashSet::new(),
                neighbours: HashMap::with_capacity((width * height * 8) as usize) }
    }

    pub fn seed(mut self) -> World {
        self.generation = (0..self.width).cartesian_product(0..self.height)
            .filter(|_| random())
            .collect::<HashSet<Point>>();
        self.calculate_neighbours();
        self
    }

    pub fn evolve(&mut self) -> &World {
        self.generation = self.neighbours.iter()
                              .filter(|&(n, c)| self.decide_fate(n, *c))
                              .map(|(n, _)| *n)
                              .collect::<HashSet<Point>>();
        self.calculate_neighbours();
        self.age += 1;
        self
    }

    fn calculate_neighbours(&mut self) {
        self.neighbours.clear();
        for &(x, y) in self.generation.iter() {
            let neighbours = (-1..2).cartesian_product(-1..2)
                                    .filter(|&(dx, dy)| dx != 0 || dy != 0)
                                    .map(|(dx, dy)| (dx + x, dy + y));
            for n in neighbours {
                *self.neighbours.entry(n).or_insert(0) += 1;
            }
        }
    }

    fn decide_fate(&self, p: &Point, c: usize) -> bool {
        if self.generation.contains(p) {
            c == 3 || c == 2
        } else {
            c == 3
        }
    }
}

impl fmt::Display for World {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut buf = String::with_capacity(((self.width + 2) * (self.height + 2) + 50) as usize);
        for x in 0..self.width + 2 {
            buf.push(if x == 0 { '┌' } else if x == self.width + 1 { '┐' } else { '─' });
        }
        buf.push('\n');
        for y in 0..self.height {
            buf.push('│');
            for x in 0..self.width {
                buf.push(if self.generation.contains(&(x, y)) { '*' } else { ' ' });
            }
            buf.push('|');
            if y == 0 {
                buf.push_str(&format!(" cells: {}", self.generation.len()));
            }
            if y == 1 {
                buf.push_str(&format!(" age: {}", self.age));
            }
            buf.push('\n');
        }
        for x in 0..self.width + 2 {
            buf.push(if x == 0 { '└' } else if x == self.width + 1 { '┘' } else { '─' });
        }
        write!(f, "{}", buf)
    }
}
<commit_msg>Fix indentations<commit_after>use itertools::Itertools;
use std::collections::{HashMap, HashSet};
use std::fmt;
use rand::random;

type Point = (isize, isize);

#[derive(Debug, Clone)]
pub struct World {
    width: isize,
    height: isize,
    generation: HashSet<Point>,
    neighbours: HashMap<Point, usize>,
    age: usize,
}

impl World {
    pub fn new(width: isize, height: isize)  -> World {
        World { width: width, height: height, age: 0, generation: HashSet::new(),
                neighbours: HashMap::with_capacity((width * height * 8) as usize) }
    }

    pub fn seed(mut self) -> World {
        self.generation = (0..self.width).cartesian_product(0..self.height)
                                         .filter(|_| random())
                                         .collect::<HashSet<Point>>();
        self.calculate_neighbours();
        self
    }

    pub fn evolve(&mut self) -> &World {
        self.generation = self.neighbours.iter()
                              .filter(|&(n, c)| self.decide_fate(n, *c))
                              .map(|(n, _)| *n)
                              .collect::<HashSet<Point>>();
        self.calculate_neighbours();
        self.age += 1;
        self
    }

    fn calculate_neighbours(&mut self) {
        self.neighbours.clear();
        for &(x, y) in self.generation.iter() {
            let neighbours = (-1..2).cartesian_product(-1..2)
                                    .filter(|&(dx, dy)| dx != 0 || dy != 0)
                                    .map(|(dx, dy)| (dx + x, dy + y));
            for n in neighbours {
                *self.neighbours.entry(n).or_insert(0) += 1;
            }
        }
    }

    fn decide_fate(&self, p: &Point, c: usize) -> bool {
        if self.generation.contains(p) {
            c == 3 || c == 2
        } else {
            c == 3
        }
    }
}

impl fmt::Display for World {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut buf = String::with_capacity(((self.width + 2) * (self.height + 2) + 50) as usize);
        for x in 0..self.width + 2 {
            buf.push(if x == 0 { '┌' } else if x == self.width + 1 { '┐' } else { '─' });
        }
        buf.push('\n');
        for y in 0..self.height {
            buf.push('│');
            for x in 0..self.width {
                buf.push(if self.generation.contains(&(x, y)) { '*' } else { ' ' });
            }
            buf.push('|');
            if y == 0 {
                buf.push_str(&format!(" cells: {}", self.generation.len()));
            }
            if y == 1 {
                buf.push_str(&format!(" age: {}", self.age));
            }
            buf.push('\n');
        }
        for x in 0..self.width + 2 {
            buf.push(if x == 0 { '└' } else if x == self.width + 1 { '┘' } else { '─' });
        }
        write!(f, "{}", buf)
    }
}
<|endoftext|>


<commit_before>//! Winit allows you to build a window on as many platforms as possible.
//!
//! # Building a window
//!
//! Before you can build a window, you first need to build an `EventsLoop`. This is done with the
//! `EventsLoop::new()` function. Example:
//!
//! ```no_run
//! use winit::EventsLoop;
//! let events_loop = EventsLoop::new();
//! ```
//!
//! Once this is done there are two ways to create a window:
//!
//!  - Calling `Window::new(&events_loop)`.
//!  - Calling `let builder = WindowBuilder::new()` then `builder.build(&events_loop)`.
//!
//! The first way is the simpliest way and will give you default values for everything.
//!
//! The second way allows you to customize the way your window will look and behave by modifying
//! the fields of the `WindowBuilder` object before you create the window.
//!
//! # Events handling
//!
//! Once a window has been created, it will *generate events*. For example whenever the user moves
//! the window, resizes the window, moves the mouse, etc. an event is generated.
//!
//! The events generated by a window can be retreived from the `EventsLoop` the window was created
//! with.
//!
//! There are two ways to do so. The first is to call `events_loop.poll_events(...)`, which will
//! retreive all the events pending on the windows and immediately return after no new event is
//! available. You usually want to use this method in application that render continuously on the
//! screen, such as video games.
//!
//! ```no_run
//! use winit::Event;
//! use winit::WindowEvent;
//! # use winit::EventsLoop;
//! # let events_loop = EventsLoop::new();
//!
//! loop {
//!     events_loop.poll_events(|event| {
//!         match event {
//!             Event::WindowEvent { event: WindowEvent::Resized(w, h), .. } => {
//!                 println!("The window was resized to {}x{}", w, h);
//!             },
//!             _ => ()
//!         }
//!     });
//! }
//! ```
//!
//! The second way is to call `events_loop.run_forever(...)`. As its name tells, it will run
//! forever unless it is stopped by calling `events_loop.interrupt()`.
//!
//! ```no_run
//! use winit::Event;
//! use winit::WindowEvent;
//! # use winit::EventsLoop;
//! # let events_loop = EventsLoop::new();
//!
//! events_loop.run_forever(|event| {
//!     match event {
//!         Event::WindowEvent { event: WindowEvent::Closed, .. } => {
//!             println!("The window was closed ; stopping");
//!             events_loop.interrupt();
//!         },
//!         _ => ()
//!     }
//! });
//! ```
//!
//! If you use multiple windows, the `WindowEvent` event has a member named `window_id`. You can
//! compare it with the value returned by the `id()` method of `Window` in order to know which
//! window has received the event.
//!
//! # Drawing on the window
//!
//! Winit doesn't provide any function that allows drawing on a window. However it allows you to
//! retreive the raw handle of the window (see the `os` module for that), which in turn allows you
//! to create an OpenGL/Vulkan/DirectX/Metal/etc. context that will draw on the window.
//!

#[macro_use]
extern crate lazy_static;

#[macro_use]
extern crate shared_library;

extern crate libc;

#[cfg(target_os = "windows")]
extern crate winapi;
#[cfg(target_os = "windows")]
extern crate kernel32;
#[cfg(target_os = "windows")]
extern crate shell32;
#[cfg(target_os = "windows")]
extern crate gdi32;
#[cfg(target_os = "windows")]
extern crate user32;
#[cfg(target_os = "windows")]
extern crate dwmapi;
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[macro_use]
extern crate objc;
#[cfg(target_os = "macos")]
extern crate cgl;
#[cfg(target_os = "macos")]
extern crate cocoa;
#[cfg(target_os = "macos")]
extern crate core_foundation;
#[cfg(target_os = "macos")]
extern crate core_graphics;
#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
extern crate x11_dl;
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))]
#[macro_use(wayland_env,declare_handler)]
extern crate wayland_client;

use std::sync::Arc;

pub use events::*;
pub use window::{WindowProxy, PollEventsIterator, WaitEventsIterator};
pub use window::{AvailableMonitorsIter, MonitorId, get_available_monitors, get_primary_monitor};
pub use native_monitor::NativeMonitorId;

#[macro_use]
mod api_transition;

mod api;
mod platform;
mod events;
mod window;

pub mod os;

/// Represents a window.
///
/// # Example
///
/// ```no_run
/// use winit::Event;
/// use winit::EventsLoop;
/// use winit::Window;
/// use winit::WindowEvent;
///
/// let events_loop = EventsLoop::new();
/// let window = Window::new(&events_loop).unwrap();
///
/// events_loop.run_forever(|event| {
///     match event {
///         Event::WindowEvent { event: WindowEvent::Closed, .. } => {
///             events_loop.interrupt();
///         },
///         _ => ()
///     }
/// });
/// ```
pub struct Window {
    window: platform::Window2,
}

/// Provides a way to retreive events from the windows that were registered to it.
// TODO: document usage in multiple threads
pub struct EventsLoop {
    events_loop: Arc<platform::EventsLoop>,
}

impl EventsLoop {
    /// Builds a new events loop.
    pub fn new() -> EventsLoop {
        EventsLoop {
            events_loop: Arc::new(platform::EventsLoop::new()),
        }
    }

    /// Fetches all the events that are pending, calls the callback function for each of them,
    /// and returns.
    #[inline]
    pub fn poll_events<F>(&self, callback: F)
        where F: FnMut(Event)
    {
        self.events_loop.poll_events(callback)
    }

    /// Runs forever until `interrupt()` is called. Whenever an event happens, calls the callback.
    #[inline]
    pub fn run_forever<F>(&self, callback: F)
        where F: FnMut(Event)
    {
        self.events_loop.run_forever(callback)
    }

    /// If we called `run_forever()`, stops the process of waiting for events.
    // TODO: what if we're waiting from multiple threads?
    #[inline]
    pub fn interrupt(&self) {
        self.events_loop.interrupt()
    }
}

/// Object that allows you to build windows.
#[derive(Clone)]
pub struct WindowBuilder {
    /// The attributes to use to create the window.
    pub window: WindowAttributes,

    // Platform-specific configuration. Private.
    platform_specific: platform::PlatformSpecificWindowBuilderAttributes,
}

/// Error that can happen while creating a window or a headless renderer.
#[derive(Debug)]
pub enum CreationError {
    OsError(String),
    /// TODO: remove this error
    NotSupported,
}

impl CreationError {
    fn to_string(&self) -> &str {
        match *self {
            CreationError::OsError(ref text) => &text,
            CreationError::NotSupported => "Some of the requested attributes are not supported",
        }
    }
}

impl std::fmt::Display for CreationError {
    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        formatter.write_str(self.to_string())
    }
}

impl std::error::Error for CreationError {
    fn description(&self) -> &str {
        self.to_string()
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum MouseCursor {
    /// The platform-dependent default cursor.
    Default,
    /// A simple crosshair.
    Crosshair,
    /// A hand (often used to indicate links in web browsers).
    Hand,
    /// Self explanatory.
    Arrow,
    /// Indicates something is to be moved.
    Move,
    /// Indicates text that may be selected or edited.
    Text,
    /// Program busy indicator.
    Wait,
    /// Help indicator (often rendered as a "?")
    Help,
    /// Progress indicator. Shows that processing is being done. But in contrast
    /// with "Wait" the user may still interact with the program. Often rendered
    /// as a spinning beach ball, or an arrow with a watch or hourglass.
    Progress,

    /// Cursor showing that something cannot be done.
    NotAllowed,
    ContextMenu,
    NoneCursor,
    Cell,
    VerticalText,
    Alias,
    Copy,
    NoDrop,
    Grab,
    Grabbing,
    AllScroll,
    ZoomIn,
    ZoomOut,

    /// Indicate that some edge is to be moved. For example, the 'SeResize' cursor
    /// is used when the movement starts from the south-east corner of the box.
    EResize,
    NResize,
    NeResize,
    NwResize,
    SResize,
    SeResize,
    SwResize,
    WResize,
    EwResize,
    NsResize,
    NeswResize,
    NwseResize,
    ColResize,
    RowResize,
}

/// Describes how glutin handles the cursor.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum CursorState {
    /// Normal cursor behavior.
    Normal,

    /// The cursor will be invisible when over the window.
    Hide,

    /// Grabs the mouse cursor. The cursor's motion will be confined to this
    /// window and the window has exclusive access to further events regarding
    /// the cursor.
    ///
    /// This is useful for first-person cameras for example.
    Grab,
}

/// Attributes to use when creating a window.
#[derive(Clone)]
pub struct WindowAttributes {
    /// The dimensions of the window. If this is `None`, some platform-specific dimensions will be
    /// used.
    ///
    /// The default is `None`.
    pub dimensions: Option<(u32, u32)>,

    /// The minimum dimensions a window can be, If this is `None`, the window will have no minimum dimensions (aside from reserved).
    ///
    /// The default is `None`.
    pub min_dimensions: Option<(u32, u32)>,

    /// The maximum dimensions a window can be, If this is `None`, the maximum will have no maximum or will be set to the primary monitor's dimensions by the platform.
    ///
    /// The default is `None`.
    pub max_dimensions: Option<(u32, u32)>,

    /// If `Some`, the window will be in fullscreen mode with the given monitor.
    ///
    /// The default is `None`.
    pub monitor: Option<platform::MonitorId>,

    /// The title of the window in the title bar.
    ///
    /// The default is `"glutin window"`.
    pub title: String,

    /// Whether the window should be immediately visible upon creation.
    ///
    /// The default is `true`.
    pub visible: bool,

    /// Whether the the window should be transparent. If this is true, writing colors
    /// with alpha values different than `1.0` will produce a transparent window.
    ///
    /// The default is `false`.
    pub transparent: bool,

    /// Whether the window should have borders and bars.
    ///
    /// The default is `true`.
    pub decorations: bool,

    /// [iOS only] Enable multitouch, see [UIView#multipleTouchEnabled]
    /// (https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/occ/instp/UIView/multipleTouchEnabled)
    pub multitouch: bool,

    /// A function called upon resizing, necessary to receive resize events on Mac and possibly
    /// other systems.
    pub resize_callback: Option<fn(u32, u32)>,
}

impl Default for WindowAttributes {
    #[inline]
    fn default() -> WindowAttributes {
        WindowAttributes {
            dimensions: None,
            min_dimensions: None,
            max_dimensions: None,
            monitor: None,
            title: "glutin window".to_owned(),
            visible: true,
            transparent: false,
            decorations: true,
            multitouch: false,
            resize_callback: None,
        }
    }
}

mod native_monitor {
    /// Native platform identifier for a monitor. Different platforms use fundamentally different types
    /// to represent a monitor ID.
    #[derive(Clone, PartialEq, Eq)]
    pub enum NativeMonitorId {
        /// Cocoa and X11 use a numeric identifier to represent a monitor.
        Numeric(u32),

        /// Win32 uses a Unicode string to represent a monitor.
        Name(String),

        /// Other platforms (Android) don't support monitor identification.
        Unavailable
    }
}
<commit_msg>Remove resize_callback from WindowsAttributes<commit_after>//! Winit allows you to build a window on as many platforms as possible.
//!
//! # Building a window
//!
//! Before you can build a window, you first need to build an `EventsLoop`. This is done with the
//! `EventsLoop::new()` function. Example:
//!
//! ```no_run
//! use winit::EventsLoop;
//! let events_loop = EventsLoop::new();
//! ```
//!
//! Once this is done there are two ways to create a window:
//!
//!  - Calling `Window::new(&events_loop)`.
//!  - Calling `let builder = WindowBuilder::new()` then `builder.build(&events_loop)`.
//!
//! The first way is the simpliest way and will give you default values for everything.
//!
//! The second way allows you to customize the way your window will look and behave by modifying
//! the fields of the `WindowBuilder` object before you create the window.
//!
//! # Events handling
//!
//! Once a window has been created, it will *generate events*. For example whenever the user moves
//! the window, resizes the window, moves the mouse, etc. an event is generated.
//!
//! The events generated by a window can be retreived from the `EventsLoop` the window was created
//! with.
//!
//! There are two ways to do so. The first is to call `events_loop.poll_events(...)`, which will
//! retreive all the events pending on the windows and immediately return after no new event is
//! available. You usually want to use this method in application that render continuously on the
//! screen, such as video games.
//!
//! ```no_run
//! use winit::Event;
//! use winit::WindowEvent;
//! # use winit::EventsLoop;
//! # let events_loop = EventsLoop::new();
//!
//! loop {
//!     events_loop.poll_events(|event| {
//!         match event {
//!             Event::WindowEvent { event: WindowEvent::Resized(w, h), .. } => {
//!                 println!("The window was resized to {}x{}", w, h);
//!             },
//!             _ => ()
//!         }
//!     });
//! }
//! ```
//!
//! The second way is to call `events_loop.run_forever(...)`. As its name tells, it will run
//! forever unless it is stopped by calling `events_loop.interrupt()`.
//!
//! ```no_run
//! use winit::Event;
//! use winit::WindowEvent;
//! # use winit::EventsLoop;
//! # let events_loop = EventsLoop::new();
//!
//! events_loop.run_forever(|event| {
//!     match event {
//!         Event::WindowEvent { event: WindowEvent::Closed, .. } => {
//!             println!("The window was closed ; stopping");
//!             events_loop.interrupt();
//!         },
//!         _ => ()
//!     }
//! });
//! ```
//!
//! If you use multiple windows, the `WindowEvent` event has a member named `window_id`. You can
//! compare it with the value returned by the `id()` method of `Window` in order to know which
//! window has received the event.
//!
//! # Drawing on the window
//!
//! Winit doesn't provide any function that allows drawing on a window. However it allows you to
//! retreive the raw handle of the window (see the `os` module for that), which in turn allows you
//! to create an OpenGL/Vulkan/DirectX/Metal/etc. context that will draw on the window.
//!

#[macro_use]
extern crate lazy_static;

#[macro_use]
extern crate shared_library;

extern crate libc;

#[cfg(target_os = "windows")]
extern crate winapi;
#[cfg(target_os = "windows")]
extern crate kernel32;
#[cfg(target_os = "windows")]
extern crate shell32;
#[cfg(target_os = "windows")]
extern crate gdi32;
#[cfg(target_os = "windows")]
extern crate user32;
#[cfg(target_os = "windows")]
extern crate dwmapi;
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[macro_use]
extern crate objc;
#[cfg(target_os = "macos")]
extern crate cgl;
#[cfg(target_os = "macos")]
extern crate cocoa;
#[cfg(target_os = "macos")]
extern crate core_foundation;
#[cfg(target_os = "macos")]
extern crate core_graphics;
#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
extern crate x11_dl;
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))]
#[macro_use(wayland_env,declare_handler)]
extern crate wayland_client;

use std::sync::Arc;

pub use events::*;
pub use window::{WindowProxy, PollEventsIterator, WaitEventsIterator};
pub use window::{AvailableMonitorsIter, MonitorId, get_available_monitors, get_primary_monitor};
pub use native_monitor::NativeMonitorId;

#[macro_use]
mod api_transition;

mod api;
mod platform;
mod events;
mod window;

pub mod os;

/// Represents a window.
///
/// # Example
///
/// ```no_run
/// use winit::Event;
/// use winit::EventsLoop;
/// use winit::Window;
/// use winit::WindowEvent;
///
/// let events_loop = EventsLoop::new();
/// let window = Window::new(&events_loop).unwrap();
///
/// events_loop.run_forever(|event| {
///     match event {
///         Event::WindowEvent { event: WindowEvent::Closed, .. } => {
///             events_loop.interrupt();
///         },
///         _ => ()
///     }
/// });
/// ```
pub struct Window {
    window: platform::Window2,
}

/// Provides a way to retreive events from the windows that were registered to it.
// TODO: document usage in multiple threads
pub struct EventsLoop {
    events_loop: Arc<platform::EventsLoop>,
}

impl EventsLoop {
    /// Builds a new events loop.
    pub fn new() -> EventsLoop {
        EventsLoop {
            events_loop: Arc::new(platform::EventsLoop::new()),
        }
    }

    /// Fetches all the events that are pending, calls the callback function for each of them,
    /// and returns.
    #[inline]
    pub fn poll_events<F>(&self, callback: F)
        where F: FnMut(Event)
    {
        self.events_loop.poll_events(callback)
    }

    /// Runs forever until `interrupt()` is called. Whenever an event happens, calls the callback.
    #[inline]
    pub fn run_forever<F>(&self, callback: F)
        where F: FnMut(Event)
    {
        self.events_loop.run_forever(callback)
    }

    /// If we called `run_forever()`, stops the process of waiting for events.
    // TODO: what if we're waiting from multiple threads?
    #[inline]
    pub fn interrupt(&self) {
        self.events_loop.interrupt()
    }
}

/// Object that allows you to build windows.
#[derive(Clone)]
pub struct WindowBuilder {
    /// The attributes to use to create the window.
    pub window: WindowAttributes,

    // Platform-specific configuration. Private.
    platform_specific: platform::PlatformSpecificWindowBuilderAttributes,
}

/// Error that can happen while creating a window or a headless renderer.
#[derive(Debug)]
pub enum CreationError {
    OsError(String),
    /// TODO: remove this error
    NotSupported,
}

impl CreationError {
    fn to_string(&self) -> &str {
        match *self {
            CreationError::OsError(ref text) => &text,
            CreationError::NotSupported => "Some of the requested attributes are not supported",
        }
    }
}

impl std::fmt::Display for CreationError {
    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        formatter.write_str(self.to_string())
    }
}

impl std::error::Error for CreationError {
    fn description(&self) -> &str {
        self.to_string()
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum MouseCursor {
    /// The platform-dependent default cursor.
    Default,
    /// A simple crosshair.
    Crosshair,
    /// A hand (often used to indicate links in web browsers).
    Hand,
    /// Self explanatory.
    Arrow,
    /// Indicates something is to be moved.
    Move,
    /// Indicates text that may be selected or edited.
    Text,
    /// Program busy indicator.
    Wait,
    /// Help indicator (often rendered as a "?")
    Help,
    /// Progress indicator. Shows that processing is being done. But in contrast
    /// with "Wait" the user may still interact with the program. Often rendered
    /// as a spinning beach ball, or an arrow with a watch or hourglass.
    Progress,

    /// Cursor showing that something cannot be done.
    NotAllowed,
    ContextMenu,
    NoneCursor,
    Cell,
    VerticalText,
    Alias,
    Copy,
    NoDrop,
    Grab,
    Grabbing,
    AllScroll,
    ZoomIn,
    ZoomOut,

    /// Indicate that some edge is to be moved. For example, the 'SeResize' cursor
    /// is used when the movement starts from the south-east corner of the box.
    EResize,
    NResize,
    NeResize,
    NwResize,
    SResize,
    SeResize,
    SwResize,
    WResize,
    EwResize,
    NsResize,
    NeswResize,
    NwseResize,
    ColResize,
    RowResize,
}

/// Describes how glutin handles the cursor.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum CursorState {
    /// Normal cursor behavior.
    Normal,

    /// The cursor will be invisible when over the window.
    Hide,

    /// Grabs the mouse cursor. The cursor's motion will be confined to this
    /// window and the window has exclusive access to further events regarding
    /// the cursor.
    ///
    /// This is useful for first-person cameras for example.
    Grab,
}

/// Attributes to use when creating a window.
#[derive(Clone)]
pub struct WindowAttributes {
    /// The dimensions of the window. If this is `None`, some platform-specific dimensions will be
    /// used.
    ///
    /// The default is `None`.
    pub dimensions: Option<(u32, u32)>,

    /// The minimum dimensions a window can be, If this is `None`, the window will have no minimum dimensions (aside from reserved).
    ///
    /// The default is `None`.
    pub min_dimensions: Option<(u32, u32)>,

    /// The maximum dimensions a window can be, If this is `None`, the maximum will have no maximum or will be set to the primary monitor's dimensions by the platform.
    ///
    /// The default is `None`.
    pub max_dimensions: Option<(u32, u32)>,

    /// If `Some`, the window will be in fullscreen mode with the given monitor.
    ///
    /// The default is `None`.
    pub monitor: Option<platform::MonitorId>,

    /// The title of the window in the title bar.
    ///
    /// The default is `"glutin window"`.
    pub title: String,

    /// Whether the window should be immediately visible upon creation.
    ///
    /// The default is `true`.
    pub visible: bool,

    /// Whether the the window should be transparent. If this is true, writing colors
    /// with alpha values different than `1.0` will produce a transparent window.
    ///
    /// The default is `false`.
    pub transparent: bool,

    /// Whether the window should have borders and bars.
    ///
    /// The default is `true`.
    pub decorations: bool,

    /// [iOS only] Enable multitouch, see [UIView#multipleTouchEnabled]
    /// (https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/occ/instp/UIView/multipleTouchEnabled)
    pub multitouch: bool,
}

impl Default for WindowAttributes {
    #[inline]
    fn default() -> WindowAttributes {
        WindowAttributes {
            dimensions: None,
            min_dimensions: None,
            max_dimensions: None,
            monitor: None,
            title: "glutin window".to_owned(),
            visible: true,
            transparent: false,
            decorations: true,
            multitouch: false,
        }
    }
}

mod native_monitor {
    /// Native platform identifier for a monitor. Different platforms use fundamentally different types
    /// to represent a monitor ID.
    #[derive(Clone, PartialEq, Eq)]
    pub enum NativeMonitorId {
        /// Cocoa and X11 use a numeric identifier to represent a monitor.
        Numeric(u32),

        /// Win32 uses a Unicode string to represent a monitor.
        Name(String),

        /// Other platforms (Android) don't support monitor identification.
        Unavailable
    }
}
<|endoftext|>


<commit_before>///! Cell grid utilities
use crate::space::Space;
use euclid::vec2;

/// Space for a cell grid. Used for both square and hex tile maps.
///
/// When used for hex maps, `CellSpace` is still a regular euclidean space and does not use axis
/// staggering. Squares in `CellSpace` coordinates are distorted into lozenges when displayed as a
/// hex map. For a flat-top hex map, the convention is that the positive x-axis points to the
/// 4-o'clock (southeast) neighbor hex and the positive y-axis points to the 8-o'clock (southwest)
/// neighbor hex. For a pointy-top hex map, x-axis points to the 3-o'clock (east) neighbor hex and
/// y-axis points to the 7-o'clock (southwest) neighbor hex.
pub struct CellSpace;

impl Space for CellSpace {
    type T = i32;
}

pub type CellVector = euclid::Vector2D<i32, CellSpace>;

/// User data for field of view cells.
pub trait FovValue: PartialEq + Clone {
    /// Construct a new FovValue for a position based on the previous one along the line of sight.
    fn advance(&self, offset: CellVector) -> Option<Self>;
}

/// Point in FOV arc polar coordinates for the desired geometry.
pub trait PolarPoint: Sized + Clone {
    /// Create the beginning and end points for radius 1 unit circle.
    ///
    /// These are the initial cells checked by the FOV algorithm.
    fn unit_circle_endpoints() -> (Self, Self);

    /// Return whether this point is earlier in the circle than the other.
    fn is_below(&self, other: &Self) -> bool;

    /// Return the vector offset for this point.
    fn to_v2(&self) -> CellVector;

    /// Return the point corresponding to this one on the next circle with +1 radius.
    fn expand(&self) -> Self;

    /// Step forward on the current radius.
    fn advance(&mut self);
}

/// Field of view iterator.
pub struct Fov<P, T> {
    stack: Vec<Arc<P, T>>,
    /// Extra values generated by special cases.
    side_channel: Vec<(CellVector, T)>,
}

impl<P: PolarPoint, T: FovValue> Fov<P, T> {
    /// Create a new field of view iterator with a seed userdata for the origin position.
    pub fn new(init: T) -> Fov<P, T> {
        // We could run f for (0, 0) here, but the traditional way for the FOV to work is to only
        // consider your surroundings, not the origin site itself.
        Fov {
            stack: vec![Arc::new(init.clone())],
            // The FOV algorithm will not generate the origin point, so we use
            // the side channel to explicitly add it in the beginning.
            side_channel: vec![(vec2(0, 0), init)],
        }
    }
}

impl<P: PolarPoint, T: FovValue> Iterator for Fov<P, T> {
    type Item = (CellVector, T);
    fn next(&mut self) -> Option<(CellVector, T)> {
        // Empty the side channel before proceeding to the algorithm proper.
        if let Some(ret) = self.side_channel.pop() {
            return Some(ret);
        }

        // Start processing the next arc in the stack.
        if let Some(current) = self.stack.pop() {
            if current.arc_has_split(&mut self.stack) {
                return self.next();
            }

            debug_assert!(current.group_value == current.prev_value.advance(current.pt.to_v2()));

            let pos = current.pt.to_v2();
            let ret = current.group_value.clone();

            current.advance(&mut self.stack);

            if let Some(ret) = ret {
                Some((pos, ret))
            } else {
                self.next()
            }
        } else {
            None
        }
    }
}

struct Arc<P, T> {
    /// Start point of current arc.
    begin: P,
    /// Point currently being processed.
    pt: P,
    /// End point of current arc.
    end: P,
    /// The user value from previous iteration.
    prev_value: T,
    /// The user value for this group.
    group_value: Option<T>,
}

impl<P: PolarPoint, T: FovValue> Arc<P, T> {
    pub fn new(init: T) -> Arc<P, T> {
        let (begin, end) = P::unit_circle_endpoints();
        Self::expand(begin, end, init)
    }

    fn expand(begin: P, end: P, prev_value: T) -> Arc<P, T> {
        let group_value = prev_value.advance(begin.to_v2());
        Arc {
            begin: begin.clone(),
            pt: begin,
            end,
            prev_value,
            group_value,
        }
    }

    /// Consume the given arc and add its descendent, if any, to the stack.
    pub fn advance(mut self, stack: &mut Vec<Arc<P, T>>) {
        self.pt.advance();
        if self.pt.is_below(&self.end) {
            stack.push(self);
        } else if let Some(group_value) = self.group_value {
            stack.push(Arc::expand(
                self.begin.expand(),
                self.end.expand(),
                group_value,
            ));
        }
    }

    /// If the arc has advanced into a different value group, split it into the given stack.
    ///
    /// Return true if arc was split, false otherwise.
    pub fn arc_has_split(&self, stack: &mut Vec<Arc<P, T>>) -> bool {
        let next_value = self.prev_value.advance(self.pt.to_v2());
        if next_value != self.group_value {
            // Using the literal instead of the constructor to avoid recomputing next_value.
            stack.push(Arc {
                begin: self.pt.clone(),
                pt: self.pt.clone(),
                end: self.end.clone(),
                prev_value: self.prev_value.clone(),
                group_value: next_value,
            });

            // Extend current arc if it has a group value.
            if let Some(ref group_value) = self.group_value {
                stack.push(Arc::expand(
                    self.begin.expand(),
                    self.pt.expand(),
                    group_value.clone(),
                ));
            }

            true
        } else {
            false
        }
    }
}
<commit_msg>Rename Arc to FovArc to prevent confusion with sync::Arc<commit_after>///! Cell grid utilities
use crate::space::Space;
use euclid::vec2;

/// Space for a cell grid. Used for both square and hex tile maps.
///
/// When used for hex maps, `CellSpace` is still a regular euclidean space and does not use axis
/// staggering. Squares in `CellSpace` coordinates are distorted into lozenges when displayed as a
/// hex map. For a flat-top hex map, the convention is that the positive x-axis points to the
/// 4-o'clock (southeast) neighbor hex and the positive y-axis points to the 8-o'clock (southwest)
/// neighbor hex. For a pointy-top hex map, x-axis points to the 3-o'clock (east) neighbor hex and
/// y-axis points to the 7-o'clock (southwest) neighbor hex.
pub struct CellSpace;

impl Space for CellSpace {
    type T = i32;
}

pub type CellVector = euclid::Vector2D<i32, CellSpace>;

/// User data for field of view cells.
pub trait FovValue: PartialEq + Clone {
    /// Construct a new FovValue for a position based on the previous one along the line of sight.
    fn advance(&self, offset: CellVector) -> Option<Self>;
}

/// Point in FOV arc polar coordinates for the desired geometry.
pub trait PolarPoint: Sized + Clone {
    /// Create the beginning and end points for radius 1 unit circle.
    ///
    /// These are the initial cells checked by the FOV algorithm.
    fn unit_circle_endpoints() -> (Self, Self);

    /// Return whether this point is earlier in the circle than the other.
    fn is_below(&self, other: &Self) -> bool;

    /// Return the vector offset for this point.
    fn to_v2(&self) -> CellVector;

    /// Return the point corresponding to this one on the next circle with +1 radius.
    fn expand(&self) -> Self;

    /// Step forward on the current radius.
    fn advance(&mut self);
}

/// Field of view iterator.
pub struct Fov<P, T> {
    stack: Vec<FovArc<P, T>>,
    /// Extra values generated by special cases.
    side_channel: Vec<(CellVector, T)>,
}

impl<P: PolarPoint, T: FovValue> Fov<P, T> {
    /// Create a new field of view iterator with a seed userdata for the origin position.
    pub fn new(init: T) -> Fov<P, T> {
        // We could run f for (0, 0) here, but the traditional way for the FOV to work is to only
        // consider your surroundings, not the origin site itself.
        Fov {
            stack: vec![FovArc::new(init.clone())],
            // The FOV algorithm will not generate the origin point, so we use
            // the side channel to explicitly add it in the beginning.
            side_channel: vec![(vec2(0, 0), init)],
        }
    }
}

impl<P: PolarPoint, T: FovValue> Iterator for Fov<P, T> {
    type Item = (CellVector, T);
    fn next(&mut self) -> Option<(CellVector, T)> {
        // Empty the side channel before proceeding to the algorithm proper.
        if let Some(ret) = self.side_channel.pop() {
            return Some(ret);
        }

        // Start processing the next arc in the stack.
        if let Some(current) = self.stack.pop() {
            if current.arc_has_split(&mut self.stack) {
                return self.next();
            }

            debug_assert!(current.group_value == current.prev_value.advance(current.pt.to_v2()));

            let pos = current.pt.to_v2();
            let ret = current.group_value.clone();

            current.advance(&mut self.stack);

            if let Some(ret) = ret {
                Some((pos, ret))
            } else {
                self.next()
            }
        } else {
            None
        }
    }
}

struct FovArc<P, T> {
    /// Start point of current arc.
    begin: P,
    /// Point currently being processed.
    pt: P,
    /// End point of current arc.
    end: P,
    /// The user value from previous iteration.
    prev_value: T,
    /// The user value for this group.
    group_value: Option<T>,
}

impl<P: PolarPoint, T: FovValue> FovArc<P, T> {
    pub fn new(init: T) -> FovArc<P, T> {
        let (begin, end) = P::unit_circle_endpoints();
        Self::expand(begin, end, init)
    }

    fn expand(begin: P, end: P, prev_value: T) -> FovArc<P, T> {
        let group_value = prev_value.advance(begin.to_v2());
        FovArc {
            begin: begin.clone(),
            pt: begin,
            end,
            prev_value,
            group_value,
        }
    }

    /// Consume the given arc and add its descendant, if any, to the stack.
    pub fn advance(mut self, stack: &mut Vec<FovArc<P, T>>) {
        self.pt.advance();
        if self.pt.is_below(&self.end) {
            stack.push(self);
        } else if let Some(group_value) = self.group_value {
            stack.push(FovArc::expand(
                self.begin.expand(),
                self.end.expand(),
                group_value,
            ));
        }
    }

    /// If the arc has advanced into a different value group, split it into the given stack.
    ///
    /// Return true if arc was split, false otherwise.
    pub fn arc_has_split(&self, stack: &mut Vec<FovArc<P, T>>) -> bool {
        let next_value = self.prev_value.advance(self.pt.to_v2());
        if next_value != self.group_value {
            // Using the literal instead of the constructor to avoid recomputing next_value.
            stack.push(FovArc {
                begin: self.pt.clone(),
                pt: self.pt.clone(),
                end: self.end.clone(),
                prev_value: self.prev_value.clone(),
                group_value: next_value,
            });

            // Extend current arc if it has a group value.
            if let Some(ref group_value) = self.group_value {
                stack.push(FovArc::expand(
                    self.begin.expand(),
                    self.pt.expand(),
                    group_value.clone(),
                ));
            }

            true
        } else {
            false
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! # Cap'n Proto Runtime Library
//!
//! This crate contains basic facilities for reading and writing
//! [Cap'n Proto](https://capnproto.org) messages in Rust. It is intended to
//! be used in conjunction with code generated by the
//! [capnpc-rust](https://github.com/capnproto/capnproto-rust/capnpc) crate.
#![cfg_attr(feature = "rpc_try", feature(try_trait))]

#[cfg(any(feature="quickcheck", test))]
extern crate quickcheck;

pub mod any_pointer;
pub mod any_pointer_list;
pub mod capability;
pub mod capability_list;
pub mod constant;
pub mod data;
pub mod data_list;
pub mod enum_list;
pub mod list_list;
pub mod message;
pub mod primitive_list;
pub mod private;
pub mod raw;
pub mod serialize;
pub mod serialize_packed;
pub mod struct_list;
pub mod text;
pub mod text_list;
pub mod traits;

/// Eight bytes of memory with opaque interior.
///
/// This type is used to ensure that the data of a message is properly aligned.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(C, align(8))]
pub struct Word {
    raw_content: [u8; 8],
}

///
/// Constructs a word with the given bytes.
///
pub const fn word(b0: u8, b1: u8, b2: u8, b3: u8, b4: u8, b5: u8, b6: u8, b7: u8) -> Word {
    Word { raw_content: [b0,b1,b2,b3,b4,b5,b6,b7] }
}

impl Word {
    /// Does this, but faster:
    /// `::std::iter::repeat(Word(0)).take(length).collect()`
    pub fn allocate_zeroed_vec(length: usize) -> Vec<Word> {
        let mut result : Vec<Word> = Vec::with_capacity(length);
        unsafe {
            result.set_len(length);
            let p : *mut u8 = result.as_mut_ptr() as *mut u8;
            ::std::ptr::write_bytes(p, 0u8, length * ::std::mem::size_of::<Word>());
        }
        result
    }

    /// Converts a byte slice into a `Word` slice. Unsafe due to possible alignment issues.
    /// Only call this if you know that `bytes.to_ptr()` falls on an eight-byte boundary.
    pub unsafe fn bytes_to_words<'a>(bytes: &'a [u8]) -> &'a [Word] {
        ::std::slice::from_raw_parts(bytes.as_ptr() as *const Word, bytes.len() / 8)
    }

    /// Converts a mutable byte slice into a mutable `Word` slice. Unsafe due to possible
    /// alignment issues. Only call this if you know that `bytes.to_ptr()` falls on an eight-byte
    /// boundary.
    pub unsafe fn bytes_to_words_mut<'a>(bytes: &'a mut [u8]) -> &'a mut [Word] {
        ::std::slice::from_raw_parts_mut(bytes.as_ptr() as *mut Word, bytes.len() / 8)
    }

    pub fn words_to_bytes<'a>(words: &'a [Word]) -> &'a [u8] {
        unsafe {
            ::std::slice::from_raw_parts(words.as_ptr() as *const u8, words.len() * 8)
        }
    }

    pub fn words_to_bytes_mut<'a>(words: &'a mut [Word]) -> &'a mut [u8] {
        unsafe {
            ::std::slice::from_raw_parts_mut(words.as_mut_ptr() as *mut u8, words.len() * 8)
        }
    }
}

#[cfg(any(feature="quickcheck", test))]
impl quickcheck::Arbitrary for Word {
    fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Word {
        crate::word(quickcheck::Arbitrary::arbitrary(g),
               quickcheck::Arbitrary::arbitrary(g),
               quickcheck::Arbitrary::arbitrary(g),
               quickcheck::Arbitrary::arbitrary(g),
               quickcheck::Arbitrary::arbitrary(g),
               quickcheck::Arbitrary::arbitrary(g),
               quickcheck::Arbitrary::arbitrary(g),
               quickcheck::Arbitrary::arbitrary(g))
    }
}

/// Size of a message. Every generated struct has a method `.total_size()` that returns this.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct MessageSize {
    pub word_count: u64,

    /// Size of the capability table.
    pub cap_count: u32
}

impl MessageSize {
    pub fn plus_eq(&mut self, other : MessageSize) {
        self.word_count += other.word_count;
        self.cap_count += other.cap_count;
    }
}

/// An enum value or union discriminant that was not found among those defined in a schema.
#[derive(PartialEq, Clone, Copy, Debug)]
pub struct NotInSchema(pub u16);

impl ::std::fmt::Display for NotInSchema {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
        write!(fmt, "Enum value or union discriminant {} was not present in the schema.", self.0)
    }
}

impl ::std::error::Error for NotInSchema {
    fn description<'a>(&'a self) -> &'a str {
        "Enum value or union discriminant was not present in schema."
    }
}

/// Because messages are lazily validated, the return type of any method that reads a pointer field
/// must be wrapped in a Result.
pub type Result<T> = ::std::result::Result<T, Error>;

/// Describes an arbitrary error that prevented an operation from completing.
#[derive(Debug, Clone)]
pub struct Error {
    /// The general kind of the error. Code that decides how to respond to an error
    /// should read only this field in making its decision.
    pub kind: ErrorKind,

    /// Human-readable failure description.
    pub description: String,
}

/// The general nature of an error. The purpose of this enum is not to describe the error itself,
/// but rather to describe how the client might want to respond to the error.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ErrorKind {
    /// Something went wrong. This is the usual error kind. It includes decoding errors.
    Failed,

    /// The call failed because of a temporary lack of resources. This could be space resources
    /// (out of memory, out of disk space) or time resources (request queue overflow, operation
    /// timed out).
    ///
    /// The operation might work if tried again, but it should NOT be repeated immediately as this
    /// may simply exacerbate the problem.
    Overloaded,

    /// The call required communication over a connection that has been lost. The callee will need
    /// to re-establish connections and try again.
    Disconnected,

    /// The requested method is not implemented. The caller may wish to revert to a fallback
    /// approach based on other methods.
    Unimplemented,
}

impl Error {
    pub fn failed(description: String) -> Error {
        Error { description: description, kind: ErrorKind::Failed }
    }
    pub fn overloaded(description: String) -> Error {
        Error { description: description, kind: ErrorKind::Overloaded }
    }
    pub fn disconnected(description: String) -> Error {
        Error { description: description, kind: ErrorKind::Disconnected }
    }
    pub fn unimplemented(description: String) -> Error {
        Error { description: description, kind: ErrorKind::Unimplemented }
    }
}

impl ::std::convert::From<::std::io::Error> for Error {
    fn from(err: ::std::io::Error) -> Error {
        use std::io;
        let kind = match err.kind() {
            io::ErrorKind::TimedOut => ErrorKind::Overloaded,
            io::ErrorKind::BrokenPipe |
            io::ErrorKind::ConnectionRefused |
            io::ErrorKind::ConnectionReset |
            io::ErrorKind::ConnectionAborted |
            io::ErrorKind::NotConnected  => ErrorKind::Disconnected,
            _ => ErrorKind::Failed,
        };
        Error { description: format!("{}", err), kind: kind }
    }
}

impl ::std::convert::From<::std::string::FromUtf8Error> for Error {
    fn from(err: ::std::string::FromUtf8Error) -> Error {
        Error::failed(format!("{}", err))
    }
}

impl ::std::convert::From<::std::str::Utf8Error> for Error {
    fn from(err: ::std::str::Utf8Error) -> Error {
        Error::failed(format!("{}", err))
    }
}

impl ::std::convert::From<NotInSchema> for Error {
    fn from(e: NotInSchema) -> Error {
        Error::failed(format!("Enum value or union discriminant {} was not present in schema.", e.0))
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
        write!(fmt, "{:?}: {}", self.kind, self.description)
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        &self.description
    }
    fn cause(&self) -> Option<&dyn (::std::error::Error)> {
        None
    }
}

/// Helper struct that allows `MessageBuilder::get_segments_for_output()` to avoid heap allocations
/// in the single-segment case.
pub enum OutputSegments<'a> {
    SingleSegment([&'a [Word]; 1]),
    MultiSegment(Vec<&'a [Word]>),
}

impl <'a> ::std::ops::Deref for OutputSegments<'a> {
    type Target = [&'a [Word]];
    fn deref<'b>(&'b self) -> &'b [&'a [Word]] {
        match *self {
            OutputSegments::SingleSegment(ref s) => {
                s
            }
            OutputSegments::MultiSegment(ref v) => {
                v
            }
        }
    }
}

impl<'s> message::ReaderSegments for OutputSegments<'s> {
    fn get_segment<'a>(&'a self, id: u32) -> Option<&'a [Word]> {
        match *self {
            OutputSegments::SingleSegment(ref s) => {
                s.get(id as usize).map(|slice| *slice)
            }
            OutputSegments::MultiSegment(ref v) => {
                v.get(id as usize).map(|slice| *slice)
            }
        }
    }
}
<commit_msg>remove unneeded 'extern crate'<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! # Cap'n Proto Runtime Library
//!
//! This crate contains basic facilities for reading and writing
//! [Cap'n Proto](https://capnproto.org) messages in Rust. It is intended to
//! be used in conjunction with code generated by the
//! [capnpc-rust](https://github.com/capnproto/capnproto-rust/capnpc) crate.
#![cfg_attr(feature = "rpc_try", feature(try_trait))]

pub mod any_pointer;
pub mod any_pointer_list;
pub mod capability;
pub mod capability_list;
pub mod constant;
pub mod data;
pub mod data_list;
pub mod enum_list;
pub mod list_list;
pub mod message;
pub mod primitive_list;
pub mod private;
pub mod raw;
pub mod serialize;
pub mod serialize_packed;
pub mod struct_list;
pub mod text;
pub mod text_list;
pub mod traits;

/// Eight bytes of memory with opaque interior.
///
/// This type is used to ensure that the data of a message is properly aligned.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(C, align(8))]
pub struct Word {
    raw_content: [u8; 8],
}

///
/// Constructs a word with the given bytes.
///
pub const fn word(b0: u8, b1: u8, b2: u8, b3: u8, b4: u8, b5: u8, b6: u8, b7: u8) -> Word {
    Word { raw_content: [b0,b1,b2,b3,b4,b5,b6,b7] }
}

impl Word {
    /// Does this, but faster:
    /// `::std::iter::repeat(Word(0)).take(length).collect()`
    pub fn allocate_zeroed_vec(length: usize) -> Vec<Word> {
        let mut result : Vec<Word> = Vec::with_capacity(length);
        unsafe {
            result.set_len(length);
            let p : *mut u8 = result.as_mut_ptr() as *mut u8;
            ::std::ptr::write_bytes(p, 0u8, length * ::std::mem::size_of::<Word>());
        }
        result
    }

    /// Converts a byte slice into a `Word` slice. Unsafe due to possible alignment issues.
    /// Only call this if you know that `bytes.to_ptr()` falls on an eight-byte boundary.
    pub unsafe fn bytes_to_words<'a>(bytes: &'a [u8]) -> &'a [Word] {
        ::std::slice::from_raw_parts(bytes.as_ptr() as *const Word, bytes.len() / 8)
    }

    /// Converts a mutable byte slice into a mutable `Word` slice. Unsafe due to possible
    /// alignment issues. Only call this if you know that `bytes.to_ptr()` falls on an eight-byte
    /// boundary.
    pub unsafe fn bytes_to_words_mut<'a>(bytes: &'a mut [u8]) -> &'a mut [Word] {
        ::std::slice::from_raw_parts_mut(bytes.as_ptr() as *mut Word, bytes.len() / 8)
    }

    pub fn words_to_bytes<'a>(words: &'a [Word]) -> &'a [u8] {
        unsafe {
            ::std::slice::from_raw_parts(words.as_ptr() as *const u8, words.len() * 8)
        }
    }

    pub fn words_to_bytes_mut<'a>(words: &'a mut [Word]) -> &'a mut [u8] {
        unsafe {
            ::std::slice::from_raw_parts_mut(words.as_mut_ptr() as *mut u8, words.len() * 8)
        }
    }
}

#[cfg(any(feature="quickcheck", test))]
impl quickcheck::Arbitrary for Word {
    fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Word {
        crate::word(quickcheck::Arbitrary::arbitrary(g),
               quickcheck::Arbitrary::arbitrary(g),
               quickcheck::Arbitrary::arbitrary(g),
               quickcheck::Arbitrary::arbitrary(g),
               quickcheck::Arbitrary::arbitrary(g),
               quickcheck::Arbitrary::arbitrary(g),
               quickcheck::Arbitrary::arbitrary(g),
               quickcheck::Arbitrary::arbitrary(g))
    }
}

/// Size of a message. Every generated struct has a method `.total_size()` that returns this.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct MessageSize {
    pub word_count: u64,

    /// Size of the capability table.
    pub cap_count: u32
}

impl MessageSize {
    pub fn plus_eq(&mut self, other : MessageSize) {
        self.word_count += other.word_count;
        self.cap_count += other.cap_count;
    }
}

/// An enum value or union discriminant that was not found among those defined in a schema.
#[derive(PartialEq, Clone, Copy, Debug)]
pub struct NotInSchema(pub u16);

impl ::std::fmt::Display for NotInSchema {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
        write!(fmt, "Enum value or union discriminant {} was not present in the schema.", self.0)
    }
}

impl ::std::error::Error for NotInSchema {
    fn description<'a>(&'a self) -> &'a str {
        "Enum value or union discriminant was not present in schema."
    }
}

/// Because messages are lazily validated, the return type of any method that reads a pointer field
/// must be wrapped in a Result.
pub type Result<T> = ::std::result::Result<T, Error>;

/// Describes an arbitrary error that prevented an operation from completing.
#[derive(Debug, Clone)]
pub struct Error {
    /// The general kind of the error. Code that decides how to respond to an error
    /// should read only this field in making its decision.
    pub kind: ErrorKind,

    /// Human-readable failure description.
    pub description: String,
}

/// The general nature of an error. The purpose of this enum is not to describe the error itself,
/// but rather to describe how the client might want to respond to the error.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ErrorKind {
    /// Something went wrong. This is the usual error kind. It includes decoding errors.
    Failed,

    /// The call failed because of a temporary lack of resources. This could be space resources
    /// (out of memory, out of disk space) or time resources (request queue overflow, operation
    /// timed out).
    ///
    /// The operation might work if tried again, but it should NOT be repeated immediately as this
    /// may simply exacerbate the problem.
    Overloaded,

    /// The call required communication over a connection that has been lost. The callee will need
    /// to re-establish connections and try again.
    Disconnected,

    /// The requested method is not implemented. The caller may wish to revert to a fallback
    /// approach based on other methods.
    Unimplemented,
}

impl Error {
    pub fn failed(description: String) -> Error {
        Error { description: description, kind: ErrorKind::Failed }
    }
    pub fn overloaded(description: String) -> Error {
        Error { description: description, kind: ErrorKind::Overloaded }
    }
    pub fn disconnected(description: String) -> Error {
        Error { description: description, kind: ErrorKind::Disconnected }
    }
    pub fn unimplemented(description: String) -> Error {
        Error { description: description, kind: ErrorKind::Unimplemented }
    }
}

impl ::std::convert::From<::std::io::Error> for Error {
    fn from(err: ::std::io::Error) -> Error {
        use std::io;
        let kind = match err.kind() {
            io::ErrorKind::TimedOut => ErrorKind::Overloaded,
            io::ErrorKind::BrokenPipe |
            io::ErrorKind::ConnectionRefused |
            io::ErrorKind::ConnectionReset |
            io::ErrorKind::ConnectionAborted |
            io::ErrorKind::NotConnected  => ErrorKind::Disconnected,
            _ => ErrorKind::Failed,
        };
        Error { description: format!("{}", err), kind: kind }
    }
}

impl ::std::convert::From<::std::string::FromUtf8Error> for Error {
    fn from(err: ::std::string::FromUtf8Error) -> Error {
        Error::failed(format!("{}", err))
    }
}

impl ::std::convert::From<::std::str::Utf8Error> for Error {
    fn from(err: ::std::str::Utf8Error) -> Error {
        Error::failed(format!("{}", err))
    }
}

impl ::std::convert::From<NotInSchema> for Error {
    fn from(e: NotInSchema) -> Error {
        Error::failed(format!("Enum value or union discriminant {} was not present in schema.", e.0))
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
        write!(fmt, "{:?}: {}", self.kind, self.description)
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        &self.description
    }
    fn cause(&self) -> Option<&dyn (::std::error::Error)> {
        None
    }
}

/// Helper struct that allows `MessageBuilder::get_segments_for_output()` to avoid heap allocations
/// in the single-segment case.
pub enum OutputSegments<'a> {
    SingleSegment([&'a [Word]; 1]),
    MultiSegment(Vec<&'a [Word]>),
}

impl <'a> ::std::ops::Deref for OutputSegments<'a> {
    type Target = [&'a [Word]];
    fn deref<'b>(&'b self) -> &'b [&'a [Word]] {
        match *self {
            OutputSegments::SingleSegment(ref s) => {
                s
            }
            OutputSegments::MultiSegment(ref v) => {
                v
            }
        }
    }
}

impl<'s> message::ReaderSegments for OutputSegments<'s> {
    fn get_segment<'a>(&'a self, id: u32) -> Option<&'a [Word]> {
        match *self {
            OutputSegments::SingleSegment(ref s) => {
                s.get(id as usize).map(|slice| *slice)
            }
            OutputSegments::MultiSegment(ref v) => {
                v.get(id as usize).map(|slice| *slice)
            }
        }
    }
}
<|endoftext|>


<commit_before>pub mod actions;
pub mod boot_source;
pub mod drive;
pub mod instance_info;
pub mod logger;
pub mod machine_configuration;
pub mod net;

use serde_json::Value;
use std::{fmt, result};

use futures::sync::oneshot;
use http_service::{empty_response, json_fault_message, json_response};
use hyper;
use hyper::{Method, StatusCode};

use data_model::vm::{BlockDeviceConfig, DriveError, MachineConfiguration, PatchDrivePayload};
use net_util::TapError;

use self::actions::ActionBody;
use self::boot_source::BootSourceBody;
use self::logger::APILoggerDescription;
use self::net::NetworkInterfaceBody;

pub type SyncOutcomeSender = oneshot::Sender<Box<GenerateResponse + Send>>;
pub type SyncOutcomeReceiver = oneshot::Receiver<Box<GenerateResponse + Send>>;

pub enum ParsedRequest {
    Dummy,
    GetInstanceInfo,
    GetMMDS,
    PatchMMDS(Value),
    PutMMDS(Value),
    Sync(SyncRequest, SyncOutcomeReceiver),
}

pub trait IntoParsedRequest {
    fn into_parsed_request(self, method: Method) -> result::Result<ParsedRequest, String>;
}

// Sync requests have outcomes which implement this trait. The idea is for each outcome to be a
// struct which is cheaply and quickly instantiated by the VMM thread, then passed back the the API
// thread, and then unpacked into a http response using the implementation of
// the generate_response() method.
pub trait GenerateResponse {
    fn generate_response(&self) -> hyper::Response;
}

// This allows us to return a boxed Result directly as a SyncOutcome, if both the ok and the error
// types implement the GenerateResponse trait.
impl<T, U> GenerateResponse for result::Result<T, U>
where
    T: GenerateResponse,
    U: GenerateResponse,
{
    fn generate_response(&self) -> hyper::Response {
        match *self {
            Ok(ref v) => v.generate_response(),
            Err(ref e) => e.generate_response(),
        }
    }
}

// This enum contains messages for the VMM which represent sync requests. They each contain various
// bits of information (ids, paths, etc.), together with an OutcomeSender, which is always present.
pub enum SyncRequest {
    GetMachineConfiguration(SyncOutcomeSender),
    PatchDrive(Value, SyncOutcomeSender),
    PutBootSource(BootSourceBody, SyncOutcomeSender),
    PutDrive(BlockDeviceConfig, SyncOutcomeSender),
    PutLogger(APILoggerDescription, SyncOutcomeSender),
    PutMachineConfiguration(MachineConfiguration, SyncOutcomeSender),
    PutNetworkInterface(NetworkInterfaceBody, SyncOutcomeSender),
    RescanBlockDevice(ActionBody, SyncOutcomeSender),
    StartInstance(SyncOutcomeSender),
}

impl fmt::Debug for SyncRequest {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "SyncRequest")
    }
}

// TODO: we should move toward having both the ok status and various possible sync request errors
// in this file, because there are many common sync outcomes.

#[derive(PartialEq)]
pub enum OkStatus {
    Created,
    Ok,
    NoContent,
}

impl GenerateResponse for OkStatus {
    fn generate_response(&self) -> hyper::Response {
        use self::OkStatus::*;
        match *self {
            Created => empty_response(StatusCode::Created),
            Ok => empty_response(StatusCode::Ok),
            NoContent => empty_response(StatusCode::NoContent),
        }
    }
}

// Potential errors associated with sync requests.
#[derive(Debug)]
pub enum Error {
    DriveOperationFailed(DriveError),
    GuestCIDAlreadyInUse,
    GuestMacAddressInUse,
    InstanceStartFailed(ErrorType, String),
    InvalidPayload,
    MicroVMAlreadyRunning,
    OpenTap(TapError),
    OperationFailed,
    OperationNotAllowedPreBoot,
    UpdateNotAllowedPostBoot,
    UpdateNotImplemented,
}

#[derive(Debug)]
pub enum ErrorType {
    UserError,
    InternalError,
}

impl GenerateResponse for Error {
    fn generate_response(&self) -> hyper::Response {
        use self::Error::*;
        match *self {
            DriveOperationFailed(ref e) => e.generate_response(),
            GuestCIDAlreadyInUse => json_response(
                StatusCode::BadRequest,
                json_fault_message("The specified guest CID is already in use."),
            ),
            GuestMacAddressInUse => json_response(
                StatusCode::BadRequest,
                json_fault_message("The specified guest MAC address is already in use."),
            ),
            InstanceStartFailed(ref error_type, ref error_msg) => {
                let status_code = match error_type {
                    ErrorType::InternalError => StatusCode::InternalServerError,
                    ErrorType::UserError => StatusCode::BadRequest,
                };

                json_response(status_code, json_fault_message(error_msg))
            }
            InvalidPayload => json_response(
                StatusCode::BadRequest,
                json_fault_message("The request payload is invalid."),
            ),
            MicroVMAlreadyRunning => json_response(
                StatusCode::Forbidden,
                json_fault_message("The microVM is already running."),
            ),
            OpenTap(ref e) => json_response(
                StatusCode::BadRequest,
                json_fault_message(format!("Could not open TAP device. {:?}", e)),
            ),
            OperationFailed => json_response(
                StatusCode::BadRequest,
                json_fault_message(format!("The operation failed.")),
            ),
            OperationNotAllowedPreBoot => json_response(
                StatusCode::Forbidden,
                json_fault_message(format!("The operation is now allowed before boot.")),
            ),
            UpdateNotAllowedPostBoot => json_response(
                StatusCode::Forbidden,
                json_fault_message("The update operation is not allowed after boot."),
            ),
            UpdateNotImplemented => json_response(
                StatusCode::InternalServerError,
                json_fault_message("Update operation is not implemented yet."),
            ),
        }
    }
}

pub type Result<T> = result::Result<T, Error>;

impl IntoParsedRequest for PatchDrivePayload {
    fn into_parsed_request(self, method: Method) -> result::Result<ParsedRequest, String> {
        match method {
            Method::Patch => {
                let (sender, receiver) = oneshot::channel();
                Ok(ParsedRequest::Sync(
                    SyncRequest::PatchDrive(self.fields, sender),
                    receiver,
                ))
            }
            _ => Err(format!("Invalid method {}!", method)),
        }
    }
}

#[cfg(test)]
impl PartialEq for ParsedRequest {
    fn eq(&self, other: &ParsedRequest) -> bool {
        match (self, other) {
            (
                &ParsedRequest::Sync(ref sync_req, _),
                &ParsedRequest::Sync(ref other_sync_req, _),
            ) => sync_req == other_sync_req,
            (&ParsedRequest::Dummy, &ParsedRequest::Dummy) => true,
            (&ParsedRequest::GetInstanceInfo, &ParsedRequest::GetInstanceInfo) => true,
            (&ParsedRequest::GetMMDS, &ParsedRequest::GetMMDS) => true,
            (&ParsedRequest::PutMMDS(ref val), &ParsedRequest::PutMMDS(ref other_val)) => {
                val == other_val
            }
            (&ParsedRequest::PatchMMDS(ref val), &ParsedRequest::PatchMMDS(ref other_val)) => {
                val == other_val
            }
            _ => false,
        }
    }
}

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

    use serde_json::Map;
    use std;

    // Implementation for the "==" operator.
    // Can't derive PartialEq directly because the sender members can't be compared.
    impl PartialEq for SyncRequest {
        fn eq(&self, other: &SyncRequest) -> bool {
            match (self, other) {
                (
                    &SyncRequest::PatchDrive(ref payload, _),
                    &SyncRequest::PatchDrive(ref other_payload, _),
                ) => payload == other_payload,
                (
                    &SyncRequest::PutBootSource(ref bsb, _),
                    &SyncRequest::PutBootSource(ref other_bsb, _),
                ) => bsb == other_bsb,
                (
                    &SyncRequest::PutDrive(ref ddesc, _),
                    &SyncRequest::PutDrive(ref other_ddesc, _),
                ) => ddesc == other_ddesc,
                (
                    &SyncRequest::PutLogger(ref logdesc, _),
                    &SyncRequest::PutLogger(ref other_logdesc, _),
                ) => logdesc == other_logdesc,
                (
                    &SyncRequest::PutMachineConfiguration(ref mcb, _),
                    &SyncRequest::PutMachineConfiguration(ref other_mcb, _),
                ) => mcb == other_mcb,
                (
                    &SyncRequest::PutNetworkInterface(ref netif, _),
                    &SyncRequest::PutNetworkInterface(ref other_netif, _),
                ) => netif == other_netif,
                (
                    &SyncRequest::RescanBlockDevice(ref req, _),
                    &SyncRequest::RescanBlockDevice(ref other_req, _),
                ) => req == other_req,
                (&SyncRequest::StartInstance(_), &SyncRequest::StartInstance(_)) => true,
                _ => false,
            }
        }
    }

    #[test]
    fn test_into_parsed_request() {
        let mut fields = Map::<String, Value>::new();
        fields.insert(String::from("drive_id"), Value::String(String::from("foo")));
        fields.insert(String::from("is_read_only"), Value::Bool(true));
        let pdp = PatchDrivePayload {
            fields: Value::Object(fields),
        };
        let (sender, receiver) = oneshot::channel();

        assert!(
            pdp.clone()
                .into_parsed_request(Method::Patch)
                .eq(&Ok(ParsedRequest::Sync(
                    SyncRequest::PatchDrive(pdp.fields.clone(), sender),
                    receiver
                )))
        );

        assert!(pdp.into_parsed_request(Method::Put).is_err());
    }

    #[test]
    fn test_generate_response_okstatus() {
        let mut ret = OkStatus::Created.generate_response();
        assert_eq!(ret.status(), StatusCode::Created);

        ret = OkStatus::NoContent.generate_response();
        assert_eq!(ret.status(), StatusCode::NoContent);
    }

    #[test]
    fn test_generate_response_error() {
        let mut ret =
            Error::DriveOperationFailed(DriveError::InvalidBlockDeviceID).generate_response();
        assert_eq!(ret.status(), StatusCode::BadRequest);

        ret = Error::GuestCIDAlreadyInUse.generate_response();
        assert_eq!(ret.status(), StatusCode::BadRequest);

        ret = Error::GuestMacAddressInUse.generate_response();
        assert_eq!(ret.status(), StatusCode::BadRequest);

        ret = Error::InstanceStartFailed(ErrorType::InternalError, "Dummy error".to_string())
            .generate_response();
        assert_eq!(ret.status(), StatusCode::InternalServerError);

        ret = Error::InstanceStartFailed(ErrorType::UserError, "Dummy error".to_string())
            .generate_response();
        assert_eq!(ret.status(), StatusCode::BadRequest);

        ret = Error::InvalidPayload.generate_response();
        assert_eq!(ret.status(), StatusCode::BadRequest);

        ret = Error::MicroVMAlreadyRunning.generate_response();
        assert_eq!(ret.status(), StatusCode::Forbidden);

        ret = Error::OpenTap(TapError::OpenTun(std::io::Error::from_raw_os_error(22)))
            .generate_response();
        assert_eq!(ret.status(), StatusCode::BadRequest);

        ret = Error::OperationFailed.generate_response();
        assert_eq!(ret.status(), StatusCode::BadRequest);

        ret = Error::OperationNotAllowedPreBoot.generate_response();
        assert_eq!(ret.status(), StatusCode::Forbidden);

        ret = Error::UpdateNotAllowedPostBoot.generate_response();
        assert_eq!(ret.status(), StatusCode::Forbidden);

        ret = Error::UpdateNotImplemented.generate_response();
        assert_eq!(ret.status(), StatusCode::InternalServerError);
    }

}
<commit_msg>api_server: fix bug when creating body for errors<commit_after>pub mod actions;
pub mod boot_source;
pub mod drive;
pub mod instance_info;
pub mod logger;
pub mod machine_configuration;
pub mod net;

use serde_json::Value;
use std::{fmt, result};

use futures::sync::oneshot;
use http_service::{empty_response, json_fault_message, json_response};
use hyper;
use hyper::{Method, StatusCode};

use data_model::vm::{BlockDeviceConfig, DriveError, MachineConfiguration, PatchDrivePayload};
use net_util::TapError;

use self::actions::ActionBody;
use self::boot_source::BootSourceBody;
use self::logger::APILoggerDescription;
use self::net::NetworkInterfaceBody;

pub type SyncOutcomeSender = oneshot::Sender<Box<GenerateResponse + Send>>;
pub type SyncOutcomeReceiver = oneshot::Receiver<Box<GenerateResponse + Send>>;

pub enum ParsedRequest {
    Dummy,
    GetInstanceInfo,
    GetMMDS,
    PatchMMDS(Value),
    PutMMDS(Value),
    Sync(SyncRequest, SyncOutcomeReceiver),
}

pub trait IntoParsedRequest {
    fn into_parsed_request(self, method: Method) -> result::Result<ParsedRequest, String>;
}

// Sync requests have outcomes which implement this trait. The idea is for each outcome to be a
// struct which is cheaply and quickly instantiated by the VMM thread, then passed back the the API
// thread, and then unpacked into a http response using the implementation of
// the generate_response() method.
pub trait GenerateResponse {
    fn generate_response(&self) -> hyper::Response;
}

// This allows us to return a boxed Result directly as a SyncOutcome, if both the ok and the error
// types implement the GenerateResponse trait.
impl<T, U> GenerateResponse for result::Result<T, U>
where
    T: GenerateResponse,
    U: GenerateResponse,
{
    fn generate_response(&self) -> hyper::Response {
        match *self {
            Ok(ref v) => v.generate_response(),
            Err(ref e) => e.generate_response(),
        }
    }
}

// This enum contains messages for the VMM which represent sync requests. They each contain various
// bits of information (ids, paths, etc.), together with an OutcomeSender, which is always present.
pub enum SyncRequest {
    GetMachineConfiguration(SyncOutcomeSender),
    PatchDrive(Value, SyncOutcomeSender),
    PutBootSource(BootSourceBody, SyncOutcomeSender),
    PutDrive(BlockDeviceConfig, SyncOutcomeSender),
    PutLogger(APILoggerDescription, SyncOutcomeSender),
    PutMachineConfiguration(MachineConfiguration, SyncOutcomeSender),
    PutNetworkInterface(NetworkInterfaceBody, SyncOutcomeSender),
    RescanBlockDevice(ActionBody, SyncOutcomeSender),
    StartInstance(SyncOutcomeSender),
}

impl fmt::Debug for SyncRequest {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "SyncRequest")
    }
}

// TODO: we should move toward having both the ok status and various possible sync request errors
// in this file, because there are many common sync outcomes.

#[derive(PartialEq)]
pub enum OkStatus {
    Created,
    Ok,
    NoContent,
}

impl GenerateResponse for OkStatus {
    fn generate_response(&self) -> hyper::Response {
        use self::OkStatus::*;
        match *self {
            Created => empty_response(StatusCode::Created),
            Ok => empty_response(StatusCode::Ok),
            NoContent => empty_response(StatusCode::NoContent),
        }
    }
}

// Potential errors associated with sync requests.
#[derive(Debug)]
pub enum Error {
    DriveOperationFailed(DriveError),
    GuestCIDAlreadyInUse,
    GuestMacAddressInUse,
    InstanceStartFailed(ErrorType, String),
    InvalidPayload,
    MicroVMAlreadyRunning,
    OpenTap(TapError),
    OperationFailed,
    OperationNotAllowedPreBoot,
    UpdateNotAllowedPostBoot,
    UpdateNotImplemented,
}

/// We need to implement to string because we are sending the errors to the clients by
/// using json_fault_message function that expects a type which implements AsRef<str>.
/// When using the default Debug formatting, we end up with invalid jsons because we don't
/// escape the quotes in the error message.
impl ToString for Error {
    fn to_string(&self) -> String {
        match self {
            Error::InstanceStartFailed(_, ref err_msg) => err_msg.replace("\"", ""),
            _ => {
                let err_msg = format!("{:?}", self);
                err_msg.replace("\"", "")
            }
        }
    }
}

#[derive(Debug)]
pub enum ErrorType {
    UserError,
    InternalError,
}

impl GenerateResponse for Error {
    fn generate_response(&self) -> hyper::Response {
        use self::Error::*;
        match *self {
            DriveOperationFailed(ref e) => e.generate_response(),
            GuestCIDAlreadyInUse => json_response(
                StatusCode::BadRequest,
                json_fault_message("The specified guest CID is already in use."),
            ),
            GuestMacAddressInUse => json_response(
                StatusCode::BadRequest,
                json_fault_message("The specified guest MAC address is already in use."),
            ),
            InstanceStartFailed(ref error_type, _) => {
                let status_code = match error_type {
                    ErrorType::InternalError => StatusCode::InternalServerError,
                    ErrorType::UserError => StatusCode::BadRequest,
                };

                json_response(status_code, json_fault_message(self.to_string()))
            }
            InvalidPayload => json_response(
                StatusCode::BadRequest,
                json_fault_message("The request payload is invalid."),
            ),
            MicroVMAlreadyRunning => json_response(
                StatusCode::Forbidden,
                json_fault_message("The microVM is already running."),
            ),
            OpenTap(_) => json_response(
                StatusCode::BadRequest,
                json_fault_message(format!("Could not open TAP device. {}", self.to_string())),
            ),
            OperationFailed => json_response(
                StatusCode::BadRequest,
                json_fault_message(format!("The operation failed.")),
            ),
            OperationNotAllowedPreBoot => json_response(
                StatusCode::Forbidden,
                json_fault_message(format!("The operation is now allowed before boot.")),
            ),
            UpdateNotAllowedPostBoot => json_response(
                StatusCode::Forbidden,
                json_fault_message("The update operation is not allowed after boot."),
            ),
            UpdateNotImplemented => json_response(
                StatusCode::InternalServerError,
                json_fault_message("Update operation is not implemented yet."),
            ),
        }
    }
}

pub type Result<T> = result::Result<T, Error>;

impl IntoParsedRequest for PatchDrivePayload {
    fn into_parsed_request(self, method: Method) -> result::Result<ParsedRequest, String> {
        match method {
            Method::Patch => {
                let (sender, receiver) = oneshot::channel();
                Ok(ParsedRequest::Sync(
                    SyncRequest::PatchDrive(self.fields, sender),
                    receiver,
                ))
            }
            _ => Err(format!("Invalid method {}!", method)),
        }
    }
}

#[cfg(test)]
impl PartialEq for ParsedRequest {
    fn eq(&self, other: &ParsedRequest) -> bool {
        match (self, other) {
            (
                &ParsedRequest::Sync(ref sync_req, _),
                &ParsedRequest::Sync(ref other_sync_req, _),
            ) => sync_req == other_sync_req,
            (&ParsedRequest::Dummy, &ParsedRequest::Dummy) => true,
            (&ParsedRequest::GetInstanceInfo, &ParsedRequest::GetInstanceInfo) => true,
            (&ParsedRequest::GetMMDS, &ParsedRequest::GetMMDS) => true,
            (&ParsedRequest::PutMMDS(ref val), &ParsedRequest::PutMMDS(ref other_val)) => {
                val == other_val
            }
            (&ParsedRequest::PatchMMDS(ref val), &ParsedRequest::PatchMMDS(ref other_val)) => {
                val == other_val
            }
            _ => false,
        }
    }
}

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

    use futures::{Future, Stream};
    use hyper::{Body, Response};
    use serde_json::{self, Map};
    use std;

    // Implementation for the "==" operator.
    // Can't derive PartialEq directly because the sender members can't be compared.
    impl PartialEq for SyncRequest {
        fn eq(&self, other: &SyncRequest) -> bool {
            match (self, other) {
                (
                    &SyncRequest::PatchDrive(ref payload, _),
                    &SyncRequest::PatchDrive(ref other_payload, _),
                ) => payload == other_payload,
                (
                    &SyncRequest::PutBootSource(ref bsb, _),
                    &SyncRequest::PutBootSource(ref other_bsb, _),
                ) => bsb == other_bsb,
                (
                    &SyncRequest::PutDrive(ref ddesc, _),
                    &SyncRequest::PutDrive(ref other_ddesc, _),
                ) => ddesc == other_ddesc,
                (
                    &SyncRequest::PutLogger(ref logdesc, _),
                    &SyncRequest::PutLogger(ref other_logdesc, _),
                ) => logdesc == other_logdesc,
                (
                    &SyncRequest::PutMachineConfiguration(ref mcb, _),
                    &SyncRequest::PutMachineConfiguration(ref other_mcb, _),
                ) => mcb == other_mcb,
                (
                    &SyncRequest::PutNetworkInterface(ref netif, _),
                    &SyncRequest::PutNetworkInterface(ref other_netif, _),
                ) => netif == other_netif,
                (
                    &SyncRequest::RescanBlockDevice(ref req, _),
                    &SyncRequest::RescanBlockDevice(ref other_req, _),
                ) => req == other_req,
                (&SyncRequest::StartInstance(_), &SyncRequest::StartInstance(_)) => true,
                _ => false,
            }
        }
    }

    #[test]
    fn test_into_parsed_request() {
        let mut fields = Map::<String, Value>::new();
        fields.insert(String::from("drive_id"), Value::String(String::from("foo")));
        fields.insert(String::from("is_read_only"), Value::Bool(true));
        let pdp = PatchDrivePayload {
            fields: Value::Object(fields),
        };
        let (sender, receiver) = oneshot::channel();

        assert!(
            pdp.clone()
                .into_parsed_request(Method::Patch)
                .eq(&Ok(ParsedRequest::Sync(
                    SyncRequest::PatchDrive(pdp.fields.clone(), sender),
                    receiver
                )))
        );

        assert!(pdp.into_parsed_request(Method::Put).is_err());
    }

    #[test]
    fn test_generate_response_okstatus() {
        let mut ret = OkStatus::Created.generate_response();
        assert_eq!(ret.status(), StatusCode::Created);

        ret = OkStatus::NoContent.generate_response();
        assert_eq!(ret.status(), StatusCode::NoContent);
    }

    fn get_body(
        response: Response<Body>,
    ) -> std::result::Result<serde_json::Value, serde_json::Error> {
        let body = response
            .body()
            .map_err(|_| ())
            .fold(vec![], |mut acc, chunk| {
                acc.extend_from_slice(&chunk);
                Ok(acc)
            }).and_then(|v| String::from_utf8(v).map_err(|_| ()));
        serde_json::from_str::<Value>(body.wait().unwrap().as_ref())
    }

    #[test]
    fn test_generate_response_error() {
        let mut ret =
            Error::DriveOperationFailed(DriveError::InvalidBlockDeviceID).generate_response();
        assert_eq!(ret.status(), StatusCode::BadRequest);
        assert!(get_body(ret).is_ok());

        ret = Error::GuestCIDAlreadyInUse.generate_response();
        assert_eq!(ret.status(), StatusCode::BadRequest);
        assert!(get_body(ret).is_ok());

        ret = Error::GuestMacAddressInUse.generate_response();
        assert_eq!(ret.status(), StatusCode::BadRequest);
        assert!(get_body(ret).is_ok());

        ret = Error::InstanceStartFailed(
            ErrorType::InternalError,
            "Dummy error message.".to_string(),
        ).generate_response();
        assert_eq!(ret.status(), StatusCode::InternalServerError);
        assert!(get_body(ret).is_ok());

        ret = Error::InstanceStartFailed(ErrorType::UserError, "Dummy error message.".to_string())
            .generate_response();
        assert_eq!(ret.status(), StatusCode::BadRequest);
        assert!(get_body(ret).is_ok());

        ret = Error::InvalidPayload.generate_response();
        assert_eq!(ret.status(), StatusCode::BadRequest);
        assert!(get_body(ret).is_ok());

        ret = Error::MicroVMAlreadyRunning.generate_response();
        assert_eq!(ret.status(), StatusCode::Forbidden);
        assert!(get_body(ret).is_ok());

        ret = Error::OpenTap(TapError::OpenTun(std::io::Error::from_raw_os_error(22)))
            .generate_response();
        assert_eq!(ret.status(), StatusCode::BadRequest);
        assert!(get_body(ret).is_ok());

        ret = Error::OperationFailed.generate_response();
        assert_eq!(ret.status(), StatusCode::BadRequest);
        assert!(get_body(ret).is_ok());

        ret = Error::OperationNotAllowedPreBoot.generate_response();
        assert_eq!(ret.status(), StatusCode::Forbidden);
        assert!(get_body(ret).is_ok());

        ret = Error::UpdateNotAllowedPostBoot.generate_response();
        assert_eq!(ret.status(), StatusCode::Forbidden);
        assert!(get_body(ret).is_ok());

        ret = Error::UpdateNotImplemented.generate_response();
        assert_eq!(ret.status(), StatusCode::InternalServerError);
        assert!(get_body(ret).is_ok());
    }
}
<|endoftext|>