<commit_before>//! This module implements a simple asset loader and cache.
//!
//! While ggez offers functions to load raw game assets such as
//! music files, images, etc, it provides no facilities for managing
//! them.  Ideally you want to load all the assets you need at once,
//! hold on to them for a time (the course of a level for instance),
//! and then potentially ditch the ones you don't need.
//! This module offers cache-like functionality to do exactly this.
//!
//! It will return an `Rc` containing the item loaded, so multiple
//! items can safely access (read-only) instances of the same asset.
//! (In the same thread, at least.)
//!
//! What it does NOT do is allow you to free individual assets from
//! the cache.  This is on purpose.  If you want fine-grained manual
//! memory management you know where to get it.  This is more a memory
//! pool like thing where you allocate a bunch of objects, keep them
//! around for however long you need them (while the game is loaded,
//! while a particular scene is loaded, etc), and then free them all.
//!
//! If you want to make a stack of asset managers, where one
//! has access to the assets higher up in the stack...
//! Just build one and clone it.  All the Rc's in it will get
//! cloned along with it, providing exactly the behavior you
//! want except better.  :D
//!
//! Though whether or not asset handles from the old one will be valid
//! with the new one... hmmm.  That might not be a big problem since we
//! can just request new asset handles from the new cache and they'll already
//! be there, so that might be the way to go?

// TODO: This is not thread safe; should we offer one that it?
// TODO: Check out calx-resource:
// https://github.com/rsaarelm/calx/blob/master/calx-resource/src/lib.rs
// It has a) nifty macros to build these automatically,
// and b) an asset type that will serialize to a key, and then
// deserialize the key to that asset.  Very neat!  But also
// a bit labyrenthine.
// It DOES also make thread-safety work through thread_local!().

use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::fmt::Debug;
use std::path::Path;
use std::rc::Rc;
use ggez;
use ggez::{Context, GameError, GameResult};
use ggez::graphics;

pub trait Loadable<K, E> {
    fn load(_key: &K) -> Result<Self, E> where Self: Sized;
}

pub trait StateLoadable<K, E, S> {
    fn load_state(_key: &K, &mut S) -> Result<Self, E> where Self: Sized;
}

use std::marker::PhantomData;

/// An opaque asset handle that can be used for O(1) fetches
/// of assets.
// TODO: Add a UUID or something to this....
#[derive(Debug)]
pub struct Handle<T> {
    idx: usize,
    _phantom: PhantomData<*const T>,
}

impl<T> Copy for Handle<T> {}

impl<T> Clone for Handle<T> {
    fn clone(&self) -> Self {
        Handle {
            idx: self.idx,
            _phantom: PhantomData,
        }
    }
}

// We COULD use a generic interning crate such as symtern or symbol-map to
// implement the Handle -> Asset map here.  It might be useful.
// But it wouldn't get us all the way because we'd still need to maintain
// the Key -> Handle association ourselves.
#[derive(Debug, Clone)]
pub struct AssetCache<K, V>
    where K: Ord + Clone + Debug
{
    handles: Vec<Rc<V>>,
    keys: BTreeMap<K, Handle<V>>,
    next_handle: usize,
}

