<commit_before>use std::ptr;
use std::marker::PhantomData;
use gl;
use gl::types::*;
use context::Context;
use image_data::{Image2d, TextelFormat, ImageFormat};
use types::GLError;

pub struct Texture<T: TextureType> {
    gl_id: GLuint,
    phantom: PhantomData<*mut T>
}
pub type Texture2d = Texture<Tx2d>;
pub type TextureCubeMap = Texture<TxCubeMap>;

impl<T: TextureType> Texture<T> {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl<T: TextureType> Drop for Texture<T> {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteTextures(1, &self.gl_id as *const GLuint);
        }
    }
}

impl Context {
    pub unsafe fn gen_texture<T: TextureType>(&self) -> Texture<T> {
        let mut id : GLuint =  0;

        gl::GenTextures(1, &mut id as *mut GLuint);
        dbg_gl_sanity_check! {
            GLError::InvalidValue => "`n` is negative",
            _ => "Unknown error"
        }

        Texture {
            gl_id: id,
            phantom: PhantomData
        }
    }
}

pub trait ImageTargetType {
    fn gl_enum(&self) -> GLenum;
}

pub trait TextureType {
    type ImageTargetType: ImageTargetType;

    fn target() -> TextureBindingTarget;
}

pub struct Tx2d;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Tx2dImageTarget {
    Texture2d = gl::TEXTURE_2D as isize
}

impl ImageTargetType for Tx2dImageTarget {
    fn gl_enum(&self) -> GLenum {
        *self as GLenum
    }
}

impl TextureType for Tx2d {
    type ImageTargetType = Tx2dImageTarget;

    fn target() -> TextureBindingTarget {
        TextureBindingTarget::Texture2d
    }
}

pub struct TxCubeMap;

gl_enum! {
    pub gl_enum TxCubeMapImageTarget {
        CubeMapPositiveX as TEXTURE_CUBE_MAP_POSITIVE_X =
            gl::TEXTURE_CUBE_MAP_POSITIVE_X,
        CubeMapNegativeX as TEXTURE_CUBE_MAP_NEGATIVE_X =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_X,
        CubeMapPositiveY as TEXTURE_CUBE_MAP_POSITIVE_Y =
            gl::TEXTURE_CUBE_MAP_POSITIVE_Y,
        CubeMapNegativeY as TEXTURE_CUBE_MAP_NEGATIVE_Y =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_Y,
        CubeMapPositiveZ as TEXTURE_CUBE_MAP_POSITIVE_Z =
            gl::TEXTURE_CUBE_MAP_POSITIVE_Z,
        CubeMapNegativeZ as TEXTURE_CUBE_MAP_NEGATIVE_Z =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_Z
    }
}

impl ImageTargetType for TxCubeMapImageTarget {
    fn gl_enum(&self) -> GLenum {
        self.gl_enum()
    }
}

impl TextureType for TxCubeMap {
    type ImageTargetType = TxCubeMapImageTarget;

    fn target() -> TextureBindingTarget {
        TextureBindingTarget::TextureCubeMap
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TextureBindingTarget {
    Texture2d = gl::TEXTURE_2D as isize,
    TextureCubeMap = gl::TEXTURE_CUBE_MAP as isize
}

impl TextureBindingTarget {
    pub fn gl_enum(&self) -> GLenum {
        *self as GLenum
    }
}

// HACK: Done to allow glitter::TEXTURE_2D as both a
//       TextureBindingTarget and Tx2dImageTarget
pub struct VariantTexture2d;

impl From<VariantTexture2d> for TextureBindingTarget {
    fn from(_: VariantTexture2d) -> TextureBindingTarget {
        TextureBindingTarget::Texture2d
    }
}

impl From<VariantTexture2d> for Tx2dImageTarget {
    fn from(_: VariantTexture2d) -> Tx2dImageTarget {
        Tx2dImageTarget::Texture2d
    }
}

impl ImageTargetType for VariantTexture2d {
    fn gl_enum(&self) -> GLenum {
        gl::TEXTURE_2D
    }
}

// TODO: Use type refinements someday...
#[derive(Debug, Clone, Copy)]
pub enum TextureFilter {
    Nearest,
    Linear
}

#[derive(Debug, Clone, Copy)]
pub enum TextureMipmapFilter {
    Filter(TextureFilter),
    MipmapFilter { criterion: TextureFilter, mipmap: TextureFilter }
}

pub const NEAREST : TextureFilter = TextureFilter::Nearest;
pub const LINEAR : TextureFilter = TextureFilter::Linear;
pub const NEAREST_MIPMAP_NEAREST : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Nearest,
        mipmap: TextureFilter::Nearest
    };
pub const LINEAR_MIPMAP_NEAREST : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Linear,
        mipmap: TextureFilter::Nearest
    };
pub const NEAREST_MIPMAP_LINEAR : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Nearest,
        mipmap: TextureFilter::Linear
    };
pub const LINEAR_MIPMAP_LINEAR : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Linear,
        mipmap: TextureFilter::Linear
    };

#[allow(dead_code)]
impl TextureFilter {
    fn from_gl(gl_enum: GLenum) -> Result<Self, ()> {
        match gl_enum {
            gl::NEAREST => { Ok(self::NEAREST) },
            gl::LINEAR => { Ok(self::LINEAR) },
            _ => { Err(()) }
        }
    }

    fn gl_enum(&self) -> GLenum {
        match *self {
            self::NEAREST => gl::NEAREST,
            self::LINEAR => gl::LINEAR
        }
    }
}

#[allow(dead_code)]
impl TextureMipmapFilter {
    fn from_gl(gl_enum: GLenum) -> Result<Self, ()> {
        match gl_enum {
            gl::NEAREST => { Ok(TextureMipmapFilter::Filter(self::NEAREST)) },
            gl::LINEAR => { Ok(TextureMipmapFilter::Filter(self::LINEAR)) },
            gl::NEAREST_MIPMAP_NEAREST => { Ok(self::NEAREST_MIPMAP_NEAREST) },
            gl::LINEAR_MIPMAP_NEAREST => { Ok(self::LINEAR_MIPMAP_NEAREST) },
            gl::NEAREST_MIPMAP_LINEAR => { Ok(self::NEAREST_MIPMAP_LINEAR) },
            gl::LINEAR_MIPMAP_LINEAR => { Ok(self::LINEAR_MIPMAP_LINEAR) },
            _ => { Err(()) }
        }
    }

    fn gl_enum(&self) -> GLenum {
        match *self {
            TextureMipmapFilter::Filter(self::LINEAR) => { gl::LINEAR },
            TextureMipmapFilter::Filter(self::NEAREST) => { gl::NEAREST },
            self::NEAREST_MIPMAP_NEAREST => { gl::NEAREST_MIPMAP_NEAREST },
            self::LINEAR_MIPMAP_NEAREST => { gl::LINEAR_MIPMAP_NEAREST },
            self::NEAREST_MIPMAP_LINEAR => { gl::NEAREST_MIPMAP_LINEAR },
            self::LINEAR_MIPMAP_LINEAR => { gl::LINEAR_MIPMAP_LINEAR }
        }
    }
}

impl From<TextureFilter> for TextureMipmapFilter {
    fn from(filter: TextureFilter) -> TextureMipmapFilter {
        TextureMipmapFilter::Filter(filter)
    }
}

gl_enum! {
    pub gl_enum TextureWrapMode {
        ClampToEdge as CLAMP_TO_EDGE = gl::CLAMP_TO_EDGE,
        MirroredRepeat as MIRRORED_REPEAT = gl::MIRRORED_REPEAT,
        Repeat as REPEAT = gl::REPEAT
    }
}

unsafe fn _tex_parameter_iv(target: TextureBindingTarget,
                            pname: GLenum,
                            params: *const GLint)
{
    gl::TexParameteriv(target.gl_enum(), pname, params);
    dbg_gl_sanity_check! {
        GLError::InvalidEnum => "`target` or `pname` is not an accepted defined value, or `params` should have defined a symbolic constant and does not",
        _ => "Unknown error"
    }
}

unsafe fn _tex_image_2d<T: ImageTargetType>(target: T,
                                            level: u32,
                                            internal_format: TextelFormat,
                                            width: u32,
                                            height: u32,
                                            border: u32,
                                            format: ImageFormat,
                                            image_ptr: *const u8) {
    debug_assert!(internal_format == format.textel_format);
    gl::TexImage2D(target.gl_enum(),
                   level as GLint,
                   internal_format.gl_enum() as GLint,
                   width as GLint,
                   height as GLint,
                   border as GLint,
                   format.textel_format.gl_enum(),
                   format.textel_type.gl_enum(),
                   image_ptr as *const GLvoid);
    dbg_gl_sanity_check! {
        GLError::InvalidEnum => "`target`, `format`, or `type` is not an accepted value",
        GLError::InvalidValue => "`target`, `level`, `internalformat`, `width`, `height`, or `border` is an invalid value",
        GLError::InvalidOperation => "`format` conflicts with either `internalformat` or `type`",
        _ => "Unknown error"
    }
}

pub trait TextureBinding {
    type TextureType: TextureType;

    fn target() -> TextureBindingTarget {
        Self::TextureType::target()
    }

    fn set_min_filter<F: Into<TextureMipmapFilter>>(&mut self, filter: F) {
        let gl_int = filter.into().gl_enum() as GLint;
        unsafe {
            _tex_parameter_iv(Self::target(),
                              gl::TEXTURE_MIN_FILTER,
                              &gl_int as *const GLint);
        }
    }

    fn set_mag_filter(&mut self, filter: TextureFilter) {
        let gl_int = filter.gl_enum() as GLint;
        unsafe {
            _tex_parameter_iv(Self::target(),
                              gl::TEXTURE_MAG_FILTER,
                              &gl_int as *const GLint);
        }
    }

    fn set_wrap_s(&mut self, wrap_mode: TextureWrapMode) {
        let gl_int = wrap_mode.gl_enum() as GLint;
        unsafe {
            _tex_parameter_iv(Self::target(),
                              gl::TEXTURE_WRAP_S,
                              &gl_int as *const GLint);
        }
    }

    fn set_wrap_t(&mut self, wrap_mode: TextureWrapMode) {
        let gl_int = wrap_mode.gl_enum() as GLint;
        unsafe {
            _tex_parameter_iv(Self::target(),
                              gl::TEXTURE_WRAP_T,
                              &gl_int as *const GLint);
        }
    }

    fn image_2d<I>(&mut self,
                   target: <Self::TextureType as TextureType>::ImageTargetType,
                   level: u32,
                   img: &I)
        where I: Image2d
    {
        unsafe {
            _tex_image_2d(target,
                          level,
                          img.format().textel_format,
                          img.width() as u32,
                          img.height() as u32,
                          0,
                          img.format(),
                          img.textel_bytes().as_ptr());
        }
    }

