<commit_before>#![crate_name = "raft"]
#![crate_type="lib"]
#![doc(html_logo_url = "https://raw.githubusercontent.com/Hoverbear/raft/master/raft.png")]
#![doc(html_root_url = "https://hoverbear.github.io/raft/raft/")]

#![feature(test)]

//! This is the Raft Distributed Consensus Protocol implemented for Rust.
//! [Raft](http://raftconsensus.github.io/) is described as:
//!
//! > Raft is a consensus algorithm that is designed to be easy to understand. It's equivalent to
//! > Paxos in fault-tolerance and performance. The difference is that it's decomposed into
//! > relatively independent subproblems, and it cleanly addresses all major pieces needed for
//! > practical systems.
//!
//! This implementation utilizes [Cap'n Proto](https://kentonv.github.io/capnproto/) for its RPC,
//! [`mio`](https://github.com/carllerche/mio) for it's async event loop.
//!
//! If this package fails to build for you it is possibly because you do not have the
//! [`capnp`](https://capnproto.org/capnp-tool.html) utility installed. You should be able to find
//! appropriate packages for most popular distributions.
//!
//! # Consuming this library
//!
//! Consuming this library works in a few parts:
//!
//! 1. Implement or consume a Persistent Log and a State Machine such that they will hook into
//!    your application desirably.
//! 2. Create a `Server` with those implementations. It will independently fire up and join the
//!    cluster.
//! 3. Interact with the cluster by issuing `.propose()` and `.query()` calls via the `Client`
//! 4. React to calls to `.propose()` and `.query()` from the implemented `StateMachine`
//!
//! ## Peristent Log
//!
//! A `Log` represents the **replicated, persistent log** of your application. It has a
//! strong ordering such that `A → B → C` and should **only** act to store information. Entries
//! placed into the log should not be acted on in any way by the consuming application as they
//! have not been committed to the cluster.
//!
//! Some ideas for a Persistent Log implementation:
//!   * A PostgreSQL / SQLite instance.
//!   * A plain old file.
//!   * A vector in memory *(Note: Log compaction is still pending, so be aware of running out!)*
//!
//! > It is our belief that in many cases the implementation of `Log` will be generic to
//! > application purposes. You are encouraged to submit your own implementations to us!
//!
//! ## State Machine
//!
//! The `StateMachine` represents the **stateful representation** of your application. Events
//! are applied to the `StateMachine` in the correct ordering at the time of commit. This is where
//! your application **should** act on information.
//!
//! In the `StateMachine` there are both mutable (`.apply()`) and immutable (`.query()`) calls.
//! There is a considerable performance difference, as `.query()` calls do not pass through the
//! durablable `Log` while `.apply()` events do.
//!
//! Some ideas for a State Machine implementation:
//!   * A Hashmap or key-value store (Example provided)
//!   * A single register (Example provided)
//!   * Basically anything from `std::collections`
//!
//! ## Client Requests
//!
//! Client requests are the **only** way to interact with the Raft cluster. Calls to `.propose()`
//! and `.query()` are automatically routed to the relevant `Leader` node and behave as blocking
//! calls.
//!
//! This means `.propose()` won't return until the entry is durably replicated into the log of at
//! least the majority of the cluster and has been commited.
//!

extern crate bufstream;
extern crate capnp;
extern crate mio;
extern crate rand;
extern crate uuid;
extern crate test;
#[macro_use] extern crate log;
#[macro_use] extern crate scoped_log;
#[macro_use] extern crate wrapped_enum;
#[cfg(test)] extern crate env_logger;
#[cfg(feature = "serde")] extern crate serde;

/// Prepares the environment testing. Should be called as the first line of every test with the
/// name of the test as the only argument.
///
/// TODO: Make this an annotation like #[rust_test] instead of a macro.
#[cfg(test)]
macro_rules! setup_test {
    ($test_name:expr) => (
        let _ = env_logger::init();
        push_log_scope!($test_name);
    );
}

pub mod state_machine;
pub mod persistent_log;
pub mod messages_capnp {
    #![allow(dead_code)]
    include!(concat!(env!("OUT_DIR"), "/messages_capnp.rs"));
}

mod backoff;
mod client;
mod connection;
mod messages;
mod consensus;
mod server;
mod state;

pub use server::Server;
pub use state_machine::StateMachine;
pub use persistent_log::Log;
pub use client::Client;

use std::{io, net, ops, fmt};

use uuid::Uuid;

/// A simple convienence type.
pub type Result<T> = std::result::Result<T, Error>;

wrapped_enum!{
    #[doc = "The generic `raft::Error` is composed of one of the errors that can originate from the"]
    #[doc = "various libraries consumed by the library."]
    #[doc = "With the exception of the `Raft` variant these are generated from `try!()` macros invoking"]
    #[doc = "on `io::Error` or `capnp::Error` by using"]
    #[doc = "[`FromError`](https://doc.rust-lang.org/std/error/#the-fromerror-trait)."]
    #[derive(Debug)]
    pub enum Error {
        /// An error originating from the [Cap'n Proto](https://github.com/dwrensha/capnproto-rust) library.
        CapnProto(capnp::Error),
        /// A specific error produced when a bad Cap'n proto message is discovered.
        SchemaError(capnp::NotInSchema),
        /// Errors originating from `std::io`.
        Io(io::Error),
        /// Raft specific errors.
        Raft(RaftError),
        /// Errors related to parsing addresses.
        AddrParse(net::AddrParseError),
    }
}

/// A Raft Error represents a Raft specific error that consuming code is expected to handle
/// gracefully.
#[derive(Debug)]
pub enum RaftError {
    /// The server ran out of slots in the slab for new connections
    ConnectionLimitReached,
    /// A client reported an invalid client id
    InvalidClientId,
    /// A consensus module reported back a leader not in the cluster.
    ClusterViolation,
    /// A remote connection attempted to use an unknown connection type in the connection preamble
    UnknownConnectionType,
    /// An invalid peer in in the peer set. Returned Server::new().
    InvalidPeerSet,
    /// Registering a connection failed
    ConnectionRegisterFailed,
    /// Failed to find a leader in the cluster. Try again later.
    LeaderSearchExhausted,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::CapnProto(ref error) => fmt::Display::fmt(error, f),
            Error::SchemaError(ref error) => fmt::Display::fmt(error, f),
            Error::Io(ref error) => fmt::Display::fmt(error, f),
            Error::Raft(ref error) => fmt::Debug::fmt(error, f),
            Error::AddrParse(ref error) => fmt::Debug::fmt(error, f),
        }
    }
}

/// The term of a log entry.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Term(u64);
impl From<u64> for Term {
    fn from(val: u64) -> Term {
        Term(val)
    }
}
impl Into<u64> for Term {
    fn into(self) -> u64 {
        self.0
    }
}
impl ops::Add<u64> for Term {
    type Output = Term;
    fn add(self, rhs: u64) -> Term {
        Term(self.0.checked_add(rhs).expect("overflow while incrementing Term"))
    }
}
impl ops::Sub<u64> for Term {
    type Output = Term;
    fn sub(self, rhs: u64) -> Term {
        Term(self.0.checked_sub(rhs).expect("underflow while decrementing Term"))
    }
}
impl fmt::Display for Term {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

/// The index of a log entry.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct LogIndex(u64);
impl From<u64> for LogIndex {
    fn from(val: u64) -> LogIndex {
        LogIndex(val)
    }
}
impl Into<u64> for LogIndex {
    fn into(self) -> u64 {
        self.0
    }
}
impl ops::Add<u64> for LogIndex {
    type Output = LogIndex;
    fn add(self, rhs: u64) -> LogIndex {
        LogIndex(self.0.checked_add(rhs).expect("overflow while incrementing LogIndex"))
    }
}
impl ops::Sub<u64> for LogIndex {
    type Output = LogIndex;
    fn sub(self, rhs: u64) -> LogIndex {
        LogIndex(self.0.checked_sub(rhs).expect("underflow while decrementing LogIndex"))
    }
}
impl fmt::Display for LogIndex {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

/// The id of a Raft server. Must be unique among the participants in a
/// consensus group.
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub struct ServerId(u64);
impl From<u64> for ServerId {
    fn from(val: u64) -> ServerId {
        ServerId(val)
    }
}
impl Into<u64> for ServerId {
    fn into(self) -> u64 {
        self.0
    }
}
impl fmt::Debug for ServerId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ServerId({})", self.0)
    }
}
impl fmt::Display for ServerId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

/// The ID of a Raft client.
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub struct ClientId(Uuid);
impl ClientId {
    fn new() -> ClientId {
        ClientId(Uuid::new_v4())
    }
    fn as_bytes(&self) -> &[u8] {
        self.0.as_bytes()
    }
    fn from_bytes(bytes: &[u8]) -> Result<ClientId> {
        match Uuid::from_bytes(bytes) {
            Some(uuid) => Ok(ClientId(uuid)),
            None => Err(Error::Raft(RaftError::InvalidClientId)),
        }
    }
}
impl fmt::Debug for ClientId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ClientId({})", self.0)
    }
}
impl fmt::Display for ClientId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}
<commit_msg>Auto merge of #89 - Hoverbear:docs, r=Hoverbear<commit_after>#![crate_name = "raft"]
#![crate_type="lib"]
#![doc(html_logo_url = "https://raw.githubusercontent.com/Hoverbear/raft/master/raft.png")]
#![doc(html_root_url = "https://hoverbear.github.io/raft/raft/")]

#![feature(test)]

//! This is the Raft Distributed Consensus Protocol implemented for Rust.
//! [Raft](http://raftconsensus.github.io/) is described as:
//!
//! > Raft is a consensus algorithm that is designed to be easy to understand. It's equivalent to
//! > Paxos in fault-tolerance and performance. The difference is that it's decomposed into
//! > relatively independent subproblems, and it cleanly addresses all major pieces needed for
//! > practical systems.
//!
//! This implementation utilizes [Cap'n Proto](https://kentonv.github.io/capnproto/) for its RPC,
//! [`mio`](https://github.com/carllerche/mio) for it's async event loop.
//!
//! If this package fails to build for you it is possibly because you do not have the
//! [`capnp`](https://capnproto.org/capnp-tool.html) utility installed. You should be able to find
//! appropriate packages for most popular distributions.
//!
//! # Consuming this library
//!
//! Consuming this library works in a few parts:
//!
//! 1. Implement or consume a Persistent Log and a State Machine such that they will hook into
//!    your application desirably.
//! 2. Create a `Server` with those implementations. It will independently fire up and join the
//!    cluster.
//! 3. Interact with the cluster by issuing `.propose()` and `.query()` calls via the `Client`
//! 4. React to calls to `.propose()` and `.query()` from the implemented `StateMachine`
//!
//! ## Peristent Log
//!
//! A `Log` represents the **replicated, persistent log** of your application. It has a
//! strong ordering such that `A → B → C` and should **only** act to store information. Entries
//! placed into the log should not be acted on in any way by the consuming application as they
//! have not been committed to the cluster.
//!
//! Some ideas for a Persistent Log implementation:
//!
//!   * A PostgreSQL / SQLite instance.
//!   * A plain old file.
//!   * A vector in memory *(Note: Log compaction is still pending, so be aware of running out!)*
//!
//! > It is our belief that in many cases the implementation of `Log` will be generic to
//! > application purposes. You are encouraged to submit your own implementations to us!
//!
//! ## State Machine
//!
//! The `StateMachine` represents the **stateful representation** of your application. Events
//! are applied to the `StateMachine` in the correct ordering at the time of commit. This is where
//! your application **should** act on information.
//!
//! In the `StateMachine` there are both mutable (`.apply()`) and immutable (`.query()`) calls.
//! There is a considerable performance difference, as `.query()` calls do not pass through the
//! durablable `Log` while `.apply()` events do.
//!
//! Some ideas for a State Machine implementation:
//!
//!   * A Hashmap or key-value store (Example provided)
//!   * A single register (Example provided)
//!   * Basically anything from `std::collections`
//!
//! ## Client Requests
//!
//! Client requests are the **only** way to interact with the Raft cluster. Calls to `.propose()`
//! and `.query()` are automatically routed to the relevant `Leader` node and behave as blocking
//! calls.
//!
//! This means `.propose()` won't return until the entry is durably replicated into the log of at
//! least the majority of the cluster and has been commited. `.query()` will perform better if
//! you wish to only read data and not have it pass through the persisted log.
//!