impl<K, V> AssetCache<K, V>
    where K: Ord + Clone + Debug
{
    /// Creates a new `AssetCache` that loads assets
    /// when necessary with the given loader function.
    pub fn new() -> Self {
        AssetCache {
            handles: Vec::new(),
            keys: BTreeMap::new(),
            next_handle: 0,
        }
    }

    fn new_handle(&mut self) -> Handle<V> {
        let i = self.next_handle;
        self.next_handle += 1;
        Handle {
            idx: i,
            _phantom: PhantomData,
        }
    }

    // Inserts the given asset into the handles vec at the given
    // location, and inserts the key into the key->handle mapping.
    // Performs asserts that will panic if something
    // gets out of sync (which should be impossible).
    fn bind_handle(&mut self, key: K, h: Handle<V>, value: Rc<V>) {
        assert!(h.idx == self.handles.len());
        self.handles.push(value);

        assert!(!self.keys.contains_key(&key));
        self.keys.insert(key, h);
    }

    // Adds a new item to the cache, returns an Rc reference to it
    // and an Handle.
    fn add_item(&mut self, key: K, value: V) -> (Handle<V>, Rc<V>) {
        let handle = self.new_handle();
        let rc = Rc::new(value);
        self.bind_handle(key, handle, rc.clone());
        (handle, rc)
    }

    /// Retrieves an asset via its handle.
    /// This is always safe (and fast) because for a handle
    /// to be valid its object *must* exist in the cache.
    pub fn get(&self, handle: Handle<V>) -> Rc<V> {
        assert!(handle.idx < self.handles.len());
        self.handles[handle.idx].clone()
    }

    /// Not sure this is even right, but...
    pub fn get_mut<'a>(&'a mut self, handle: Handle<V>) -> Option<&'a mut V> {
        assert!(handle.idx < self.handles.len());
        use std::rc::Rc;
        Rc::get_mut(&mut self.handles[handle.idx])
    }

    // fn add_item_mut(&mut self, key: K, value: &mut V) -> (Handle, Rc<&mut V>) {
    //     let handle = self.new_handle();
    //     let entry = self.entry(key.clone());
    //     match entry {
    //         Entry::Vacant(e) => {
    //             let v = V::load(key)?;
    //             let v_rc = Rc::new(v);
    //             Ok(e.insert(v_rc));
    //             Ok(self.add_item(key.clone(), v));
    //         }
    //         Entry::Occupied(e) => Ok(e.into_mut()),
    //     }

    // }

    /// Gets the given asset, loading it if necessary.
    /// Returns an Rc to the value, plus an Handle
    /// which can be used to retrieve it quickly.
    // Oh my goodness getting the E type param to the
    // right place was amazingly difficult.
    pub fn get_key<E>(&mut self, key: &K) -> Result<(Handle<V>, Rc<V>), E>
        where V: Loadable<K, E>
    {
        if let Some(handle) = self.keys.get(key) {
            return Ok((*handle, self.get(*handle)));
        };

        let v = V::load(key)?;
        let res = self.add_item(key.clone(), v);
        Ok(res)
    }

    // pub fn get_mut<E, S>(&mut self, key: &K) -> Result<&mut Rc<V>, E>
    //     where V: Loadable<K, E>
    // {
    //     // entry.or_insert_with() isn't quite powerful
    //     // enough 'cause it doesn't propegate Results.  ;_;
    //     let entry = self.contents.entry(key.clone());
    //     match entry {
    //         Entry::Vacant(e) => {
    //             let v = V::load(key)?;
    //             let v_rc = Rc::new(v);
    //             Ok(e.insert(v_rc));
    //             Ok(self.add_item(key.clone(), v));
    //         }
    //         Entry::Occupied(e) => Ok(e.into_mut()),
    //     }
    // }

    /// Gets the given asset, loading it with a state object if necessary.
    pub fn get_key_state<E, S>(&mut self, key: &K, state: &mut S) -> Result<(Handle<V>, Rc<V>), E>
        where V: StateLoadable<K, E, S>
    {
        if let Some(handle) = self.keys.get(key) {
            return Ok((*handle, self.get(*handle)));
        };

        let v = V::load_state(key, state)?;
        let res = self.add_item(key.clone(), v);
        Ok(res)
    }

    // /// Removes all assets from the cache
    // /// and frees any excess memory it uses.
    // /// This is now unsafe because it introduces the possibility
    // /// of dangling handles!  We can have a stack of bindings, kinda,
    // /// to manage this.  (Or just create/delete new state objects.)
    // pub fn clear(&mut self) {
    //     let map = BTreeMap::new();
    //     self.contents = map;
    // }

    /// Returns true if the given asset is loaded.
    pub fn loaded(&self, key: &K) -> bool {
        self.keys.contains_key(key)
    }

    /// Takes a slice containing a list of keys,
    /// and loads all the keys so that their objects
    /// are immediately accessible.
    pub fn preload<E>(&mut self, keys: &[K])
        where V: Loadable<K, E>
    {
        for k in keys {
            let _ = self.get_key(k);
        }
    }

    /// Preloads objects that require a state to load.
    pub fn preload_state<E, S>(&mut self, keys: &[K], state: &mut S)
        where V: StateLoadable<K, E, S>
    {
        for k in keys {
            let _ = self.get_key_state(k, state);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    impl<'a> Loadable<&'a str, ()> for String {
        fn load(key: &&str) -> Result<String, ()> {
            Ok(key.to_string())
        }
    }

    impl<'a> StateLoadable<&'a str, (), i32> for String {
        fn load_state(key: &&str, state: &mut i32) -> Result<String, ()> {
            *state += 1;
            Ok(key.to_string())
        }
    }

    #[test]
    fn test_assetcache() {
        let mut a = AssetCache::<&str, String>::new();
        {
            assert!(!a.loaded(&"foo"));
            let (handle, s1) = a.get_key(&"foo").unwrap();
            assert!(a.loaded(&"foo"));
            assert_eq!(*s1, "foo");
            let gotten_with_handle = a.get(handle);
            assert_eq!(*s1, *gotten_with_handle);
        }
    }

    #[test]
    fn test_stateful_assetcache() {
        let mut a = AssetCache::<&str, String>::new();
        {
            let s = &mut 10;
            assert!(!a.loaded(&"foo"));
            let (handle, s1) = a.get_key_state(&"foo", s).unwrap();
            assert_eq!(*s1, "foo");
            assert_eq!(*s, 11);
            assert!(a.loaded(&"foo"));

            let gotten_with_handle = a.get(handle);
            assert_eq!(*s1, *gotten_with_handle);
            assert_eq!(*s, 11);

        }

    }

    #[test]
    fn test_mut_assetcache() {
        let mut a = AssetCache::<&str, String>::new();
        assert!(!a.loaded(&"foo"));
        let (h, _) = a.get_key(&"foo").unwrap();

        {
            let mut_value = a.get_mut(h.clone());
            assert!(mut_value.is_some());
            let m = mut_value.unwrap();
            assert_eq!("foo", *m);
            *m += "Foobaz";
            assert_eq!("fooFoobaz", *m);
        }
        // Now get it again and ensure it's mutated.
        {
            let mut_value = a.get_mut(h.clone());
            assert!(mut_value.is_some());
            let m = mut_value.unwrap();
            assert_eq!("fooFoobaz", *m);
        }

    }
}
<commit_msg>Switched asset BTreeMap to HashMap<commit_after>//! This module implements a simple asset loader and cache.
//!
//! While ggez offers functions to load raw game assets such as
//! music files, images, etc, it provides no facilities for managing
//! them.  Ideally you want to load all the assets you need at once,
//! hold on to them for a time (the course of a level for instance),
//! and then potentially ditch the ones you don't need.
//! This module offers cache-like functionality to do exactly this.
//!
//! It will return an `Rc` containing the item loaded, so multiple
//! items can safely access (read-only) instances of the same asset.
//! (In the same thread, at least.)
//!
//! What it does NOT do is allow you to free individual assets from
//! the cache.  This is on purpose.  If you want fine-grained manual
//! memory management you know where to get it.  This is more a memory
//! pool like thing where you allocate a bunch of objects, keep them
//! around for however long you need them (while the game is loaded,
//! while a particular scene is loaded, etc), and then free them all.
//!
//! If you want to make a stack of asset managers, where one
//! has access to the assets higher up in the stack...
//! Just build one and clone it.  All the Rc's in it will get
//! cloned along with it, providing exactly the behavior you
//! want except better.  :D
//!
//! Though whether or not asset handles from the old one will be valid
//! with the new one... hmmm.  That might not be a big problem since we
//! can just request new asset handles from the new cache and they'll already
//! be there, so that might be the way to go?

// TODO: This is not thread safe; should we offer one that it?
// TODO: Check out calx-resource:
// https://github.com/rsaarelm/calx/blob/master/calx-resource/src/lib.rs
// It has a) nifty macros to build these automatically,
// and b) an asset type that will serialize to a key, and then
// deserialize the key to that asset.  Very neat!  But also
// a bit labyrenthine.
// It DOES also make thread-safety work through thread_local!().

use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::fmt::Debug;
use std::path::Path;
use std::rc::Rc;
use std::hash::Hash;
use ggez;
use ggez::{Context, GameError, GameResult};
use ggez::graphics;

pub trait Loadable<K, E> {
    fn load(_key: &K) -> Result<Self, E> where Self: Sized;
}

pub trait StateLoadable<K, E, S> {
    fn load_state(_key: &K, &mut S) -> Result<Self, E> where Self: Sized;
}

use std::marker::PhantomData;

/// An opaque asset handle that can be used for O(1) fetches
/// of assets.
// TODO: Add a UUID or something to this....
#[derive(Debug)]
pub struct Handle<T> {
    idx: usize,
    _phantom: PhantomData<*const T>,
}

impl<T> Copy for Handle<T> {}

impl<T> Clone for Handle<T> {
    fn clone(&self) -> Self {
        Handle {
            idx: self.idx,
            _phantom: PhantomData,
        }
    }
}

// We COULD use a generic interning crate such as symtern or symbol-map to
// implement the Handle -> Asset map here.  It might be useful.
// But it wouldn't get us all the way because we'd still need to maintain
// the Key -> Handle association ourselves.
#[derive(Debug, Clone)]
pub struct AssetCache<K, V>
    where K: Hash + Eq + Clone + Debug
{
    handles: Vec<Rc<V>>,
    keys: HashMap<K, Handle<V>>,
    next_handle: usize,
}

impl<K, V> AssetCache<K, V>
    where K: Hash + Eq + Clone + Debug
{
    /// Creates a new `AssetCache` that loads assets
    /// when necessary with the given loader function.
    pub fn new() -> Self {
        AssetCache {
            handles: Vec::new(),
            keys: HashMap::new(),
            next_handle: 0,
        }
    }

    fn new_handle(&mut self) -> Handle<V> {
        let i = self.next_handle;
        self.next_handle += 1;
        Handle {
            idx: i,
            _phantom: PhantomData,
        }
    }

    // Inserts the given asset into the handles vec at the given
    // location, and inserts the key into the key->handle mapping.
    // Performs asserts that will panic if something
    // gets out of sync (which should be impossible).
    fn bind_handle(&mut self, key: K, h: Handle<V>, value: Rc<V>) {
        assert!(h.idx == self.handles.len());
        self.handles.push(value);

        assert!(!self.keys.contains_key(&key));
        self.keys.insert(key, h);
    }

    // Adds a new item to the cache, returns an Rc reference to it
    // and an Handle.
    fn add_item(&mut self, key: K, value: V) -> (Handle<V>, Rc<V>) {
        let handle = self.new_handle();
        let rc = Rc::new(value);
        self.bind_handle(key, handle, rc.clone());
        (handle, rc)
    }

    /// Retrieves an asset via its handle.
    /// This is always safe (and fast) because for a handle
    /// to be valid its object *must* exist in the cache.
    pub fn get(&self, handle: Handle<V>) -> Rc<V> {
        assert!(handle.idx < self.handles.len());
        self.handles[handle.idx].clone()
    }

    /// Not sure this is even right, but...
    pub fn get_mut<'a>(&'a mut self, handle: Handle<V>) -> Option<&'a mut V> {
        assert!(handle.idx < self.handles.len());
        use std::rc::Rc;
        Rc::get_mut(&mut self.handles[handle.idx])
    }

    // fn add_item_mut(&mut self, key: K, value: &mut V) -> (Handle, Rc<&mut V>) {
    //     let handle = self.new_handle();
    //     let entry = self.entry(key.clone());
    //     match entry {
    //         Entry::Vacant(e) => {
    //             let v = V::load(key)?;
    //             let v_rc = Rc::new(v);
    //             Ok(e.insert(v_rc));
    //             Ok(self.add_item(key.clone(), v));
    //         }
    //         Entry::Occupied(e) => Ok(e.into_mut()),
    //     }

    // }

    /// Gets the given asset, loading it if necessary.
    /// Returns an Rc to the value, plus an Handle
    /// which can be used to retrieve it quickly.
    // Oh my goodness getting the E type param to the
    // right place was amazingly difficult.
    pub fn get_key<E>(&mut self, key: &K) -> Result<(Handle<V>, Rc<V>), E>
        where V: Loadable<K, E>
    {
        if let Some(handle) = self.keys.get(key) {
            return Ok((*handle, self.get(*handle)));
        };

        let v = V::load(key)?;
        let res = self.add_item(key.clone(), v);
        Ok(res)
    }

    // pub fn get_mut<E, S>(&mut self, key: &K) -> Result<&mut Rc<V>, E>
    //     where V: Loadable<K, E>
    // {
    //     // entry.or_insert_with() isn't quite powerful
    //     // enough 'cause it doesn't propegate Results.  ;_;
    //     let entry = self.contents.entry(key.clone());
    //     match entry {
    //         Entry::Vacant(e) => {
    //             let v = V::load(key)?;
    //             let v_rc = Rc::new(v);
    //             Ok(e.insert(v_rc));
    //             Ok(self.add_item(key.clone(), v));
    //         }
    //         Entry::Occupied(e) => Ok(e.into_mut()),
    //     }
    // }

    /// Gets the given asset, loading it with a state object if necessary.
    pub fn get_key_state<E, S>(&mut self, key: &K, state: &mut S) -> Result<(Handle<V>, Rc<V>), E>
        where V: StateLoadable<K, E, S>
    {
        if let Some(handle) = self.keys.get(key) {
            return Ok((*handle, self.get(*handle)));
        };

        let v = V::load_state(key, state)?;
        let res = self.add_item(key.clone(), v);
        Ok(res)
    }

    // /// Removes all assets from the cache
    // /// and frees any excess memory it uses.
    // /// This is now unsafe because it introduces the possibility
    // /// of dangling handles!  We can have a stack of bindings, kinda,
    // /// to manage this.  (Or just create/delete new state objects.)
    // pub fn clear(&mut self) {
    //     let map = BTreeMap::new();
    //     self.contents = map;
    // }

    /// Returns true if the given asset is loaded.
    pub fn loaded(&self, key: &K) -> bool {
        self.keys.contains_key(key)
    }

    /// Takes a slice containing a list of keys,
    /// and loads all the keys so that their objects
    /// are immediately accessible.
    pub fn preload<E>(&mut self, keys: &[K])
        where V: Loadable<K, E>
    {
        for k in keys {
            let _ = self.get_key(k);
        }
    }

    /// Preloads objects that require a state to load.
    pub fn preload_state<E, S>(&mut self, keys: &[K], state: &mut S)
        where V: StateLoadable<K, E, S>
    {
        for k in keys {
            let _ = self.get_key_state(k, state);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    impl<'a> Loadable<&'a str, ()> for String {
        fn load(key: &&str) -> Result<String, ()> {
            Ok(key.to_string())
        }
    }

    impl<'a> StateLoadable<&'a str, (), i32> for String {
        fn load_state(key: &&str, state: &mut i32) -> Result<String, ()> {
            *state += 1;
            Ok(key.to_string())
        }
    }

    #[test]
    fn test_assetcache() {
        let mut a = AssetCache::<&str, String>::new();
        {
            assert!(!a.loaded(&"foo"));
            let (handle, s1) = a.get_key(&"foo").unwrap();
            assert!(a.loaded(&"foo"));
            assert_eq!(*s1, "foo");
            let gotten_with_handle = a.get(handle);
            assert_eq!(*s1, *gotten_with_handle);
        }
    }

    #[test]
    fn test_stateful_assetcache() {
        let mut a = AssetCache::<&str, String>::new();
        {
            let s = &mut 10;
            assert!(!a.loaded(&"foo"));
            let (handle, s1) = a.get_key_state(&"foo", s).unwrap();
            assert_eq!(*s1, "foo");
            assert_eq!(*s, 11);
            assert!(a.loaded(&"foo"));

            let gotten_with_handle = a.get(handle);
            assert_eq!(*s1, *gotten_with_handle);
            assert_eq!(*s, 11);

        }

    }

    #[test]
    fn test_mut_assetcache() {
        let mut a = AssetCache::<&str, String>::new();
        assert!(!a.loaded(&"foo"));
        let (h, _) = a.get_key(&"foo").unwrap();

        {
            let mut_value = a.get_mut(h.clone());
            assert!(mut_value.is_some());
            let m = mut_value.unwrap();
            assert_eq!("foo", *m);
            *m += "Foobaz";
            assert_eq!("fooFoobaz", *m);
        }
        // Now get it again and ensure it's mutated.
        {
            let mut_value = a.get_mut(h.clone());
            assert!(mut_value.is_some());
            let m = mut_value.unwrap();
            assert_eq!("fooFoobaz", *m);
        }

    }
}
<|endoftext|>


<commit_before>//! Color items, including everything from rgb, hsb/l/v, lap, alpha, luma and more, provided by the
//! palette crate. See [the palette docs](https://docs.rs/palette) for more details or see the
//! [**named**](./named/index.html) module for a set of provided color constants.

#[doc(inline)]
pub use palette::*;

pub use self::named::*;
pub use self::tango::*;

/// The default scalar value for working with color components, hues, etc.
pub type DefaultScalar = f32;

/// A short-hand constructor for `Srgb::new`.
pub fn srgb(r: f32, g: f32, b: f32) -> Srgb {
    Srgb::new(r, g, b)
}

/// A short-hand constructor for `Srgba::new`.
pub fn srgba(r: f32, g: f32, b: f32, a: f32) -> Srgba {
    Srgba::new(r, g, b, a)
}

/// A short-hand constructor for `Hsl::new(RgbHue::from_degrees(h * 360.0), s, l)`.
///
/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is
/// 360 degrees (or 2 PI radians).
pub fn hsl(h: f32, s: f32, l: f32) -> Hsl {
    Hsl::new(RgbHue::from_degrees(h * 360.0), s, l)
}

/// A short-hand constructor for `Hsla::new(RgbHue::from_degrees(h * 360.0), s, l, a)`.
///
/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is
/// 360 degrees (or 2 PI radians).
pub fn hsla(h: f32, s: f32, l: f32, a: f32) -> Hsla {
    Hsla::new(RgbHue::from_degrees(h * 360.0), s, l, a)
}

/// A short-hand constructor for `Hsv::new(RgbHue::from_degrees(h * 360.0), s, v)`.
///
/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is
/// 360 degrees (or 2 PI radians).
pub fn hsv(h: f32, s: f32, v: f32) -> Hsv {
    Hsv::new(RgbHue::from_degrees(h * 360.0), s, v)
}

/// A short-hand constructor for `Hsva::new(RgbHue::from_degrees(h * 360.0), s, v, a)`.
///
/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is
/// 360 degrees (or 2 PI radians).
pub fn hsva(h: f32, s: f32, v: f32, a: f32) -> Hsva {
    Hsva::new(RgbHue::from_degrees(h * 360.0), s, v, a)
}

pub mod tango {
    //! A set of provided, named color constants.
    //!
    //! These colors come from the [Tango
    //! palette](http://tango.freedesktop.org/Tango_Icon_Theme_Guidelines) which provides
    //! aesthetically reasonable defaults for colors. Each color also comes with a light and dark
    //! version.
    use super::{Alpha, Srgb, Srgba};

    macro_rules! make_color {
        ($r:expr, $g:expr, $b:expr, $a:expr) => {
            Alpha {
                color: Srgb {
                    red: $r as f32 / 255.0,
                    green: $g as f32 / 255.0,
                    blue: $b as f32 / 255.0,
                    standard: std::marker::PhantomData,
                },
                alpha: $a as f32 / 255.0,
            }
        };
        ($r:expr, $g:expr, $b:expr) => {
            make_color!($r, $g, $b, 255)
        };
    }

    /// Scarlet Red - Light - #EF2929
    pub const LIGHT_RED: Srgba<f32> = make_color!(239, 41, 41);
    /// Scarlet Red - Regular - #CC0000
    pub const RED: Srgba<f32> = make_color!(204, 0, 0);
    /// Scarlet Red - Dark - #A30000
    pub const DARK_RED: Srgba<f32> = make_color!(164, 0, 0);

    /// Orange - Light - #FCAF3E
    pub const LIGHT_ORANGE: Srgba<f32> = make_color!(252, 175, 62);
    /// Orange - Regular - #F57900
    pub const ORANGE: Srgba<f32> = make_color!(245, 121, 0);
    /// Orange - Dark - #CE5C00
    pub const DARK_ORANGE: Srgba<f32> = make_color!(206, 92, 0);

    /// Butter - Light - #FCE94F
    pub const LIGHT_YELLOW: Srgba<f32> = make_color!(252, 233, 79);
    /// Butter - Regular - #EDD400
    pub const YELLOW: Srgba<f32> = make_color!(237, 212, 0);
    /// Butter - Dark - #C4A000
    pub const DARK_YELLOW: Srgba<f32> = make_color!(196, 160, 0);

    /// Chameleon - Light - #8AE234
    pub const LIGHT_GREEN: Srgba<f32> = make_color!(138, 226, 52);
    /// Chameleon - Regular - #73D216
    pub const GREEN: Srgba<f32> = make_color!(115, 210, 22);
    /// Chameleon - Dark - #4E9A06
    pub const DARK_GREEN: Srgba<f32> = make_color!(78, 154, 6);

    /// Sky Blue - Light - #729FCF
    pub const LIGHT_BLUE: Srgba<f32> = make_color!(114, 159, 207);
    /// Sky Blue - Regular - #3465A4
    pub const BLUE: Srgba<f32> = make_color!(52, 101, 164);
    /// Sky Blue - Dark - #204A87
    pub const DARK_BLUE: Srgba<f32> = make_color!(32, 74, 135);

    /// Plum - Light - #AD7FA8
    pub const LIGHT_PURPLE: Srgba<f32> = make_color!(173, 127, 168);
    /// Plum - Regular - #75507B
    pub const PURPLE: Srgba<f32> = make_color!(117, 80, 123);
    /// Plum - Dark - #5C3566
    pub const DARK_PURPLE: Srgba<f32> = make_color!(92, 53, 102);

    /// Chocolate - Light - #E9B96E
    pub const LIGHT_BROWN: Srgba<f32> = make_color!(233, 185, 110);
    /// Chocolate - Regular - #C17D11
    pub const BROWN: Srgba<f32> = make_color!(193, 125, 17);
    /// Chocolate - Dark - #8F5902
    pub const DARK_BROWN: Srgba<f32> = make_color!(143, 89, 2);

    /// Straight Black.
    pub const BLACK: Srgba<f32> = make_color!(0, 0, 0);
    /// Straight White.
    pub const WHITE: Srgba<f32> = make_color!(255, 255, 255);

    /// Alluminium - Light
    pub const LIGHT_GRAY: Srgba<f32> = make_color!(238, 238, 236);
    /// Alluminium - Regular
    pub const GRAY: Srgba<f32> = make_color!(211, 215, 207);
    /// Alluminium - Dark
    pub const DARK_GRAY: Srgba<f32> = make_color!(186, 189, 182);

    /// Aluminium - Light - #EEEEEC
    pub const LIGHT_GREY: Srgba<f32> = make_color!(238, 238, 236);
    /// Aluminium - Regular - #D3D7CF
    pub const GREY: Srgba<f32> = make_color!(211, 215, 207);
    /// Aluminium - Dark - #BABDB6
    pub const DARK_GREY: Srgba<f32> = make_color!(186, 189, 182);

    /// Charcoal - Light - #888A85
    pub const LIGHT_CHARCOAL: Srgba<f32> = make_color!(136, 138, 133);
    /// Charcoal - Regular - #555753
    pub const CHARCOAL: Srgba<f32> = make_color!(85, 87, 83);
    /// Charcoal - Dark - #2E3436
    pub const DARK_CHARCOAL: Srgba<f32> = make_color!(46, 52, 54);

    /// Transparent
    pub const TRANSPARENT: Srgba<f32> = make_color!(0.0, 0.0, 0.0, 0.0);
}
<commit_msg>Re-add `Rgb` and `Rgba` types, aliased to `Srgb` and `Srgba` types.<commit_after>//! Color items, including everything from rgb, hsb/l/v, lap, alpha, luma and more, provided by the
//! palette crate. See [the palette docs](https://docs.rs/palette) for more details or see the
//! [**named**](./named/index.html) module for a set of provided color constants.

#[doc(inline)]
pub use palette::*;

pub use self::named::*;
pub use self::tango::*;

/// The default scalar value for working with color components, hues, etc.
pub type DefaultScalar = f32;

/// A color represented as red, green and blue intensities.
///
/// This type is an alias for the `Srgb` type, a type that represents the sRGB color space.
///
/// If you are looking for more advanced control over the RGB space and component type, please see
/// the `palette` crate's generic `Rgb` type.
pub type Rgb<S = DefaultScalar> = Srgb<S>;

/// The same as `Rgb`, but with an alpha value representing opacity.
///
/// This type is an alias for the `Srgba` type, a type that represents the sRGB color space
/// alongside an alpha value.
///
/// If you are looking for more advanced control over the RGB space and component type, please see
/// the `palette` crate's generic `Rgb` type.
pub type Rgba<S = DefaultScalar> = Srgba<S>;

/// A short-hand constructor for `Rgb::new`.
pub fn rgb(r: f32, g: f32, b: f32) -> Rgb {
    srgb(r, g, b)
}

/// A short-hand constructor for `Rgba::new`.
pub fn rgba(r: f32, g: f32, b: f32, a: f32) -> Rgba {
    srgba(r, g, b, a)
}

/// A short-hand constructor for `Srgb::new`.
pub fn srgb(r: f32, g: f32, b: f32) -> Srgb {
    Srgb::new(r, g, b)
}

/// A short-hand constructor for `Srgba::new`.
pub fn srgba(r: f32, g: f32, b: f32, a: f32) -> Srgba {
    Srgba::new(r, g, b, a)
}

/// A short-hand constructor for `Hsl::new(RgbHue::from_degrees(h * 360.0), s, l)`.
///
/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is
/// 360 degrees (or 2 PI radians).
pub fn hsl(h: f32, s: f32, l: f32) -> Hsl {
    Hsl::new(RgbHue::from_degrees(h * 360.0), s, l)
}

/// A short-hand constructor for `Hsla::new(RgbHue::from_degrees(h * 360.0), s, l, a)`.
///
/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is
/// 360 degrees (or 2 PI radians).
pub fn hsla(h: f32, s: f32, l: f32, a: f32) -> Hsla {
    Hsla::new(RgbHue::from_degrees(h * 360.0), s, l, a)
}

/// A short-hand constructor for `Hsv::new(RgbHue::from_degrees(h * 360.0), s, v)`.
///
/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is
/// 360 degrees (or 2 PI radians).
pub fn hsv(h: f32, s: f32, v: f32) -> Hsv {
    Hsv::new(RgbHue::from_degrees(h * 360.0), s, v)
}

/// A short-hand constructor for `Hsva::new(RgbHue::from_degrees(h * 360.0), s, v, a)`.
///
/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is
/// 360 degrees (or 2 PI radians).
pub fn hsva(h: f32, s: f32, v: f32, a: f32) -> Hsva {
    Hsva::new(RgbHue::from_degrees(h * 360.0), s, v, a)
}

pub mod tango {
    //! A set of provided, named color constants.
    //!
    //! These colors come from the [Tango
    //! palette](http://tango.freedesktop.org/Tango_Icon_Theme_Guidelines) which provides
    //! aesthetically reasonable defaults for colors. Each color also comes with a light and dark
    //! version.
    use super::{Alpha, Srgb, Srgba};

    macro_rules! make_color {
        ($r:expr, $g:expr, $b:expr, $a:expr) => {
            Alpha {
                color: Srgb {
                    red: $r as f32 / 255.0,
                    green: $g as f32 / 255.0,
                    blue: $b as f32 / 255.0,
                    standard: std::marker::PhantomData,
                },
                alpha: $a as f32 / 255.0,
            }
        };
        ($r:expr, $g:expr, $b:expr) => {
            make_color!($r, $g, $b, 255)
        };
    }

    /// Scarlet Red - Light - #EF2929
    pub const LIGHT_RED: Srgba<f32> = make_color!(239, 41, 41);
    /// Scarlet Red - Regular - #CC0000
    pub const RED: Srgba<f32> = make_color!(204, 0, 0);
    /// Scarlet Red - Dark - #A30000
    pub const DARK_RED: Srgba<f32> = make_color!(164, 0, 0);

    /// Orange - Light - #FCAF3E
    pub const LIGHT_ORANGE: Srgba<f32> = make_color!(252, 175, 62);
    /// Orange - Regular - #F57900
    pub const ORANGE: Srgba<f32> = make_color!(245, 121, 0);
    /// Orange - Dark - #CE5C00
    pub const DARK_ORANGE: Srgba<f32> = make_color!(206, 92, 0);

    /// Butter - Light - #FCE94F
    pub const LIGHT_YELLOW: Srgba<f32> = make_color!(252, 233, 79);
    /// Butter - Regular - #EDD400
    pub const YELLOW: Srgba<f32> = make_color!(237, 212, 0);
    /// Butter - Dark - #C4A000
    pub const DARK_YELLOW: Srgba<f32> = make_color!(196, 160, 0);

    /// Chameleon - Light - #8AE234
    pub const LIGHT_GREEN: Srgba<f32> = make_color!(138, 226, 52);
    /// Chameleon - Regular - #73D216
    pub const GREEN: Srgba<f32> = make_color!(115, 210, 22);
    /// Chameleon - Dark - #4E9A06
    pub const DARK_GREEN: Srgba<f32> = make_color!(78, 154, 6);

    /// Sky Blue - Light - #729FCF
    pub const LIGHT_BLUE: Srgba<f32> = make_color!(114, 159, 207);
    /// Sky Blue - Regular - #3465A4
    pub const BLUE: Srgba<f32> = make_color!(52, 101, 164);
    /// Sky Blue - Dark - #204A87
    pub const DARK_BLUE: Srgba<f32> = make_color!(32, 74, 135);

    /// Plum - Light - #AD7FA8
    pub const LIGHT_PURPLE: Srgba<f32> = make_color!(173, 127, 168);
    /// Plum - Regular - #75507B
    pub const PURPLE: Srgba<f32> = make_color!(117, 80, 123);
    /// Plum - Dark - #5C3566
    pub const DARK_PURPLE: Srgba<f32> = make_color!(92, 53, 102);

    /// Chocolate - Light - #E9B96E
    pub const LIGHT_BROWN: Srgba<f32> = make_color!(233, 185, 110);
    /// Chocolate - Regular - #C17D11
    pub const BROWN: Srgba<f32> = make_color!(193, 125, 17);
    /// Chocolate - Dark - #8F5902
    pub const DARK_BROWN: Srgba<f32> = make_color!(143, 89, 2);

    /// Straight Black.
    pub const BLACK: Srgba<f32> = make_color!(0, 0, 0);
    /// Straight White.
    pub const WHITE: Srgba<f32> = make_color!(255, 255, 255);

    /// Alluminium - Light
    pub const LIGHT_GRAY: Srgba<f32> = make_color!(238, 238, 236);
    /// Alluminium - Regular
    pub const GRAY: Srgba<f32> = make_color!(211, 215, 207);
    /// Alluminium - Dark
    pub const DARK_GRAY: Srgba<f32> = make_color!(186, 189, 182);

    /// Aluminium - Light - #EEEEEC
    pub const LIGHT_GREY: Srgba<f32> = make_color!(238, 238, 236);
    /// Aluminium - Regular - #D3D7CF
    pub const GREY: Srgba<f32> = make_color!(211, 215, 207);
    /// Aluminium - Dark - #BABDB6
    pub const DARK_GREY: Srgba<f32> = make_color!(186, 189, 182);

    /// Charcoal - Light - #888A85
    pub const LIGHT_CHARCOAL: Srgba<f32> = make_color!(136, 138, 133);
    /// Charcoal - Regular - #555753
    pub const CHARCOAL: Srgba<f32> = make_color!(85, 87, 83);
    /// Charcoal - Dark - #2E3436
    pub const DARK_CHARCOAL: Srgba<f32> = make_color!(46, 52, 54);

    /// Transparent
    pub const TRANSPARENT: Srgba<f32> = make_color!(0.0, 0.0, 0.0, 0.0);
}
<|endoftext|>


<commit_before>//! Color managemement.
//!
//! # Example
//!
//! ```rust
//! use termion::{color, style};
//!
//! use std::io;
//!
//! fn main() {
//!     println!("{}Red", color::Fg(color::Red));
//!     println!("{}Blue", color::Fg(color::Blue));
//!     println!("{}Back again", color::Fg(color::Reset));
//! }
//! ```

use std::fmt;

/// A terminal color.
pub trait Color {
    /// Write the foreground version of this color.
    fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result;
    /// Write the background version of this color.
    fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result;
}

macro_rules! derive_color {
    ($doc:expr, $name:ident, $value:expr) => {
        #[doc = $doc]
        #[derive(Copy, Clone, Debug)]
        pub struct $name;

        impl Color for $name {
            #[inline]
            fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, csi!("38;5;", $value, "m"))
            }

            #[inline]
            fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, csi!("48;5;", $value, "m"))
            }
        }
    };
}