    fn image_2d_empty<T: ImageTargetType>(&mut self,
                                          target: T,
                                          level: u32,
                                          format: ImageFormat,
                                          width: u32,
                                          height: u32)
    {
        unsafe {
            _tex_image_2d(target,
                          level,
                          format.textel_format,
                          width,
                          height,
                          0,
                          format,
                          ptr::null());
        }
    }
}

pub struct Texture2dBinding<'a> {
    phantom: PhantomData<&'a mut Texture2d>
}

impl<'a> TextureBinding for Texture2dBinding<'a> {
    type TextureType = Tx2d;
}

pub struct TextureCubeMapBinding<'a> {
    phantom: PhantomData<&'a mut TextureCubeMap>
}

impl<'a> TextureBinding for TextureCubeMapBinding<'a> {
    type TextureType = TxCubeMap;
}

unsafe fn _bind_texture<T: TextureType>(texture: &mut Texture<T>) {
    gl::BindTexture(T::target().gl_enum(), texture.gl_id());
    dbg_gl_error! {
        GLError::InvalidEnum => "`target` is not one of the allowed values",
        GLError::InvalidOperation => "`texture` was created with a target that doesn't match `target`",
        _ => "Unknown error"
    }
}

pub struct Texture2dBinder;
impl Texture2dBinder {
    pub fn bind(&mut self, texture: &mut Texture2d) -> Texture2dBinding {
        unsafe {
            _bind_texture(texture);
        }
        Texture2dBinding { phantom: PhantomData }
    }
}

pub struct TextureCubeMapBinder;
impl TextureCubeMapBinder {
    pub fn bind(&mut self, texture: &mut TextureCubeMap)
        -> TextureCubeMapBinding
    {
        unsafe {
            _bind_texture(texture);
        }
        TextureCubeMapBinding { phantom: PhantomData }
    }
}
<commit_msg>Re-add `TEXTURE_2D` and `TEXTURE_CUBE_MAP` consts<commit_after>use std::ptr;
use std::marker::PhantomData;
use gl;
use gl::types::*;
use context::Context;
use image_data::{Image2d, TextelFormat, ImageFormat};
use types::GLError;

pub struct Texture<T: TextureType> {
    gl_id: GLuint,
    phantom: PhantomData<*mut T>
}
pub type Texture2d = Texture<Tx2d>;
pub type TextureCubeMap = Texture<TxCubeMap>;

impl<T: TextureType> Texture<T> {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl<T: TextureType> Drop for Texture<T> {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteTextures(1, &self.gl_id as *const GLuint);
        }
    }
}

impl Context {
    pub unsafe fn gen_texture<T: TextureType>(&self) -> Texture<T> {
        let mut id : GLuint =  0;

        gl::GenTextures(1, &mut id as *mut GLuint);
        dbg_gl_sanity_check! {
            GLError::InvalidValue => "`n` is negative",
            _ => "Unknown error"
        }

        Texture {
            gl_id: id,
            phantom: PhantomData
        }
    }
}

pub trait ImageTargetType {
    fn gl_enum(&self) -> GLenum;
}

pub trait TextureType {
    type ImageTargetType: ImageTargetType;

    fn target() -> TextureBindingTarget;
}

pub struct Tx2d;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Tx2dImageTarget {
    Texture2d = gl::TEXTURE_2D as isize
}

impl ImageTargetType for Tx2dImageTarget {
    fn gl_enum(&self) -> GLenum {
        *self as GLenum
    }
}

impl TextureType for Tx2d {
    type ImageTargetType = Tx2dImageTarget;

    fn target() -> TextureBindingTarget {
        TextureBindingTarget::Texture2d
    }
}

pub struct TxCubeMap;

gl_enum! {
    pub gl_enum TxCubeMapImageTarget {
        CubeMapPositiveX as TEXTURE_CUBE_MAP_POSITIVE_X =
            gl::TEXTURE_CUBE_MAP_POSITIVE_X,
        CubeMapNegativeX as TEXTURE_CUBE_MAP_NEGATIVE_X =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_X,
        CubeMapPositiveY as TEXTURE_CUBE_MAP_POSITIVE_Y =
            gl::TEXTURE_CUBE_MAP_POSITIVE_Y,
        CubeMapNegativeY as TEXTURE_CUBE_MAP_NEGATIVE_Y =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_Y,
        CubeMapPositiveZ as TEXTURE_CUBE_MAP_POSITIVE_Z =
            gl::TEXTURE_CUBE_MAP_POSITIVE_Z,
        CubeMapNegativeZ as TEXTURE_CUBE_MAP_NEGATIVE_Z =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_Z
    }
}

impl ImageTargetType for TxCubeMapImageTarget {
    fn gl_enum(&self) -> GLenum {
        self.gl_enum()
    }
}

impl TextureType for TxCubeMap {
    type ImageTargetType = TxCubeMapImageTarget;

    fn target() -> TextureBindingTarget {
        TextureBindingTarget::TextureCubeMap
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TextureBindingTarget {
    Texture2d = gl::TEXTURE_2D as isize,
    TextureCubeMap = gl::TEXTURE_CUBE_MAP as isize
}

impl TextureBindingTarget {
    pub fn gl_enum(&self) -> GLenum {
        *self as GLenum
    }
}

// HACK: Done to allow glitter::TEXTURE_2D as both a
//       TextureBindingTarget and Tx2dImageTarget
pub struct VariantTexture2d;

impl From<VariantTexture2d> for TextureBindingTarget {
    fn from(_: VariantTexture2d) -> TextureBindingTarget {
        TextureBindingTarget::Texture2d
    }
}

impl From<VariantTexture2d> for Tx2dImageTarget {
    fn from(_: VariantTexture2d) -> Tx2dImageTarget {
        Tx2dImageTarget::Texture2d
    }
}

impl ImageTargetType for VariantTexture2d {
    fn gl_enum(&self) -> GLenum {
        gl::TEXTURE_2D
    }
}

pub const TEXTURE_CUBE_MAP : TextureBindingTarget =
    TextureBindingTarget::TextureCubeMap;
pub const TEXTURE_2D : VariantTexture2d = VariantTexture2d;

// TODO: Use type refinements someday...
#[derive(Debug, Clone, Copy)]
pub enum TextureFilter {
    Nearest,
    Linear
}

#[derive(Debug, Clone, Copy)]
pub enum TextureMipmapFilter {
    Filter(TextureFilter),
    MipmapFilter { criterion: TextureFilter, mipmap: TextureFilter }
}

pub const NEAREST : TextureFilter = TextureFilter::Nearest;
pub const LINEAR : TextureFilter = TextureFilter::Linear;
pub const NEAREST_MIPMAP_NEAREST : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Nearest,
        mipmap: TextureFilter::Nearest
    };
pub const LINEAR_MIPMAP_NEAREST : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Linear,
        mipmap: TextureFilter::Nearest
    };
pub const NEAREST_MIPMAP_LINEAR : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Nearest,
        mipmap: TextureFilter::Linear
    };
pub const LINEAR_MIPMAP_LINEAR : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Linear,
        mipmap: TextureFilter::Linear
    };

#[allow(dead_code)]
impl TextureFilter {
    fn from_gl(gl_enum: GLenum) -> Result<Self, ()> {
        match gl_enum {
            gl::NEAREST => { Ok(self::NEAREST) },
            gl::LINEAR => { Ok(self::LINEAR) },
            _ => { Err(()) }
        }
    }

    fn gl_enum(&self) -> GLenum {
        match *self {
            self::NEAREST => gl::NEAREST,
            self::LINEAR => gl::LINEAR
        }
    }
}

#[allow(dead_code)]
impl TextureMipmapFilter {
    fn from_gl(gl_enum: GLenum) -> Result<Self, ()> {
        match gl_enum {
            gl::NEAREST => { Ok(TextureMipmapFilter::Filter(self::NEAREST)) },
            gl::LINEAR => { Ok(TextureMipmapFilter::Filter(self::LINEAR)) },
            gl::NEAREST_MIPMAP_NEAREST => { Ok(self::NEAREST_MIPMAP_NEAREST) },
            gl::LINEAR_MIPMAP_NEAREST => { Ok(self::LINEAR_MIPMAP_NEAREST) },
            gl::NEAREST_MIPMAP_LINEAR => { Ok(self::NEAREST_MIPMAP_LINEAR) },
            gl::LINEAR_MIPMAP_LINEAR => { Ok(self::LINEAR_MIPMAP_LINEAR) },
            _ => { Err(()) }
        }
    }

    fn gl_enum(&self) -> GLenum {
        match *self {
            TextureMipmapFilter::Filter(self::LINEAR) => { gl::LINEAR },
            TextureMipmapFilter::Filter(self::NEAREST) => { gl::NEAREST },
            self::NEAREST_MIPMAP_NEAREST => { gl::NEAREST_MIPMAP_NEAREST },
            self::LINEAR_MIPMAP_NEAREST => { gl::LINEAR_MIPMAP_NEAREST },
            self::NEAREST_MIPMAP_LINEAR => { gl::NEAREST_MIPMAP_LINEAR },
            self::LINEAR_MIPMAP_LINEAR => { gl::LINEAR_MIPMAP_LINEAR }
        }
    }
}

impl From<TextureFilter> for TextureMipmapFilter {
    fn from(filter: TextureFilter) -> TextureMipmapFilter {
        TextureMipmapFilter::Filter(filter)
    }
}

gl_enum! {
    pub gl_enum TextureWrapMode {
        ClampToEdge as CLAMP_TO_EDGE = gl::CLAMP_TO_EDGE,
        MirroredRepeat as MIRRORED_REPEAT = gl::MIRRORED_REPEAT,
        Repeat as REPEAT = gl::REPEAT
    }
}

unsafe fn _tex_parameter_iv(target: TextureBindingTarget,
                            pname: GLenum,
                            params: *const GLint)
{
    gl::TexParameteriv(target.gl_enum(), pname, params);
    dbg_gl_sanity_check! {
        GLError::InvalidEnum => "`target` or `pname` is not an accepted defined value, or `params` should have defined a symbolic constant and does not",
        _ => "Unknown error"
    }
}

unsafe fn _tex_image_2d<T: ImageTargetType>(target: T,
                                            level: u32,
                                            internal_format: TextelFormat,
                                            width: u32,
                                            height: u32,
                                            border: u32,
                                            format: ImageFormat,
                                            image_ptr: *const u8) {
    debug_assert!(internal_format == format.textel_format);
    gl::TexImage2D(target.gl_enum(),
                   level as GLint,
                   internal_format.gl_enum() as GLint,
                   width as GLint,
                   height as GLint,
                   border as GLint,
                   format.textel_format.gl_enum(),
                   format.textel_type.gl_enum(),
                   image_ptr as *const GLvoid);
    dbg_gl_sanity_check! {
        GLError::InvalidEnum => "`target`, `format`, or `type` is not an accepted value",
        GLError::InvalidValue => "`target`, `level`, `internalformat`, `width`, `height`, or `border` is an invalid value",
        GLError::InvalidOperation => "`format` conflicts with either `internalformat` or `type`",
        _ => "Unknown error"
    }
}