extern crate bufstream;
extern crate capnp;
extern crate mio;
extern crate rand;
extern crate uuid;
extern crate test;
#[macro_use] extern crate log;
#[macro_use] extern crate scoped_log;
#[macro_use] extern crate wrapped_enum;
#[cfg(test)] extern crate env_logger;
#[cfg(feature = "serde")] extern crate serde;

/// Prepares the environment testing. Should be called as the first line of every test with the
/// name of the test as the only argument.
///
/// TODO: Make this an annotation like #[rust_test] instead of a macro.
#[cfg(test)]
macro_rules! setup_test {
    ($test_name:expr) => (
        let _ = env_logger::init();
        push_log_scope!($test_name);
    );
}

pub mod state_machine;
pub mod persistent_log;
pub mod messages_capnp {
    #![allow(dead_code)]
    include!(concat!(env!("OUT_DIR"), "/messages_capnp.rs"));
}

mod backoff;
mod client;
mod connection;
mod messages;
mod consensus;
mod server;
mod state;

pub use server::Server;
pub use state_machine::StateMachine;
pub use persistent_log::Log;
pub use client::Client;

use std::{io, net, ops, fmt};

use uuid::Uuid;

/// A simple convienence type.
pub type Result<T> = std::result::Result<T, Error>;

wrapped_enum!{
    #[doc = "The generic `raft::Error` is composed of one of the errors that can originate from the"]
    #[doc = "various libraries consumed by the library."]
    #[doc = "With the exception of the `Raft` variant these are generated from `try!()` macros invoking"]
    #[doc = "on `io::Error` or `capnp::Error` by using"]
    #[doc = "[`FromError`](https://doc.rust-lang.org/std/error/#the-fromerror-trait)."]
    #[derive(Debug)]
    pub enum Error {
        /// An error originating from the [Cap'n Proto](https://github.com/dwrensha/capnproto-rust) library.
        CapnProto(capnp::Error),
        /// A specific error produced when a bad Cap'n proto message is discovered.
        SchemaError(capnp::NotInSchema),
        /// Errors originating from `std::io`.
        Io(io::Error),
        /// Raft specific errors.
        Raft(RaftError),
        /// Errors related to parsing addresses.
        AddrParse(net::AddrParseError),
    }
}

/// A Raft Error represents a Raft specific error that consuming code is expected to handle
/// gracefully.
#[derive(Debug)]
pub enum RaftError {
    /// The server ran out of slots in the slab for new connections
    ConnectionLimitReached,
    /// A client reported an invalid client id
    InvalidClientId,
    /// A consensus module reported back a leader not in the cluster.
    ClusterViolation,
    /// A remote connection attempted to use an unknown connection type in the connection preamble
    UnknownConnectionType,
    /// An invalid peer in in the peer set. Returned Server::new().
    InvalidPeerSet,
    /// Registering a connection failed
    ConnectionRegisterFailed,
    /// Failed to find a leader in the cluster. Try again later.
    LeaderSearchExhausted,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::CapnProto(ref error) => fmt::Display::fmt(error, f),
            Error::SchemaError(ref error) => fmt::Display::fmt(error, f),
            Error::Io(ref error) => fmt::Display::fmt(error, f),
            Error::Raft(ref error) => fmt::Debug::fmt(error, f),
            Error::AddrParse(ref error) => fmt::Debug::fmt(error, f),
        }
    }
}

/// The term of a log entry.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Term(u64);
impl From<u64> for Term {
    fn from(val: u64) -> Term {
        Term(val)
    }
}
impl Into<u64> for Term {
    fn into(self) -> u64 {
        self.0
    }
}
impl ops::Add<u64> for Term {
    type Output = Term;
    fn add(self, rhs: u64) -> Term {
        Term(self.0.checked_add(rhs).expect("overflow while incrementing Term"))
    }
}
impl ops::Sub<u64> for Term {
    type Output = Term;
    fn sub(self, rhs: u64) -> Term {
        Term(self.0.checked_sub(rhs).expect("underflow while decrementing Term"))
    }
}
impl fmt::Display for Term {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

/// The index of a log entry.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct LogIndex(u64);
impl From<u64> for LogIndex {
    fn from(val: u64) -> LogIndex {
        LogIndex(val)
    }
}
impl Into<u64> for LogIndex {
    fn into(self) -> u64 {
        self.0
    }
}
impl ops::Add<u64> for LogIndex {
    type Output = LogIndex;
    fn add(self, rhs: u64) -> LogIndex {
        LogIndex(self.0.checked_add(rhs).expect("overflow while incrementing LogIndex"))
    }
}
impl ops::Sub<u64> for LogIndex {
    type Output = LogIndex;
    fn sub(self, rhs: u64) -> LogIndex {
        LogIndex(self.0.checked_sub(rhs).expect("underflow while decrementing LogIndex"))
    }
}
impl fmt::Display for LogIndex {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

/// The id of a Raft server. Must be unique among the participants in a
/// consensus group. Represented as a `u64`.
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub struct ServerId(u64);
impl From<u64> for ServerId {
    fn from(val: u64) -> ServerId {
        ServerId(val)
    }
}
impl Into<u64> for ServerId {
    fn into(self) -> u64 {
        self.0
    }
}
impl fmt::Debug for ServerId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ServerId({})", self.0)
    }
}
impl fmt::Display for ServerId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

/// The ID of a Raft client. Represented as a `Uuid::v4`.
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub struct ClientId(Uuid);
impl ClientId {
    fn new() -> ClientId {
        ClientId(Uuid::new_v4())
    }
    fn as_bytes(&self) -> &[u8] {
        self.0.as_bytes()
    }
    fn from_bytes(bytes: &[u8]) -> Result<ClientId> {
        match Uuid::from_bytes(bytes) {
            Some(uuid) => Ok(ClientId(uuid)),
            None => Err(Error::Raft(RaftError::InvalidClientId)),
        }
    }
}
impl From<Uuid> for ClientId {
    fn from(val: Uuid) -> ClientId {
        ClientId(val)
    }
}
impl Into<Uuid> for ClientId {
    fn into(self) -> Uuid {
        self.0
    }
}
impl fmt::Debug for ClientId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ClientId({})", self.0)
    }
}
impl fmt::Display for ClientId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! The official Piston window wrapper for the Piston game engine
//!
//! **Notice! If this is your first time visiting Piston, [start here](https://github.com/PistonDevelopers/piston).**
//!
//! The purpose of this library is to provide an easy-to-use,
//! simple-to-get-started and convenient-for-applications API for Piston.
//!
//! Sets up:
//!
//! - [Gfx](https://github.com/gfx-rs/gfx) with an OpenGL back-end.
//! - [gfx_graphics](https://github.com/pistondevelopers/gfx_graphics)
//! for 2D rendering.
//! - [glutin_window](https://github.com/pistondevelopers/glutin_window)
//! as default window back-end, but this can be swapped (see below).
//!
//! ### Example
//!
//! ```no_run
//! extern crate piston_window;
//!
//! use piston_window::*;
//!
//! fn main() {
//!     let mut window: PistonWindow =
//!         WindowSettings::new("Hello World!", [512; 2])
//!             .build().unwrap();
//!     while let Some(e) = window.next() {
//!         window.draw_2d(&e, |c, g| {
//!             clear([0.5, 0.5, 0.5, 1.0], g);
//!             rectangle([1.0, 0.0, 0.0, 1.0], // red
//!                       [0.0, 0.0, 100.0, 100.0], // rectangle
//!                       c.transform, g);
//!         });
//!     }
//! }
//! ```
//!
//! The `draw_2d` function calls the closure on render events.
//! There is no need to filter events manually, and there is no overhead.
//!
//! ### Swap to another window back-end
//!
//! Change the generic parameter to the window back-end you want to use.
//!
//! ```ignore
//! extern crate piston_window;
//! extern crate sdl2_window;
//!
//! use piston_window::*;
//! use sdl2_window::Sdl2Window;
//!
//! # fn main() {
//!
//! let window: PistonWindow<Sdl2Window> =
//!     WindowSettings::new("title", [512; 2])
//!         .build().unwrap();
//!
//! # }
//! ```
//!
//! ### sRGB
//!
//! The impl of `BuildFromWindowSettings` in this library turns on
//! `WindowSettings::srgb`, because it is required by gfx_graphics.
//!
//! Most images such as those found on the internet uses sRGB,
//! that has a non-linear gamma corrected space.
//! When rendering 3D, make sure textures and colors are in linear gamma space.
//! Alternative is to use `Srgb8` and `Srgba8` formats for textures.
//!
//! For more information about sRGB, see
//! https://github.com/PistonDevelopers/piston/issues/1014
//!
//! ### Library dependencies
//!
//! This library is meant to be used in applications only.
//! It is not meant to be depended on by generic libraries.
//! Instead, libraries should depend on the lower abstractions,
//! such as the [Piston core](https://github.com/pistondevelopers/piston).

extern crate piston;
extern crate gfx;
extern crate gfx_device_gl;
extern crate gfx_graphics;
extern crate graphics;
extern crate shader_version;
extern crate glutin_window;
pub extern crate texture;

use glutin_window::GlutinWindow;
pub use shader_version::OpenGL;
pub use graphics::*;
pub use piston::window::*;
pub use piston::input::*;
pub use piston::event_loop::*;
pub use gfx_graphics::{ Texture, TextureSettings, Filter, Flip };

use gfx_graphics::{ Gfx2d, GfxGraphics };
use std::time::Duration;

/// Actual gfx::Stream implementation carried by the window.
pub type GfxEncoder = gfx::Encoder<gfx_device_gl::Resources,
    gfx_device_gl::CommandBuffer>;
/// Glyph cache.
pub type Glyphs = gfx_graphics::GlyphCache<'static, gfx_device_gl::Factory,
    gfx_device_gl::Resources>;
/// 2D graphics.
pub type G2d<'a> = GfxGraphics<'a,
    gfx_device_gl::Resources,
    gfx_device_gl::CommandBuffer>;
/// Texture type compatible with `G2d`.
pub type G2dTexture = Texture<gfx_device_gl::Resources>;

/// Contains everything required for controlling window, graphics, event loop.
pub struct PistonWindow<W: Window = GlutinWindow> {
    /// The window.
    pub window: W,
    /// GFX encoder.
    pub encoder: GfxEncoder,
    /// GFX device.
    pub device: gfx_device_gl::Device,
    /// Output frame buffer.
    pub output_color: gfx::handle::RenderTargetView<
        gfx_device_gl::Resources, gfx::format::Srgba8>,
    /// Output stencil buffer.
    pub output_stencil: gfx::handle::DepthStencilView<
        gfx_device_gl::Resources, gfx::format::DepthStencil>,
    /// Gfx2d.
    pub g2d: Gfx2d<gfx_device_gl::Resources>,
    /// Event loop state.
    pub events: Events,
    /// The factory that was created along with the device.
    pub factory: gfx_device_gl::Factory,
}

impl<W> BuildFromWindowSettings for PistonWindow<W>
    where W: Window + OpenGLWindow + BuildFromWindowSettings
{
    fn build_from_window_settings(settings: &WindowSettings) -> Result<PistonWindow<W>, String> {
        // Turn on sRGB.
        let settings = settings.clone().srgb(true);

        // Use OpenGL 3.2 by default, because this is what window backends
        // usually do.
        let opengl = settings.get_maybe_opengl().unwrap_or(OpenGL::V3_2);
        let samples = settings.get_samples();

        Ok(PistonWindow::new(opengl, samples, try!(settings.build())))
    }
}

fn create_main_targets(dim: gfx::texture::Dimensions) ->
(gfx::handle::RenderTargetView<
    gfx_device_gl::Resources, gfx::format::Srgba8>,
 gfx::handle::DepthStencilView<
    gfx_device_gl::Resources, gfx::format::DepthStencil>) {
    use gfx::format::{DepthStencil, Format, Formatted, Srgba8};
    use gfx::memory::Typed;

    let color_format: Format = <Srgba8 as Formatted>::get_format();
    let depth_format: Format = <DepthStencil as Formatted>::get_format();
    let (output_color, output_stencil) =
        gfx_device_gl::create_main_targets_raw(dim,
                                               color_format.0,
                                               depth_format.0);
    let output_color = Typed::new(output_color);
    let output_stencil = Typed::new(output_stencil);
    (output_color, output_stencil)
}