derive_color!("Black.", Black, "0");
derive_color!("Red.", Red, "1");
derive_color!("Green.", Green, "2");
derive_color!("Yellow.", Yellow, "3");
derive_color!("Blue.", Blue, "4");
derive_color!("Magenta.", Magenta, "5");
derive_color!("Cyan.", Cyan, "6");
derive_color!("White.", White, "7");
derive_color!("High-intensity light black.", LightBlack, "8");
derive_color!("High-intensity light red.", LightRed, "9");
derive_color!("High-intensity light green.", LightGreen, "10");
derive_color!("High-intensity light yellow.", LightYellow, "11");
derive_color!("High-intensity light blue.", LightBlue, "12");
derive_color!("High-intensity light magenta.", LightMagenta, "13");
derive_color!("High-intensity light cyan.", LightCyan, "14");
derive_color!("High-intensity light white.", LightWhite, "15");

/// An arbitrary ANSI color value.
#[derive(Clone, Copy, Debug)]
pub struct AnsiValue(pub u8);

impl AnsiValue {
    /// 216-color (r, g, b ≤ 5) RGB.
    pub fn rgb(r: u8, g: u8, b: u8) -> AnsiValue {
        debug_assert!(r <= 5, "Red color fragment (r = {}) is out of bound. Make sure r ≤ 5.", r);
        debug_assert!(g <= 5, "Green color fragment (g = {}) is out of bound. Make sure g ≤ 5.", g);
        debug_assert!(b <= 5, "Blue color fragment (b = {}) is out of bound. Make sure b ≤ 5.", b);

        AnsiValue(16 + 36 * r + 6 * g + b)
    }