pub trait TextureBinding {
    type TextureType: TextureType;

    fn target() -> TextureBindingTarget {
        Self::TextureType::target()
    }

    fn set_min_filter<F: Into<TextureMipmapFilter>>(&mut self, filter: F) {
        let gl_int = filter.into().gl_enum() as GLint;
        unsafe {
            _tex_parameter_iv(Self::target(),
                              gl::TEXTURE_MIN_FILTER,
                              &gl_int as *const GLint);
        }
    }

    fn set_mag_filter(&mut self, filter: TextureFilter) {
        let gl_int = filter.gl_enum() as GLint;
        unsafe {
            _tex_parameter_iv(Self::target(),
                              gl::TEXTURE_MAG_FILTER,
                              &gl_int as *const GLint);
        }
    }

    fn set_wrap_s(&mut self, wrap_mode: TextureWrapMode) {
        let gl_int = wrap_mode.gl_enum() as GLint;
        unsafe {
            _tex_parameter_iv(Self::target(),
                              gl::TEXTURE_WRAP_S,
                              &gl_int as *const GLint);
        }
    }

    fn set_wrap_t(&mut self, wrap_mode: TextureWrapMode) {
        let gl_int = wrap_mode.gl_enum() as GLint;
        unsafe {
            _tex_parameter_iv(Self::target(),
                              gl::TEXTURE_WRAP_T,
                              &gl_int as *const GLint);
        }
    }

    fn image_2d<I>(&mut self,
                   target: <Self::TextureType as TextureType>::ImageTargetType,
                   level: u32,
                   img: &I)
        where I: Image2d
    {
        unsafe {
            _tex_image_2d(target,
                          level,
                          img.format().textel_format,
                          img.width() as u32,
                          img.height() as u32,
                          0,
                          img.format(),
                          img.textel_bytes().as_ptr());
        }
    }

    fn image_2d_empty<T: ImageTargetType>(&mut self,
                                          target: T,
                                          level: u32,
                                          format: ImageFormat,
                                          width: u32,
                                          height: u32)
    {
        unsafe {
            _tex_image_2d(target,
                          level,
                          format.textel_format,
                          width,
                          height,
                          0,
                          format,
                          ptr::null());
        }
    }
}

pub struct Texture2dBinding<'a> {
    phantom: PhantomData<&'a mut Texture2d>
}

impl<'a> TextureBinding for Texture2dBinding<'a> {
    type TextureType = Tx2d;
}

pub struct TextureCubeMapBinding<'a> {
    phantom: PhantomData<&'a mut TextureCubeMap>
}

impl<'a> TextureBinding for TextureCubeMapBinding<'a> {
    type TextureType = TxCubeMap;
}

unsafe fn _bind_texture<T: TextureType>(texture: &mut Texture<T>) {
    gl::BindTexture(T::target().gl_enum(), texture.gl_id());
    dbg_gl_error! {
        GLError::InvalidEnum => "`target` is not one of the allowed values",
        GLError::InvalidOperation => "`texture` was created with a target that doesn't match `target`",
        _ => "Unknown error"
    }
}

pub struct Texture2dBinder;
impl Texture2dBinder {
    pub fn bind(&mut self, texture: &mut Texture2d) -> Texture2dBinding {
        unsafe {
            _bind_texture(texture);
        }
        Texture2dBinding { phantom: PhantomData }
    }
}

pub struct TextureCubeMapBinder;
impl TextureCubeMapBinder {
    pub fn bind(&mut self, texture: &mut TextureCubeMap)
        -> TextureCubeMapBinding
    {
        unsafe {
            _bind_texture(texture);
        }
        TextureCubeMapBinding { phantom: PhantomData }
    }
}
<|endoftext|>


<commit_before>use dailyschedule::{Handler, Schedule};
use std::cell::{Cell, RefCell};
use std::collections::BTreeMap;
use std::path;
use std::rc::Rc;
use super::config;
use super::serial;
use time::{Duration, Timespec, at_utc, at};
use zoneinfo::ZoneInfo;
use ticker::Ticker;
use std::sync::mpsc::{channel, Sender};
use std::thread;

#[derive(Eq, PartialEq, Debug, Copy, Clone)]
enum Context {
    Off,
    On
}

struct Switch {
    serial: serial::SerialClient,
    alias: String,
    last_on: Cell<Timespec>,
    state: Cell<Context>,
    valid_events: RefCell<BTreeMap<Timespec, Context>>,
    /// when "hot" perform actual relay operations
    hot: Cell<bool>,
}

impl Switch {
    fn new(alias: String, serial: serial::SerialClient) -> Switch {
        Switch {
            alias: alias,
            serial: serial,
            last_on: Cell::new(Timespec::new(0, 0)),
            state: Cell::new(Context::Off),
            valid_events: RefCell::new(BTreeMap::new()),
            hot: Cell::new(false),
        }
    }
}

impl Switch {
    fn set_switch_state(&self, state: Context) {
        self.state.set(state);
        self.dispatch_context();
    }

    fn dispatch_context(&self) {
        if self.hot.get() {
            match self.state.get() {
                Context::Off => self.serial.switch_off(&self.alias[..]),
                Context::On => self.serial.switch_on(&self.alias[..]),
            }
        }
    }

    fn make_hot(&self) {
        self.hot.set(true);
        self.dispatch_context();
    }
}

impl Handler<Context> for Switch {
    /// Hint the event-handler for future events; this function will
    /// add only valid events (where on event lies before the off event) to
    /// the valid events list.
    fn hint(&self, ts: &Timespec, context: &Context) {
        match context {
            &Context::On => self.last_on.set(*ts),
            &Context::Off => {
                if *ts > self.last_on.get() {
                    let mut events = self.valid_events.borrow_mut();
                    events.insert(self.last_on.get(), Context::On);
                    events.insert(*ts, Context::Off);
                }
            }
        }
    }

    /// Perform action only when the timestamp is considered valid;
    /// Remove the current or prior timestamps from the expected timestamps.
    fn kick(&self, ts: &Timespec, context: &Context) {
        if self.valid_events.borrow().contains_key(ts) {
            println!("XXX: {} {:?} {}", at(*ts).asctime(), context, self.alias); // XXX
            self.set_switch_state(*context);

            let mut events = self.valid_events.borrow_mut();

            // don't like the clone here, but keeps events mutable inside the loop
            for (e, _) in events.clone().iter().take_while(|&(&e, _)| e <= *ts) {
                events.remove(e);
            }
        }
    }
}

struct TrackerInner {
    serial: serial::SerialClient,
    schedule: Schedule<Context, Switch>,
    schedule_ref: Timespec,
    initial: bool,
    switches: BTreeMap<String, Rc<Switch>>,
}

impl TrackerInner {
    fn load_schedule(&mut self, config: &config::Config) {
        self.switches.clear();
        for circle in config.circles.iter() {
            let switch = Rc::new(Switch::new(circle.alias.clone(), self.serial.clone()));
            match circle.default {
                config::CircleSetting::On => switch.set_switch_state(Context::On),
                config::CircleSetting::Off => switch.set_switch_state(Context::Off),
                config::CircleSetting::Schedule => {
                    for toggle in circle.toggles.iter() {
                        let start = toggle.start.into_dailyevent(&config.device);
                        let end = toggle.end.into_dailyevent(&config.device);

                        self.schedule.add_event(start, switch.clone(), Context::On);
                        self.schedule.add_event(end, switch.clone(), Context::Off);
                    }
                }
            }
            self.switches.insert(circle.alias.clone(), switch);
        }
    }

    fn new(config: &config::Config, zoneinfo: &ZoneInfo) -> TrackerInner {
        let schedule = Schedule::new(zoneinfo.clone());
        let serial = serial::Serial::spawn();

        // XXX: register circles / connect etc...

        let mut tracker = TrackerInner {
            schedule: schedule,
            serial: serial,
            schedule_ref: Timespec::new(0,0),
            initial: true,
            switches: BTreeMap::new(),
        };

        tracker.load_schedule(config);

        tracker
    }

    fn update_schedule(&mut self) {
        self.schedule.update_schedule(self.schedule_ref);
        self.schedule_ref = self.schedule_ref + Duration::days(1);
    }

    fn process_tick(&mut self, timestamp: Timespec) {
        if self.initial {
            let mut tm = at_utc(timestamp);
            tm.tm_hour = 0;
            tm.tm_min = 0;
            tm.tm_sec = 0;
            tm.tm_nsec = 0;
            self.schedule_ref = tm.to_timespec();

            // fill schedule for 48 hours:
            self.update_schedule();
            self.update_schedule();
        }

        if (self.schedule_ref - timestamp) <= Duration::days(1) {
            // make sure that at least 1 day of future updates is known
            self.update_schedule();
        }

        self.schedule.kick_event(timestamp);

        if self.initial {
            self.initial = false;
            // configure the switch to actually set the relay (otherwise the initial kicks will
            // quickly toggle switches unintendedly
            for (_, ref mut switch) in self.switches.iter_mut() {
                switch.make_hot();
            }
        }
    }
}

pub struct Tracker {
    zoneinfo: ZoneInfo,
    inner: TrackerInner,
}

#[derive(Copy, Clone)]
enum Message {
    Tick,
    Teardown,
}

impl Tracker {
    pub fn spawn(configfile: path::PathBuf) -> TrackerClient {
        let (tx, rx) = channel();

        let joiner = thread::spawn(move || {
            let config = config::Config::new(&configfile).unwrap(); // XXX
            let mut tracker = Tracker::new(&config);
            let ticker = Ticker::spawn(&config.device.ntp_server,
                                       Duration::seconds(10),
                                       Duration::days(1),
                                       Message::Tick);

            tx.send(ticker.get_sender()).ok().expect("BUG: tracker thread unable to communicate with spawner");

            for (event, timestamp) in ticker.recv_iter() {
                match event {
                    Message::Tick => {
                        if let Some(timestamp) = timestamp {
                            println!("tick: {}", at(timestamp).asctime());
                            tracker.inner.process_tick(timestamp);
                        }
                    },
                    Message::Teardown => {
                        break;
                    },
                }
            }
            ticker.stop_ticker();
        });

        let sender = rx.recv().ok().expect("BUG: tracker thread unable to bootstrap");

        TrackerClient {
            tx: sender,
            join: joiner
        }
    }