impl<W> PistonWindow<W>
    where W: Window
{
    /// Creates a new piston window.
    pub fn new(opengl: OpenGL, samples: u8, mut window: W) -> Self
        where W: OpenGLWindow
    {
        let (device, mut factory) =
            gfx_device_gl::create(|s|
                window.get_proc_address(s) as *const _);

        let (output_color, output_stencil) = {
            let aa = samples as gfx::texture::NumSamples;
            let draw_size = window.draw_size();
            let dim = (draw_size.width as u16, draw_size.height as u16,
                       1, aa.into());
            create_main_targets(dim)
        };

        let g2d = Gfx2d::new(opengl, &mut factory);
        let encoder = factory.create_command_buffer().into();
        let events = Events::new(EventSettings::new());
        PistonWindow {
            window: window,
            encoder: encoder,
            device: device,
            output_color: output_color,
            output_stencil: output_stencil,
            g2d: g2d,
            events: events,
            factory: factory,
        }
    }

    /// Renders 2D graphics.
    ///
    /// Calls the closure on render events.
    /// There is no need to filter events manually, and there is no overhead.
    pub fn draw_2d<E, F, U>(&mut self, e: &E, f: F) -> Option<U> where
        W: OpenGLWindow,
        E: GenericEvent,
        F: FnOnce(Context, &mut G2d) -> U
    {
        if let Some(args) = e.render_args() {
            self.window.make_current();
            let res = self.g2d.draw(
                &mut self.encoder,
                &self.output_color,
                &self.output_stencil,
                args.viewport(),
                f
            );
            self.encoder.flush(&mut self.device);
            Some(res)
        } else {
            None
        }
    }

    /// Renders 3D graphics.
    ///
    /// Calls the closure on render events.
    /// There is no need to filter events manually, and there is no overhead.
    pub fn draw_3d<E, F, U>(&mut self, e: &E, f: F) -> Option<U> where
        W: OpenGLWindow,
        E: GenericEvent,
        F: FnOnce(&mut Self) -> U
    {
        if let Some(_) = e.render_args() {
            self.window.make_current();
            let res = f(self);
            self.encoder.flush(&mut self.device);
            Some(res)
        } else {
            None
        }
    }

    /// Returns next event.
    /// Cleans up after rendering and resizes frame buffers.
    pub fn next(&mut self) -> Option<Event> {
        if let Some(e) = self.events.next(&mut self.window) {
            self.event(&e);
            Some(e)
        } else {
            None
        }
    }

    /// Let window handle new event.
    /// Cleans up after rendering and resizes frame buffers.
    pub fn event<E: GenericEvent>(&mut self, event: &E) {
        use gfx::Device;
        use gfx::memory::Typed;

        if let Some(_) = event.after_render_args() {
            // After swapping buffers.
            self.device.cleanup();
        }

        // Check whether window has resized and update the output.
        let dim = self.output_color.raw().get_dimensions();
        let (w, h) = (dim.0, dim.1);
        let draw_size = self.window.draw_size();
        if w != draw_size.width as u16 || h != draw_size.height as u16 {
            let dim = (draw_size.width as u16,
                       draw_size.height as u16,
                       dim.2, dim.3);
            let (output_color, output_stencil) = create_main_targets(dim);
            self.output_color = output_color;
            self.output_stencil = output_stencil;
        }
    }
}

impl<W> Window for PistonWindow<W>
    where W: Window
{
    fn should_close(&self) -> bool { self.window.should_close() }
    fn set_should_close(&mut self, value: bool) {
        self.window.set_should_close(value)
    }
    fn size(&self) -> Size { self.window.size() }
    fn draw_size(&self) -> Size { self.window.draw_size() }
    fn swap_buffers(&mut self) { self.window.swap_buffers() }
    fn wait_event(&mut self) -> Input {
        Window::wait_event(&mut self.window)
    }
    fn wait_event_timeout(&mut self, timeout: Duration) -> Option<Input> {
        Window::wait_event_timeout(&mut self.window, timeout)
    }
    fn poll_event(&mut self) -> Option<Input> {
        Window::poll_event(&mut self.window)
    }
}

impl<W> AdvancedWindow for PistonWindow<W>
    where W: AdvancedWindow
{
    fn get_title(&self) -> String { self.window.get_title() }
    fn set_title(&mut self, title: String) {
        self.window.set_title(title)
    }
    fn get_exit_on_esc(&self) -> bool { self.window.get_exit_on_esc() }
    fn set_exit_on_esc(&mut self, value: bool) {
        self.window.set_exit_on_esc(value)
    }
    fn set_capture_cursor(&mut self, value: bool) {
        self.window.set_capture_cursor(value)
    }
    fn show(&mut self) { self.window.show() }
    fn hide(&mut self) { self.window.hide() }
    fn get_position(&self) -> Option<Position> {
        self.window.get_position()
    }
    fn set_position<P: Into<Position>>(&mut self, pos: P) {
        self.window.set_position(pos)
    }
}

impl<W> EventLoop for PistonWindow<W>
    where W: Window
{
    fn get_event_settings(&self) -> EventSettings {
        self.events.get_event_settings()
    }

    fn set_event_settings(&mut self, settings: EventSettings) {
        self.events.set_event_settings(settings);
    }
}
<commit_msg>Reexport `Factory`<commit_after>#![deny(missing_docs)]

//! The official Piston window wrapper for the Piston game engine
//!
//! **Notice! If this is your first time visiting Piston, [start here](https://github.com/PistonDevelopers/piston).**
//!
//! The purpose of this library is to provide an easy-to-use,
//! simple-to-get-started and convenient-for-applications API for Piston.
//!
//! Sets up:
//!
//! - [Gfx](https://github.com/gfx-rs/gfx) with an OpenGL back-end.
//! - [gfx_graphics](https://github.com/pistondevelopers/gfx_graphics)
//! for 2D rendering.
//! - [glutin_window](https://github.com/pistondevelopers/glutin_window)
//! as default window back-end, but this can be swapped (see below).
//!
//! ### Example
//!
//! ```no_run
//! extern crate piston_window;
//!
//! use piston_window::*;
//!
//! fn main() {
//!     let mut window: PistonWindow =
//!         WindowSettings::new("Hello World!", [512; 2])
//!             .build().unwrap();
//!     while let Some(e) = window.next() {
//!         window.draw_2d(&e, |c, g| {
//!             clear([0.5, 0.5, 0.5, 1.0], g);
//!             rectangle([1.0, 0.0, 0.0, 1.0], // red
//!                       [0.0, 0.0, 100.0, 100.0], // rectangle
//!                       c.transform, g);
//!         });
//!     }
//! }
//! ```
//!
//! The `draw_2d` function calls the closure on render events.
//! There is no need to filter events manually, and there is no overhead.
//!
//! ### Swap to another window back-end
//!
//! Change the generic parameter to the window back-end you want to use.
//!
//! ```ignore
//! extern crate piston_window;
//! extern crate sdl2_window;
//!
//! use piston_window::*;
//! use sdl2_window::Sdl2Window;
//!
//! # fn main() {
//!
//! let window: PistonWindow<Sdl2Window> =
//!     WindowSettings::new("title", [512; 2])
//!         .build().unwrap();
//!
//! # }
//! ```
//!
//! ### sRGB
//!
//! The impl of `BuildFromWindowSettings` in this library turns on
//! `WindowSettings::srgb`, because it is required by gfx_graphics.
//!
//! Most images such as those found on the internet uses sRGB,
//! that has a non-linear gamma corrected space.
//! When rendering 3D, make sure textures and colors are in linear gamma space.
//! Alternative is to use `Srgb8` and `Srgba8` formats for textures.
//!
//! For more information about sRGB, see
//! https://github.com/PistonDevelopers/piston/issues/1014
//!
//! ### Library dependencies
//!
//! This library is meant to be used in applications only.
//! It is not meant to be depended on by generic libraries.
//! Instead, libraries should depend on the lower abstractions,
//! such as the [Piston core](https://github.com/pistondevelopers/piston).

extern crate piston;
extern crate gfx;
extern crate gfx_device_gl;
extern crate gfx_graphics;
extern crate graphics;
extern crate shader_version;
extern crate glutin_window;
pub extern crate texture;

use glutin_window::GlutinWindow;
pub use shader_version::OpenGL;
pub use graphics::*;
pub use piston::window::*;
pub use piston::input::*;
pub use piston::event_loop::*;
pub use gfx_graphics::{ Texture, TextureSettings, Filter, Flip };

use gfx_graphics::{ Gfx2d, GfxGraphics };
use std::time::Duration;

/// Actual factory used by Gfx backend.
pub type GfxFactory = gfx_device_gl::Factory;
/// Actual gfx::Stream implementation carried by the window.
pub type GfxEncoder = gfx::Encoder<gfx_device_gl::Resources,
    gfx_device_gl::CommandBuffer>;
/// Glyph cache.
pub type Glyphs = gfx_graphics::GlyphCache<'static, gfx_device_gl::Factory,
    gfx_device_gl::Resources>;
/// 2D graphics.
pub type G2d<'a> = GfxGraphics<'a,
    gfx_device_gl::Resources,
    gfx_device_gl::CommandBuffer>;
/// Texture type compatible with `G2d`.
pub type G2dTexture = Texture<gfx_device_gl::Resources>;

/// Contains everything required for controlling window, graphics, event loop.
pub struct PistonWindow<W: Window = GlutinWindow> {
    /// The window.
    pub window: W,
    /// GFX encoder.
    pub encoder: GfxEncoder,
    /// GFX device.
    pub device: gfx_device_gl::Device,
    /// Output frame buffer.
    pub output_color: gfx::handle::RenderTargetView<
        gfx_device_gl::Resources, gfx::format::Srgba8>,
    /// Output stencil buffer.
    pub output_stencil: gfx::handle::DepthStencilView<
        gfx_device_gl::Resources, gfx::format::DepthStencil>,
    /// Gfx2d.
    pub g2d: Gfx2d<gfx_device_gl::Resources>,
    /// Event loop state.
    pub events: Events,
    /// The factory that was created along with the device.
    pub factory: gfx_device_gl::Factory,
}

impl<W> BuildFromWindowSettings for PistonWindow<W>
    where W: Window + OpenGLWindow + BuildFromWindowSettings
{
    fn build_from_window_settings(settings: &WindowSettings) -> Result<PistonWindow<W>, String> {
        // Turn on sRGB.
        let settings = settings.clone().srgb(true);

        // Use OpenGL 3.2 by default, because this is what window backends
        // usually do.
        let opengl = settings.get_maybe_opengl().unwrap_or(OpenGL::V3_2);
        let samples = settings.get_samples();

        Ok(PistonWindow::new(opengl, samples, try!(settings.build())))
    }
}

fn create_main_targets(dim: gfx::texture::Dimensions) ->
(gfx::handle::RenderTargetView<
    gfx_device_gl::Resources, gfx::format::Srgba8>,
 gfx::handle::DepthStencilView<
    gfx_device_gl::Resources, gfx::format::DepthStencil>) {
    use gfx::format::{DepthStencil, Format, Formatted, Srgba8};
    use gfx::memory::Typed;

    let color_format: Format = <Srgba8 as Formatted>::get_format();
    let depth_format: Format = <DepthStencil as Formatted>::get_format();
    let (output_color, output_stencil) =
        gfx_device_gl::create_main_targets_raw(dim,
                                               color_format.0,
                                               depth_format.0);
    let output_color = Typed::new(output_color);
    let output_stencil = Typed::new(output_stencil);
    (output_color, output_stencil)
}