    /// Grayscale color.
    ///
    /// There are 24 shades of gray.
    pub fn grayscale(shade: u8) -> AnsiValue {
        // Unfortunately, there are a little less than fifty shades.
        debug_assert!(shade < 24, "Grayscale out of bound (shade = {}). There are only 24 shades of \
                      gray.", shade);

        AnsiValue(0xE8 + shade)
    }
}

impl Color for AnsiValue {
    #[inline]
    fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("38;5;{}m"), self.0)
    }

    #[inline]
    fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("48;5;{}m"), self.0)
    }
}

/// A truecolor RGB.
#[derive(Debug, Clone)]
pub struct Rgb(pub u8, pub u8, pub u8);

impl Color for Rgb {
    #[inline]
    fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("38;2;{};{};{}m"), self.0, self.1, self.2)
    }

    #[inline]
    fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("48;2;{};{};{}m"), self.0, self.1, self.2)
    }
}

/// Reset colors to defaults.
#[derive(Debug)]
pub struct Reset;

impl Color for Reset {
    #[inline]
    fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("39m"))
    }

    #[inline]
    fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("49m"))
    }
}

/// A foreground color.
#[derive(Debug, Clone)]
pub struct Fg<C: Color>(pub C);

impl<C: Color> fmt::Display for Fg<C> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.write_fg(f)
    }
}

/// A background color.
#[derive(Debug, Clone)]
pub struct Bg<C: Color>(pub C);

impl<C: Color> fmt::Display for Bg<C> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.write_bg(f)
    }
}
<commit_msg>Derive Copy for color::{Rgb, Fg, Bg, Reset} (#54)<commit_after>//! Color managemement.
//!
//! # Example
//!
//! ```rust
//! use termion::{color, style};
//!
//! use std::io;
//!
//! fn main() {
//!     println!("{}Red", color::Fg(color::Red));
//!     println!("{}Blue", color::Fg(color::Blue));
//!     println!("{}Back again", color::Fg(color::Reset));
//! }
//! ```

use std::fmt;

/// A terminal color.
pub trait Color {
    /// Write the foreground version of this color.
    fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result;
    /// Write the background version of this color.
    fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result;
}

macro_rules! derive_color {
    ($doc:expr, $name:ident, $value:expr) => {
        #[doc = $doc]
        #[derive(Copy, Clone, Debug)]
        pub struct $name;

        impl Color for $name {
            #[inline]
            fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, csi!("38;5;", $value, "m"))
            }

            #[inline]
            fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, csi!("48;5;", $value, "m"))
            }
        }
    };
}

derive_color!("Black.", Black, "0");
derive_color!("Red.", Red, "1");
derive_color!("Green.", Green, "2");
derive_color!("Yellow.", Yellow, "3");
derive_color!("Blue.", Blue, "4");
derive_color!("Magenta.", Magenta, "5");
derive_color!("Cyan.", Cyan, "6");
derive_color!("White.", White, "7");
derive_color!("High-intensity light black.", LightBlack, "8");
derive_color!("High-intensity light red.", LightRed, "9");
derive_color!("High-intensity light green.", LightGreen, "10");
derive_color!("High-intensity light yellow.", LightYellow, "11");
derive_color!("High-intensity light blue.", LightBlue, "12");
derive_color!("High-intensity light magenta.", LightMagenta, "13");
derive_color!("High-intensity light cyan.", LightCyan, "14");
derive_color!("High-intensity light white.", LightWhite, "15");

/// An arbitrary ANSI color value.
#[derive(Clone, Copy, Debug)]
pub struct AnsiValue(pub u8);

impl AnsiValue {
    /// 216-color (r, g, b ≤ 5) RGB.
    pub fn rgb(r: u8, g: u8, b: u8) -> AnsiValue {
        debug_assert!(r <= 5, "Red color fragment (r = {}) is out of bound. Make sure r ≤ 5.", r);
        debug_assert!(g <= 5, "Green color fragment (g = {}) is out of bound. Make sure g ≤ 5.", g);
        debug_assert!(b <= 5, "Blue color fragment (b = {}) is out of bound. Make sure b ≤ 5.", b);

        AnsiValue(16 + 36 * r + 6 * g + b)
    }

    /// Grayscale color.
    ///
    /// There are 24 shades of gray.
    pub fn grayscale(shade: u8) -> AnsiValue {
        // Unfortunately, there are a little less than fifty shades.
        debug_assert!(shade < 24, "Grayscale out of bound (shade = {}). There are only 24 shades of \
                      gray.", shade);

        AnsiValue(0xE8 + shade)
    }
}

impl Color for AnsiValue {
    #[inline]
    fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("38;5;{}m"), self.0)
    }

    #[inline]
    fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("48;5;{}m"), self.0)
    }
}

/// A truecolor RGB.
#[derive(Debug, Clone, Copy)]
pub struct Rgb(pub u8, pub u8, pub u8);

impl Color for Rgb {
    #[inline]
    fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("38;2;{};{};{}m"), self.0, self.1, self.2)
    }

    #[inline]
    fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("48;2;{};{};{}m"), self.0, self.1, self.2)
    }
}

/// Reset colors to defaults.
#[derive(Debug, Clone, Copy)]
pub struct Reset;

impl Color for Reset {
    #[inline]
    fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("39m"))
    }

    #[inline]
    fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("49m"))
    }
}

/// A foreground color.
#[derive(Debug, Clone, Copy)]
pub struct Fg<C: Color>(pub C);

impl<C: Color> fmt::Display for Fg<C> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.write_fg(f)
    }
}

/// A background color.
#[derive(Debug, Clone, Copy)]
pub struct Bg<C: Color>(pub C);

impl<C: Color> fmt::Display for Bg<C> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.write_bg(f)
    }
}
<|endoftext|>


<commit_before>use common::*;
use main;
use glw::gl_buffer::{GLSliceBuffer, Triangles, Lines};
use glw::gl_context::GLContext;
use glw::shader::Shader;
use glw::vertex;
use nalgebra::na::{Vec2, Vec3};
use ncollide3df32::bounding_volume::LooseBoundingVolume;
use ncollide3df32::bounding_volume::aabb::AABB;
use std::collections::HashMap;
use std::rc::Rc;

static MAX_WORLD_SIZE: uint = 40000;

#[deriving(Copy, Clone, PartialEq, Eq, Hash)]
pub enum BlockType {
  Grass,
  Dirt,
  Stone,
}

#[deriving(Clone)]
/// A voxel-ish block in the game world.
pub struct Block {
  pub block_type: BlockType,
  pub id: main::Id,
}

impl Block {
  // Construct outlines for this Block, to sharpen the edges.
  pub fn to_outlines(bounds: &AABB) -> [vertex::ColoredVertex, ..LINE_VERTICES_PER_BOX] {
    to_outlines(&bounds.loosened(0.002))
  }