    fn new(config: &config::Config) -> Tracker {
        let zoneinfo = ZoneInfo::get_local_zoneinfo().ok().expect("BUG: not able to load local zoneinfo");

        let tracker = Tracker {
            inner: TrackerInner::new(config, &zoneinfo),
            zoneinfo: zoneinfo,
        };

        tracker
    }
}

pub struct TrackerClient {
    tx: Sender<(Message, Option<Timespec>)>,
    join: thread::JoinHandle<()>,
}

impl TrackerClient {
    pub fn teardown(self) {
        (&self).tx.send((Message::Teardown, None)).ok().expect("BUG: not able to shutdown tracker");
        self.join();
    }

    pub fn join(self) {
        self.join.join().ok().expect("BUG: not able to join tracker");
    }
}
<commit_msg>tracker: last bits from non-thread based approach<commit_after>use dailyschedule::{Handler, Schedule};
use std::cell::{Cell, RefCell};
use std::collections::BTreeMap;
use std::path;
use std::rc::Rc;
use super::config;
use super::serial;
use time::{Duration, Timespec, at_utc, at};
use zoneinfo::ZoneInfo;
use ticker::Ticker;
use std::sync::mpsc::{channel, Sender};
use std::thread;

#[derive(Eq, PartialEq, Debug, Copy, Clone)]
enum Context {
    Off,
    On
}

struct Switch {
    serial: serial::SerialClient,
    alias: String,
    last_on: Cell<Timespec>,
    state: Cell<Context>,
    valid_events: RefCell<BTreeMap<Timespec, Context>>,
    /// when "hot" perform actual relay operations
    hot: Cell<bool>,
}

impl Switch {
    fn new(alias: String, serial: serial::SerialClient) -> Switch {
        Switch {
            alias: alias,
            serial: serial,
            last_on: Cell::new(Timespec::new(0, 0)),
            state: Cell::new(Context::Off),
            valid_events: RefCell::new(BTreeMap::new()),
            hot: Cell::new(false),
        }
    }
}

impl Switch {
    fn set_switch_state(&self, state: Context) {
        self.state.set(state);
        self.dispatch_context();
    }

    fn dispatch_context(&self) {
        if self.hot.get() {
            match self.state.get() {
                Context::Off => self.serial.switch_off(&self.alias[..]),
                Context::On => self.serial.switch_on(&self.alias[..]),
            }
        }
    }

    fn make_hot(&self) {
        self.hot.set(true);
        self.dispatch_context();
    }
}

impl Handler<Context> for Switch {
    /// Hint the event-handler for future events; this function will
    /// add only valid events (where on event lies before the off event) to
    /// the valid events list.
    fn hint(&self, ts: &Timespec, context: &Context) {
        match context {
            &Context::On => self.last_on.set(*ts),
            &Context::Off => {
                if *ts > self.last_on.get() {
                    let mut events = self.valid_events.borrow_mut();
                    events.insert(self.last_on.get(), Context::On);
                    events.insert(*ts, Context::Off);
                }
            }
        }
    }

    /// Perform action only when the timestamp is considered valid;
    /// Remove the current or prior timestamps from the expected timestamps.
    fn kick(&self, ts: &Timespec, context: &Context) {
        if self.valid_events.borrow().contains_key(ts) {
            println!("XXX: {} {:?} {}", at(*ts).asctime(), context, self.alias); // XXX
            self.set_switch_state(*context);

            let mut events = self.valid_events.borrow_mut();

            // don't like the clone here, but keeps events mutable inside the loop
            for (e, _) in events.clone().iter().take_while(|&(&e, _)| e <= *ts) {
                events.remove(e);
            }
        }
    }
}

struct TrackerInner {
    serial: serial::SerialClient,
    schedule: Schedule<Context, Switch>,
    schedule_ref: Timespec,
    initial: bool,
    switches: BTreeMap<String, Rc<Switch>>,
}

impl TrackerInner {
    fn load_schedule(&mut self, config: &config::Config) {
        self.switches.clear();
        for circle in config.circles.iter() {
            let switch = Rc::new(Switch::new(circle.alias.clone(), self.serial.clone()));
            match circle.default {
                config::CircleSetting::On => switch.set_switch_state(Context::On),
                config::CircleSetting::Off => switch.set_switch_state(Context::Off),
                config::CircleSetting::Schedule => {
                    for toggle in circle.toggles.iter() {
                        let start = toggle.start.into_dailyevent(&config.device);
                        let end = toggle.end.into_dailyevent(&config.device);

                        self.schedule.add_event(start, switch.clone(), Context::On);
                        self.schedule.add_event(end, switch.clone(), Context::Off);
                    }
                }
            }
            self.switches.insert(circle.alias.clone(), switch);
        }
    }

    fn new(config: &config::Config, zoneinfo: &ZoneInfo) -> TrackerInner {
        let schedule = Schedule::new(zoneinfo.clone());
        let serial = serial::Serial::spawn();

        // XXX: register circles / connect etc...

        let mut tracker = TrackerInner {
            schedule: schedule,
            serial: serial,
            schedule_ref: Timespec::new(0,0),
            initial: true,
            switches: BTreeMap::new(),
        };

        tracker.load_schedule(config);

        tracker
    }

    fn update_schedule(&mut self) {
        self.schedule.update_schedule(self.schedule_ref);
        self.schedule_ref = self.schedule_ref + Duration::days(1);
    }

    fn process_tick(&mut self, timestamp: Timespec) {
        if self.initial {
            let mut tm = at_utc(timestamp);
            tm.tm_hour = 0;
            tm.tm_min = 0;
            tm.tm_sec = 0;
            tm.tm_nsec = 0;
            self.schedule_ref = tm.to_timespec();

            // fill schedule for 48 hours:
            self.update_schedule();
            self.update_schedule();
        }

        if (self.schedule_ref - timestamp) <= Duration::days(1) {
            // make sure that at least 1 day of future updates is known
            self.update_schedule();
        }

        self.schedule.kick_event(timestamp);

        if self.initial {
            self.initial = false;
            // configure the switch to actually set the relay (otherwise the initial kicks will
            // quickly toggle switches unintendedly
            for (_, ref mut switch) in self.switches.iter_mut() {
                switch.make_hot();
            }
        }
    }
}

#[derive(Copy, Clone)]
enum Message {
    Tick,
    Teardown,
}

pub struct Tracker {
    tx: Sender<(Message, Option<Timespec>)>,
    join: thread::JoinHandle<()>,
}

impl Tracker {
    pub fn spawn(configfile: path::PathBuf) -> Tracker {
        let zoneinfo = ZoneInfo::get_local_zoneinfo().ok().expect("BUG: not able to load local zoneinfo");
        let (tx, rx) = channel();

        let joiner = thread::spawn(move || {
            let config = config::Config::new(&configfile).unwrap(); // XXX
            let mut tracker = TrackerInner::new(&config, &zoneinfo);
            let ticker = Ticker::spawn(&config.device.ntp_server,
                                       Duration::seconds(10),
                                       Duration::days(1),
                                       Message::Tick);

            tx.send(ticker.get_sender()).ok().expect("BUG: tracker thread unable to communicate with spawner");

            for (event, timestamp) in ticker.recv_iter() {
                match event {
                    Message::Tick => {
                        if let Some(timestamp) = timestamp {
                            println!("tick: {}", at(timestamp).asctime());
                            tracker.process_tick(timestamp);
                        }
                    },
                    Message::Teardown => {
                        break;
                    },
                }
            }
            ticker.stop_ticker();
        });

        let sender = rx.recv().ok().expect("BUG: tracker thread unable to bootstrap");

        Tracker {
            tx: sender,
            join: joiner
        }
    }

    pub fn teardown(self) {
        (&self).tx.send((Message::Teardown, None)).ok().expect("BUG: not able to shutdown tracker");
        self.join();
    }

    pub fn join(self) {
        self.join.join().ok().expect("BUG: not able to join tracker");
    }
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::io::Result as IoResult;
use std::path::{Path, PathBuf};
use std::fs;
use std::env;

use flate2::read::GzDecoder;
use tar::Archive;
use curl::http;
use tempdir::TempDir;

use error::TldrError::{self, UpdateError};

#[derive(Debug)]
pub struct Updater {
    url: String,
}

impl Updater {

    pub fn new(url: String) -> Updater {
        Updater {
            url: url,
        }
    }

    /// Download the archive
    fn download(&self) -> Result<http::Response, TldrError> {
        let resp = try!(
            http::handle()
                 .follow_location(1)
                 .get(&self.url[..])
                 .exec()
        );
        Ok(resp)
    }

    /// Decompress and open the archive
    fn decompress<R: Read>(&self, reader: R) -> Result<Archive<GzDecoder<R>>, TldrError> {
        let decoder = try!(GzDecoder::new(reader).map_err(|_| UpdateError("Could not decode gzip data".into())));
        Ok(Archive::new(decoder))
    }

    /// Extract archive, return pages and license
    fn extract<R: Read>(&self, archive: &mut Archive<R>, path: &Path) -> Result<(PathBuf, PathBuf), TldrError> {
        try!(archive.unpack(path).map_err(|e| {
            UpdateError(format!("Could not unpack compressed data: {}", e))
        }));
        let repodir = path.join("tldr-master");
        Ok((repodir.join("pages"), repodir.join("LICENSE.md")))
    }

    fn get_pages(&self, path: &Path) -> Vec<PathBuf> {
    }

    /// Update the pages cache.
    pub fn update(&self) -> Result<(), TldrError> {
        // First, download the compressed data
        let response = try!(self.download());

        // Decompress the response body into an `Archive`
        let mut archive = try!(self.decompress(response.get_body()));

        // Create temporary directory
        let dir = try!(TempDir::new("tldr").map_err(|e| {
            UpdateError(format!("Could not create temporary directory: {}", e))
        }));

        // Get paths to pages and license
        let (pages_path, license_path) = try!(self.extract(&mut archive, dir.path()));

        // Copy files
        let home_dir = try!(env::home_dir().ok_or(UpdateError("Could not determine home directory".into())));
        let cache_dir = home_dir.join(".tldr").join("cache");
        try!(fs::copy(license_path, cache_dir.join("LICENSE.md")).map_err(|e| {
            UpdateError(format!("Could not extract license file: {}", e))
        }));

        Ok(())
    }

}
<commit_msg>Create cache dir if it doesn't exist yet<commit_after>use std::io::Read;
use std::io::Result as IoResult;
use std::path::{Path, PathBuf};
use std::fs;
use std::env;

use flate2::read::GzDecoder;
use tar::Archive;
use curl::http;
use tempdir::TempDir;

use error::TldrError::{self, UpdateError};

#[derive(Debug)]
pub struct Updater {
    url: String,
}

impl Updater {

    pub fn new(url: String) -> Updater {
        Updater {
            url: url,
        }
    }