impl<W> PistonWindow<W>
    where W: Window
{
    /// Creates a new piston window.
    pub fn new(opengl: OpenGL, samples: u8, mut window: W) -> Self
        where W: OpenGLWindow
    {
        let (device, mut factory) =
            gfx_device_gl::create(|s|
                window.get_proc_address(s) as *const _);

        let (output_color, output_stencil) = {
            let aa = samples as gfx::texture::NumSamples;
            let draw_size = window.draw_size();
            let dim = (draw_size.width as u16, draw_size.height as u16,
                       1, aa.into());
            create_main_targets(dim)
        };

        let g2d = Gfx2d::new(opengl, &mut factory);
        let encoder = factory.create_command_buffer().into();
        let events = Events::new(EventSettings::new());
        PistonWindow {
            window: window,
            encoder: encoder,
            device: device,
            output_color: output_color,
            output_stencil: output_stencil,
            g2d: g2d,
            events: events,
            factory: factory,
        }
    }

    /// Renders 2D graphics.
    ///
    /// Calls the closure on render events.
    /// There is no need to filter events manually, and there is no overhead.
    pub fn draw_2d<E, F, U>(&mut self, e: &E, f: F) -> Option<U> where
        W: OpenGLWindow,
        E: GenericEvent,
        F: FnOnce(Context, &mut G2d) -> U
    {
        if let Some(args) = e.render_args() {
            self.window.make_current();
            let res = self.g2d.draw(
                &mut self.encoder,
                &self.output_color,
                &self.output_stencil,
                args.viewport(),
                f
            );
            self.encoder.flush(&mut self.device);
            Some(res)
        } else {
            None
        }
    }

    /// Renders 3D graphics.
    ///
    /// Calls the closure on render events.
    /// There is no need to filter events manually, and there is no overhead.
    pub fn draw_3d<E, F, U>(&mut self, e: &E, f: F) -> Option<U> where
        W: OpenGLWindow,
        E: GenericEvent,
        F: FnOnce(&mut Self) -> U
    {
        if let Some(_) = e.render_args() {
            self.window.make_current();
            let res = f(self);
            self.encoder.flush(&mut self.device);
            Some(res)
        } else {
            None
        }
    }

    /// Returns next event.
    /// Cleans up after rendering and resizes frame buffers.
    pub fn next(&mut self) -> Option<Event> {
        if let Some(e) = self.events.next(&mut self.window) {
            self.event(&e);
            Some(e)
        } else {
            None
        }
    }

    /// Let window handle new event.
    /// Cleans up after rendering and resizes frame buffers.
    pub fn event<E: GenericEvent>(&mut self, event: &E) {
        use gfx::Device;
        use gfx::memory::Typed;

        if let Some(_) = event.after_render_args() {
            // After swapping buffers.
            self.device.cleanup();
        }

        // Check whether window has resized and update the output.
        let dim = self.output_color.raw().get_dimensions();
        let (w, h) = (dim.0, dim.1);
        let draw_size = self.window.draw_size();
        if w != draw_size.width as u16 || h != draw_size.height as u16 {
            let dim = (draw_size.width as u16,
                       draw_size.height as u16,
                       dim.2, dim.3);
            let (output_color, output_stencil) = create_main_targets(dim);
            self.output_color = output_color;
            self.output_stencil = output_stencil;
        }
    }
}

impl<W> Window for PistonWindow<W>
    where W: Window
{
    fn should_close(&self) -> bool { self.window.should_close() }
    fn set_should_close(&mut self, value: bool) {
        self.window.set_should_close(value)
    }
    fn size(&self) -> Size { self.window.size() }
    fn draw_size(&self) -> Size { self.window.draw_size() }
    fn swap_buffers(&mut self) { self.window.swap_buffers() }
    fn wait_event(&mut self) -> Input {
        Window::wait_event(&mut self.window)
    }
    fn wait_event_timeout(&mut self, timeout: Duration) -> Option<Input> {
        Window::wait_event_timeout(&mut self.window, timeout)
    }
    fn poll_event(&mut self) -> Option<Input> {
        Window::poll_event(&mut self.window)
    }
}

impl<W> AdvancedWindow for PistonWindow<W>
    where W: AdvancedWindow
{
    fn get_title(&self) -> String { self.window.get_title() }
    fn set_title(&mut self, title: String) {
        self.window.set_title(title)
    }
    fn get_exit_on_esc(&self) -> bool { self.window.get_exit_on_esc() }
    fn set_exit_on_esc(&mut self, value: bool) {
        self.window.set_exit_on_esc(value)
    }
    fn set_capture_cursor(&mut self, value: bool) {
        self.window.set_capture_cursor(value)
    }
    fn show(&mut self) { self.window.show() }
    fn hide(&mut self) { self.window.hide() }
    fn get_position(&self) -> Option<Position> {
        self.window.get_position()
    }
    fn set_position<P: Into<Position>>(&mut self, pos: P) {
        self.window.set_position(pos)
    }
}