  pub fn to_texture_triangles(bounds: &AABB) -> [vertex::WorldTextureVertex, ..TRIANGLE_VERTICES_PER_BOX] {
    let (x1, y1, z1) = (bounds.mins().x, bounds.mins().y, bounds.mins().z);
    let (x2, y2, z2) = (bounds.maxs().x, bounds.maxs().y, bounds.maxs().z);

    let vtx = |x, y, z, nx, ny, nz, tx, ty| {
      vertex::WorldTextureVertex {
        world_position: Vec3::new(x, y, z),
        texture_position: Vec2::new(tx, ty),
        normal: Vec3::new(nx, ny, nz),
      }
    };

    // Remember: x increases to the right, y increases up, and z becomes more
    // negative as depth from the viewer increases.
    [
      // front
      vtx(x1, y1, z2,  0.0,  0.0,  1.0, 0.00, 0.50),
      vtx(x2, y2, z2,  0.0,  0.0,  1.0, 0.25, 0.25),
      vtx(x1, y2, z2,  0.0,  0.0,  1.0, 0.25, 0.50),
      vtx(x1, y1, z2,  0.0,  0.0,  1.0, 0.00, 0.50),
      vtx(x2, y1, z2,  0.0,  0.0,  1.0, 0.00, 0.25),
      vtx(x2, y2, z2,  0.0,  0.0,  1.0, 0.25, 0.25),
      // left
      vtx(x1, y1, z1, -1.0,  0.0,  0.0, 0.75, 0.00),
      vtx(x1, y2, z2, -1.0,  0.0,  0.0, 0.50, 0.25),
      vtx(x1, y2, z1, -1.0,  0.0,  0.0, 0.50, 0.00),
      vtx(x1, y1, z1, -1.0,  0.0,  0.0, 0.75, 0.00),
      vtx(x1, y1, z2, -1.0,  0.0,  0.0, 0.75, 0.25),
      vtx(x1, y2, z2, -1.0,  0.0,  0.0, 0.50, 0.25),
      // top
      vtx(x1, y2, z1,  0.0,  1.0,  0.0, 0.25, 0.25),
      vtx(x2, y2, z2,  0.0,  1.0,  0.0, 0.50, 0.50),
      vtx(x2, y2, z1,  0.0,  1.0,  0.0, 0.25, 0.50),
      vtx(x1, y2, z1,  0.0,  1.0,  0.0, 0.25, 0.25),
      vtx(x1, y2, z2,  0.0,  1.0,  0.0, 0.50, 0.25),
      vtx(x2, y2, z2,  0.0,  1.0,  0.0, 0.50, 0.50),
      // back
      vtx(x1, y1, z1,  0.0,  0.0, -1.0, 0.75, 0.50),
      vtx(x2, y2, z1,  0.0,  0.0, -1.0, 0.50, 0.25),
      vtx(x2, y1, z1,  0.0,  0.0, -1.0, 0.75, 0.25),
      vtx(x1, y1, z1,  0.0,  0.0, -1.0, 0.75, 0.50),
      vtx(x1, y2, z1,  0.0,  0.0, -1.0, 0.50, 0.50),
      vtx(x2, y2, z1,  0.0,  0.0, -1.0, 0.50, 0.25),
      // right
      vtx(x2, y1, z1,  1.0,  0.0,  0.0, 0.75, 0.75),
      vtx(x2, y2, z2,  1.0,  0.0,  0.0, 0.50, 0.50),
      vtx(x2, y1, z2,  1.0,  0.0,  0.0, 0.75, 0.50),
      vtx(x2, y1, z1,  1.0,  0.0,  0.0, 0.75, 0.75),
      vtx(x2, y2, z1,  1.0,  0.0,  0.0, 0.50, 0.75),
      vtx(x2, y2, z2,  1.0,  0.0,  0.0, 0.50, 0.50),
      // bottom
      vtx(x1, y1, z1,  0.0, -1.0,  0.0, 0.75, 0.50),
      vtx(x2, y1, z2,  0.0, -1.0,  0.0, 1.00, 0.25),
      vtx(x1, y1, z2,  0.0, -1.0,  0.0, 1.00, 0.50),
      vtx(x1, y1, z1,  0.0, -1.0,  0.0, 0.75, 0.50),
      vtx(x2, y1, z1,  0.0, -1.0,  0.0, 0.75, 0.25),
      vtx(x2, y1, z2,  0.0, -1.0,  0.0, 1.00, 0.25),
    ]
  }
}

pub struct BlockBuffers {
  id_to_index: HashMap<main::Id, uint>,
  index_to_id: Vec<main::Id>,

  triangles: GLSliceBuffer<vertex::WorldTextureVertex>,
  outlines: GLSliceBuffer<vertex::ColoredVertex>,
}

impl BlockBuffers {
  pub unsafe fn new(gl: &GLContext, color_shader: &Rc<Shader>, texture_shader: &Rc<Shader>) -> BlockBuffers {
    BlockBuffers {
      id_to_index: HashMap::new(),
      index_to_id: Vec::new(),
      triangles: GLSliceBuffer::new(
        gl,
        texture_shader.clone(),
        [ vertex::AttribData { name: "position", size: 3 },
          vertex::AttribData { name: "texture_position", size: 2 },
          vertex::AttribData { name: "vertex_normal", size: 3 },
        ],
        TRIANGLE_VERTICES_PER_BOX,
        MAX_WORLD_SIZE,
        Triangles
      ),
      outlines: GLSliceBuffer::new(
        gl,
        color_shader.clone(),
        [ vertex::AttribData { name: "position", size: 3 },
          vertex::AttribData { name: "in_color", size: 4 },
        ],
        LINE_VERTICES_PER_BOX,
        MAX_WORLD_SIZE,
        Lines
      ),
    }
  }

  pub fn push(
    &mut self,
    gl: &GLContext,
    id: main::Id,
    triangles: &[vertex::WorldTextureVertex],
    outlines: &[vertex::ColoredVertex]
  ) {
    self.id_to_index.insert(id, self.index_to_id.len());
    self.index_to_id.push(id);
    self.triangles.push(gl, triangles);
    self.outlines.push(gl, outlines);
  }

  pub fn swap_remove(&mut self, gl: &GLContext, id: main::Id) {
    let idx = *unwrap!(self.id_to_index.find(&id));
    let swapped_id = self.index_to_id[self.index_to_id.len() - 1];
    unwrap!(self.index_to_id.swap_remove(idx));
    self.id_to_index.remove(&id);
    self.triangles.swap_remove(gl, idx);
    self.outlines.swap_remove(gl, idx);
    if id != swapped_id {
      self.id_to_index.insert(swapped_id, idx);
    }
  }

  pub fn draw(&self, gl: &GLContext) {
    self.triangles.draw(gl);
    self.outlines.draw(gl);
  }
}

<commit_msg>don't index right onto the edge of textures<commit_after>use common::*;
use main;
use glw::gl_buffer::{GLSliceBuffer, Triangles, Lines};
use glw::gl_context::GLContext;
use glw::shader::Shader;
use glw::vertex;
use nalgebra::na::{Vec2, Vec3};
use ncollide3df32::bounding_volume::LooseBoundingVolume;
use ncollide3df32::bounding_volume::aabb::AABB;
use std::collections::HashMap;
use std::rc::Rc;

static MAX_WORLD_SIZE: uint = 40000;

#[deriving(Copy, Clone, PartialEq, Eq, Hash)]
pub enum BlockType {
  Grass,
  Dirt,
  Stone,
}

#[deriving(Clone)]
/// A voxel-ish block in the game world.
pub struct Block {
  pub block_type: BlockType,
  pub id: main::Id,
}

impl Block {
  // Construct outlines for this Block, to sharpen the edges.
  pub fn to_outlines(bounds: &AABB) -> [vertex::ColoredVertex, ..LINE_VERTICES_PER_BOX] {
    to_outlines(&bounds.loosened(0.002))
  }

  pub fn to_texture_triangles(bounds: &AABB) -> [vertex::WorldTextureVertex, ..TRIANGLE_VERTICES_PER_BOX] {
    let (x1, y1, z1) = (bounds.mins().x, bounds.mins().y, bounds.mins().z);
    let (x2, y2, z2) = (bounds.maxs().x, bounds.maxs().y, bounds.maxs().z);

    let vtx = |x, y, z, nx, ny, nz, tx, ty| {
      vertex::WorldTextureVertex {
        world_position: Vec3::new(x, y, z),
        texture_position: Vec2::new(tx, ty),
        normal: Vec3::new(nx, ny, nz),
      }
    };

    // hacky little solution so that we don't index right onto the edge of a
    // texture; if we do, we get edges showing up in rendering.
    let d = 0.001;

    // Remember: x increases to the right, y increases up, and z becomes more
    // negative as depth from the viewer increases.
    [
      // front
      vtx(x1, y1, z2,  0.0,  0.0,  1.0, 0.00 + d, 0.50 - d),
      vtx(x2, y2, z2,  0.0,  0.0,  1.0, 0.25 - d, 0.25 + d),
      vtx(x1, y2, z2,  0.0,  0.0,  1.0, 0.25 - d, 0.50 - d),
      vtx(x1, y1, z2,  0.0,  0.0,  1.0, 0.00 + d, 0.50 - d),
      vtx(x2, y1, z2,  0.0,  0.0,  1.0, 0.00 + d, 0.25 + d),
      vtx(x2, y2, z2,  0.0,  0.0,  1.0, 0.25 - d, 0.25 + d),
      // left
      vtx(x1, y1, z1, -1.0,  0.0,  0.0, 0.75 - d, 0.00 + d),
      vtx(x1, y2, z2, -1.0,  0.0,  0.0, 0.50 + d, 0.25 - d),
      vtx(x1, y2, z1, -1.0,  0.0,  0.0, 0.50 + d, 0.00 + d),
      vtx(x1, y1, z1, -1.0,  0.0,  0.0, 0.75 - d, 0.00 + d),
      vtx(x1, y1, z2, -1.0,  0.0,  0.0, 0.75 - d, 0.25 - d),
      vtx(x1, y2, z2, -1.0,  0.0,  0.0, 0.50 + d, 0.25 - d),
      // top
      vtx(x1, y2, z1,  0.0,  1.0,  0.0, 0.25 + d, 0.25 + d),
      vtx(x2, y2, z2,  0.0,  1.0,  0.0, 0.50 - d, 0.50 - d),
      vtx(x2, y2, z1,  0.0,  1.0,  0.0, 0.25 + d, 0.50 - d),
      vtx(x1, y2, z1,  0.0,  1.0,  0.0, 0.25 + d, 0.25 + d),
      vtx(x1, y2, z2,  0.0,  1.0,  0.0, 0.50 - d, 0.25 + d),
      vtx(x2, y2, z2,  0.0,  1.0,  0.0, 0.50 - d, 0.50 - d),
      // back
      vtx(x1, y1, z1,  0.0,  0.0, -1.0, 0.75 - d, 0.50 - d),
      vtx(x2, y2, z1,  0.0,  0.0, -1.0, 0.50 + d, 0.25 + d),
      vtx(x2, y1, z1,  0.0,  0.0, -1.0, 0.75 - d, 0.25 + d),
      vtx(x1, y1, z1,  0.0,  0.0, -1.0, 0.75 - d, 0.50 - d),
      vtx(x1, y2, z1,  0.0,  0.0, -1.0, 0.50 + d, 0.50 - d),
      vtx(x2, y2, z1,  0.0,  0.0, -1.0, 0.50 + d, 0.25 + d),
      // right
      vtx(x2, y1, z1,  1.0,  0.0,  0.0, 0.75 - d, 0.75 - d),
      vtx(x2, y2, z2,  1.0,  0.0,  0.0, 0.50 + d, 0.50 + d),
      vtx(x2, y1, z2,  1.0,  0.0,  0.0, 0.75 - d, 0.50 + d),
      vtx(x2, y1, z1,  1.0,  0.0,  0.0, 0.75 - d, 0.75 - d),
      vtx(x2, y2, z1,  1.0,  0.0,  0.0, 0.50 + d, 0.75 - d),
      vtx(x2, y2, z2,  1.0,  0.0,  0.0, 0.50 + d, 0.50 + d),
      // bottom
      vtx(x1, y1, z1,  0.0, -1.0,  0.0, 0.75 + d, 0.50 - d),
      vtx(x2, y1, z2,  0.0, -1.0,  0.0, 1.00 - d, 0.25 + d),
      vtx(x1, y1, z2,  0.0, -1.0,  0.0, 1.00 - d, 0.50 - d),
      vtx(x1, y1, z1,  0.0, -1.0,  0.0, 0.75 + d, 0.50 - d),
      vtx(x2, y1, z1,  0.0, -1.0,  0.0, 0.75 + d, 0.25 + d),
      vtx(x2, y1, z2,  0.0, -1.0,  0.0, 1.00 - d, 0.25 + d),
    ]
  }
}

pub struct BlockBuffers {
  id_to_index: HashMap<main::Id, uint>,
  index_to_id: Vec<main::Id>,

  triangles: GLSliceBuffer<vertex::WorldTextureVertex>,
  outlines: GLSliceBuffer<vertex::ColoredVertex>,
}

impl BlockBuffers {
  pub unsafe fn new(gl: &GLContext, color_shader: &Rc<Shader>, texture_shader: &Rc<Shader>) -> BlockBuffers {
    BlockBuffers {
      id_to_index: HashMap::new(),
      index_to_id: Vec::new(),
      triangles: GLSliceBuffer::new(
        gl,
        texture_shader.clone(),
        [ vertex::AttribData { name: "position", size: 3 },
          vertex::AttribData { name: "texture_position", size: 2 },
          vertex::AttribData { name: "vertex_normal", size: 3 },
        ],
        TRIANGLE_VERTICES_PER_BOX,
        MAX_WORLD_SIZE,
        Triangles
      ),
      outlines: GLSliceBuffer::new(
        gl,
        color_shader.clone(),
        [ vertex::AttribData { name: "position", size: 3 },
          vertex::AttribData { name: "in_color", size: 4 },
        ],
        LINE_VERTICES_PER_BOX,
        MAX_WORLD_SIZE,
        Lines
      ),
    }
  }