    /// Download the archive
    fn download(&self) -> Result<http::Response, TldrError> {
        let resp = try!(
            http::handle()
                 .follow_location(1)
                 .get(&self.url[..])
                 .exec()
        );
        Ok(resp)
    }

    /// Decompress and open the archive
    fn decompress<R: Read>(&self, reader: R) -> Result<Archive<GzDecoder<R>>, TldrError> {
        let decoder = try!(GzDecoder::new(reader).map_err(|_| UpdateError("Could not decode gzip data".into())));
        Ok(Archive::new(decoder))
    }

    /// Extract archive, return pages and license
    fn extract<R: Read>(&self, archive: &mut Archive<R>, path: &Path) -> Result<(PathBuf, PathBuf), TldrError> {
        try!(archive.unpack(path).map_err(|e| {
            UpdateError(format!("Could not unpack compressed data: {}", e))
        }));
        let repodir = path.join("tldr-master");
        Ok((repodir.join("pages"), repodir.join("LICENSE.md")))
    }

    fn get_pages(&self, path: &Path) -> Vec<PathBuf> {
    }

    /// Update the pages cache.
    pub fn update(&self) -> Result<(), TldrError> {
        // First, download the compressed data
        let response = try!(self.download());

        // Decompress the response body into an `Archive`
        let mut archive = try!(self.decompress(response.get_body()));

        // Create temporary directory
        let dir = try!(TempDir::new("tldr").map_err(|e| {
            UpdateError(format!("Could not create temporary directory: {}", e))
        }));

        // Get paths to pages and license
        let (pages_src, license_src) = try!(self.extract(&mut archive, dir.path()));

        // Determine path to cache
        let home_dir = try!(env::home_dir().ok_or(UpdateError("Could not determine home directory".into())));
        let cache_dir = home_dir.join(".tldr").join("cache");

        // Make sure that cache dir exists
        try!(fs::create_dir_all(&cache_dir).map_err(|e| {
            UpdateError(format!("Could not create cache directory: {}", e))
        }));

        // Copy license file
        let license_dst = &cache_dir.join("LICENSE.md");
        debug!("Copy license from {:?} to {:?}", &license_src, &license_dst);
        try!(fs::copy(&license_src, &license_dst).map_err(|e| {
            UpdateError(format!("Could not extract license file: {}", e))
        }));

        Ok(())
    }

}
<|endoftext|>


<commit_before>use libc::{c_int, c_char, c_uint, size_t, ptrdiff_t};

use tree::{ParseStatus, Encoding, NodeKind};

use tree::node::CNode;
use tree::document::CDocument;
use tree::parse_result::CParseResult;

extern "C" {
    pub fn pugi_version() -> c_int;

    pub fn pugi_parse_flag_cdata() -> c_uint;
    pub fn pugi_parse_flag_comments() -> c_uint;
    pub fn pugi_parse_flag_declaration() -> c_uint;
    pub fn pugi_parse_flag_default() -> c_uint;
    pub fn pugi_parse_flag_doctype() -> c_uint;
    pub fn pugi_parse_flag_eol() -> c_uint;
    pub fn pugi_parse_flag_escapes() -> c_uint;
    pub fn pugi_parse_flag_fragment() -> c_uint;
    pub fn pugi_parse_flag_full() -> c_uint;
    pub fn pugi_parse_flag_minimal() -> c_uint;
    pub fn pugi_parse_flag_pi() -> c_uint;
    pub fn pugi_parse_flag_trim_pcdata() -> c_uint;
    pub fn pugi_parse_flag_ws_pcdata() -> c_uint;
    pub fn pugi_parse_flag_ws_pcdata_single() -> c_uint;
    pub fn pugi_parse_flag_wconv_attribute() -> c_uint;
    pub fn pugi_parse_flag_wnorm_attribute() -> c_uint;

    pub fn pugi_format_flag_default() -> c_uint;
    pub fn pugi_format_flag_indent() -> c_uint;
    pub fn pugi_format_flag_indent_attributes() -> c_uint;
    pub fn pugi_format_flag_no_empty_element_tags() -> c_uint;
    pub fn pugi_format_flag_no_declaration() -> c_uint;
    pub fn pugi_format_flag_no_escapes() -> c_uint;
    pub fn pugi_format_flag_raw() -> c_uint;
    pub fn pugi_format_flag_save_file_text() -> c_uint;
    pub fn pugi_format_flag_write_bom() -> c_uint;

    pub fn pugi_parse_result_status(parse_result: *const CParseResult) -> ParseStatus;
    pub fn pugi_parse_result_offset(parse_result: *const CParseResult) -> ptrdiff_t;
    pub fn pugi_parse_result_encoding(parse_result: *const CParseResult) -> Encoding;
    pub fn pugi_parse_result_description(parse_result: *const CParseResult) -> *const c_char;

    pub fn pugi_delete_parse_result(parse_result: *const CParseResult);

    pub fn pugi_new_document() -> *mut CDocument;
    pub fn pugi_delete_document(document: *mut CDocument);

    pub fn pugi_reset_document_with(document: *mut CDocument, proto: *const CDocument);

    pub fn pugi_load_file(document: *mut CDocument, path: *const c_char, options: c_uint,
                      encoding: Encoding)
        -> *const CParseResult;

    pub fn pugi_load_buffer(document: *mut CDocument, contents: *const c_char, size: size_t,
                        options: c_uint, encoding: Encoding)
        -> *const CParseResult;

    pub fn pugi_save_file(document: *const CDocument, path: *const c_char, indent: *const c_char,
                      options: c_uint, encoding: Encoding)
        -> c_int;

    pub fn pugi_delete_node(node: *mut CNode);

    pub fn pugi_node_equal(lhs: *const CNode, rhs: *const CNode) -> c_int;

    pub fn pugi_node_hash_value(node: *mut CNode) -> size_t;
    pub fn pugi_node_type(node: *const CNode) -> NodeKind;
    pub fn pugi_node_name(node: *const CNode) -> *const c_char;
    pub fn pugi_node_value(node: *const CNode) -> *const c_char;

    pub fn pugi_node_text(node: *const CNode) -> *const c_char;

    pub fn pugi_node_parent(node: *const CNode) -> *mut CNode;
    pub fn pugi_node_child_by_name(node: *const CNode, name: *const c_char) -> *mut CNode;

    pub fn pugi_node_first_child(node: *const CNode) -> *mut CNode;
    pub fn pugi_node_last_child(node: *const CNode) -> *mut CNode;
    pub fn pugi_node_next_sibling(node: *const CNode) -> *mut CNode;
    pub fn pugi_node_previous_sibling(node: *const CNode) -> *mut CNode;
    pub fn pugi_node_next_sibling_by_name(node: *const CNode, name: *const c_char) -> *mut CNode;
    pub fn pugi_node_previous_sibling_by_name(node: *const CNode, name: *const c_char) -> *mut CNode;

    pub fn pugi_node_find_child_by_name_and_attribute(node: *const CNode, name: *const c_char,
                                                  attribute_name: *const c_char,
                                                  attribute_value: *const c_char)
        -> *mut CNode;
    pub fn pugi_node_find_child_by_attribute(node: *const CNode, attribute_name: *const c_char,
                                         attribute_value: *const c_char)
        -> *mut CNode;

    pub fn pugi_node_child_value(node: *mut CNode) -> *const c_char;
    pub fn pugi_node_child_value_by_name(node: *mut CNode, name: *const c_char) -> *mut CNode;

    // pub fn pugi_node_attribute(node: *mut CNode, name: *const c_char) -> *mut CAttribute;
    pub fn pugi_node_path(node: *const CNode, delimiter: c_char) -> *const c_char;

    pub fn pugi_node_first_element_by_path(node: *const CNode, path: *const c_char, delimiter: c_char)
        -> *mut CNode;

    pub fn pugi_node_root(node: *const CNode) -> *mut CNode;

    pub fn pugi_node_set_name(node: *mut CNode, name: *const c_char) -> c_int;
    pub fn pugi_node_set_value(node: *mut CNode, name: *const c_char) -> c_int;

    pub fn pugi_node_append_attribute(node: *mut CNode, name: *const c_char, value: *const c_char)
        -> c_int;
    pub fn pugi_node_prepend_attribute(node: *mut CNode, name: *const c_char, value: *const c_char)
        -> c_int;

    pub fn pugi_node_append_child(node: *mut CNode, node_type: NodeKind) -> *mut CNode;
    pub fn pugi_node_prepend_child(node: *mut CNode, node_type: NodeKind) -> *mut CNode;

    pub fn pugi_node_append_copy(node: *mut CNode, proto: *mut CNode) -> *mut CNode;
    pub fn pugi_node_prepend_copy(node: *mut CNode, proto: *mut CNode) -> *mut CNode;

    pub fn pugi_node_remove_attribute(node: *mut CNode, name: *const c_char) -> c_int;
    pub fn pugi_node_remove_child(node: *mut CNode, to_be_removed_child: *const CNode) -> c_int;

    // pub fn pugi_node_print(node: *mut CNode,

    // pub fn pugi_node_find_attribute_by_predicate
    // pub fn pugi_node_find_child_by_predicate
    // pub fn pugi_node_find_node_by_predicate

    // pub fn pugi_node_map_sibling
    // pub fn pugi_node_map_attributes

    // pub fn pugi_xpath_delete_xpath_node(node: *mut CXPathNode);

    // pub fn pugi_xpath_node_node(node: *mut CXPathNode) -> *mut CNode;
    // pub fn pugi_xpath_node_attribute(node: *mut CXPathNode) -> *mut CAttribute;

    // pub fn pugi_xpath_delete_xpath_node_set(node_set: *const CNodeSet);

    // pub fn pugi_xpath_node_set_size(node_set: *const CNodeSet) -> size_t;
    // pub fn pugi_xpath_node_set_is_empty(node_set: *const CNodeSet) -> c_int;

    // pub fn pugi_xpath_node_set_index(node_set: *mut CNodeSet, index: size_t) -> *mut CXPathNode;

    // pub fn pugi_xpath_node_set_map

    // pub fn pugi_xpath_delete_xpath_query(xpath: *const CXPath);

    // pub fn pugi_xpath_query_evaluate_boolean(xpath: *const CXPath, node: *mut CNode) -> c_int;
    // pub fn pugi_xpath_query_evaluate_number(xpath: *const CXPath, node: *mut CNode) -> c_double;
    // pub fn pugi_xpath_query_evaluate_string(xpath: *const CXPath, node: *mut CNode) -> *const c_char;
    // pub fn pugi_xpath_query_evaluate_node_set(xpath: *const CXPath, node: *mut CNode)
    //     -> *const CNodeSet;

    // pub fn pugi_xpath_query_return_type(xpath: *const CXPath) -> XPathValueType;

    // pub fn pugi_xpath_query_parse_is_success(xpath: *const CXPath) -> c_int;

    // pub fn pugi_xpath_select_single_node(node: *mut CNode, xpath: *const CXPath) -> *mut CXPathNode;
    // pub fn pugi_xpath_select_nodes(node: *mut CNode, xpath: *const CXPath) -> *const CNodeSet;
}
<commit_msg>Removing unneed function from wrapper<commit_after>use libc::{c_int, c_char, c_uint, size_t, ptrdiff_t};

use tree::{ParseStatus, Encoding, NodeKind};

use tree::node::CNode;
use tree::document::CDocument;
use tree::parse_result::CParseResult;

extern "C" {
    pub fn pugi_version() -> c_int;

    pub fn pugi_parse_flag_cdata() -> c_uint;
    pub fn pugi_parse_flag_comments() -> c_uint;
    pub fn pugi_parse_flag_declaration() -> c_uint;
    pub fn pugi_parse_flag_default() -> c_uint;
    pub fn pugi_parse_flag_doctype() -> c_uint;
    pub fn pugi_parse_flag_eol() -> c_uint;
    pub fn pugi_parse_flag_escapes() -> c_uint;
    pub fn pugi_parse_flag_fragment() -> c_uint;
    pub fn pugi_parse_flag_full() -> c_uint;
    pub fn pugi_parse_flag_minimal() -> c_uint;
    pub fn pugi_parse_flag_pi() -> c_uint;
    pub fn pugi_parse_flag_trim_pcdata() -> c_uint;
    pub fn pugi_parse_flag_ws_pcdata() -> c_uint;
    pub fn pugi_parse_flag_ws_pcdata_single() -> c_uint;
    pub fn pugi_parse_flag_wconv_attribute() -> c_uint;
    pub fn pugi_parse_flag_wnorm_attribute() -> c_uint;

    pub fn pugi_format_flag_default() -> c_uint;
    pub fn pugi_format_flag_indent() -> c_uint;
    pub fn pugi_format_flag_indent_attributes() -> c_uint;
    pub fn pugi_format_flag_no_empty_element_tags() -> c_uint;
    pub fn pugi_format_flag_no_declaration() -> c_uint;
    pub fn pugi_format_flag_no_escapes() -> c_uint;
    pub fn pugi_format_flag_raw() -> c_uint;
    pub fn pugi_format_flag_save_file_text() -> c_uint;
    pub fn pugi_format_flag_write_bom() -> c_uint;

    pub fn pugi_parse_result_status(parse_result: *const CParseResult) -> ParseStatus;
    pub fn pugi_parse_result_offset(parse_result: *const CParseResult) -> ptrdiff_t;
    pub fn pugi_parse_result_encoding(parse_result: *const CParseResult) -> Encoding;
    pub fn pugi_parse_result_description(parse_result: *const CParseResult) -> *const c_char;

    pub fn pugi_delete_parse_result(parse_result: *const CParseResult);

    pub fn pugi_new_document() -> *mut CDocument;
    pub fn pugi_delete_document(document: *mut CDocument);

    pub fn pugi_reset_document_with(document: *mut CDocument, proto: *const CDocument);

    pub fn pugi_load_file(document: *mut CDocument, path: *const c_char, options: c_uint,
                      encoding: Encoding)
        -> *const CParseResult;

    pub fn pugi_load_buffer(document: *mut CDocument, contents: *const c_char, size: size_t,
                        options: c_uint, encoding: Encoding)
        -> *const CParseResult;

    pub fn pugi_save_file(document: *const CDocument, path: *const c_char, indent: *const c_char,
                      options: c_uint, encoding: Encoding)
        -> c_int;

    pub fn pugi_delete_node(node: *mut CNode);

    pub fn pugi_node_equal(lhs: *const CNode, rhs: *const CNode) -> c_int;

    pub fn pugi_node_type(node: *const CNode) -> NodeKind;
    pub fn pugi_node_name(node: *const CNode) -> *const c_char;
    pub fn pugi_node_value(node: *const CNode) -> *const c_char;

    pub fn pugi_node_text(node: *const CNode) -> *const c_char;

    pub fn pugi_node_parent(node: *const CNode) -> *mut CNode;
    pub fn pugi_node_child_by_name(node: *const CNode, name: *const c_char) -> *mut CNode;

    pub fn pugi_node_first_child(node: *const CNode) -> *mut CNode;
    pub fn pugi_node_last_child(node: *const CNode) -> *mut CNode;
    pub fn pugi_node_next_sibling(node: *const CNode) -> *mut CNode;
    pub fn pugi_node_previous_sibling(node: *const CNode) -> *mut CNode;
    pub fn pugi_node_next_sibling_by_name(node: *const CNode, name: *const c_char) -> *mut CNode;
    pub fn pugi_node_previous_sibling_by_name(node: *const CNode, name: *const c_char) -> *mut CNode;

    pub fn pugi_node_find_child_by_name_and_attribute(node: *const CNode, name: *const c_char,
                                                  attribute_name: *const c_char,
                                                  attribute_value: *const c_char)
        -> *mut CNode;
    pub fn pugi_node_find_child_by_attribute(node: *const CNode, attribute_name: *const c_char,
                                         attribute_value: *const c_char)
        -> *mut CNode;

    pub fn pugi_node_child_value(node: *mut CNode) -> *const c_char;
    pub fn pugi_node_child_value_by_name(node: *mut CNode, name: *const c_char) -> *mut CNode;

    // pub fn pugi_node_attribute(node: *mut CNode, name: *const c_char) -> *mut CAttribute;
    pub fn pugi_node_path(node: *const CNode, delimiter: c_char) -> *const c_char;

    pub fn pugi_node_first_element_by_path(node: *const CNode, path: *const c_char, delimiter: c_char)
        -> *mut CNode;

    pub fn pugi_node_root(node: *const CNode) -> *mut CNode;

    pub fn pugi_node_set_name(node: *mut CNode, name: *const c_char) -> c_int;
    pub fn pugi_node_set_value(node: *mut CNode, name: *const c_char) -> c_int;

    pub fn pugi_node_append_attribute(node: *mut CNode, name: *const c_char, value: *const c_char)
        -> c_int;
    pub fn pugi_node_prepend_attribute(node: *mut CNode, name: *const c_char, value: *const c_char)
        -> c_int;

    pub fn pugi_node_append_child(node: *mut CNode, node_type: NodeKind) -> *mut CNode;
    pub fn pugi_node_prepend_child(node: *mut CNode, node_type: NodeKind) -> *mut CNode;

    pub fn pugi_node_append_copy(node: *mut CNode, proto: *mut CNode) -> *mut CNode;
    pub fn pugi_node_prepend_copy(node: *mut CNode, proto: *mut CNode) -> *mut CNode;

    pub fn pugi_node_remove_attribute(node: *mut CNode, name: *const c_char) -> c_int;
    pub fn pugi_node_remove_child(node: *mut CNode, to_be_removed_child: *const CNode) -> c_int;

    // pub fn pugi_node_print(node: *mut CNode,

    // pub fn pugi_node_find_attribute_by_predicate
    // pub fn pugi_node_find_child_by_predicate
    // pub fn pugi_node_find_node_by_predicate

    // pub fn pugi_node_map_sibling
    // pub fn pugi_node_map_attributes

    // pub fn pugi_xpath_delete_xpath_node(node: *mut CXPathNode);

    // pub fn pugi_xpath_node_node(node: *mut CXPathNode) -> *mut CNode;
    // pub fn pugi_xpath_node_attribute(node: *mut CXPathNode) -> *mut CAttribute;

    // pub fn pugi_xpath_delete_xpath_node_set(node_set: *const CNodeSet);

    // pub fn pugi_xpath_node_set_size(node_set: *const CNodeSet) -> size_t;
    // pub fn pugi_xpath_node_set_is_empty(node_set: *const CNodeSet) -> c_int;

    // pub fn pugi_xpath_node_set_index(node_set: *mut CNodeSet, index: size_t) -> *mut CXPathNode;

    // pub fn pugi_xpath_node_set_map

    // pub fn pugi_xpath_delete_xpath_query(xpath: *const CXPath);

    // pub fn pugi_xpath_query_evaluate_boolean(xpath: *const CXPath, node: *mut CNode) -> c_int;
    // pub fn pugi_xpath_query_evaluate_number(xpath: *const CXPath, node: *mut CNode) -> c_double;
    // pub fn pugi_xpath_query_evaluate_string(xpath: *const CXPath, node: *mut CNode) -> *const c_char;
    // pub fn pugi_xpath_query_evaluate_node_set(xpath: *const CXPath, node: *mut CNode)
    //     -> *const CNodeSet;

    // pub fn pugi_xpath_query_return_type(xpath: *const CXPath) -> XPathValueType;

    // pub fn pugi_xpath_query_parse_is_success(xpath: *const CXPath) -> c_int;

    // pub fn pugi_xpath_select_single_node(node: *mut CNode, xpath: *const CXPath) -> *mut CXPathNode;
    // pub fn pugi_xpath_select_nodes(node: *mut CNode, xpath: *const CXPath) -> *const CNodeSet;
}
<|endoftext|>


<commit_before>use mio::*;
use mio::net::*;
use mio::unix::UnixReady;
use network::buffer_queue::BufferQueue;
use network::pool::Checkout;
use network::{ClientResult,Readiness};
use network::protocol::ProtocolResult;
use openssl::ssl::{self,HandshakeError,MidHandshakeSslStream,Ssl,SslStream};

pub enum TlsState {
  Initial,
  Handshake,
  Established,
  Error(HandshakeError<TcpStream>),
}

pub struct TlsHandshake {
  pub readiness:       Readiness,
  pub front:           Option<TcpStream>,
  pub ssl:             Option<Ssl>,
  pub stream:          Option<SslStream<TcpStream>>,
  mid:                 Option<MidHandshakeSslStream<TcpStream>>,
  state:               TlsState,
}

impl TlsHandshake {
  pub fn new(ssl:Ssl, sock: TcpStream) -> TlsHandshake {
    TlsHandshake {
      front:          Some(sock),
      ssl:            Some(ssl),
      mid:            None,
      stream:         None,
      state:          TlsState::Initial,
      readiness:      Readiness {
                        front_interest:  UnixReady::from(Ready::readable()) | UnixReady::hup() | UnixReady::error(),
                        back_interest:   UnixReady::from(Ready::empty()),
                        front_readiness: UnixReady::from(Ready::empty()),
                        back_readiness:  UnixReady::from(Ready::empty()),
      },
    }
  }