impl<W> EventLoop for PistonWindow<W>
    where W: Window
{
    fn get_event_settings(&self) -> EventSettings {
        self.events.get_event_settings()
    }

    fn set_event_settings(&mut self, settings: EventSettings) {
        self.events.set_event_settings(settings);
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! The official Piston window back-end for the Piston game engine

extern crate piston;
extern crate gfx;
extern crate gfx_device_gl;
extern crate gfx_graphics;
extern crate graphics;
extern crate shader_version;
extern crate glutin_window;

use glutin_window::GlutinWindow;
pub use shader_version::OpenGL;
pub use graphics::*;
pub use piston::window::*;
pub use piston::event::*;
pub use piston::input::*;

use std::cell::RefCell;
use std::rc::Rc;
use std::any::Any;

use piston::{ event, window };
use gfx::traits::*;
use gfx_graphics::{ Gfx2d, GfxGraphics };

/// Actual gfx::Stream implementation carried by the window.
pub type GfxStream = gfx::OwnedStream<gfx_device_gl::Device, gfx_device_gl::Output>;
/// Glyph cache.
type PistonGlyphCache = gfx_graphics::GlyphCache<gfx_device_gl::Resources, gfx_device_gl::Factory>;
/// 2D graphics.
type PistonGraphics<'a> = GfxGraphics<'a, gfx_device_gl::Resources, gfx_device_gl::CommandBuffer, gfx_device_gl::Output>;

/// Creates a window using default window back-end.
pub fn window(settings: WindowSettings) -> Rc<RefCell<GlutinWindow>> {
    Rc::new(RefCell::new(GlutinWindow::new(settings)))
}

/// Contains everything required for controlling window, graphics, event loop.
pub struct PistonWindow<W: window::Window = GlutinWindow, T = ()> {
    /// The window.
    pub window: Rc<RefCell<W>>,
    /// GFX stream.
    pub stream: Rc<RefCell<GfxStream>>,
    /// GFX device.
    pub device: Rc<RefCell<gfx_device_gl::Device>>,
    /// Gfx2d.
    pub g2d: Rc<RefCell<Gfx2d<gfx_device_gl::Resources>>>,
    /// The event loop.
    pub events: Rc<RefCell<event::WindowEvents<W, event::Event<W::Event>>>>,
    /// The event.
    pub event: Option<event::Event<W::Event>>,
    /// Application structure.
    pub app: Rc<RefCell<T>>,
    /// The factory that was created along with the device.
    pub factory: Rc<RefCell<gfx_device_gl::Factory>>,
}

impl From<WindowSettings> for PistonWindow {
    fn from(settings: WindowSettings) -> PistonWindow {
        PistonWindow::new(window(settings), empty_app())
    }
}

impl<W, T> Clone for PistonWindow<W, T>
    where W: window::Window, W::Event: Clone
{
    fn clone(&self) -> Self {
        PistonWindow {
            window: self.window.clone(),
            stream: self.stream.clone(),
            device: self.device.clone(),
            g2d: self.g2d.clone(),
            events: self.events.clone(),
            event: self.event.clone(),
            app: self.app.clone(),
            factory: self.factory.clone(),
        }
    }
}

impl<W, T> PistonWindow<W, T>
    where W: window::Window, W::Event: event::GenericEvent
{
    /// Creates a new piston object.
    pub fn new(window: Rc<RefCell<W>>, app: Rc<RefCell<T>>) -> Self
        where W: window::OpenGLWindow
    {
        use piston::event::Events;
        use piston::window::{ OpenGLWindow, Window };

        let (device, mut factory) =
            gfx_device_gl::create(|s| window.borrow_mut().get_proc_address(s));

        let draw_size = window.borrow().draw_size();
        let output = factory.make_fake_output(draw_size.width as u16, draw_size.height as u16);

        let g2d = Gfx2d::new(&mut factory);

        let stream = factory.create_stream(output);

        PistonWindow {
            window: window.clone(),
            stream: Rc::new(RefCell::new(stream)),
            device: Rc::new(RefCell::new(device)),
            g2d: Rc::new(RefCell::new(g2d)),
            events: Rc::new(RefCell::new(window.events())),
            event: None,
            app: app,
            factory: Rc::new(RefCell::new(factory)),
        }
    }

    /// Changes application structure.
    pub fn app<U>(self, app: Rc<RefCell<U>>) -> PistonWindow<W, U> {
        PistonWindow {
            window: self.window,
            stream: self.stream,
            device: self.device,
            g2d: self.g2d,
            events: self.events,
            event: self.event,
            app: app,
            factory: self.factory,
        }
    }

    /// Renders 2D graphics.
    pub fn draw_2d<F>(&self, f: F) where
        F: FnMut(Context, &mut GfxGraphics<
            gfx_device_gl::Resources, gfx_device_gl::CommandBuffer,
            gfx_device_gl::Output>)
    {
        use piston::event::RenderEvent;

        if let Some(ref e) = self.event {
            if let Some(args) = e.render_args() {
                let mut stream = self.stream.borrow_mut();
                {
                    let (renderer, output) = stream.access();
                    self.g2d.borrow_mut().draw(renderer, output, args.viewport(), f);
                }
                stream.flush(&mut *self.device.borrow_mut());
            }
        }
    }

    /// Renders 3D graphics.
    pub fn draw_3d<F>(&self, mut f: F) where
        F: FnMut(&mut GfxStream)
    {
        use piston::event::RenderEvent;

        if let Some(ref e) = self.event {
            if let Some(_) = e.render_args() {
                let mut stream = self.stream.borrow_mut();
                f(&mut *stream);
                stream.flush(&mut *self.device.borrow_mut())
            }
        }
    }
}

impl<W, T> Iterator for PistonWindow<W, T>
    where W: window::Window, W::Event: event::GenericEvent
{
    type Item = PistonWindow<W, T>;

    fn next(&mut self) -> Option<PistonWindow<W, T>> {
        use piston::event::*;

        if let Some(e) = self.events.borrow_mut().next() {
            if let Some(_) = e.after_render_args() {
                // After swapping buffers.
                self.device.borrow_mut().cleanup();
            }

            if let Some(_) = e.resize_args() {
                let mut stream = self.stream.borrow_mut();
                let draw_size = self.window.borrow().draw_size();
                stream.out.width = draw_size.width as u16;
                stream.out.height = draw_size.height as u16;
            }

            Some(PistonWindow {
                window: self.window.clone(),
                stream: self.stream.clone(),
                device: self.device.clone(),
                g2d: self.g2d.clone(),
                events: self.events.clone(),
                event: Some(e),
                app: self.app.clone(),
                factory: self.factory.clone(),
            })
        } else { None }
    }
}

impl<W, T> event::GenericEvent for PistonWindow<W, T>
    where W: window::Window, W::Event: event::GenericEvent
{
    fn event_id(&self) -> event::EventId {
        match self.event {
            Some(ref e) => e.event_id(),
            None => event::EventId("")
        }
    }

    fn with_args<'a, F, U>(&'a self, f: F) -> U
       where F: FnMut(&Any) -> U
    {
        self.event.as_ref().unwrap().with_args(f)
    }

    fn from_args(event_id: event::EventId, any: &Any, old_event: &Self) -> Option<Self> {
        if let Some(ref e) = old_event.event {
            match event::GenericEvent::from_args(event_id, any, e) {
                Some(e) => {
                    Some(PistonWindow {
                        window: old_event.window.clone(),
                        stream: old_event.stream.clone(),
                        device: old_event.device.clone(),
                        g2d: old_event.g2d.clone(),
                        events: old_event.events.clone(),
                        event: Some(e),
                        app: old_event.app.clone(),
                        factory: old_event.factory.clone(),
                    })
                }
                None => None
            }
        } else { None }
    }
}

impl<W, T> window::Window for PistonWindow<W, T>
    where W: window::Window
{
    type Event = <W as window::Window>::Event;

    fn should_close(&self) -> bool { self.window.borrow().should_close() }
    fn size(&self) -> window::Size { self.window.borrow().size() }
    fn draw_size(&self) -> window::Size { self.window.borrow().draw_size() }
    fn swap_buffers(&mut self) { self.window.borrow_mut().swap_buffers() }
    fn poll_event(&mut self) -> Option<Self::Event> {
        window::Window::poll_event(&mut *self.window.borrow_mut())
    }
}

impl<W, T> window::AdvancedWindow for PistonWindow<W, T>
    where W: window::AdvancedWindow
{
    fn get_title(&self) -> String { self.window.borrow().get_title() }
    fn set_title(&mut self, title: String) {
        self.window.borrow_mut().set_title(title)
    }
    fn get_exit_on_esc(&self) -> bool { self.window.borrow().get_exit_on_esc() }
    fn set_exit_on_esc(&mut self, value: bool) {
        self.window.borrow_mut().set_exit_on_esc(value)
    }
    fn set_capture_cursor(&mut self, value: bool) {
        self.window.borrow_mut().set_capture_cursor(value)
    }
}

/// Creates a new empty application.
pub fn empty_app() -> Rc<RefCell<()>> { Rc::new(RefCell::new(())) }
<commit_msg>Renamed to `G2d` and `Glyphs`<commit_after>#![deny(missing_docs)]

//! The official Piston window back-end for the Piston game engine

extern crate piston;
extern crate gfx;
extern crate gfx_device_gl;
extern crate gfx_graphics;
extern crate graphics;
extern crate shader_version;
extern crate glutin_window;

use glutin_window::GlutinWindow;
pub use shader_version::OpenGL;
pub use graphics::*;
pub use piston::window::*;
pub use piston::event::*;
pub use piston::input::*;

use std::cell::RefCell;
use std::rc::Rc;
use std::any::Any;

use piston::{ event, window };
use gfx::traits::*;
use gfx_graphics::{ Gfx2d, GfxGraphics };

/// Actual gfx::Stream implementation carried by the window.
pub type GfxStream = gfx::OwnedStream<gfx_device_gl::Device, gfx_device_gl::Output>;
/// Glyph cache.
type Glyphs = gfx_graphics::GlyphCache<gfx_device_gl::Resources, gfx_device_gl::Factory>;
/// 2D graphics.
type G2d<'a> = GfxGraphics<'a, gfx_device_gl::Resources, gfx_device_gl::CommandBuffer, gfx_device_gl::Output>;

/// Creates a window using default window back-end.
pub fn window(settings: WindowSettings) -> Rc<RefCell<GlutinWindow>> {
    Rc::new(RefCell::new(GlutinWindow::new(settings)))
}

/// Contains everything required for controlling window, graphics, event loop.
pub struct PistonWindow<W: window::Window = GlutinWindow, T = ()> {
    /// The window.
    pub window: Rc<RefCell<W>>,
    /// GFX stream.
    pub stream: Rc<RefCell<GfxStream>>,
    /// GFX device.
    pub device: Rc<RefCell<gfx_device_gl::Device>>,
    /// Gfx2d.
    pub g2d: Rc<RefCell<Gfx2d<gfx_device_gl::Resources>>>,
    /// The event loop.
    pub events: Rc<RefCell<event::WindowEvents<W, event::Event<W::Event>>>>,
    /// The event.
    pub event: Option<event::Event<W::Event>>,
    /// Application structure.
    pub app: Rc<RefCell<T>>,
    /// The factory that was created along with the device.
    pub factory: Rc<RefCell<gfx_device_gl::Factory>>,
}

impl From<WindowSettings> for PistonWindow {
    fn from(settings: WindowSettings) -> PistonWindow {
        PistonWindow::new(window(settings), empty_app())
    }
}

impl<W, T> Clone for PistonWindow<W, T>
    where W: window::Window, W::Event: Clone
{
    fn clone(&self) -> Self {
        PistonWindow {
            window: self.window.clone(),
            stream: self.stream.clone(),
            device: self.device.clone(),
            g2d: self.g2d.clone(),
            events: self.events.clone(),
            event: self.event.clone(),
            app: self.app.clone(),
            factory: self.factory.clone(),
        }
    }
}

impl<W, T> PistonWindow<W, T>
    where W: window::Window, W::Event: event::GenericEvent
{
    /// Creates a new piston object.
    pub fn new(window: Rc<RefCell<W>>, app: Rc<RefCell<T>>) -> Self
        where W: window::OpenGLWindow
    {
        use piston::event::Events;
        use piston::window::{ OpenGLWindow, Window };

        let (device, mut factory) =
            gfx_device_gl::create(|s| window.borrow_mut().get_proc_address(s));

        let draw_size = window.borrow().draw_size();
        let output = factory.make_fake_output(draw_size.width as u16, draw_size.height as u16);

        let g2d = Gfx2d::new(&mut factory);

        let stream = factory.create_stream(output);

        PistonWindow {
            window: window.clone(),
            stream: Rc::new(RefCell::new(stream)),
            device: Rc::new(RefCell::new(device)),
            g2d: Rc::new(RefCell::new(g2d)),
            events: Rc::new(RefCell::new(window.events())),
            event: None,
            app: app,
            factory: Rc::new(RefCell::new(factory)),
        }
    }

    /// Changes application structure.
    pub fn app<U>(self, app: Rc<RefCell<U>>) -> PistonWindow<W, U> {
        PistonWindow {
            window: self.window,
            stream: self.stream,
            device: self.device,
            g2d: self.g2d,
            events: self.events,
            event: self.event,
            app: app,
            factory: self.factory,
        }
    }

    /// Renders 2D graphics.
    pub fn draw_2d<F>(&self, f: F) where
        F: FnMut(Context, &mut GfxGraphics<
            gfx_device_gl::Resources, gfx_device_gl::CommandBuffer,
            gfx_device_gl::Output>)
    {
        use piston::event::RenderEvent;

        if let Some(ref e) = self.event {
            if let Some(args) = e.render_args() {
                let mut stream = self.stream.borrow_mut();
                {
                    let (renderer, output) = stream.access();
                    self.g2d.borrow_mut().draw(renderer, output, args.viewport(), f);
                }
                stream.flush(&mut *self.device.borrow_mut());
            }
        }
    }

    /// Renders 3D graphics.
    pub fn draw_3d<F>(&self, mut f: F) where
        F: FnMut(&mut GfxStream)
    {
        use piston::event::RenderEvent;

        if let Some(ref e) = self.event {
            if let Some(_) = e.render_args() {
                let mut stream = self.stream.borrow_mut();
                f(&mut *stream);
                stream.flush(&mut *self.device.borrow_mut())
            }
        }
    }
}

impl<W, T> Iterator for PistonWindow<W, T>
    where W: window::Window, W::Event: event::GenericEvent
{
    type Item = PistonWindow<W, T>;

    fn next(&mut self) -> Option<PistonWindow<W, T>> {
        use piston::event::*;

        if let Some(e) = self.events.borrow_mut().next() {
            if let Some(_) = e.after_render_args() {
                // After swapping buffers.
                self.device.borrow_mut().cleanup();
            }

            if let Some(_) = e.resize_args() {
                let mut stream = self.stream.borrow_mut();
                let draw_size = self.window.borrow().draw_size();
                stream.out.width = draw_size.width as u16;
                stream.out.height = draw_size.height as u16;
            }

            Some(PistonWindow {
                window: self.window.clone(),
                stream: self.stream.clone(),
                device: self.device.clone(),
                g2d: self.g2d.clone(),
                events: self.events.clone(),
                event: Some(e),
                app: self.app.clone(),
                factory: self.factory.clone(),
            })
        } else { None }
    }
}

impl<W, T> event::GenericEvent for PistonWindow<W, T>
    where W: window::Window, W::Event: event::GenericEvent
{
    fn event_id(&self) -> event::EventId {
        match self.event {
            Some(ref e) => e.event_id(),
            None => event::EventId("")
        }
    }

    fn with_args<'a, F, U>(&'a self, f: F) -> U
       where F: FnMut(&Any) -> U
    {
        self.event.as_ref().unwrap().with_args(f)
    }

    fn from_args(event_id: event::EventId, any: &Any, old_event: &Self) -> Option<Self> {
        if let Some(ref e) = old_event.event {
            match event::GenericEvent::from_args(event_id, any, e) {
                Some(e) => {
                    Some(PistonWindow {
                        window: old_event.window.clone(),
                        stream: old_event.stream.clone(),
                        device: old_event.device.clone(),
                        g2d: old_event.g2d.clone(),
                        events: old_event.events.clone(),
                        event: Some(e),
                        app: old_event.app.clone(),
                        factory: old_event.factory.clone(),
                    })
                }
                None => None
            }
        } else { None }
    }
}

impl<W, T> window::Window for PistonWindow<W, T>
    where W: window::Window
{
    type Event = <W as window::Window>::Event;

    fn should_close(&self) -> bool { self.window.borrow().should_close() }
    fn size(&self) -> window::Size { self.window.borrow().size() }
    fn draw_size(&self) -> window::Size { self.window.borrow().draw_size() }
    fn swap_buffers(&mut self) { self.window.borrow_mut().swap_buffers() }
    fn poll_event(&mut self) -> Option<Self::Event> {
        window::Window::poll_event(&mut *self.window.borrow_mut())
    }
}

impl<W, T> window::AdvancedWindow for PistonWindow<W, T>
    where W: window::AdvancedWindow
{
    fn get_title(&self) -> String { self.window.borrow().get_title() }
    fn set_title(&mut self, title: String) {
        self.window.borrow_mut().set_title(title)
    }
    fn get_exit_on_esc(&self) -> bool { self.window.borrow().get_exit_on_esc() }
    fn set_exit_on_esc(&mut self, value: bool) {
        self.window.borrow_mut().set_exit_on_esc(value)
    }
    fn set_capture_cursor(&mut self, value: bool) {
        self.window.borrow_mut().set_capture_cursor(value)
    }
}

/// Creates a new empty application.
pub fn empty_app() -> Rc<RefCell<()>> { Rc::new(RefCell::new(())) }
<|endoftext|>


<commit_before>//! SQLite support for the `r2d2` connection pool.
#![warn(missing_docs)]
extern crate r2d2;
extern crate rusqlite;

use std::convert::Into;
use std::path::PathBuf;

/// An `r2d2::ManageConnection` for `rusqlite::SqliteConnection`s.
///
/// ## Example
///
/// ```rust
/// extern crate r2d2;
/// extern crate r2d2_sqlite;
/// extern crate rusqlite;
///
/// use std::sync::Arc;
/// use std::default::Default;
/// use std::thread;
/// use r2d2_sqlite::SQLiteConnectionManager;
/// use rusqlite::OpenFlags;
///
/// fn main() {
///     let manager = SQLiteConnectionManager::new(
///             "file:dummy.db?mode=memory&cache=shared",
///             OpenFlags::SQLITE_OPEN_URI | OpenFlags::SQLITE_OPEN_CREATE | OpenFlags::SQLITE_OPEN_READ_WRITE);
///     let pool = Arc::new(r2d2::Pool::new(manager).unwrap());
///
///     for i in 0..10i32 {
///         let pool = pool.clone();
///         thread::spawn(move || {
///             let conn = pool.get().unwrap();
///             conn.execute("PRAGMA user_version=?1", &[&i]).unwrap();
///         });
///     }
/// }
/// ```
pub struct SQLiteConnectionManager {
    path: PathBuf,
    flags: rusqlite::OpenFlags,
}

impl SQLiteConnectionManager {
    /// Creates a new `SQLiteConnectionManager`.
    ///
    /// See `rusqlite::SqliteConnection::open_with_flags` for a description of
    /// the parameter types.
    pub fn new<T>(path: T, flags: rusqlite::OpenFlags) -> SQLiteConnectionManager
    where
        T: Into<PathBuf>,
    {
        SQLiteConnectionManager {
            path: path.into(),
            flags: flags,
        }
    }
}