  pub fn push(
    &mut self,
    gl: &GLContext,
    id: main::Id,
    triangles: &[vertex::WorldTextureVertex],
    outlines: &[vertex::ColoredVertex]
  ) {
    self.id_to_index.insert(id, self.index_to_id.len());
    self.index_to_id.push(id);
    self.triangles.push(gl, triangles);
    self.outlines.push(gl, outlines);
  }

  pub fn swap_remove(&mut self, gl: &GLContext, id: main::Id) {
    let idx = *unwrap!(self.id_to_index.find(&id));
    let swapped_id = self.index_to_id[self.index_to_id.len() - 1];
    unwrap!(self.index_to_id.swap_remove(idx));
    self.id_to_index.remove(&id);
    self.triangles.swap_remove(gl, idx);
    self.outlines.swap_remove(gl, idx);
    if id != swapped_id {
      self.id_to_index.insert(swapped_id, idx);
    }
  }

  pub fn draw(&self, gl: &GLContext) {
    self.triangles.draw(gl);
    self.outlines.draw(gl);
  }
}

<|endoftext|>


<commit_before>/// Utilities for writing messages to the Janus log.
extern crate chrono;
extern crate colored;

use self::chrono::{DateTime, Local};
use self::colored::{Color, Colorize};
use super::ffi;
use std::ffi::CString;
use std::fmt::Write;

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
/// A Janus log level. Lower is more severe.
pub enum LogLevel {
    Fatal = 1,
    Err = 2,
    Warn = 3,
    Info = 4,
    Verb = 5,
    Huge = 6,
    Dbg = 7,
}

impl LogLevel {
    /// The color associated with each log level's label (if colors are enabled.)
    fn color(&self) -> Option<Color> {
        match *self {
            LogLevel::Fatal => Some(Color::Magenta),
            LogLevel::Err => Some(Color::Red),
            LogLevel::Warn => Some(Color::Yellow),
            _ => None,
        }
    }
}

#[derive(Debug, Clone)]
pub struct LogParameters {
    pub max_log_level: i32,
    pub log_timestamps: bool,
    pub log_colors: bool,
    pub clock: fn() -> DateTime<Local>,
}

impl Default for LogParameters {
    fn default() -> Self {
        unsafe {
            Self {
                max_log_level: ffi::janus_log_level,
                log_timestamps: ffi::janus_log_timestamps == 1,
                log_colors: ffi::janus_log_colors == 1,
                clock: Local::now,
            }
        }
    }
}

/// Writes a message at the given log level to the Janus log, using the provided parameters to control
/// how the log message is formatted.
pub fn write_log(level: LogLevel, message: &str, params: LogParameters) {
    if level as i32 <= params.max_log_level {
        let output = CString::new(print_log(level, message, params)).expect("Null character in log message :(");
        unsafe { ffi::janus_vprintf(output.as_ptr()) }
    }
}

/// Prints a message at the given log level into an owned string, using the provided parameters to control
/// how the log message is formatted.
pub fn print_log(level: LogLevel, message: &str, params: LogParameters) -> String {
    let mut output = String::with_capacity(message.len() + 40);
    if params.log_timestamps {
        write!(output, "{} ", (params.clock)().format("[%a %b %e %T %Y]")).unwrap();
    }
    if level <= LogLevel::Warn {
        let name = format!("[{:?}] ", level).to_uppercase();
        match level.color() {
            Some(c) if params.log_colors => write!(output, "{}", name.color(c)).unwrap(),
            _ => output.push_str(&name),
        }
    }
    output.push_str(message);
    output.push('\n');
    output
}

/// Writes a message at the given log level to the Janus log.
pub fn log(level: LogLevel, message: &str) {
    write_log(level, message, LogParameters::default());
}

#[cfg(test)]
mod tests {

    use super::*;
    use super::chrono::TimeZone;

    fn fixed_clock(year: i32, month: u32, day: u32, hour: u32, min: u32, sec: u32) -> DateTime<Local> {
        Local.ymd(year, month, day).and_hms(hour, min, sec)
    }

    #[test]
    fn log_format_correctness() {
        assert_eq!(
            "[Tue Oct 10 01:37:46 2017] [WARN] Test message.\n",
            print_log(
                LogLevel::Warn,
                "Test message.",
                LogParameters {
                    max_log_level: 6,
                    log_timestamps: true,
                    log_colors: false,
                    clock: || fixed_clock(2017, 10, 10, 1, 37, 46),
                }
            )
        )
    }
}
<commit_msg>Use write! in logging for consistency<commit_after>/// Utilities for writing messages to the Janus log.
extern crate chrono;
extern crate colored;

use self::chrono::{DateTime, Local};
use self::colored::{Color, Colorize};
use super::ffi;
use std::ffi::CString;
use std::fmt::Write;

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
/// A Janus log level. Lower is more severe.
pub enum LogLevel {
    Fatal = 1,
    Err = 2,
    Warn = 3,
    Info = 4,
    Verb = 5,
    Huge = 6,
    Dbg = 7,
}

impl LogLevel {
    /// The color associated with each log level's label (if colors are enabled.)
    fn color(&self) -> Option<Color> {
        match *self {
            LogLevel::Fatal => Some(Color::Magenta),
            LogLevel::Err => Some(Color::Red),
            LogLevel::Warn => Some(Color::Yellow),
            _ => None,
        }
    }
}

#[derive(Debug, Clone)]
pub struct LogParameters {
    pub max_log_level: i32,
    pub log_timestamps: bool,
    pub log_colors: bool,
    pub clock: fn() -> DateTime<Local>,
}

impl Default for LogParameters {
    fn default() -> Self {
        unsafe {
            Self {
                max_log_level: ffi::janus_log_level,
                log_timestamps: ffi::janus_log_timestamps == 1,
                log_colors: ffi::janus_log_colors == 1,
                clock: Local::now,
            }
        }
    }
}

/// Writes a message at the given log level to the Janus log, using the provided parameters to control
/// how the log message is formatted.
pub fn write_log(level: LogLevel, message: &str, params: LogParameters) {
    if level as i32 <= params.max_log_level {
        let output = CString::new(print_log(level, message, params)).expect("Null character in log message :(");
        unsafe { ffi::janus_vprintf(output.as_ptr()) }
    }
}

/// Prints a message at the given log level into an owned string, using the provided parameters to control
/// how the log message is formatted.
pub fn print_log(level: LogLevel, message: &str, params: LogParameters) -> String {
    let mut output = String::with_capacity(message.len() + 40);
    if params.log_timestamps {
        write!(output, "{} ", (params.clock)().format("[%a %b %e %T %Y]")).unwrap();
    }
    if level <= LogLevel::Warn {
        let prefix = format!("[{:?}] ", level).to_uppercase();
        let prefix = match level.color() {
            Some(c) if params.log_colors => format!("{}", prefix.color(c)),
            _ => prefix,
        };
        write!(output, "{}", prefix).unwrap();
    }
    write!(output, "{}\n", message).unwrap();
    output
}

/// Writes a message at the given log level to the Janus log.
pub fn log(level: LogLevel, message: &str) {
    write_log(level, message, LogParameters::default());
}

#[cfg(test)]
mod tests {

    use super::*;
    use super::chrono::TimeZone;

    fn fixed_clock(year: i32, month: u32, day: u32, hour: u32, min: u32, sec: u32) -> DateTime<Local> {
        Local.ymd(year, month, day).and_hms(hour, min, sec)
    }

    #[test]
    fn log_format_correctness() {
        assert_eq!(
            "[Tue Oct 10 01:37:46 2017] [WARN] Test message.\n",
            print_log(
                LogLevel::Warn,
                "Test message.",
                LogParameters {
                    max_log_level: 6,
                    log_timestamps: true,
                    log_colors: false,
                    clock: || fixed_clock(2017, 10, 10, 1, 37, 46),
                }
            )
        )
    }
}
<|endoftext|>


<commit_before>use std::fmt;

use bytes::Bytes;
use h2::ReleaseCapacity;

/// A piece of a message body.
pub struct Chunk(Inner);

struct Inner {
    bytes: Bytes,
    _flow_control: Option<AutoRelease>,
}

struct AutoRelease {
    cap: usize,
    release: ReleaseCapacity,
}

impl Drop for AutoRelease {
    fn drop(&mut self) {
        let _ = self.release.release_capacity(self.cap);
    }
}

impl Chunk {
    pub(crate) fn h2(bytes: Bytes, rel_cap: &ReleaseCapacity) -> Chunk {
        let cap = bytes.len();
        Chunk(Inner {
            bytes: bytes,
            _flow_control: Some(AutoRelease {
                cap: cap,
                release: rel_cap.clone(),
            }),
        })
    }
}

impl From<Vec<u8>> for Chunk {
    #[inline]
    fn from(v: Vec<u8>) -> Chunk {
        Chunk::from(Bytes::from(v))
    }
}

impl From<&'static [u8]> for Chunk {
    #[inline]
    fn from(slice: &'static [u8]) -> Chunk {
        Chunk::from(Bytes::from_static(slice))
    }
}

impl From<String> for Chunk {
    #[inline]
    fn from(s: String) -> Chunk {
        s.into_bytes().into()
    }
}

impl From<&'static str> for Chunk {
    #[inline]
    fn from(slice: &'static str) -> Chunk {
        slice.as_bytes().into()
    }
}

impl From<Bytes> for Chunk {
    #[inline]
    fn from(bytes: Bytes) -> Chunk {
        Chunk(Inner {
            bytes: bytes,
            _flow_control: None,
        })
    }
}

impl From<Chunk> for Bytes {
    #[inline]
    fn from(chunk: Chunk) -> Bytes {
        chunk.0.bytes
    }
}

impl ::std::ops::Deref for Chunk {
    type Target = [u8];

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

impl AsRef<[u8]> for Chunk {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        &self.0.bytes
    }
}

impl fmt::Debug for Chunk {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self.as_ref(), f)
    }
}

impl Default for Chunk {
    #[inline]
    fn default() -> Chunk {
        Chunk::from(Bytes::new())
    }
}

impl IntoIterator for Chunk {
    type Item = u8;
    type IntoIter = <Bytes as IntoIterator>::IntoIter;

    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        self.0.bytes.into_iter()
    }
}

impl Extend<u8> for Chunk {
    #[inline]
    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=u8> {
        self.0.bytes.extend(iter)
    }
}
<commit_msg>docs(body): add more details about Chunk<commit_after>use std::fmt;

use bytes::Bytes;
use h2::ReleaseCapacity;

/// A piece of a message body.
///
/// These are returned by [`Body`](::Body). It is an efficient buffer type,
/// and wraps auto-management of flow control in the case of HTTP2 messages.
///
/// A `Chunk` can be easily created by many of Rust's standard types that
/// represent a collection of bytes, using `Chunk::from`.
pub struct Chunk {
    /// The buffer of bytes making up this body.
    bytes: Bytes,
    /// A possible HTTP2 marker to ensure we release window capacity.
    ///
    /// This version just automatically releases all capacity when `Chunk`
    /// is dropped.
    _flow_control: Option<AutoRelease>,
}

struct AutoRelease {
    cap: usize,
    release: ReleaseCapacity,
}

impl Drop for AutoRelease {
    fn drop(&mut self) {
        let _ = self.release.release_capacity(self.cap);
    }
}

impl Chunk {
    pub(crate) fn h2(bytes: Bytes, rel_cap: &ReleaseCapacity) -> Chunk {
        let cap = bytes.len();
        Chunk {
            bytes: bytes,
            _flow_control: Some(AutoRelease {
                cap: cap,
                release: rel_cap.clone(),
            }),
        }
    }