  pub fn readable(&mut self) -> (ProtocolResult,ClientResult) {
    match self.state {
      TlsState::Error(_) => return (ProtocolResult::Continue, ClientResult::CloseClient),
      TlsState::Initial => {
        let ssl     = self.ssl.take().expect("TlsHandshake should have a Ssl backend");
        let sock    = self.front.take().expect("TlsHandshake should have a front socket");
        match ssl.accept(sock) {
          Ok(stream) => {
            self.stream = Some(stream);
            self.state = TlsState::Established;
            return (ProtocolResult::Upgrade, ClientResult::Continue);
          },
          Err(HandshakeError::SetupFailure(e)) => {
            error!("accept: handshake setup failed: {:?}", e);
            self.state = TlsState::Error(HandshakeError::SetupFailure(e));
            return (ProtocolResult::Continue, ClientResult::CloseClient);
          },
          Err(HandshakeError::Failure(e)) => {
            error!("accept: handshake failed: {:?}", e);
            self.state = TlsState::Error(HandshakeError::Failure(e));
            return (ProtocolResult::Continue, ClientResult::CloseClient);
          },
          Err(HandshakeError::WouldBlock(mid)) => {
            self.state = TlsState::Handshake;
            self.mid = Some(mid);
            self.readiness.front_readiness.remove(Ready::readable());
            return (ProtocolResult::Continue, ClientResult::Continue);
          }
        }
      },
      TlsState::Handshake => {
        let mid = self.mid.take().expect("TlsHandshake should have a MidHandshakeSslStream backend");
        match mid.handshake() {
          Ok(stream) => {
            self.stream = Some(stream);
            self.state = TlsState::Established;
            return (ProtocolResult::Upgrade, ClientResult::Continue);
          },
          Err(HandshakeError::SetupFailure(e)) => {
            debug!("mid handshake setup failed: {:?}", e);
            self.state = TlsState::Error(HandshakeError::SetupFailure(e));
            return (ProtocolResult::Continue, ClientResult::CloseClient);
          },
          Err(HandshakeError::Failure(e)) => {
            debug!("mid handshake failed: {:?}", e);
            self.state = TlsState::Error(HandshakeError::Failure(e));
            return (ProtocolResult::Continue, ClientResult::CloseClient);
          },
          Err(HandshakeError::WouldBlock(new_mid)) => {
            self.state = TlsState::Handshake;
            self.mid = Some(new_mid);
            self.readiness.front_readiness.remove(Ready::readable());
            return (ProtocolResult::Continue, ClientResult::Continue);
          }
        }
      },
      TlsState::Established => {
        return (ProtocolResult::Upgrade, ClientResult::Continue);
      }
    }

  }