impl r2d2::ManageConnection for SQLiteConnectionManager {
    type Connection = rusqlite::Connection;
    type Error = rusqlite::Error;

    fn connect(&self) -> Result<rusqlite::Connection, rusqlite::Error> {
        rusqlite::Connection::open_with_flags(&self.path, self.flags)
    }

    fn is_valid(&self, conn: &mut rusqlite::Connection) -> Result<(), rusqlite::Error> {
        // http://sqlite.org/pragma.html#pragma_schema_version
        conn.execute_batch("PRAGMA schema_verion")
    }

    fn has_broken(&self, conn: &mut rusqlite::Connection) -> bool {
        // pending transaction or at least one statement busy
        !conn.is_autocommit() || conn.is_busy()
    }
}

// http://sqlite.org/c3ref/db_release_memory.html
// http://sqlite.org/c3ref/interrupt.html
<commit_msg>Fix clippy warnings<commit_after>//! SQLite support for the `r2d2` connection pool.
#![warn(missing_docs)]
extern crate r2d2;
extern crate rusqlite;

use std::convert::Into;
use std::path::PathBuf;

/// An `r2d2::ManageConnection` for `rusqlite::SqliteConnection`s.
///
/// ## Example
///
/// ```rust
/// extern crate r2d2;
/// extern crate r2d2_sqlite;
/// extern crate rusqlite;
///
/// use std::sync::Arc;
/// use std::default::Default;
/// use std::thread;
/// use r2d2_sqlite::SQLiteConnectionManager;
/// use rusqlite::OpenFlags;
///
/// fn main() {
///     let manager = SQLiteConnectionManager::new(
///             "file:dummy.db?mode=memory&cache=shared",
///             OpenFlags::SQLITE_OPEN_URI | OpenFlags::SQLITE_OPEN_CREATE | OpenFlags::SQLITE_OPEN_READ_WRITE);
///     let pool = Arc::new(r2d2::Pool::new(manager).unwrap());
///
///     for i in 0..10i32 {
///         let pool = pool.clone();
///         thread::spawn(move || {
///             let conn = pool.get().unwrap();
///             conn.execute("PRAGMA user_version=?1", &[&i]).unwrap();
///         });
///     }
/// }
/// ```
pub struct SQLiteConnectionManager {
    path: PathBuf,
    flags: rusqlite::OpenFlags,
}

impl SQLiteConnectionManager {
    /// Creates a new `SQLiteConnectionManager`.
    ///
    /// See `rusqlite::SqliteConnection::open_with_flags` for a description of
    /// the parameter types.
    pub fn new<T>(path: T, flags: rusqlite::OpenFlags) -> SQLiteConnectionManager
    where
        T: Into<PathBuf>,
    {
        SQLiteConnectionManager {
            path: path.into(),
            flags,
        }
    }
}

impl r2d2::ManageConnection for SQLiteConnectionManager {
    type Connection = rusqlite::Connection;
    type Error = rusqlite::Error;

    fn connect(&self) -> Result<rusqlite::Connection, rusqlite::Error> {
        rusqlite::Connection::open_with_flags(&self.path, self.flags)
    }

    fn is_valid(&self, conn: &mut rusqlite::Connection) -> Result<(), rusqlite::Error> {
        // http://sqlite.org/pragma.html#pragma_schema_version
        conn.execute_batch("PRAGMA schema_verion")
    }

    fn has_broken(&self, conn: &mut rusqlite::Connection) -> bool {
        // pending transaction or at least one statement busy
        !conn.is_autocommit() || conn.is_busy()
    }
}

// http://sqlite.org/c3ref/db_release_memory.html
// http://sqlite.org/c3ref/interrupt.html
<|endoftext|>


<commit_before>#![feature(libc)]
#![feature(rustc_private)]

extern crate libc;
use libc::{c_int, c_ulong, c_void};

extern crate rustc_back;

use std::io::Error;

#[link(name = "c")]
extern {
    fn ioctl(fd : c_int, request : c_ulong, ...) -> c_int;
}

#[cfg(test)]
struct HotDataSupportingFixture {
    base_dir : std::path::PathBuf,
    fs_image_file : std::fs::File,
    fs_image_dir : std::path::PathBuf
}

#[cfg(test)]
impl Drop for HotDataSupportingFixture {
    fn drop(&mut self) {
        assert!(Command::new("sudo").arg("umount").arg(&self.base_dir.as_os_str()).status().is_ok());
        assert!(std::fs::remove_dir_all(&self.base_dir).is_ok());
        assert!(std::fs::remove_dir_all(&self.fs_image_dir).is_ok());
    }
}

use std::process::Command;

#[cfg(test)]
impl HotDataSupportingFixture {
    fn new() -> HotDataSupportingFixture {
        let tmpdir = rustc_back::tempdir::TempDir::new("hot-data-test").unwrap();
        let image_path = tmpdir.path().join("btrfs-image");
        let mount_dir = tmpdir.path().join("btrfs-mount-point");

        let image_file = std::fs::File::create(&image_path).unwrap();
        assert!(image_file.set_len(1024*1024*100).is_ok());
        assert!(image_file.sync_all().is_ok());

        assert!(std::fs::create_dir(&mount_dir).is_ok());

        assert!(Command::new("mkfs.btrfs").arg(&image_path.as_os_str()).status().is_ok());
        assert!(Command::new("sudo").arg("mount").arg(&image_path.as_os_str()).arg(&mount_dir.as_os_str()).status().is_ok());

        HotDataSupportingFixture { base_dir : mount_dir,
                                   fs_image_file : image_file,
                                   fs_image_dir : tmpdir.into_path() }
    }
}

#[test]
fn ioctl_binding_returns_error() {
    unsafe {
        let mut result = hot_data { live: 1,
                                    resv: [0,0,0],
                                    temp: 0,
                                    avg_delta_reads: 0,
                                    avg_delta_writes: 0,
                                    last_read_time: 0,
                                    last_write_time: 0,
                                    num_reads: 0,
                                    num_writes: 0,
                                    future: [0,0,0,0]};
        let ret = ioctl(33, 1, (&mut result as *mut _ as *mut c_void));
        assert!(ret != 0);
        // EBADF == 9
        assert_eq!(Error::last_os_error().raw_os_error().unwrap(), 9);
    }
}

#[repr(C)]
struct hot_data {
    live : u8,
    resv : [u8; 3],
    temp : u32,
    avg_delta_reads : u64,
    avg_delta_writes : u64,
    last_read_time : u64,
    last_write_time : u64,
    num_reads : u32,
    num_writes : u32,
    future : [u64; 4]
}
<commit_msg>Hacking<commit_after>#![feature(libc)]
#![feature(rustc_private)]

extern crate libc;
use libc::{c_int, c_ulong, c_void};

extern crate rustc_back;

use std::io::Error;
use std::result::Result;
use std::os::unix::io::AsRawFd;

#[link(name = "c")]
extern {
    fn ioctl(fd : c_int, request : c_ulong, ...) -> c_int;
}

const IOC_WRITE: i32 = 1;
const IOC_READ:  i32 = 2;

const IOC_NRBITS:   usize = 8;
const IOC_TYPEBITS: usize = 8;
const IOC_SIZEBITS: usize = 14;

const IOC_NRSHIFT:   usize = 0us;
const IOC_TYPESHIFT: usize = IOC_NRSHIFT   + IOC_NRBITS;
const IOC_SIZESHIFT: usize = IOC_TYPESHIFT + IOC_TYPEBITS;
const IOC_DIRSHIFT:  usize = IOC_SIZESHIFT + IOC_SIZEBITS;

#[inline]
pub fn ioc(dir: i32, ty: i32, nr: i32, size: i32) -> c_ulong {
    ((dir  << IOC_DIRSHIFT)  |
    (ty   << IOC_TYPESHIFT) |
    (nr   << IOC_NRSHIFT)   |
    (size << IOC_SIZESHIFT)) as c_ulong
}

fn get_hot_data(fd: c_int) -> Result<hot_data, Error> {
    let mut result = hot_data { live: 1,
                                resv: [0,0,0],
                                temp: 0,
                                avg_delta_reads: 0,
                                avg_delta_writes: 0,
                                last_read_time: 0,
                                last_write_time: 0,
                                num_reads: 0,
                                num_writes: 0,
                                future: [0,0,0,0]};
    unsafe {
        if ioctl(fd, ioc(IOC_READ, 'f' as i32, 17, std::mem::size_of::<hot_data>() as i32), &mut result) == 0
        {
            Ok(result)
        }
        else
        {
            Err(Error::last_os_error())
        }
    }
}

#[cfg(test)]
struct HotDataSupportingFixture {
    base_dir : std::path::PathBuf,
    fs_image_file : std::fs::File,
    fs_image_dir : std::path::PathBuf
}

#[cfg(test)]
impl Drop for HotDataSupportingFixture {
    fn drop(&mut self) {
        assert!(Command::new("sudo").arg("umount").arg(&self.base_dir.as_os_str()).status().is_ok());
        assert!(std::fs::remove_dir_all(&self.base_dir).is_ok());
        assert!(std::fs::remove_dir_all(&self.fs_image_dir).is_ok());
    }
}

#[cfg(test)]
use std::process::Command;

#[cfg(test)]
impl HotDataSupportingFixture {
    fn new_btrfs() -> HotDataSupportingFixture {
        let tmpdir = rustc_back::tempdir::TempDir::new("hot-data-test").unwrap();
        let image_path = tmpdir.path().join("btrfs-image");
        let mount_dir = tmpdir.path().join("btrfs-mount-point");

        let image_file = std::fs::File::create(&image_path).unwrap();
        assert!(image_file.set_len(1024*1024*100).is_ok());
        assert!(image_file.sync_all().is_ok());

        assert!(std::fs::create_dir(&mount_dir).is_ok());

        assert!(Command::new("mkfs.btrfs").arg(&image_path.as_os_str()).status().is_ok());
        assert!(Command::new("sudo").arg("mount").arg("-o").arg("hot_track").arg(&image_path.as_os_str()).arg(&mount_dir.as_os_str()).status().is_ok());
        assert!(Command::new("sudo").arg("chmod").arg("777").arg(&mount_dir.as_os_str()).status().is_ok());

        HotDataSupportingFixture { base_dir : mount_dir,
                                   fs_image_file : image_file,
                                   fs_image_dir : tmpdir.into_path() }
    }

    fn new_xfs() -> HotDataSupportingFixture {
        let tmpdir = rustc_back::tempdir::TempDir::new("hot-data-test").unwrap();
        let image_path = tmpdir.path().join("xfs-image");
        let mount_dir = tmpdir.path().join("xfs-mount-point");

        let image_file = std::fs::File::create(&image_path).unwrap();
        assert!(image_file.set_len(1024*1024*100).is_ok());
        assert!(image_file.sync_all().is_ok());

        assert!(std::fs::create_dir(&mount_dir).is_ok());

        assert!(Command::new("mkfs.xfs").arg(&image_path.as_os_str()).status().is_ok());
        assert!(Command::new("sudo").arg("mount").arg("-o").arg("hot_track").arg(&image_path.as_os_str()).arg(&mount_dir.as_os_str()).status().is_ok());
        assert!(Command::new("sudo").arg("chmod").arg("777").arg(&mount_dir.as_os_str()).status().is_ok());

        HotDataSupportingFixture { base_dir : mount_dir,
                                   fs_image_file : image_file,
                                   fs_image_dir : tmpdir.into_path() }
    }
}

#[test]
fn ioctl_binding_returns_error() {
    match get_hot_data(33) {
        Ok(_) => panic!("ioctl unexpectedly succeeded"),
        Err(e) => assert_eq!(e.raw_os_error().unwrap(), 9) // EBADF == 9
    }
}

#[test]
fn get_hot_data_returns_unsupported() {
    let test_file = std::fs::File::open("/home/chris/.zshrc").ok().unwrap();
    match get_hot_data(test_file.as_raw_fd()) {
        Ok(_) => panic!("Call unexpectedly succeeded"),
        Err(e) => assert_eq!(e.raw_os_error().unwrap(), 95) // ENOTSUP == 95
    }
}