    /// Converts this `Chunk` directly into the `Bytes` type without copies.
    ///
    /// This is simply an inherent alias for `Bytes::from(chunk)`, which exists,
    /// but doesn't appear in rustdocs.
    #[inline]
    pub fn into_bytes(self) -> Bytes {
        self.into()
    }
}

impl From<Vec<u8>> for Chunk {
    #[inline]
    fn from(v: Vec<u8>) -> Chunk {
        Chunk::from(Bytes::from(v))
    }
}

impl From<&'static [u8]> for Chunk {
    #[inline]
    fn from(slice: &'static [u8]) -> Chunk {
        Chunk::from(Bytes::from_static(slice))
    }
}

impl From<String> for Chunk {
    #[inline]
    fn from(s: String) -> Chunk {
        s.into_bytes().into()
    }
}

impl From<&'static str> for Chunk {
    #[inline]
    fn from(slice: &'static str) -> Chunk {
        slice.as_bytes().into()
    }
}

impl From<Bytes> for Chunk {
    #[inline]
    fn from(bytes: Bytes) -> Chunk {
        Chunk {
            bytes: bytes,
            _flow_control: None,
        }
    }
}

impl From<Chunk> for Bytes {
    #[inline]
    fn from(chunk: Chunk) -> Bytes {
        chunk.bytes
    }
}

impl ::std::ops::Deref for Chunk {
    type Target = [u8];

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

impl AsRef<[u8]> for Chunk {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        &self.bytes
    }
}

impl fmt::Debug for Chunk {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self.as_ref(), f)
    }
}

impl Default for Chunk {
    #[inline]
    fn default() -> Chunk {
        Chunk::from(Bytes::new())
    }
}

impl IntoIterator for Chunk {
    type Item = u8;
    type IntoIter = <Bytes as IntoIterator>::IntoIter;

    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        self.bytes.into_iter()
    }
}

impl Extend<u8> for Chunk {
    #[inline]
    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=u8> {
        self.bytes.extend(iter)
    }
}
<|endoftext|>


<commit_before>use failure::{Backtrace, Context, Error, Fail};
use std::fmt;
use std::fmt::Display;

#[derive(Debug)]
pub struct ModbusError {
    inner: Context<ModbusErrorKind>,
}

#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)]
pub enum ModbusErrorKind {
    #[fail(display = "Function code received in the query is not recognized or allowed by slave")]
    IllegalFunction,
    //  {
    //     display("Illegal function")
    // }
    #[fail(display = "Data address of some or all the required entities are not allowed or do not exist in slave")]
    IllegalDataAddress,
    //  {
    //     display("Illegal data address")
    // }
    #[fail(display = "Value is not accepted by slave")]
    IllegalDataValue,
    //  {
    //     display("Illegal data value")
    // }
    #[fail(display = "Unrecoverable error occurred while slave was attempting to perform requested action")]
    SlaveDeviceOrServerFailure,
    //  {
    //     display("Slave device or server failure")
    // }
    #[fail(display = "Acknowledge")]
    Acknowledge,
    //  {
    //     display("Acknowledge")
    // }
    #[fail(display = "Slave device or server is busy")]
    SlaveDeviceOrServerIsBusy,
    //  {
    //     display("Slave device or server is busy")
    // }
    #[fail(display = "Negative acknowledge")]
    NegativeAcknowledge,
    //  {
    //     display("Negative acknowledge")
    // }
    #[fail(display = "Memory parity error")]
    MemoryParityError,
    //  {
    //     display("Memory parity error")
    // }
    #[fail(display = "Gateway path unavailable")]
    GatewayPathUnavailable,
    //  {
    //     display("Gateway path unavailable")
    // }
    #[fail(display = "Target device failed to respond")]
    TargetDeviceFailedToRespond,
    //  {
    //     display("Target device failed to respond")
    // }
    #[fail(display = "Invalid CRC")]
    InvalidCRC,
    //  {
    //     display("Invalid CRC")
    // }
    #[fail(display = "Invalid data")]
    InvalidData,
    //  {
    //     display("Invalid data")
    // }
    #[fail(display = "Invalid exception code")]
    InvalidExceptionCode,
    //  {
    //     display("Invalid exception code")
    // }
    #[fail(display = "Too many data requested")]
    TooManyData,
    //  {
    //     display("Too many data")
    // }
    #[fail(display = "Response not from requested slave")]
    ResponseNotFromRequestedSlave,
    //  {
    //     display("Response not from requested slave")
    // }
    #[fail(display = "Response not from requested slave")]
    BADSLAVE,
    //  {
    //     display("Response not from requested slave")
    // }
    #[fail(display = "libmodbus API incompatible response")]
    IncompatibleAPI,
    //  {
    //     display("libmodbus API incompatible response")
    // }
    #[fail(display = "Invalid slave ID")]
    InvalidSlaveID,
    //  {
    //     display("Invalid slave ID: '{}'", id)
    // }
    #[fail(display = "Invalid parameter given")]
    InvalidParameter,
    //  {
    //     display("Invalid parameter given: '{}'", desc)
    // }
    #[fail(display = "Unit test client failed")]
    UnitTestClientFailure,
    //  {
    //     display("Unit test client failed")
    // }
}

impl Fail for ModbusError {
    fn cause(&self) -> Option<&Fail> {
        self.inner.cause()
    }

    fn backtrace(&self) -> Option<&Backtrace> {
        self.inner.backtrace()
    }
}

impl Display for ModbusError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.inner, f)
    }
}

impl ModbusError {
    pub fn kind(&self) -> ModbusErrorKind {
        *self.inner.get_context()
    }
}

impl From<ModbusErrorKind> for ModbusError {
    fn from(kind: ModbusErrorKind) -> ModbusError {
        ModbusError { inner: Context::new(kind) }
    }
}

impl From<Context<ModbusErrorKind>> for ModbusError {
    fn from(inner: Context<ModbusErrorKind>) -> ModbusError {
        ModbusError { inner: inner }
    }
}
<commit_msg>Reduced failure error type<commit_after>// https://github.com/withoutboats/failure/issues/110
use failure;
use std::io;

#[derive(Debug, Fail)]
pub enum Error {
    #[fail(display = "IO Error {}", _0)]
    IoError(#[cause] io::Error),
    #[fail(display = "Error {}", _0)]
    Custom(failure::Error),
}

impl From <io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IoError(err)
    }
}

impl From<failure::Error> for Error {
    fn from(err: failure::Error) -> Error {
        Error::Custom(err)
    }
}
<|endoftext|>


<commit_before>//! Provides a standardized error type for oxcable.

use std::io;
use std::result;

use byteorder;
use portaudio::pa;
use portmidi;