  pub fn socket(&self) -> Option<&TcpStream> {
    match self.state {
      TlsState::Initial => self.front.as_ref(),
      TlsState::Handshake => self.mid.as_ref().map(|mid| mid.get_ref()),
      TlsState::Established => self.stream.as_ref().map(|stream| stream.get_ref()),
      TlsState::Error(ref error) => {
        match error {
          &HandshakeError::SetupFailure(_) => {
            self.front.as_ref().or_else(|| self.mid.as_ref().map(|mid| mid.get_ref()))
          },
          &HandshakeError::Failure(ref mid) | &HandshakeError::WouldBlock(ref mid) => Some(mid.get_ref())
        }
      }
    }
  }
}

<commit_msg>add a metric instead of message logs for TLS SNI errors<commit_after>use mio::*;
use mio::net::*;
use mio::unix::UnixReady;
use network::buffer_queue::BufferQueue;
use network::pool::Checkout;
use network::{ClientResult,Readiness};
use network::protocol::ProtocolResult;
use openssl::ssl::{self,HandshakeError,MidHandshakeSslStream,Ssl,SslStream};

pub enum TlsState {
  Initial,
  Handshake,
  Established,
  Error(HandshakeError<TcpStream>),
}

pub struct TlsHandshake {
  pub readiness:       Readiness,
  pub front:           Option<TcpStream>,
  pub ssl:             Option<Ssl>,
  pub stream:          Option<SslStream<TcpStream>>,
  mid:                 Option<MidHandshakeSslStream<TcpStream>>,
  state:               TlsState,
}

impl TlsHandshake {
  pub fn new(ssl:Ssl, sock: TcpStream) -> TlsHandshake {
    TlsHandshake {
      front:          Some(sock),
      ssl:            Some(ssl),
      mid:            None,
      stream:         None,
      state:          TlsState::Initial,
      readiness:      Readiness {
                        front_interest:  UnixReady::from(Ready::readable()) | UnixReady::hup() | UnixReady::error(),
                        back_interest:   UnixReady::from(Ready::empty()),
                        front_readiness: UnixReady::from(Ready::empty()),
                        back_readiness:  UnixReady::from(Ready::empty()),
      },
    }
  }

  pub fn readable(&mut self) -> (ProtocolResult,ClientResult) {
    match self.state {
      TlsState::Error(_) => return (ProtocolResult::Continue, ClientResult::CloseClient),
      TlsState::Initial => {
        let ssl     = self.ssl.take().expect("TlsHandshake should have a Ssl backend");
        let sock    = self.front.take().expect("TlsHandshake should have a front socket");
        match ssl.accept(sock) {
          Ok(stream) => {
            self.stream = Some(stream);
            self.state = TlsState::Established;
            return (ProtocolResult::Upgrade, ClientResult::Continue);
          },
          Err(HandshakeError::SetupFailure(e)) => {
            error!("accept: handshake setup failed: {:?}", e);
            self.state = TlsState::Error(HandshakeError::SetupFailure(e));
            return (ProtocolResult::Continue, ClientResult::CloseClient);
          },
          Err(HandshakeError::Failure(e)) => {
            {
              if let Some(error_stack) = e.error().ssl_error() {
                let errors = error_stack.errors();
                if errors.len() == 2 && errors[0].code() == 0x1412E0E2 && errors[1].code() == 0x1408A0E3 {
                  incr!("openssl_sni_error");
                } else {
                  error!("accept: handshake failed: {:?}", e);
                }
              } else {
                error!("accept: handshake failed: {:?}", e);
              }
            }
            self.state = TlsState::Error(HandshakeError::Failure(e));
            return (ProtocolResult::Continue, ClientResult::CloseClient);
          },
          Err(HandshakeError::WouldBlock(mid)) => {
            self.state = TlsState::Handshake;
            self.mid = Some(mid);
            self.readiness.front_readiness.remove(Ready::readable());
            return (ProtocolResult::Continue, ClientResult::Continue);
          }
        }
      },
      TlsState::Handshake => {
        let mid = self.mid.take().expect("TlsHandshake should have a MidHandshakeSslStream backend");
        match mid.handshake() {
          Ok(stream) => {
            self.stream = Some(stream);
            self.state = TlsState::Established;
            return (ProtocolResult::Upgrade, ClientResult::Continue);
          },
          Err(HandshakeError::SetupFailure(e)) => {
            debug!("mid handshake setup failed: {:?}", e);
            self.state = TlsState::Error(HandshakeError::SetupFailure(e));
            return (ProtocolResult::Continue, ClientResult::CloseClient);
          },
          Err(HandshakeError::Failure(e)) => {
            debug!("mid handshake failed: {:?}", e);
            self.state = TlsState::Error(HandshakeError::Failure(e));
            return (ProtocolResult::Continue, ClientResult::CloseClient);
          },
          Err(HandshakeError::WouldBlock(new_mid)) => {
            self.state = TlsState::Handshake;
            self.mid = Some(new_mid);
            self.readiness.front_readiness.remove(Ready::readable());
            return (ProtocolResult::Continue, ClientResult::Continue);
          }
        }
      },
      TlsState::Established => {
        return (ProtocolResult::Upgrade, ClientResult::Continue);
      }
    }

  }

  pub fn socket(&self) -> Option<&TcpStream> {
    match self.state {
      TlsState::Initial => self.front.as_ref(),
      TlsState::Handshake => self.mid.as_ref().map(|mid| mid.get_ref()),
      TlsState::Established => self.stream.as_ref().map(|stream| stream.get_ref()),
      TlsState::Error(ref error) => {
        match error {
          &HandshakeError::SetupFailure(_) => {
            self.front.as_ref().or_else(|| self.mid.as_ref().map(|mid| mid.get_ref()))
          },
          &HandshakeError::Failure(ref mid) | &HandshakeError::WouldBlock(ref mid) => Some(mid.get_ref())
        }
      }
    }
  }
}

<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementations of serialization for structures found in libcollections

use std::uint;
use std::default::Default;
use std::hash::{Hash, Hasher};

use {Decodable, Encodable, Decoder, Encoder};
use std::collections::{DList, RingBuf, TreeMap, TreeSet, HashMap, HashSet,
                       TrieMap, TrieSet};
use std::collections::enum_set::{EnumSet, CLike};

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E>
> Encodable<S, E> for DList<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            for (i, e) in self.iter().enumerate() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
            }
            Ok(())
        })
    }
}

impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for DList<T> {
    fn decode(d: &mut D) -> Result<DList<T>, E> {
        d.read_seq(|d, len| {
            let mut list = DList::new();
            for i in range(0u, len) {
                list.push_back(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(list)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E>
> Encodable<S, E> for RingBuf<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            for (i, e) in self.iter().enumerate() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
            }
            Ok(())
        })
    }
}

impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for RingBuf<T> {
    fn decode(d: &mut D) -> Result<RingBuf<T>, E> {
        d.read_seq(|d, len| {
            let mut deque: RingBuf<T> = RingBuf::new();
            for i in range(0u, len) {
                deque.push_back(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(deque)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    K: Encodable<S, E> + PartialEq + Ord,
    V: Encodable<S, E> + PartialEq
> Encodable<S, E> for TreeMap<K, V> {
    fn encode(&self, e: &mut S) -> Result<(), E> {
        e.emit_map(self.len(), |e| {
            let mut i = 0;
            for (key, val) in self.iter() {
                try!(e.emit_map_elt_key(i, |e| key.encode(e)));
                try!(e.emit_map_elt_val(i, |e| val.encode(e)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    K: Decodable<D, E> + PartialEq + Ord,
    V: Decodable<D, E> + PartialEq
> Decodable<D, E> for TreeMap<K, V> {
    fn decode(d: &mut D) -> Result<TreeMap<K, V>, E> {
        d.read_map(|d, len| {
            let mut map = TreeMap::new();
            for i in range(0u, len) {
                let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
                map.insert(key, val);
            }
            Ok(map)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E> + PartialEq + Ord
> Encodable<S, E> for TreeSet<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            let mut i = 0;
            for e in self.iter() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    T: Decodable<D, E> + PartialEq + Ord
> Decodable<D, E> for TreeSet<T> {
    fn decode(d: &mut D) -> Result<TreeSet<T>, E> {
        d.read_seq(|d, len| {
            let mut set = TreeSet::new();
            for i in range(0u, len) {
                set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(set)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E> + CLike
> Encodable<S, E> for EnumSet<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        let mut bits = 0;
        for item in self.iter() {
            bits |= item.to_uint();
        }
        s.emit_uint(bits)
    }
}

impl<
    E,
    D: Decoder<E>,
    T: Decodable<D, E> + CLike
> Decodable<D, E> for EnumSet<T> {
    fn decode(d: &mut D) -> Result<EnumSet<T>, E> {
        let bits = try!(d.read_uint());
        let mut set = EnumSet::new();
        for bit in range(0, uint::BITS) {
            if bits & (1 << bit) != 0 {
                set.insert(CLike::from_uint(1 << bit));
            }
        }
        Ok(set)
    }
}

impl<
    E,
    S: Encoder<E>,
    K: Encodable<S, E> + Hash<X> + Eq,
    V: Encodable<S, E>,
    X,
    H: Hasher<X>
> Encodable<S, E> for HashMap<K, V, H> {
    fn encode(&self, e: &mut S) -> Result<(), E> {
        e.emit_map(self.len(), |e| {
            let mut i = 0;
            for (key, val) in self.iter() {
                try!(e.emit_map_elt_key(i, |e| key.encode(e)));
                try!(e.emit_map_elt_val(i, |e| val.encode(e)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    K: Decodable<D, E> + Hash<S> + Eq,
    V: Decodable<D, E>,
    S,
    H: Hasher<S> + Default
> Decodable<D, E> for HashMap<K, V, H> {
    fn decode(d: &mut D) -> Result<HashMap<K, V, H>, E> {
        d.read_map(|d, len| {
            let hasher = Default::default();
            let mut map = HashMap::with_capacity_and_hasher(len, hasher);
            for i in range(0u, len) {
                let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
                map.insert(key, val);
            }
            Ok(map)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E> + Hash<X> + Eq,
    X,
    H: Hasher<X>
> Encodable<S, E> for HashSet<T, H> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            let mut i = 0;
            for e in self.iter() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    T: Decodable<D, E> + Hash<S> + Eq,
    S,
    H: Hasher<S> + Default
> Decodable<D, E> for HashSet<T, H> {
    fn decode(d: &mut D) -> Result<HashSet<T, H>, E> {
        d.read_seq(|d, len| {
            let mut set = HashSet::with_capacity_and_hasher(len, Default::default());
            for i in range(0u, len) {
                set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(set)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    V: Encodable<S, E>
> Encodable<S, E> for TrieMap<V> {
    fn encode(&self, e: &mut S) -> Result<(), E> {
        e.emit_map(self.len(), |e| {
                for (i, (key, val)) in self.iter().enumerate() {
                    try!(e.emit_map_elt_key(i, |e| key.encode(e)));
                    try!(e.emit_map_elt_val(i, |e| val.encode(e)));
                }
                Ok(())
            })
    }
}

impl<
    E,
    D: Decoder<E>,
    V: Decodable<D, E>
> Decodable<D, E> for TrieMap<V> {
    fn decode(d: &mut D) -> Result<TrieMap<V>, E> {
        d.read_map(|d, len| {
            let mut map = TrieMap::new();
            for i in range(0u, len) {
                let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
                map.insert(key, val);
            }
            Ok(map)
        })
    }
}

impl<E, S: Encoder<E>> Encodable<S, E> for TrieSet {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
                for (i, e) in self.iter().enumerate() {
                    try!(s.emit_seq_elt(i, |s| e.encode(s)));
                }
                Ok(())
            })
    }
}

impl<E, D: Decoder<E>> Decodable<D, E> for TrieSet {
    fn decode(d: &mut D) -> Result<TrieSet, E> {
        d.read_seq(|d, len| {
            let mut set = TrieSet::new();
            for i in range(0u, len) {
                set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(set)
        })
    }
}
<commit_msg>Add Encodable and Decodable for VecMap<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementations of serialization for structures found in libcollections

use std::uint;
use std::default::Default;
use std::hash::{Hash, Hasher};

use {Decodable, Encodable, Decoder, Encoder};
use std::collections::{DList, RingBuf, TreeMap, TreeSet, HashMap, HashSet,
                       TrieMap, TrieSet, VecMap};
use std::collections::enum_set::{EnumSet, CLike};

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E>
> Encodable<S, E> for DList<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            for (i, e) in self.iter().enumerate() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
            }
            Ok(())
        })
    }
}

impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for DList<T> {
    fn decode(d: &mut D) -> Result<DList<T>, E> {
        d.read_seq(|d, len| {
            let mut list = DList::new();
            for i in range(0u, len) {
                list.push_back(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(list)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E>
> Encodable<S, E> for RingBuf<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            for (i, e) in self.iter().enumerate() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
            }
            Ok(())
        })
    }
}

impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for RingBuf<T> {
    fn decode(d: &mut D) -> Result<RingBuf<T>, E> {
        d.read_seq(|d, len| {
            let mut deque: RingBuf<T> = RingBuf::new();
            for i in range(0u, len) {
                deque.push_back(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(deque)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    K: Encodable<S, E> + PartialEq + Ord,
    V: Encodable<S, E> + PartialEq
> Encodable<S, E> for TreeMap<K, V> {
    fn encode(&self, e: &mut S) -> Result<(), E> {
        e.emit_map(self.len(), |e| {
            let mut i = 0;
            for (key, val) in self.iter() {
                try!(e.emit_map_elt_key(i, |e| key.encode(e)));
                try!(e.emit_map_elt_val(i, |e| val.encode(e)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    K: Decodable<D, E> + PartialEq + Ord,
    V: Decodable<D, E> + PartialEq
> Decodable<D, E> for TreeMap<K, V> {
    fn decode(d: &mut D) -> Result<TreeMap<K, V>, E> {
        d.read_map(|d, len| {
            let mut map = TreeMap::new();
            for i in range(0u, len) {
                let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
                map.insert(key, val);
            }
            Ok(map)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E> + PartialEq + Ord
> Encodable<S, E> for TreeSet<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            let mut i = 0;
            for e in self.iter() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    T: Decodable<D, E> + PartialEq + Ord
> Decodable<D, E> for TreeSet<T> {
    fn decode(d: &mut D) -> Result<TreeSet<T>, E> {
        d.read_seq(|d, len| {
            let mut set = TreeSet::new();
            for i in range(0u, len) {
                set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(set)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E> + CLike
> Encodable<S, E> for EnumSet<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        let mut bits = 0;
        for item in self.iter() {
            bits |= item.to_uint();
        }
        s.emit_uint(bits)
    }
}

impl<
    E,
    D: Decoder<E>,
    T: Decodable<D, E> + CLike
> Decodable<D, E> for EnumSet<T> {
    fn decode(d: &mut D) -> Result<EnumSet<T>, E> {
        let bits = try!(d.read_uint());
        let mut set = EnumSet::new();
        for bit in range(0, uint::BITS) {
            if bits & (1 << bit) != 0 {
                set.insert(CLike::from_uint(1 << bit));
            }
        }
        Ok(set)
    }
}

impl<
    E,
    S: Encoder<E>,
    K: Encodable<S, E> + Hash<X> + Eq,
    V: Encodable<S, E>,
    X,
    H: Hasher<X>
> Encodable<S, E> for HashMap<K, V, H> {
    fn encode(&self, e: &mut S) -> Result<(), E> {
        e.emit_map(self.len(), |e| {
            let mut i = 0;
            for (key, val) in self.iter() {
                try!(e.emit_map_elt_key(i, |e| key.encode(e)));
                try!(e.emit_map_elt_val(i, |e| val.encode(e)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    K: Decodable<D, E> + Hash<S> + Eq,
    V: Decodable<D, E>,
    S,
    H: Hasher<S> + Default
> Decodable<D, E> for HashMap<K, V, H> {
    fn decode(d: &mut D) -> Result<HashMap<K, V, H>, E> {
        d.read_map(|d, len| {
            let hasher = Default::default();
            let mut map = HashMap::with_capacity_and_hasher(len, hasher);
            for i in range(0u, len) {
                let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
                map.insert(key, val);
            }
            Ok(map)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E> + Hash<X> + Eq,
    X,
    H: Hasher<X>
> Encodable<S, E> for HashSet<T, H> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            let mut i = 0;
            for e in self.iter() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    T: Decodable<D, E> + Hash<S> + Eq,
    S,
    H: Hasher<S> + Default
> Decodable<D, E> for HashSet<T, H> {
    fn decode(d: &mut D) -> Result<HashSet<T, H>, E> {
        d.read_seq(|d, len| {
            let mut set = HashSet::with_capacity_and_hasher(len, Default::default());
            for i in range(0u, len) {
                set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(set)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    V: Encodable<S, E>
> Encodable<S, E> for TrieMap<V> {
    fn encode(&self, e: &mut S) -> Result<(), E> {
        e.emit_map(self.len(), |e| {
                for (i, (key, val)) in self.iter().enumerate() {
                    try!(e.emit_map_elt_key(i, |e| key.encode(e)));
                    try!(e.emit_map_elt_val(i, |e| val.encode(e)));
                }
                Ok(())
            })
    }
}

impl<
    E,
    D: Decoder<E>,
    V: Decodable<D, E>
> Decodable<D, E> for TrieMap<V> {
    fn decode(d: &mut D) -> Result<TrieMap<V>, E> {
        d.read_map(|d, len| {
            let mut map = TrieMap::new();
            for i in range(0u, len) {
                let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
                map.insert(key, val);
            }
            Ok(map)
        })
    }
}

impl<E, S: Encoder<E>> Encodable<S, E> for TrieSet {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
                for (i, e) in self.iter().enumerate() {
                    try!(s.emit_seq_elt(i, |s| e.encode(s)));
                }
                Ok(())
            })
    }
}

impl<E, D: Decoder<E>> Decodable<D, E> for TrieSet {
    fn decode(d: &mut D) -> Result<TrieSet, E> {
        d.read_seq(|d, len| {
            let mut set = TrieSet::new();
            for i in range(0u, len) {
                set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(set)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    V: Encodable<S, E>
> Encodable<S, E> for VecMap<V> {
    fn encode(&self, e: &mut S) -> Result<(), E> {
        e.emit_map(self.len(), |e| {
                for (i, (key, val)) in self.iter().enumerate() {
                    try!(e.emit_map_elt_key(i, |e| key.encode(e)));
                    try!(e.emit_map_elt_val(i, |e| val.encode(e)));
                }
                Ok(())
            })
    }
}

impl<
    E,
    D: Decoder<E>,
    V: Decodable<D, E>
> Decodable<D, E> for VecMap<V> {
    fn decode(d: &mut D) -> Result<VecMap<V>, E> {
        d.read_map(|d, len| {
            let mut map = VecMap::new();
            for i in range(0u, len) {
                let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
                map.insert(key, val);
            }
            Ok(map)
        })
    }
}
<|endoftext|>