#[test]
fn get_hot_data_returns_no_data() {
    let fixture = HotDataSupportingFixture::new_btrfs();

    let test_file = match std::fs::File::create(&fixture.base_dir.join("test")) {
        Ok(file) => file,
        Err(e) => panic!("Failed to create {:?}: {}", &fixture.base_dir.join("test"), e)
    };
    match get_hot_data(test_file.as_raw_fd()) {
        Ok(_) => panic!("Call unexpectedly succeeded"),
        Err(e) => assert_eq!(e.raw_os_error().unwrap(), 61) // ENODATA == 61
    }
}

#[test]
fn get_hot_data_returns_fault() {
    let fixture = HotDataSupportingFixture::new_btrfs();

    let test_file = match std::fs::File::create(&fixture.base_dir.join("test")) {
        Ok(file) => file,
        Err(e) => panic!("Failed to create {:?}: {}", &fixture.base_dir.join("test"), e)
    };

    unsafe {
        if ioctl(test_file.as_raw_fd(), ioc(IOC_READ, 'f' as i32, 17, std::mem::size_of::<hot_data>() as i32), 0) == 0
        {
            panic!("Call unexpectedly succeeded");
        }
        else
        {
            assert_eq!(Error::last_os_error().raw_os_error().unwrap(), 14) // EFAULT == 14
        }
    }
}

#[cfg(test)]
use std::io::Write;
#[cfg(test)]
use std::io::Read;

#[test]
fn get_hot_data_has_correct_read_write_count() {
    let fixture = HotDataSupportingFixture::new_xfs();
    let test_file_name = fixture.base_dir.join("test_file");

    {
        let mut test_file = match std::fs::File::create(&test_file_name) {
            Ok(file) => file,
            Err(e) => panic!("Failed to create {:?}: {}", &test_file_name, e)
        };
        match test_file.write_all(b"Hello, I'm a string") {
            Err(why) => panic!("Failed to write: {}", why),
            Ok(_) => {}
        }
        test_file.sync_all();
    }

    let mut hello = match std::fs::File::open(&test_file_name) {
        Ok(file) => file,
        Err(e) => panic!("Failed to open {:?}: {}", &test_file_name, e)
    };

    let mut data = String::new();
    match hello.read_to_string(&mut data) {
        Ok(_) => assert_eq!(data, "Hello, I'm a string"),
        Err(e) => panic!("Failed to read from {:?}: {}", &test_file_name, e)
    }

    let info = match get_hot_data(hello.as_raw_fd()) {
        Ok(x) => x,
        Err(why) => panic!("get_hot_data failed: {}", why)
    };

    assert_eq!(info.num_reads, 1);
    assert_eq!(info.num_writes, 1);
}

#[repr(C)]
struct hot_data {
    live : u8,
    resv : [u8; 3],
    temp : u32,
    avg_delta_reads : u64,
    avg_delta_writes : u64,
    last_read_time : u64,
    last_write_time : u64,
    num_reads : u32,
    num_writes : u32,
    future : [u64; 4]
}
<|endoftext|>


<commit_before>//! Edge is a Web framework that is simple to use, with the most common things
//! you need out of the box, and flexible, supporting both synchronous and asynchronous
//! request handling styles; see below for examples.
//!
//! The crate exports the things that you often need from dependencies, such as headers (from `hyper`),
//! cookies (from `cookie`) and JSON serialization (from `serde_json`).
//!
//! Please note that this is an early version, and the API is likely to evolve.
//!
//! ## Overview
//!
//! In Edge you must define an *application structure* that contains the state of your application.
//! You instantiate a container around this application, and associate GET/POST/... requests
//! with given URLs to methods of your application. The container handles the routing and
//! delegates calls to the appropriate methods.
//!
//! Note that the state cannot be mutated, as is usual in Rust (and enforced by the underlying HTTP server
//! this crate uses, a.k.a. Hyper). Use appropriate concurrent data structures if you need
//! shared mutable variables: locks, mutexes, channels, etc.
//!
//! ## Why another Web framework in Rust?
//!
//! Because I wanted a simple Web framework with:
//!
//!   1. everything I needed out of the box, like cookies and forms and templating, without having to dig up third-party crates,
//!   1. the possibility to describe my application as a struct, so that callbacks could use a state (even if just for configuration).
//!
//! We focus on integration rather than modularity.
//! I hope you like this crate, if it misses something to fit your needs just open an issue or make a pull request!
//!
//! And please keep in mind that the framework is in a (very) early stage :-)
//!
//! ## Hello World
//!
//! The most basic application: no state, a single page that prints Hello, world!
//!
//! ```no_run
//! extern crate edge;
//!
//! use edge::{Edge, Request, Response};
//!
//! struct Hello;
//! impl Hello {
//!     fn hello(&self, _req: &mut Request, mut res: Response) {
//!         res.content_type("text/plain");
//!         res.send("Hello, world!")
//!     }
//! }
//!
//! fn main() {
//!     let mut edge = Edge::new("0.0.0.0:3000", Hello);
//!     edge.get("/", Hello::hello);
//!     edge.start().unwrap();
//! }
//! ```
//!
//! ## Asynchronous handling
//!
//! Under the hood, Edge uses the asynchronous version of Hyper. This means that to get the maximum
//! performance, you should avoid waiting in a handler, so that other requests
//! can be served as soon as possible. In that example, the handler waits in a separate thread before sending
//! the response.
//!
//! ```no_run
//! extern crate edge;
//!
//! use edge::{Edge, Request, Response};
//! use std::thread;
//! use std::time::Duration;
//!
//! struct AsyncHello;
//! impl AsyncHello {
//!     fn hello(&self, _req: &mut Request, mut res: Response) {
//!         thread::spawn(move || {
//!             println!("waiting 1 second");
//!             thread::sleep(Duration::from_secs(1));
//!
//!             res.content_type("text/plain");
//!             res.send("Hello, world!")
//!         });
//!
//!         // the handler returns immediately without waiting for the thread
//!     }
//! }
//!
//! fn main() {
//!     let mut edge = Edge::new("0.0.0.0:3000", AsyncHello);
//!     edge.get("/", AsyncHello::hello);
//!     edge.start().unwrap();
//! }
//! ```
//!
//! ## Templating
//!
//! Here our application has a version, still a single handler except this time
//! it accepts any page name, and renders a Handlebars template.  We're also
//! setting a custom Server header.
//!
//! ```no_run
//! extern crate edge;
//!
//! use edge::{Edge, Request, Response, Status};
//! use edge::header::Server;
//! use std::collections::BTreeMap;
//!
//! struct Templating {
//!     version: &'static str
//! }
//!
//! impl Templating {
//!     fn page_handler(&self, req: &mut Request, mut res: Response) {
//!         let mut data = BTreeMap::new();
//!         data.insert("title", req.param("page").unwrap());
//!         data.insert("version", self.version);
//!
//!         res.content_type("text/html").header(Server(format!("Edge version {}", self.version)));
//!         res.render("tmpl", data)
//!     }
//! }
//!
//! fn main() {
//!     let app = Templating { version: "0.1" };
//!     let mut edge = Edge::new("0.0.0.0:3000", app);
//!     edge.get("/:page", Templating::page_handler);
//!     edge.register_template("tmpl");
//!     edge.start().unwrap();
//! }
//! ```
//!
//! ## Using a shared mutable counter
//!
//! In this example, we use an atomic integer to track a counter. This shows a very basic
//! kind of shared state for a handler. In practice, it's best to avoid using blocking
//! mechanisms (locks, mutexes) in a handler directly. Prefer non-blocking calls,
//! like channels' try_recv, or move blocking code in a separate thread,
//! see the example for asynchronous handling above.
//!
//! ```no_run
//! extern crate edge;
//!
//! use edge::{Edge, Request, Response, Status};
//! use std::sync::atomic::{AtomicUsize, Ordering};
//!
//! struct Counting {
//!     counter: AtomicUsize
//! }
//!
//! impl Counting {
//!     fn new() -> Counting { Counting { counter: AtomicUsize::new(0) } }
//!
//!     fn home(&self, _req: &mut Request, mut res: Response) {
//!         let visits = self.counter.load(Ordering::Relaxed);
//!         self.counter.store(visits + 1, Ordering::Relaxed);
//!
//!         res.status(Status::Ok).content_type("text/plain");
//!         res.send(format!("Hello, world! {} visits", visits))
//!     }
//! }
//!
//! fn main() {
//!     let mut cter = Edge::new("0.0.0.0:3000", Counting::new());
//!     cter.get("/", Counting::home);
//!     cter.start().unwrap();
//! }
//! ```

extern crate crossbeam;
extern crate handlebars;
extern crate hyper;
extern crate num_cpus;
extern crate pulldown_cmark;
extern crate scoped_pool;
extern crate serde;
extern crate url;

#[macro_use]
extern crate log;
pub extern crate serde_json;

pub use hyper::header as header;
pub use header::CookiePair as Cookie;
pub use hyper::status::StatusCode as Status;

/// serde_json crate
pub use serde_json as json;

use handlebars::{Context, Handlebars, Helper, RenderContext, RenderError};

use hyper::net::HttpListener;
use hyper::server::Server;

use pulldown_cmark::Parser;
use pulldown_cmark::{Options, OPTION_ENABLE_TABLES, OPTION_ENABLE_FOOTNOTES};
use pulldown_cmark::html;

use scoped_pool::Pool;

use url::Url;

use std::fs::read_dir;
use std::io::Result as IoResult;
use std::net::ToSocketAddrs;
use std::path::{Path, PathBuf};

mod buffer;
mod client;
mod handler;
mod router;
mod request;
mod response;

pub use client::Client;
pub use request::Request;
pub use response::{Response, Streaming};
pub use router::{Router};

/// Structure for an Edge application.
pub struct Edge {
    base_url: Url,
    routers: Vec<router::RouterAny>,
    handlebars: Handlebars
}

impl Edge {

    /// Creates an Edge application using the given address and application.
    pub fn new(addr: &str) -> Edge {
        let mut handlebars = Handlebars::new();
        init_handlebars(&mut handlebars).unwrap();

        Edge {
            base_url: Url::parse(&("http://".to_string() + addr)).unwrap(),
            routers: Vec::new(),
            handlebars: handlebars
        }
    }

    /// Mounts the given router at the given path.
    ///
    /// Use "/" to mount the router at the root.
    pub fn mount<T>(&mut self, mount: &str, router: Router<T>) {
        let mut router = router::get_inner(router);
        router.set_prefix(mount);
        self.routers.push(router)
    }

    // Registers a template with the given name.
    pub fn register_template(&mut self, name: &str) {
        let mut path = PathBuf::new();
        path.push("views");
        path.push(name);
        path.set_extension("hbs");

        self.handlebars.register_template_file(name, &path).unwrap();
    }

    /// Runs the server in one thread per cpu.
    ///
    /// Creates one instance of `T` per request by calling `Default::default`.
    /// This method blocks the current thread.
    pub fn start(&mut self) -> IoResult<()> {
        assert!(!self.routers.is_empty(), "No router registered! Please mount at least one router");

        // get address and start listening
        let addr = self.base_url.to_socket_addrs().unwrap().next().unwrap();
        let listener = HttpListener::bind(&addr).unwrap();

        // 50% threads for the pool, 50% for the listeners
        let num_threads = ::std::cmp::max(num_cpus::get() / 2, 1);
        let pool = Pool::new(num_threads);
        pool.scoped(|pool_scope| {
            crossbeam::scope(|scope| {
                for i in 0..num_threads {
                    let listener = listener.try_clone().unwrap();
                    let base_url = &self.base_url;
                    let routers = &self.routers;
                    let handlebars = &self.handlebars;
                    scope.spawn(move || {
                        info!("thread {} listening on http://{}", i, addr);
                        Server::new(listener).handle(move |control| {
                            handler::EdgeHandler::new(pool_scope, &base_url, &routers, &handlebars, control)
                        }).unwrap();
                    });
                }
            });
        });

        Ok(())
    }
}

fn render_html(text: &str) -> String {
    let mut opts = Options::empty();
    opts.insert(OPTION_ENABLE_TABLES);
    opts.insert(OPTION_ENABLE_FOOTNOTES);

    let mut s = String::with_capacity(text.len() * 3 / 2);
    let p = Parser::new_ext(text, opts);
    html::push_html(&mut s, p);
    s
}