#[derive(Debug)]
pub enum Error {
    /// No audio resources can be opened.
    NoAudioDevices,
    /// No MIDI resources can be opened.
    NoMidiDevices,
    /// A file is not formatted properly.
    InvalidFile,
    /// A requested index is out of range.
    ///
    /// The string argument specifies which index was out of range.
    OutOfRange(&'static str),
    /// The requested operation would create a graph cycle.
    CreatesCycle,
    /// A std::io operation failed.
    Io(io::Error),
    /// A portaudio operation failed.
    PortAudio(pa::Error),
    /// A portmidi operation failed.
    PortMidi(portmidi::PortMidiError),
    /// A feature isn't supported.
    ///
    /// The string argument describes what feature.
    Unsupported(&'static str),
}

impl From<byteorder::Error> for Error {
    fn from(e: byteorder::Error) -> Self {
        match e {
            byteorder::Error::UnexpectedEOF => Error::InvalidFile,
            byteorder::Error::Io(e) => Error::Io(e),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

impl From<pa::Error> for Error {
    fn from(e: pa::Error) -> Error {
        Error::PortAudio(e)
    }
}

impl From<portmidi::PortMidiError> for Error {
    fn from(e: portmidi::PortMidiError) -> Error {
        Error::PortMidi(e)
    }
}

pub type Result<T> = result::Result<T, Error>;
<commit_msg>Implement Display for Error<commit_after>//! Provides a standardized error type for oxcable.

use std::fmt;
use std::io;
use std::result;

use byteorder;
use portaudio::pa;
use portmidi;

/// A global error type for all oxcable operations.
///
/// Many of the errors simply wrap the errors provided by our supporting
/// libraries.
#[derive(Debug)]
pub enum Error {
    /// No audio resources can be opened.
    NoAudioDevices,
    /// No MIDI resources can be opened.
    NoMidiDevices,
    /// A file is not formatted properly.
    InvalidFile,
    /// A requested index is out of range.
    ///
    /// The string argument specifies which index was out of range.
    OutOfRange(&'static str),
    /// The requested operation would create a graph cycle.
    CreatesCycle,
    /// A feature isn't supported.
    ///
    /// The string argument describes what feature.
    Unsupported(&'static str),
    /// A std::io operation failed.
    Io(io::Error),
    /// A portaudio operation failed.
    PortAudio(pa::Error),
    /// A portmidi operation failed.
    PortMidi(portmidi::PortMidiError),
}
use self::Error::*;

impl From<byteorder::Error> for Error {
    fn from(e: byteorder::Error) -> Self {
        match e {
            byteorder::Error::UnexpectedEOF => Error::InvalidFile,
            byteorder::Error::Io(e) => Error::Io(e),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

impl From<pa::Error> for Error {
    fn from(e: pa::Error) -> Error {
        Error::PortAudio(e)
    }
}

impl From<portmidi::PortMidiError> for Error {
    fn from(e: portmidi::PortMidiError) -> Error {
        Error::PortMidi(e)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &NoAudioDevices => write!(f, "No audio devices found."),
            &NoMidiDevices => write!(f, "No midi devices found."),
            &InvalidFile => write!(f, "The provided was not valid."),
            &OutOfRange(ref idx) => write!(f, "Index `{}` was out of range.", idx),
            &CreatesCycle =>
                write!(f, "The requested action creates a graph cycle."),
            &Unsupported(ref feat) =>
                write!(f, "Unsupported feature: {}", feat),
            &Io(ref e) => write!(f, "IO error: {}", e),
            &PortAudio(ref e) => write!(f, "PortAudio error: {}", e),
            &PortMidi(ref e) => write!(f, "PortMidi error: {:?}", e),
        }
    }
}

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


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

/// Error when reading to TopoJson
#[derive(Debug, PartialEq, Eq)]
pub enum Error {
    BboxExpectedArray,
    BboxExpectedNumericValues,
    TopologyExpectedObjects,
    TopologyExpectedArcs,
    TransformExpectedScale,
    TransformExpectedTranslate,
    ScaleExpectedArray,
    ScaleExpectedNumericValues,
    TranslateExpectedArray,
    TranslateExpectedNumericValues,
    TopoJsonUnknownType,
    GeometryUnknownType,
    MalformedJson,
    PropertiesExpectedObjectOrNull,
    ExpectedType { expected: String, actual: String },
    TopoToGeoUnknownKey(String),

    // FIXME: make these types more specific
    ExpectedStringValue,
    ExpectedProperty(String),
    Expectedi32Value,
    ExpectedF64Value,
    ExpectedArrayValue,
    ExpectedObjectValue,
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match *self {
            Error::BboxExpectedArray =>
            {
                write!(f, "Encountered non-array type for a 'bbox' object.")
            }
            Error::BboxExpectedNumericValues =>
            {
                write!(f, "Encountered non-numeric value within 'bbox' array.")
            }
            Error::TopologyExpectedObjects =>
            {
                write!(f, "Expected member with the name 'objects' in Topology.")
            }
            Error::TopologyExpectedArcs =>
            {
                write!(f, "Expected member with the name 'arcs' in Topology.")
            }
            Error::TransformExpectedScale =>
            {
                write!(f, "Transform must have a member with the name 'scale'.")
            }
            Error::TransformExpectedTranslate =>
            {
                write!(f, "Transform must have a member with the name 'translate'.")
            }
            Error::ScaleExpectedArray =>
            {
                write!(f, "Encountered non-array type for a 'scale' object.")
            }
            Error::ScaleExpectedNumericValues =>
            {
                write!(f, "Encountered non-numeric value within 'scale' array.")
            }
            Error::TranslateExpectedArray =>
            {
                write!(f, "Encountered non-array type for a 'translate' object.")
            }
            Error::TranslateExpectedNumericValues =>
            {
                write!(f, "Encountered non-numeric value within 'translate' array.")
            }
            Error::TopoJsonUnknownType =>
            {
                write!(f, "Encountered unknown TopoJSON object type.")
            }
            Error::GeometryUnknownType => write!(f, "Encountered unknown 'geometry' object type."),
            Error::MalformedJson =>
            // FIXME: can we report specific serialization error?
            {
                write!(f, "Encountered malformed JSON.")
            }
            Error::PropertiesExpectedObjectOrNull =>
            // FIXME: inform what type we actually found
            {
                write!(
                    f,
                    "Encountered neither object type nor null type for \
                     'properties' object."
                )
            }
            Error::ExpectedType {
                ref expected,
                ref actual,
            } => write!(
                f,
                "Expected TopoJSON type '{}', found '{}'",
                expected, actual,
            ),
            Error::TopoToGeoUnknownKey(ref key) => {
                write!(f, "No object with key '{}' in the given Topology.", key)
            }
            Error::ExpectedStringValue => write!(f, "Expected a string value."),
            Error::ExpectedProperty(ref prop_name) => {
                write!(f, "Expected TopoJSON property '{}'.", prop_name)
            }
            Error::ExpectedF64Value => write!(f, "Expected a floating-point value."),
            Error::Expectedi32Value => write!(f, "Expected a positive integer."),
            Error::ExpectedArrayValue => write!(f, "Expected an array."),
            Error::ExpectedObjectValue => write!(f, "Expected an object."),
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::BboxExpectedArray => "non-array 'bbox' type",
            Error::BboxExpectedNumericValues => "non-numeric 'bbox' array",
            Error::TopologyExpectedObjects => "no 'objects' member in topology",
            Error::TopologyExpectedArcs => "no 'arcs' member in topology",
            Error::TransformExpectedScale => "no 'scale' member in 'transform' member of topology",
            Error::TransformExpectedTranslate => "no 'translate' member in 'transform' member of topology",
            Error::ScaleExpectedArray => "non-array 'scale' type",
            Error::ScaleExpectedNumericValues => "non-numeric 'scale' array",
            Error::TranslateExpectedArray => "non-array 'translate' type",
            Error::TranslateExpectedNumericValues => "non-numeric 'translate' array",
            Error::TopoJsonUnknownType => "unknown TopoJSON object type",
            Error::GeometryUnknownType => "unknown 'geometry' object type",
            Error::MalformedJson => "malformed JSON",
            Error::PropertiesExpectedObjectOrNull => "neither object type nor null type for properties' object.",
            Error::ExpectedType { .. } => "mismatched TopoJSON type",
            Error::TopoToGeoUnknownKey(..) => "requested key not found",
            Error::ExpectedStringValue => "expected a string value",
            Error::ExpectedProperty(..) => "expected a TopoJSON property",
            Error::ExpectedF64Value => "expected a floating-point value",
            Error::Expectedi32Value => "expected a positive integer",
            Error::ExpectedArrayValue => "expected an array",
            Error::ExpectedObjectValue => "expected an object",
        }
    }
}
<commit_msg>Non exhaustive pattern for errors<commit_after>// Copyright 2018 The GeoRust Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/// Error when reading to TopoJson
#[derive(Debug, PartialEq, Eq)]
pub enum Error {
    BboxExpectedArray,
    BboxExpectedNumericValues,
    TopologyExpectedObjects,
    TopologyExpectedArcs,
    TransformExpectedScale,
    TransformExpectedTranslate,
    ScaleExpectedArray,
    ScaleExpectedNumericValues,
    TranslateExpectedArray,
    TranslateExpectedNumericValues,
    TopoJsonUnknownType,
    GeometryUnknownType,
    MalformedJson,
    PropertiesExpectedObjectOrNull,
    ExpectedType { expected: String, actual: String },
    TopoToGeoUnknownKey(String),

    // FIXME: make these types more specific
    ExpectedStringValue,
    ExpectedProperty(String),
    Expectedi32Value,
    ExpectedF64Value,
    ExpectedArrayValue,
    ExpectedObjectValue,
    #[doc(hidden)]
    __Nonexhaustive,
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match *self {
            Error::BboxExpectedArray =>
            {
                write!(f, "Encountered non-array type for a 'bbox' object.")
            }
            Error::BboxExpectedNumericValues =>
            {
                write!(f, "Encountered non-numeric value within 'bbox' array.")
            }
            Error::TopologyExpectedObjects =>
            {
                write!(f, "Expected member with the name 'objects' in Topology.")
            }
            Error::TopologyExpectedArcs =>
            {
                write!(f, "Expected member with the name 'arcs' in Topology.")
            }
            Error::TransformExpectedScale =>
            {
                write!(f, "Transform must have a member with the name 'scale'.")
            }
            Error::TransformExpectedTranslate =>
            {
                write!(f, "Transform must have a member with the name 'translate'.")
            }
            Error::ScaleExpectedArray =>
            {
                write!(f, "Encountered non-array type for a 'scale' object.")
            }
            Error::ScaleExpectedNumericValues =>
            {
                write!(f, "Encountered non-numeric value within 'scale' array.")
            }
            Error::TranslateExpectedArray =>
            {
                write!(f, "Encountered non-array type for a 'translate' object.")
            }
            Error::TranslateExpectedNumericValues =>
            {
                write!(f, "Encountered non-numeric value within 'translate' array.")
            }
            Error::TopoJsonUnknownType =>
            {
                write!(f, "Encountered unknown TopoJSON object type.")
            }
            Error::GeometryUnknownType => write!(f, "Encountered unknown 'geometry' object type."),
            Error::MalformedJson =>
            // FIXME: can we report specific serialization error?
            {
                write!(f, "Encountered malformed JSON.")
            }
            Error::PropertiesExpectedObjectOrNull =>
            // FIXME: inform what type we actually found
            {
                write!(
                    f,
                    "Encountered neither object type nor null type for \
                     'properties' object."
                )
            }
            Error::ExpectedType {
                ref expected,
                ref actual,
            } => write!(
                f,
                "Expected TopoJSON type '{}', found '{}'",
                expected, actual,
            ),
            Error::TopoToGeoUnknownKey(ref key) => {
                write!(f, "No object with key '{}' in the given Topology.", key)
            }
            Error::ExpectedStringValue => write!(f, "Expected a string value."),
            Error::ExpectedProperty(ref prop_name) => {
                write!(f, "Expected TopoJSON property '{}'.", prop_name)
            }
            Error::ExpectedF64Value => write!(f, "Expected a floating-point value."),
            Error::Expectedi32Value => write!(f, "Expected a positive integer."),
            Error::ExpectedArrayValue => write!(f, "Expected an array."),
            Error::ExpectedObjectValue => write!(f, "Expected an object."),
            Error::__Nonexhaustive => unreachable!(),
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::BboxExpectedArray => "non-array 'bbox' type",
            Error::BboxExpectedNumericValues => "non-numeric 'bbox' array",
            Error::TopologyExpectedObjects => "no 'objects' member in topology",
            Error::TopologyExpectedArcs => "no 'arcs' member in topology",
            Error::TransformExpectedScale => "no 'scale' member in 'transform' member of topology",
            Error::TransformExpectedTranslate => "no 'translate' member in 'transform' member of topology",
            Error::ScaleExpectedArray => "non-array 'scale' type",
            Error::ScaleExpectedNumericValues => "non-numeric 'scale' array",
            Error::TranslateExpectedArray => "non-array 'translate' type",
            Error::TranslateExpectedNumericValues => "non-numeric 'translate' array",
            Error::TopoJsonUnknownType => "unknown TopoJSON object type",
            Error::GeometryUnknownType => "unknown 'geometry' object type",
            Error::MalformedJson => "malformed JSON",
            Error::PropertiesExpectedObjectOrNull => "neither object type nor null type for properties' object.",
            Error::ExpectedType { .. } => "mismatched TopoJSON type",
            Error::TopoToGeoUnknownKey(..) => "requested key not found",
            Error::ExpectedStringValue => "expected a string value",
            Error::ExpectedProperty(..) => "expected a TopoJSON property",
            Error::ExpectedF64Value => "expected a floating-point value",
            Error::Expectedi32Value => "expected a positive integer",
            Error::ExpectedArrayValue => "expected an array",
            Error::ExpectedObjectValue => "expected an object",
            Error::__Nonexhaustive => unreachable!(),
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt::{Display, Formatter, Result as FmtResult};
use rustc_serialize::json::{ToJson, Json};
use std::collections::BTreeMap;
use iron::prelude::*;
use iron::status::Status;
use iron::headers::{ContentType};
use iron::modifiers::Header;
use iron::mime::Mime;
use std::str::FromStr;

#[derive(Debug)]
pub enum Error {
    BadRequest,
    Unprocessable,
    NotFound,
    Unexpected,
}

impl Error {
    pub fn status(&self) -> Status {
        match *self {
            Error::BadRequest    => Status::BadRequest,
            Error::Unprocessable => Status::UnprocessableEntity,
            Error::NotFound      => Status::NotFound,
            Error::Unexpected    => Status::InternalServerError,
        }
    }

    pub fn as_response(&self) -> Response {
        let json_type = Header(ContentType(Mime::from_str("application/json").ok().unwrap()));
        Response::with((self.status(),
                        json_type,
                        self.to_json().to_string()))
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match *self {
            Error::BadRequest    => write!(f, "BadRequest"),
            Error::Unprocessable => write!(f, "Unproccesable"),
            Error::NotFound      => write!(f, "NotFound"),
            Error::Unexpected    => write!(f, "UnexpectedError"),
        }
    }
}

impl ToJson for Error {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("message".to_string(), self.to_string().to_json());
        Json::Object(d)
    }
}

<commit_msg>Add DBError to pink_spider::Error<commit_after>use std::fmt::{Display, Formatter, Result as FmtResult};
use rustc_serialize::json::{ToJson, Json};
use std::collections::BTreeMap;
use iron::prelude::*;
use iron::status::Status;
use iron::headers::{ContentType};
use iron::modifiers::Header;
use iron::mime::Mime;
use std::str::FromStr;
use postgres;

#[derive(Debug)]
pub enum Error {
    BadRequest,
    Unprocessable,
    NotFound,
    DbError(postgres::error::Error),
    Unexpected,
}

impl Error {
    pub fn status(&self) -> Status {
        match *self {
            Error::BadRequest    => Status::BadRequest,
            Error::Unprocessable => Status::UnprocessableEntity,
            Error::NotFound      => Status::NotFound,
            Error::DbError(_)    => Status::InternalServerError,
            Error::Unexpected    => Status::InternalServerError,
        }
    }

    pub fn as_response(&self) -> Response {
        let json_type = Header(ContentType(Mime::from_str("application/json").ok().unwrap()));
        Response::with((self.status(),
                        json_type,
                        self.to_json().to_string()))
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match *self {
            Error::BadRequest     => write!(f, "BadRequest"),
            Error::Unprocessable  => write!(f, "Unproccesable"),
            Error::NotFound       => write!(f, "NotFound"),
            Error::DbError(ref e) => write!(f, "UnexpectedError: DBError {}", e),
            Error::Unexpected     => write!(f, "UnexpectedError"),
        }
    }
}

impl ToJson for Error {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("message".to_string(), self.to_string().to_json());
        Json::Object(d)
    }
}

impl From<postgres::error::Error> for Error {
    fn from(err: postgres::error::Error) -> Error {
        Error::DbError(err)
    }
}
<|endoftext|>