/// this code is based on code Copyright (c) 2015 Wayne Nilsen
/// see https://github.com/waynenilsen/handlebars-markdown-helper/blob/master/src/lib.rs#L31
///
/// because the handlebars-markdown-helper crate does not allow custom options for Markdown rendering yet
fn markdown_helper(_: &Context, h: &Helper, _ : &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
    let markdown_text_var = try!(h.param(0).ok_or_else(|| RenderError::new(
        "Param not found for helper \"markdown\"")
    ));
    let markdown = try!(markdown_text_var.value().as_string().ok_or_else(||
        RenderError::new(format!("Expected a string for parameter {:?}", markdown_text_var))
    ));
    let html = render_html(markdown);
    try!(rc.writer.write_all(html.as_bytes()));
    Ok(())
}

fn init_handlebars(handlebars: &mut Handlebars) -> IoResult<()> {
    // register markdown helper
    handlebars.register_helper("markdown", Box::new(::markdown_helper));

    // register partials folder (if it exists)
    let partials = Path::new("views/partials");
    if partials.exists() {
        for it in try!(read_dir("views/partials")) {
            let entry = try!(it);
            let path = entry.path();
            if path.extension().is_some() && path.extension().unwrap() == "hbs" {
                let name = path.file_stem().unwrap().to_str().unwrap();
                handlebars.register_template_file(name, path.as_path()).unwrap();
            }
        }
    }

    Ok(())
}
<commit_msg>export handler error type<commit_after>//! Edge is a Web framework that is simple to use, with the most common things
//! you need out of the box, and flexible, supporting both synchronous and asynchronous
//! request handling styles; see below for examples.
//!
//! The crate exports the things that you often need from dependencies, such as headers (from `hyper`),
//! cookies (from `cookie`) and JSON serialization (from `serde_json`).
//!
//! Please note that this is an early version, and the API is likely to evolve.
//!
//! ## Overview
//!
//! In Edge you must define an *application structure* that contains the state of your application.
//! You instantiate a container around this application, and associate GET/POST/... requests
//! with given URLs to methods of your application. The container handles the routing and
//! delegates calls to the appropriate methods.
//!
//! Note that the state cannot be mutated, as is usual in Rust (and enforced by the underlying HTTP server
//! this crate uses, a.k.a. Hyper). Use appropriate concurrent data structures if you need
//! shared mutable variables: locks, mutexes, channels, etc.
//!
//! ## Why another Web framework in Rust?
//!
//! Because I wanted a simple Web framework with:
//!
//!   1. everything I needed out of the box, like cookies and forms and templating, without having to dig up third-party crates,
//!   1. the possibility to describe my application as a struct, so that callbacks could use a state (even if just for configuration).
//!
//! We focus on integration rather than modularity.
//! I hope you like this crate, if it misses something to fit your needs just open an issue or make a pull request!
//!
//! And please keep in mind that the framework is in a (very) early stage :-)
//!
//! ## Hello World
//!
//! The most basic application: no state, a single page that prints Hello, world!
//!
//! ```no_run
//! extern crate edge;
//!
//! use edge::{Edge, Request, Response};
//!
//! struct Hello;
//! impl Hello {
//!     fn hello(&self, _req: &mut Request, mut res: Response) {
//!         res.content_type("text/plain");
//!         res.send("Hello, world!")
//!     }
//! }
//!
//! fn main() {
//!     let mut edge = Edge::new("0.0.0.0:3000", Hello);
//!     edge.get("/", Hello::hello);
//!     edge.start().unwrap();
//! }
//! ```
//!
//! ## Asynchronous handling
//!
//! Under the hood, Edge uses the asynchronous version of Hyper. This means that to get the maximum
//! performance, you should avoid waiting in a handler, so that other requests
//! can be served as soon as possible. In that example, the handler waits in a separate thread before sending
//! the response.
//!
//! ```no_run
//! extern crate edge;
//!
//! use edge::{Edge, Request, Response};
//! use std::thread;
//! use std::time::Duration;
//!
//! struct AsyncHello;
//! impl AsyncHello {
//!     fn hello(&self, _req: &mut Request, mut res: Response) {
//!         thread::spawn(move || {
//!             println!("waiting 1 second");
//!             thread::sleep(Duration::from_secs(1));
//!
//!             res.content_type("text/plain");
//!             res.send("Hello, world!")
//!         });
//!
//!         // the handler returns immediately without waiting for the thread
//!     }
//! }
//!
//! fn main() {
//!     let mut edge = Edge::new("0.0.0.0:3000", AsyncHello);
//!     edge.get("/", AsyncHello::hello);
//!     edge.start().unwrap();
//! }
//! ```
//!
//! ## Templating
//!
//! Here our application has a version, still a single handler except this time
//! it accepts any page name, and renders a Handlebars template.  We're also
//! setting a custom Server header.
//!
//! ```no_run
//! extern crate edge;
//!
//! use edge::{Edge, Request, Response, Status};
//! use edge::header::Server;
//! use std::collections::BTreeMap;
//!
//! struct Templating {
//!     version: &'static str
//! }
//!
//! impl Templating {
//!     fn page_handler(&self, req: &mut Request, mut res: Response) {
//!         let mut data = BTreeMap::new();
//!         data.insert("title", req.param("page").unwrap());
//!         data.insert("version", self.version);
//!
//!         res.content_type("text/html").header(Server(format!("Edge version {}", self.version)));
//!         res.render("tmpl", data)
//!     }
//! }
//!
//! fn main() {
//!     let app = Templating { version: "0.1" };
//!     let mut edge = Edge::new("0.0.0.0:3000", app);
//!     edge.get("/:page", Templating::page_handler);
//!     edge.register_template("tmpl");
//!     edge.start().unwrap();
//! }
//! ```
//!
//! ## Using a shared mutable counter
//!
//! In this example, we use an atomic integer to track a counter. This shows a very basic
//! kind of shared state for a handler. In practice, it's best to avoid using blocking
//! mechanisms (locks, mutexes) in a handler directly. Prefer non-blocking calls,
//! like channels' try_recv, or move blocking code in a separate thread,
//! see the example for asynchronous handling above.
//!
//! ```no_run
//! extern crate edge;
//!
//! use edge::{Edge, Request, Response, Status};
//! use std::sync::atomic::{AtomicUsize, Ordering};
//!
//! struct Counting {
//!     counter: AtomicUsize
//! }
//!
//! impl Counting {
//!     fn new() -> Counting { Counting { counter: AtomicUsize::new(0) } }
//!
//!     fn home(&self, _req: &mut Request, mut res: Response) {
//!         let visits = self.counter.load(Ordering::Relaxed);
//!         self.counter.store(visits + 1, Ordering::Relaxed);
//!
//!         res.status(Status::Ok).content_type("text/plain");
//!         res.send(format!("Hello, world! {} visits", visits))
//!     }
//! }
//!
//! fn main() {
//!     let mut cter = Edge::new("0.0.0.0:3000", Counting::new());
//!     cter.get("/", Counting::home);
//!     cter.start().unwrap();
//! }
//! ```

extern crate crossbeam;
extern crate handlebars;
extern crate hyper;
extern crate num_cpus;
extern crate pulldown_cmark;
extern crate scoped_pool;
extern crate serde;
extern crate url;

#[macro_use]
extern crate log;
pub extern crate serde_json;

pub use hyper::header as header;
pub use header::CookiePair as Cookie;
pub use hyper::status::StatusCode as Status;

/// serde_json crate
pub use serde_json as json;

use handlebars::{Context, Handlebars, Helper, RenderContext, RenderError};

use hyper::net::HttpListener;
use hyper::server::Server;

use pulldown_cmark::Parser;
use pulldown_cmark::{Options, OPTION_ENABLE_TABLES, OPTION_ENABLE_FOOTNOTES};
use pulldown_cmark::html;

use scoped_pool::Pool;

use url::Url;

use std::fs::read_dir;
use std::io::Result as IoResult;
use std::net::ToSocketAddrs;
use std::path::{Path, PathBuf};

mod buffer;
mod client;
mod handler;
mod router;
mod request;
mod response;

pub use client::Client;
pub use request::Request;
pub use response::{Response, Streaming, HandlerError};
pub use router::{Router};

/// Structure for an Edge application.
pub struct Edge {
    base_url: Url,
    routers: Vec<router::RouterAny>,
    handlebars: Handlebars
}

impl Edge {

    /// Creates an Edge application using the given address and application.
    pub fn new(addr: &str) -> Edge {
        let mut handlebars = Handlebars::new();
        init_handlebars(&mut handlebars).unwrap();

        Edge {
            base_url: Url::parse(&("http://".to_string() + addr)).unwrap(),
            routers: Vec::new(),
            handlebars: handlebars
        }
    }

    /// Mounts the given router at the given path.
    ///
    /// Use "/" to mount the router at the root.
    pub fn mount<T>(&mut self, mount: &str, router: Router<T>) {
        let mut router = router::get_inner(router);
        router.set_prefix(mount);
        self.routers.push(router)
    }

    // Registers a template with the given name.
    pub fn register_template(&mut self, name: &str) {
        let mut path = PathBuf::new();
        path.push("views");
        path.push(name);
        path.set_extension("hbs");

        self.handlebars.register_template_file(name, &path).unwrap();
    }

    /// Runs the server in one thread per cpu.
    ///
    /// Creates one instance of `T` per request by calling `Default::default`.
    /// This method blocks the current thread.
    pub fn start(&mut self) -> IoResult<()> {
        assert!(!self.routers.is_empty(), "No router registered! Please mount at least one router");

        // get address and start listening
        let addr = self.base_url.to_socket_addrs().unwrap().next().unwrap();
        let listener = HttpListener::bind(&addr).unwrap();

        // 50% threads for the pool, 50% for the listeners
        let num_threads = ::std::cmp::max(num_cpus::get() / 2, 1);
        let pool = Pool::new(num_threads);
        pool.scoped(|pool_scope| {
            crossbeam::scope(|scope| {
                for i in 0..num_threads {
                    let listener = listener.try_clone().unwrap();
                    let base_url = &self.base_url;
                    let routers = &self.routers;
                    let handlebars = &self.handlebars;
                    scope.spawn(move || {
                        info!("thread {} listening on http://{}", i, addr);
                        Server::new(listener).handle(move |control| {
                            handler::EdgeHandler::new(pool_scope, &base_url, &routers, &handlebars, control)
                        }).unwrap();
                    });
                }
            });
        });

        Ok(())
    }
}

fn render_html(text: &str) -> String {
    let mut opts = Options::empty();
    opts.insert(OPTION_ENABLE_TABLES);
    opts.insert(OPTION_ENABLE_FOOTNOTES);

    let mut s = String::with_capacity(text.len() * 3 / 2);
    let p = Parser::new_ext(text, opts);
    html::push_html(&mut s, p);
    s
}

/// this code is based on code Copyright (c) 2015 Wayne Nilsen
/// see https://github.com/waynenilsen/handlebars-markdown-helper/blob/master/src/lib.rs#L31
///
/// because the handlebars-markdown-helper crate does not allow custom options for Markdown rendering yet
fn markdown_helper(_: &Context, h: &Helper, _ : &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
    let markdown_text_var = try!(h.param(0).ok_or_else(|| RenderError::new(
        "Param not found for helper \"markdown\"")
    ));
    let markdown = try!(markdown_text_var.value().as_string().ok_or_else(||
        RenderError::new(format!("Expected a string for parameter {:?}", markdown_text_var))
    ));
    let html = render_html(markdown);
    try!(rc.writer.write_all(html.as_bytes()));
    Ok(())
}

fn init_handlebars(handlebars: &mut Handlebars) -> IoResult<()> {
    // register markdown helper
    handlebars.register_helper("markdown", Box::new(::markdown_helper));

    // register partials folder (if it exists)
    let partials = Path::new("views/partials");
    if partials.exists() {
        for it in try!(read_dir("views/partials")) {
            let entry = try!(it);
            let path = entry.path();
            if path.extension().is_some() && path.extension().unwrap() == "hbs" {
                let name = path.file_stem().unwrap().to_str().unwrap();
                handlebars.register_template_file(name, path.as_path()).unwrap();
            }
        }
    }

    Ok(())
}
<|endoftext|>