<commit_before>#[cfg(not(feature = "sdl_renderer"))]
pub mod renderer {
    pub mod glium_sdl2;

    use px8;
    use gfx::{Scale};

    use sdl2::video::gl_attr::GLAttr;
    use sdl2::VideoSubsystem;

    use glium;
    use glium::{DrawError, DrawParameters, IndexBuffer, Program, VertexBuffer, Surface};
    use glium::index::PrimitiveType;
    use glium::program::ProgramChooserCreationError;
    use glium::{Api, GliumCreationError, SwapBuffersError, Version};
    use glium::backend::Facade;
    use glium::texture::{ClientFormat, MipmapsOption, PixelValue, TextureCreationError, UncompressedFloatFormat};
    use glium::texture::pixel_buffer::PixelBuffer;
    use glium::texture::texture2d::Texture2d;

    use glium::uniforms::{MagnifySamplerFilter, MinifySamplerFilter};
    use nalgebra::{Diagonal, Matrix4, Vector4};

    use self::glium_sdl2::{Display, DisplayBuild, GliumSdl2Error};

    #[derive(Clone, Debug)]
    pub enum RendererError {
        Sdl(String),
        Renderer(String),
        Other(String),
    }

    pub type RendererResult<T> = Result<T, RendererError>;

    impl From<DrawError> for RendererError {
        fn from(e: DrawError) -> RendererError {
            RendererError::Renderer(format!("{:?}", e))
        }
    }

    impl From<TextureCreationError> for RendererError {
        fn from(e: TextureCreationError) -> RendererError {
            RendererError::Renderer(format!("{:?}", e))
        }
    }

    impl From<glium::vertex::BufferCreationError> for RendererError {
        fn from(e: glium::vertex::BufferCreationError) -> RendererError {
            RendererError::Renderer(format!("{:?}", e))
        }
    }

    impl From<glium::index::BufferCreationError> for RendererError {
        fn from(e: glium::index::BufferCreationError) -> RendererError {
            RendererError::Renderer(format!("{:?}", e))
        }
    }

    impl From<ProgramChooserCreationError> for RendererError {
        fn from(e: ProgramChooserCreationError) -> RendererError {
            RendererError::Renderer(format!("{:?}", e))
        }
    }

    impl From<GliumCreationError<GliumSdl2Error>> for RendererError {
        fn from(e: GliumCreationError<GliumSdl2Error>) -> RendererError {
            RendererError::Renderer(format!("{:?}", e))
        }
    }

    impl From<SwapBuffersError> for RendererError {
        fn from(e: SwapBuffersError) -> RendererError {
            RendererError::Renderer(format!("{:?}", e))
        }
    }

    unsafe impl PixelValue for px8::Color {
        fn get_format() -> ClientFormat {
            ClientFormat::U8
        }
    }

    type Texture = Texture2d;

    #[derive(Copy, Clone)]
    pub struct Vertex {
        position: [f32; 2],
        tex_coords: [f32; 2],
    }

    implement_vertex!(Vertex, position, tex_coords);

    pub struct Renderer {
        vertex_buffer: VertexBuffer<Vertex>,
        index_buffer: IndexBuffer<u16>,
        pixel_buffer: PixelBuffer<px8::Color>,
        program: Program,
        texture: Texture,
        matrix: Matrix4<f32>,
        display: Display,
    }

    const TEXTURE_WIDTH: u32 = 256;
    const TEXTURE_HEIGHT: u32 = 256;
    const TEX_OFFSET_X: f32 = px8::SCREEN_WIDTH as f32 / TEXTURE_WIDTH as f32;
    const TEX_OFFSET_Y: f32 = px8::SCREEN_HEIGHT as f32 / TEXTURE_HEIGHT as f32;

    const ASPECT_RATIO: f32 = px8::SCREEN_WIDTH as f32 / px8::SCREEN_HEIGHT as f32;

    fn aspect_ratio_correction(width: u32, height: u32) -> (f32, f32) {
        let fb_aspect_ratio = width as f32 / height as f32;
        let scale = ASPECT_RATIO / fb_aspect_ratio;
        if fb_aspect_ratio >= ASPECT_RATIO {
            (scale, 1.0)
        } else {
            (1.0, 1.0 / scale)
        }
    }

    impl Renderer {

        pub fn new(sdl_video: VideoSubsystem, fullscreen: bool, scale: Scale) -> RendererResult<Renderer> {
            let display;

            info!("SDL2 Video with opengl [glium]");

            configure_gl_attr(&mut sdl_video.gl_attr());

            if fullscreen {
                info!("SDL2 window fullscreen");

                display = try!(sdl_video.window("PX8",
                                                (px8::SCREEN_WIDTH * scale.factor()) as u32,
                                                (px8::SCREEN_HEIGHT * scale.factor()) as u32)
                    .resizable()
                    .fullscreen()
                    .position_centered()
                    .build_glium());
            } else {
                info!("SDL2 window");

                display = try!(sdl_video.window("PX8",
                                                (px8::SCREEN_WIDTH * scale.factor()) as u32,
                                                (px8::SCREEN_HEIGHT * scale.factor()) as u32)
                    .resizable()
                    .position_centered()
                    .build_glium());
            }

            info!("Init Renderer with GLIUM");

            let vertexes = [
                Vertex {
                    position: [-1.0, -1.0],
                    tex_coords: [0.0, TEX_OFFSET_Y],
                },
                Vertex {
                    position: [-1.0, 1.0],
                    tex_coords: [0.0, 0.0],
                },
                Vertex {
                    position: [1.0, 1.0],
                    tex_coords: [TEX_OFFSET_X, 0.0],
                },
                Vertex {
                    position: [1.0, -1.0],
                    tex_coords: [TEX_OFFSET_X, TEX_OFFSET_Y],
                }
            ];

            info!("Creating VertexBuffer");

            let vertex_buffer = try!(VertexBuffer::immutable(&display, &vertexes));

            info!("Creating IndexBuffer");

            let index_buffer =
            try!(IndexBuffer::immutable(&display, PrimitiveType::TriangleStrip, &[1u16, 2, 0, 3]));

            info!("Compiling shader");

            let program = try!(program!(
              &display,
              140 => {
                vertex: include_str!("shader/vert_140.glsl"),
                fragment: include_str!("shader/frag_140.glsl"),
                outputs_srgb: true
              },
              110 => {
                vertex: include_str!("shader/vert_110.glsl"),
                fragment: include_str!("shader/frag_110.glsl"),
                outputs_srgb: true
              }
            ));

            info!("Creating PixelBuffer");

            let pixel_buffer = PixelBuffer::new_empty(&display, px8::SCREEN_WIDTH * px8::SCREEN_HEIGHT);
            pixel_buffer.write(&vec![px8::Color::Black; pixel_buffer.get_size()]);

            info!("Creating Texture");
            let mut texture = try!(Texture::empty_with_format(&display,
                                                              UncompressedFloatFormat::U8U8U8,
                                                              MipmapsOption::NoMipmap,
                                                              TEXTURE_WIDTH,
                                                              TEXTURE_HEIGHT));

            info!("Uploading Pixels");
            texture.main_level().raw_upload_from_pixel_buffer(pixel_buffer.as_slice(),
                                                              0..px8::SCREEN_WIDTH as u32,
                                                              0..px8::SCREEN_HEIGHT as u32,
                                                              0..1);

            let (width, height) = display.get_context().get_framebuffer_dimensions();
            let (x_scale, y_scale) = aspect_ratio_correction(width, height);
            let matrix = Matrix4::from_diagonal(&Vector4::new(x_scale, y_scale, 1.0, 1.0));

            Ok(Renderer {
                vertex_buffer: vertex_buffer,
                index_buffer: index_buffer,
                pixel_buffer: pixel_buffer,
                program: program,
                texture: texture,
                matrix: matrix,
                display: display,
            })

        }
        pub fn draw<S: Surface>(&self, frame: &mut S) -> RendererResult<()> {
            let uniforms = uniform! {
                matrix: self.matrix.as_ref().clone(),
                tex: self.texture.sampled()
                    .minify_filter(MinifySamplerFilter::Nearest)
                    .magnify_filter(MagnifySamplerFilter::Nearest)
            };

            let params = DrawParameters { ..Default::default() };
            try!(frame.draw(&self.vertex_buffer,
                            &self.index_buffer,
                            &self.program,
                            &uniforms,
                            &params));
            Ok(())
        }

        pub fn blit(&mut self, back_buffer: &px8::ScreenBuffer) {
            self.update_pixels(back_buffer);

            let mut target = self.display.draw();
            target.clear_color(0.0, 0.0, 0.0, 0.0);
            self.draw(&mut target);
            target.finish();
        }

        pub fn update_pixels(&mut self, pixels: &px8::ScreenBuffer) {
            self.pixel_buffer.write(pixels);

            self.texture.main_level().raw_upload_from_pixel_buffer(self.pixel_buffer.as_slice(),
                                                                   0..px8::SCREEN_WIDTH as u32,
                                                                   0..px8::SCREEN_HEIGHT as u32,
                                                                   0..1);
        }

        pub fn update_dimensions(&mut self) {
            let (width, height) = self.display.get_context().get_framebuffer_dimensions();
            let (x_scale, y_scale) = aspect_ratio_correction(width, height);
            self.matrix.m11 = x_scale;
            self.matrix.m22 = y_scale;
        }

        pub fn get_dimensions(&mut self) -> (u32, u32) {
            return self.display.get_context().get_framebuffer_dimensions();
        }
    }

    #[cfg(target_os = "linux")]
    fn configure_gl_attr(gl_attr: &mut GLAttr) {
        info!("Init OPENGL for Linux");
    }

    #[cfg(target_os = "windows")]
    fn configure_gl_attr(gl_attr: &mut GLAttr) {
        info!("Init OPENGL for Windows");
    }

    #[cfg(target_os = "macos")]
    fn configure_gl_attr(gl_attr: &mut GLAttr) {
        info!("Init OPENGL for OSX");

        use sdl2::video::GLProfile;
        gl_attr.set_context_profile(GLProfile::Core);
        gl_attr.set_context_flags().forward_compatible().set();
    }

    #[cfg(target_os = "emscripten")]
    fn configure_gl_attr(gl_attr: &mut GLAttr) {
        info!("Init OPENGL for Emscripten");
    }
}

#[cfg(feature = "sdl_renderer")]
pub mod renderer {
    use px8;
    use gfx::{Scale};

    use sdl2::VideoSubsystem;
    use sdl2::render;
    use sdl2::pixels::PixelFormatEnum;

    #[derive(Clone, Debug)]
    pub enum RendererError {
        Sdl(String),
        Renderer(String),
        Other(String),
    }

    pub type RendererResult<T> = Result<T, RendererError>;

    pub struct Renderer {
        pub renderer: render::Renderer<'static>,
        pub texture: render::Texture,
    }

    impl Renderer {
        pub fn new(sdl_video: VideoSubsystem, fullscreen: bool, scale: Scale) -> RendererResult<Renderer> {
            info!("[SDL] Creating window");

            let mut window_builder = sdl_video.window("PX8",
                                                      (px8::SCREEN_WIDTH as usize * scale.factor()) as u32,
                                                      (px8::SCREEN_HEIGHT as usize * scale.factor()) as u32);

            let window;
            if fullscreen {
                window = window_builder.fullscreen().build().unwrap();
            } else {
                window = window_builder.position_centered().build().unwrap();
            }

            info!("[SDL] Creating renderer");
            let mut renderer = window.renderer().accelerated().present_vsync().build().unwrap();

            info!("[SDL] Creating texture");
            let texture = renderer.create_texture(PixelFormatEnum::BGR24,
                                                  render::TextureAccess::Streaming,
                                                  px8::SCREEN_WIDTH as u32,
                                                  px8::SCREEN_HEIGHT as u32).unwrap();

            Ok(Renderer {
                renderer: renderer,
                texture: texture,
            })
        }

        pub fn blit(&mut self, back_buffer: &px8::ScreenBuffer) {
            let mut data = Box::new([0; px8::SCREEN_HEIGHT*px8::SCREEN_WIDTH*3]);

            for x in 0..px8::SCREEN_WIDTH {
                for y in 0..px8::SCREEN_HEIGHT {
                    let col_rgb = px8::Color::to_rgb(back_buffer[x + y * px8::SCREEN_WIDTH]);

                    data[(x+y*px8::SCREEN_WIDTH)*3] = col_rgb.b;
                    data[(x+y*px8::SCREEN_WIDTH)*3+1] = col_rgb.g;
                    data[(x+y*px8::SCREEN_WIDTH)*3+2] = col_rgb.r;
                }
            }

            self.texture.update(None,
                                &mut *data,
                                px8::SCREEN_WIDTH * 3).unwrap();

            self.renderer.clear();
            self.renderer.copy(&self.texture, None, None);
            self.renderer.present();
        }

        pub fn update_dimensions(&mut self) {
        }

        pub fn get_dimensions(&mut self) -> (u32, u32) {
            let size = self.renderer.window().unwrap().size();

            return (size.0, size.1)
        }
    }
}<commit_msg>Add resizable window<commit_after>#[cfg(not(feature = "sdl_renderer"))]
pub mod renderer {
    pub mod glium_sdl2;

    use px8;
    use gfx::{Scale};

    use sdl2::video::gl_attr::GLAttr;
    use sdl2::VideoSubsystem;

    use glium;
    use glium::{DrawError, DrawParameters, IndexBuffer, Program, VertexBuffer, Surface};
    use glium::index::PrimitiveType;
    use glium::program::ProgramChooserCreationError;
    use glium::{Api, GliumCreationError, SwapBuffersError, Version};
    use glium::backend::Facade;
    use glium::texture::{ClientFormat, MipmapsOption, PixelValue, TextureCreationError, UncompressedFloatFormat};
    use glium::texture::pixel_buffer::PixelBuffer;
    use glium::texture::texture2d::Texture2d;

    use glium::uniforms::{MagnifySamplerFilter, MinifySamplerFilter};
    use nalgebra::{Diagonal, Matrix4, Vector4};

    use self::glium_sdl2::{Display, DisplayBuild, GliumSdl2Error};

    #[derive(Clone, Debug)]
    pub enum RendererError {
        Sdl(String),
        Renderer(String),
        Other(String),
    }

    pub type RendererResult<T> = Result<T, RendererError>;

    impl From<DrawError> for RendererError {
        fn from(e: DrawError) -> RendererError {
            RendererError::Renderer(format!("{:?}", e))
        }
    }

    impl From<TextureCreationError> for RendererError {
        fn from(e: TextureCreationError) -> RendererError {
            RendererError::Renderer(format!("{:?}", e))
        }
    }

    impl From<glium::vertex::BufferCreationError> for RendererError {
        fn from(e: glium::vertex::BufferCreationError) -> RendererError {
            RendererError::Renderer(format!("{:?}", e))
        }
    }

    impl From<glium::index::BufferCreationError> for RendererError {
        fn from(e: glium::index::BufferCreationError) -> RendererError {
            RendererError::Renderer(format!("{:?}", e))
        }
    }

    impl From<ProgramChooserCreationError> for RendererError {
        fn from(e: ProgramChooserCreationError) -> RendererError {
            RendererError::Renderer(format!("{:?}", e))
        }
    }

    impl From<GliumCreationError<GliumSdl2Error>> for RendererError {
        fn from(e: GliumCreationError<GliumSdl2Error>) -> RendererError {
            RendererError::Renderer(format!("{:?}", e))
        }
    }

    impl From<SwapBuffersError> for RendererError {
        fn from(e: SwapBuffersError) -> RendererError {
            RendererError::Renderer(format!("{:?}", e))
        }
    }

    unsafe impl PixelValue for px8::Color {
        fn get_format() -> ClientFormat {
            ClientFormat::U8
        }
    }

    type Texture = Texture2d;

    #[derive(Copy, Clone)]
    pub struct Vertex {
        position: [f32; 2],
        tex_coords: [f32; 2],
    }

    implement_vertex!(Vertex, position, tex_coords);

    pub struct Renderer {
        vertex_buffer: VertexBuffer<Vertex>,
        index_buffer: IndexBuffer<u16>,
        pixel_buffer: PixelBuffer<px8::Color>,
        program: Program,
        texture: Texture,
        matrix: Matrix4<f32>,
        display: Display,
    }

    const TEXTURE_WIDTH: u32 = 256;
    const TEXTURE_HEIGHT: u32 = 256;
    const TEX_OFFSET_X: f32 = px8::SCREEN_WIDTH as f32 / TEXTURE_WIDTH as f32;
    const TEX_OFFSET_Y: f32 = px8::SCREEN_HEIGHT as f32 / TEXTURE_HEIGHT as f32;

    const ASPECT_RATIO: f32 = px8::SCREEN_WIDTH as f32 / px8::SCREEN_HEIGHT as f32;

    fn aspect_ratio_correction(width: u32, height: u32) -> (f32, f32) {
        let fb_aspect_ratio = width as f32 / height as f32;
        let scale = ASPECT_RATIO / fb_aspect_ratio;
        if fb_aspect_ratio >= ASPECT_RATIO {
            (scale, 1.0)
        } else {
            (1.0, 1.0 / scale)
        }
    }

    impl Renderer {

        pub fn new(sdl_video: VideoSubsystem, fullscreen: bool, scale: Scale) -> RendererResult<Renderer> {
            let display;

            info!("SDL2 Video with opengl [glium]");

            configure_gl_attr(&mut sdl_video.gl_attr());

            if fullscreen {
                info!("SDL2 window fullscreen");

                display = try!(sdl_video.window("PX8",
                                                (px8::SCREEN_WIDTH * scale.factor()) as u32,
                                                (px8::SCREEN_HEIGHT * scale.factor()) as u32)
                    .resizable()
                    .fullscreen()
                    .position_centered()
                    .build_glium());
            } else {
                info!("SDL2 window");

                display = try!(sdl_video.window("PX8",
                                                (px8::SCREEN_WIDTH * scale.factor()) as u32,
                                                (px8::SCREEN_HEIGHT * scale.factor()) as u32)
                    .resizable()
                    .position_centered()
                    .build_glium());
            }

            info!("Init Renderer with GLIUM");

            let vertexes = [
                Vertex {
                    position: [-1.0, -1.0],
                    tex_coords: [0.0, TEX_OFFSET_Y],
                },
                Vertex {
                    position: [-1.0, 1.0],
                    tex_coords: [0.0, 0.0],
                },
                Vertex {
                    position: [1.0, 1.0],
                    tex_coords: [TEX_OFFSET_X, 0.0],
                },
                Vertex {
                    position: [1.0, -1.0],
                    tex_coords: [TEX_OFFSET_X, TEX_OFFSET_Y],
                }
            ];

            info!("Creating VertexBuffer");

            let vertex_buffer = try!(VertexBuffer::immutable(&display, &vertexes));

            info!("Creating IndexBuffer");

            let index_buffer =
            try!(IndexBuffer::immutable(&display, PrimitiveType::TriangleStrip, &[1u16, 2, 0, 3]));

            info!("Compiling shader");

            let program = try!(program!(
              &display,
              140 => {
                vertex: include_str!("shader/vert_140.glsl"),
                fragment: include_str!("shader/frag_140.glsl"),
                outputs_srgb: true
              },
              110 => {
                vertex: include_str!("shader/vert_110.glsl"),
                fragment: include_str!("shader/frag_110.glsl"),
                outputs_srgb: true
              }
            ));

            info!("Creating PixelBuffer");

            let pixel_buffer = PixelBuffer::new_empty(&display, px8::SCREEN_WIDTH * px8::SCREEN_HEIGHT);
            pixel_buffer.write(&vec![px8::Color::Black; pixel_buffer.get_size()]);

            info!("Creating Texture");
            let mut texture = try!(Texture::empty_with_format(&display,
                                                              UncompressedFloatFormat::U8U8U8,
                                                              MipmapsOption::NoMipmap,
                                                              TEXTURE_WIDTH,
                                                              TEXTURE_HEIGHT));

            info!("Uploading Pixels");
            texture.main_level().raw_upload_from_pixel_buffer(pixel_buffer.as_slice(),
                                                              0..px8::SCREEN_WIDTH as u32,
                                                              0..px8::SCREEN_HEIGHT as u32,
                                                              0..1);

            let (width, height) = display.get_context().get_framebuffer_dimensions();
            let (x_scale, y_scale) = aspect_ratio_correction(width, height);
            let matrix = Matrix4::from_diagonal(&Vector4::new(x_scale, y_scale, 1.0, 1.0));

            Ok(Renderer {
                vertex_buffer: vertex_buffer,
                index_buffer: index_buffer,
                pixel_buffer: pixel_buffer,
                program: program,
                texture: texture,
                matrix: matrix,
                display: display,
            })

        }
        pub fn draw<S: Surface>(&self, frame: &mut S) -> RendererResult<()> {
            let uniforms = uniform! {
                matrix: self.matrix.as_ref().clone(),
                tex: self.texture.sampled()
                    .minify_filter(MinifySamplerFilter::Nearest)
                    .magnify_filter(MagnifySamplerFilter::Nearest)
            };

            let params = DrawParameters { ..Default::default() };
            try!(frame.draw(&self.vertex_buffer,
                            &self.index_buffer,
                            &self.program,
                            &uniforms,
                            &params));
            Ok(())
        }

        pub fn blit(&mut self, back_buffer: &px8::ScreenBuffer) {
            self.update_pixels(back_buffer);

            let mut target = self.display.draw();
            target.clear_color(0.0, 0.0, 0.0, 0.0);
            self.draw(&mut target);
            target.finish();
        }

        pub fn update_pixels(&mut self, pixels: &px8::ScreenBuffer) {
            self.pixel_buffer.write(pixels);

            self.texture.main_level().raw_upload_from_pixel_buffer(self.pixel_buffer.as_slice(),
                                                                   0..px8::SCREEN_WIDTH as u32,
                                                                   0..px8::SCREEN_HEIGHT as u32,
                                                                   0..1);
        }

        pub fn update_dimensions(&mut self) {
            let (width, height) = self.display.get_context().get_framebuffer_dimensions();
            let (x_scale, y_scale) = aspect_ratio_correction(width, height);
            self.matrix.m11 = x_scale;
            self.matrix.m22 = y_scale;
        }

        pub fn get_dimensions(&mut self) -> (u32, u32) {
            return self.display.get_context().get_framebuffer_dimensions();
        }
    }

    #[cfg(target_os = "linux")]
    fn configure_gl_attr(gl_attr: &mut GLAttr) {
        info!("Init OPENGL for Linux");
    }

    #[cfg(target_os = "windows")]
    fn configure_gl_attr(gl_attr: &mut GLAttr) {
        info!("Init OPENGL for Windows");
    }

    #[cfg(target_os = "macos")]
    fn configure_gl_attr(gl_attr: &mut GLAttr) {
        info!("Init OPENGL for OSX");

        use sdl2::video::GLProfile;
        gl_attr.set_context_profile(GLProfile::Core);
        gl_attr.set_context_flags().forward_compatible().set();
    }

    #[cfg(target_os = "emscripten")]
    fn configure_gl_attr(gl_attr: &mut GLAttr) {
        info!("Init OPENGL for Emscripten");
    }
}

#[cfg(feature = "sdl_renderer")]
pub mod renderer {
    use px8;
    use gfx::{Scale};

    use sdl2::VideoSubsystem;
    use sdl2::render;
    use sdl2::pixels::PixelFormatEnum;

    #[derive(Clone, Debug)]
    pub enum RendererError {
        Sdl(String),
        Renderer(String),
        Other(String),
    }

    pub type RendererResult<T> = Result<T, RendererError>;

    pub struct Renderer {
        pub renderer: render::Renderer<'static>,
        pub texture: render::Texture,
    }

    impl Renderer {
        pub fn new(sdl_video: VideoSubsystem, fullscreen: bool, scale: Scale) -> RendererResult<Renderer> {
            info!("[SDL] Creating window");

            let mut window_builder = sdl_video.window("PX8",
                                                      (px8::SCREEN_WIDTH as usize * scale.factor()) as u32,
                                                      (px8::SCREEN_HEIGHT as usize * scale.factor()) as u32);

            let window;
            if fullscreen {
                window = window_builder.fullscreen().build().unwrap();
            } else {
                window = window_builder.resizable().position_centered().build().unwrap();
            }

            info!("[SDL] Creating renderer");
            let mut renderer = window.renderer().accelerated().present_vsync().build().unwrap();

            info!("[SDL] Creating texture");
            let texture = renderer.create_texture(PixelFormatEnum::BGR24,
                                                  render::TextureAccess::Streaming,
                                                  px8::SCREEN_WIDTH as u32,
                                                  px8::SCREEN_HEIGHT as u32).unwrap();

            Ok(Renderer {
                renderer: renderer,
                texture: texture,
            })
        }

        pub fn blit(&mut self, back_buffer: &px8::ScreenBuffer) {
            let mut data = Box::new([0; px8::SCREEN_HEIGHT*px8::SCREEN_WIDTH*3]);

            for x in 0..px8::SCREEN_WIDTH {
                for y in 0..px8::SCREEN_HEIGHT {
                    let col_rgb = px8::Color::to_rgb(back_buffer[x + y * px8::SCREEN_WIDTH]);

                    data[(x+y*px8::SCREEN_WIDTH)*3] = col_rgb.b;
                    data[(x+y*px8::SCREEN_WIDTH)*3+1] = col_rgb.g;
                    data[(x+y*px8::SCREEN_WIDTH)*3+2] = col_rgb.r;
                }
            }

            self.texture.update(None,
                                &mut *data,
                                px8::SCREEN_WIDTH * 3).unwrap();

            self.renderer.clear();
            self.renderer.copy(&self.texture, None, None);
            self.renderer.present();
        }

        pub fn update_dimensions(&mut self) {
        }

        pub fn get_dimensions(&mut self) -> (u32, u32) {
            let size = self.renderer.window().unwrap().size();

            return (size.0, size.1)
        }
    }
}<|endoftext|>


<commit_before>#![allow(dead_code, unused_must_use, unused_imports, unstable)]

extern crate "rustc-serialize" as rustc_serialize;
extern crate log;

use utils;
use std::fmt;
use std::str;
use std::string;
use std::old_io::{File, Open, Append, Read, Write, ReadWrite};
use std::old_io::TempDir;
use std::old_io::fs;
use std::old_io::fs::PathExtensions;
use std::old_io::{BufferedReader, BufferedWriter};
use std::old_path::BytesContainer;
use self::rustc_serialize::base64::{STANDARD, FromBase64, ToBase64};

/// A result type that's specfici to the Reader module.
/// TODO Decide if this is necessary
pub type ReaderResult<T, E> = Result<T, E>;

/// Reader struct of its basic properties.
pub struct Reader {
    /// Path to file where the Reader is created.
    path: Path,
    /// BufferedReader for reading the file. Initialized with the Path.
    read_buffer: BufferedReader<File>,
    /// BufferedWriter for writing to the file. Initialized with the Path.
    write_buffer: BufferedWriter<File>,
    /// Index counter to know how many records exist.
    id_count: u64,
}

/// ReaderFile traits
pub trait ReaderFile {
    // Opens a new File to the Path provided.
    // Returns a boxed File.
    fn open(&self) -> File;
    // Inserts a string to the database.
    fn insert_string(&mut self, String);
}

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

impl ToString for Reader {
    fn to_string(&self) -> String {
        format!("{:?}", self)
    }
}

impl Reader {
    /// Creates a new Reader from the Path provided.
    /// Opens a new BufferedReader and BufferedWriter (with Append mode) to the file.
    /// If the file doesn't exist, it is created.
    // TODO, create a .lock file to let other readers know the database is in use (see: #2).
    pub fn new(apath: &Path) -> Reader {
        Reader::file_lock_create(apath);
        // if file_lock exists, panic and crash with appropriate error.
        // Error: A .lock file already exists, if this is from a previous session, consider
        // deleting the .lock file.

        if !apath.exists() {
            let mut file = File::create(&apath.clone());
            file.write_line("0");
            file.flush();
        }

        let mut buffer_writer = match File::open_mode(&apath.clone(), Append, ReadWrite) {
                                    Ok(file)    => { BufferedWriter::new(file) },
                                    Err(..)     => {
                                        panic!("Failed to create a write buffer to file path: {}",
                                                apath.display())
                                    },
                                };

        let mut buffer_reader = match File::open_mode(&apath.clone(), Open, Read) {
                                    Ok(file)    => BufferedReader::new(file),
                                    Err(..)     => panic!("Failed to create a read buffer to file path: {}",
                                                            apath.display()),
                                };

        let current_record_count = match buffer_reader.read_line() {
                                        Ok(line)    => {
                                            let first_line = utils::string_slice(line);
                                            let input = first_line[0].trim().parse::<u64>();
                                            match input {
                                                Ok(num) => num,
                                                Err(..) => {
                                                    warn!("We can't parse the record count from metadata");
                                                    warn!("Our parsed db metadata: {:?}", first_line);
                                                    // Setting counter to zero because we can't do
                                                    // anything else.
                                                    0
                                                },
                                            }
                                        },
                                        Err(..) => {
                                            error!("Can't read database metadata! Everybody do the flop!");
                                            // Setting counter to zero because we can't do anything
                                            // else.
                                            0
                                        },
                                   };

        Reader {
            path: apath.clone(),
            read_buffer: buffer_reader,
            write_buffer: buffer_writer,
            id_count: current_record_count,
        }
    }

    /// This is a helder function that realistically shouldn't exist in production.
    /// Used primarily for "spilling" the entire database file into a Vec<String>
    fn spill(&mut self) -> Vec<String> {
        let mut result: Vec<String> = Vec::new();
        let mut buffer_reader = BufferedReader::new(File::open(&self.path.clone()));
        for line_iter in buffer_reader.lines() {
            result.push(line_iter.unwrap().trim().to_string());
        }
        return result;
    }

    /// Inserts a &str into the database.
    fn insert_str(&mut self, item: &str) {
        self.write_buffer.write_line(item);
        self.write_buffer.flush();
        self.id_count = self.id_count + 1;
        self.update_counter(self.id_count);
    }

    /// Inserts a byte array into the database.
    fn insert(&mut self, item: &[u8]) {
        self.write_buffer.write(item);
        self.write_buffer.flush();
        self.id_count = self.id_count + 1;
        self.update_counter(self.id_count);
    }

    /// Read a &str from the database
    fn read_line(&mut self) -> String {
        match self.read_buffer.read_line() {
            Ok(string)  => { string.to_string() },
            Err(..)     => {
                error!("Unable to read next line. BufferedReader error.");
                "".to_string()
            },
        }
    }

    /// Creates a .lock file to let other processes know that the database is in use.
    /// This is still unfinished and should be considered broken.
    fn file_lock_create(lockpath: &Path) -> (bool, Path) {
        if lockpath.exists() {
            return (true, lockpath.clone())
        }

        let mut filelock_path = lockpath.clone();

        // Remove the old name
        filelock_path.pop();
        // Surely, there's a less ugly way to take the filename of a Path and convert it to a string?!
        let mut filename_lock: String = str::from_utf8(lockpath.filename().unwrap()).unwrap().to_string();
        filename_lock.push_str(".lock");
        // Join the new filename with the path
        filelock_path = filelock_path.join(filename_lock);
        println!("{}", filelock_path.display());
        match File::create(&filelock_path) {
            Ok(..)  => (true, filelock_path),
            Err(..) => (false, filelock_path),
        }
    }

    /// Removes .lock file when the reader process is completed.
    fn file_lock_remove(&self, filelock: &Path) -> bool {
        fs::unlink(&filelock.clone());
        filelock.exists()
    }

    /// Updates database counter on disk.
    fn update_counter(&self, value: u64) {
        let file = File::open_mode(&self.path.clone(), Open, Write);
        let mut buffer_writer = BufferedWriter::new(file);
        buffer_writer.write_line(value.to_string().as_slice());
        buffer_writer.flush();
    }

}

impl ReaderFile for Reader {

    fn open(&self) -> File {
        match File::open_mode(&self.path, Open, ReadWrite) {
            Ok(file)    => file,
            Err(..)     => { panic!("File {} couldn't be opened!", &self.path.display()); },
        }
    }

    fn insert_string(&mut self, item: String) {
        self.insert_str(&*item);
    }

}

#[test]
fn test_open_file() {
    let reader = Reader::new(&Path::new("tests/base-test.txt"));
}

#[test]
fn test_create_file() {
    use std::rand;
    let mut path_str = String::from_str("tests/");
    path_str.push_str(&*rand::random::<usize>().to_string());
    path_str.push_str(".txt");

    let (tempdir, apath) = setup();
    let path = tempdir.path().join(rand::random::<usize>().to_string());

    //let path = Path::new(path_str);
    assert!(!path.exists());
    let reader = Reader::new(&path.clone());
    assert!(path.exists());
    fs::unlink(&path);
}

#[test]
fn test_read_file() {
    // We should output the entire contents of the database file we open
    // into standard output.
    let (tempdir, path) = setup();
    let mut reader = Reader::new(&path);
    let expected = vec!["2".to_string(), "10 11".to_string(), "20 21".to_string()];
    assert_eq!(expected, reader.spill());
}

#[test]
fn test_write_string_to_file() {
    let (tempdir, path) = setup();
    let mut reader = Reader::new(&path);
    let expected = vec!["3".to_string(), "10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_string("30 31".to_string());
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_write_str_to_file() {
    let (tempdir, path) = setup();
    let mut reader = Reader::new(&path);
    let expected = vec!["3".to_string(), "10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_str("30 31");
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_file_path_lock() {

    let (tempdir, path) = setup();

    let mut expected = path.clone();
    expected.pop();

    // Surely, there's a less ugly way to take the filename of a Path and convert it to a string?!
    let mut filename_lock: String = str::from_utf8(path.filename().unwrap()).unwrap().to_string();
    filename_lock.push_str(".lock");
    expected = expected.join(filename_lock);

    let reader = Reader::new(&expected.clone());
    assert!(expected.exists() && expected.is_file());
}

#[test]
fn test_reader_show() {
    let reader: Reader = Reader::new(&Path::new("tests/file.txt"));
    assert_eq!("Reader: ( path: tests/file.txt )", reader.to_string());
}

/// Test setup code. Current functions:
/// - Create a new file with `TempDir` and a random name.
/// - Write a 2x2 matrix of records into the base-test.txt file
/// - Returns a tuple of `TempDir` and `Path` to the file.
/// - The path is for r/w access and `TempDir` is so that the directory
///   isn't deleted before the test is completed.
#[allow(dead_code, unused_must_use)]
fn setup() -> (TempDir, Path) {
    use std::rand;

    let tmpdir = match TempDir::new("txtdb-tests") {
        Ok(dir) => dir,
        Err(..) => panic!("Cannot create test directory. Tests will fail."),
    };

    let final_dir = tmpdir.path().join(rand::random::<usize>().to_string());

    let mut file = File::create(&final_dir.clone());
    file.write_str("2\n10 11\n20 21\n");

    (tmpdir, final_dir)
}
<commit_msg>Implements delete .lock for Drop trait<commit_after>#![allow(dead_code, unused_must_use, unused_imports, unstable)]

extern crate "rustc-serialize" as rustc_serialize;
extern crate log;

use utils;
use std::fmt;
use std::str;
use std::string;
use std::ops::Drop;
use std::old_io::{File, Open, Append, Read, Write, ReadWrite};
use std::old_io::TempDir;
use std::old_io::fs;
use std::old_io::fs::PathExtensions;
use std::old_io::{BufferedReader, BufferedWriter};
use std::old_path::BytesContainer;
use self::rustc_serialize::base64::{STANDARD, FromBase64, ToBase64};

/// A result type that's specfici to the Reader module.
/// TODO Decide if this is necessary
pub type ReaderResult<T, E> = Result<T, E>;

/// Reader struct of its basic properties.
pub struct Reader {
    /// Path to file where the Reader is created.
    path: Path,
    /// BufferedReader for reading the file. Initialized with the Path.
    read_buffer: BufferedReader<File>,
    /// BufferedWriter for writing to the file. Initialized with the Path.
    write_buffer: BufferedWriter<File>,
    /// Index counter to know how many records exist.
    id_count: u64,
}

/// ReaderFile traits
pub trait ReaderFile {
    // Opens a new File to the Path provided.
    // Returns a boxed File.
    fn open(&self) -> File;
    // Inserts a string to the database.
    fn insert_string(&mut self, String);
}

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

impl ToString for Reader {
    fn to_string(&self) -> String {
        format!("{:?}", self)
    }
}

impl Reader {
    /// Creates a new Reader from the Path provided.
    /// Opens a new BufferedReader and BufferedWriter (with Append mode) to the file.
    /// If the file doesn't exist, it is created.
    // TODO, create a .lock file to let other readers know the database is in use (see: #2).
    pub fn new(apath: &Path) -> Reader {
        Reader::file_lock_create(apath);
        // if file_lock exists, panic and crash with appropriate error.
        // Error: A .lock file already exists, if this is from a previous session, consider
        // deleting the .lock file.

        if !apath.exists() {
            let mut file = File::create(&apath.clone());
            file.write_line("0");
            file.flush();
        }

        let mut buffer_writer = match File::open_mode(&apath.clone(), Append, ReadWrite) {
                                    Ok(file)    => { BufferedWriter::new(file) },
                                    Err(..)     => {
                                        panic!("Failed to create a write buffer to file path: {}",
                                                apath.display())
                                    },
                                };

        let mut buffer_reader = match File::open_mode(&apath.clone(), Open, Read) {
                                    Ok(file)    => BufferedReader::new(file),
                                    Err(..)     => panic!("Failed to create a read buffer to file path: {}",
                                                            apath.display()),
                                };

        let current_record_count = match buffer_reader.read_line() {
                                        Ok(line)    => {
                                            let first_line = utils::string_slice(line);
                                            let input = first_line[0].trim().parse::<u64>();
                                            match input {
                                                Ok(num) => num,
                                                Err(..) => {
                                                    warn!("We can't parse the record count from metadata");
                                                    warn!("Our parsed db metadata: {:?}", first_line);
                                                    // Setting counter to zero because we can't do
                                                    // anything else.
                                                    0
                                                },
                                            }
                                        },
                                        Err(..) => {
                                            error!("Can't read database metadata! Everybody do the flop!");
                                            // Setting counter to zero because we can't do anything
                                            // else.
                                            0
                                        },
                                   };

        Reader {
            path: apath.clone(),
            read_buffer: buffer_reader,
            write_buffer: buffer_writer,
            id_count: current_record_count,
        }
    }

    /// This is a helder function that realistically shouldn't exist in production.
    /// Used primarily for "spilling" the entire database file into a Vec<String>
    fn spill(&mut self) -> Vec<String> {
        let mut result: Vec<String> = Vec::new();
        let mut buffer_reader = BufferedReader::new(File::open(&self.path.clone()));
        for line_iter in buffer_reader.lines() {
            result.push(line_iter.unwrap().trim().to_string());
        }
        return result;
    }

    /// Inserts a &str into the database.
    pub fn insert_str(&mut self, item: &str) {
        self.write_buffer.write_line(item);
        self.write_buffer.flush();
        self.id_count = self.id_count + 1;
        self.update_counter(self.id_count);
    }

    /// Inserts a byte array into the database.
    pub fn insert(&mut self, item: &[u8]) {
        self.write_buffer.write(item);
        self.write_buffer.flush();
        self.id_count = self.id_count + 1;
        self.update_counter(self.id_count);
    }

    /// Read a &str from the database
    fn read_line(&mut self) -> String {
        match self.read_buffer.read_line() {
            Ok(string)  => { string.to_string() },
            Err(..)     => {
                error!("Unable to read next line. BufferedReader error.");
                "".to_string()
            },
        }
    }

    /// Creates a .lock file to let other processes know that the database is in use.
    /// This is still unfinished and should be considered broken.
    fn file_lock_create(lockpath: &Path) -> (bool, Path) {
        if lockpath.exists() {
            return (true, lockpath.clone())
        }

        let mut filelock_path = lockpath.clone();

        // Remove the old name
        filelock_path.pop();
        // Surely, there's a less ugly way to take the filename of a Path and convert it to a string?!
        let mut filename_lock: String = str::from_utf8(lockpath.filename().unwrap()).unwrap().to_string();
        filename_lock.push_str(".lock");
        // Join the new filename with the path
        filelock_path = filelock_path.join(filename_lock);
        println!("{}", filelock_path.display());
        match File::create(&filelock_path) {
            Ok(..)  => (true, filelock_path),
            Err(..) => (false, filelock_path),
        }
    }

    /// Removes .lock file when the reader process is completed.
    fn file_lock_remove(&self, filelock: &Path) -> bool {
        fs::unlink(&filelock.clone());
        filelock.exists()
    }

    /// Updates database counter on disk.
    fn update_counter(&self, value: u64) {
        let file = File::open_mode(&self.path.clone(), Open, Write);
        let mut buffer_writer = BufferedWriter::new(file);
        buffer_writer.write_line(value.to_string().as_slice());
        buffer_writer.flush();
    }

}

impl Drop for Reader {
    fn drop(&mut self) {
        let mut lock_path = self.path.clone();
        let mut filename = String::from_str(lock_path.filename_str().unwrap());
        filename.push_str(".lock");
        lock_path.set_filename(filename);
        println!("File about to remove: {}", lock_path.display());
        self.file_lock_remove(&lock_path);
    }
}

impl ReaderFile for Reader {

    fn open(&self) -> File {
        match File::open_mode(&self.path, Open, ReadWrite) {
            Ok(file)    => file,
            Err(..)     => { panic!("File {} couldn't be opened!", &self.path.display()); },
        }
    }

    fn insert_string(&mut self, item: String) {
        self.insert_str(&*item);
    }

}

#[test]
fn test_open_file() {
    let reader = Reader::new(&Path::new("tests/base-test.txt"));
}

#[test]
fn test_create_file() {
    use std::rand;
    let mut path_str = String::from_str("tests/");
    path_str.push_str(&*rand::random::<usize>().to_string());
    path_str.push_str(".txt");

    let (tempdir, apath) = setup();
    let path = tempdir.path().join(rand::random::<usize>().to_string());

    //let path = Path::new(path_str);
    assert!(!path.exists());
    let reader = Reader::new(&path.clone());
    assert!(path.exists());
    fs::unlink(&path);
}

#[test]
fn test_read_file() {
    // We should output the entire contents of the database file we open
    // into standard output.
    let (tempdir, path) = setup();
    let mut reader = Reader::new(&path);
    let expected = vec!["2".to_string(), "10 11".to_string(), "20 21".to_string()];
    assert_eq!(expected, reader.spill());
}

#[test]
fn test_write_string_to_file() {
    let (tempdir, path) = setup();
    let mut reader = Reader::new(&path);
    let expected = vec!["3".to_string(), "10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_string("30 31".to_string());
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_write_str_to_file() {
    let (tempdir, path) = setup();
    let mut reader = Reader::new(&path);
    let expected = vec!["3".to_string(), "10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_str("30 31");
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_file_path_lock() {

    let (tempdir, path) = setup();

    let mut expected = path.clone();
    expected.pop();

    // Surely, there's a less ugly way to take the filename of a Path and convert it to a string?!
    let mut filename_lock: String = str::from_utf8(path.filename().unwrap()).unwrap().to_string();
    filename_lock.push_str(".lock");
    expected = expected.join(filename_lock);

    let reader = Reader::new(&expected.clone());
    assert!(expected.exists() && expected.is_file());
}

#[test]
fn test_reader_show() {
    let reader: Reader = Reader::new(&Path::new("tests/file.txt"));
    assert_eq!("Reader: ( path: tests/file.txt )", reader.to_string());
}

/// Test setup code. Current functions:
/// - Create a new file with `TempDir` and a random name.
/// - Write a 2x2 matrix of records into the base-test.txt file
/// - Returns a tuple of `TempDir` and `Path` to the file.
/// - The path is for r/w access and `TempDir` is so that the directory
///   isn't deleted before the test is completed.
#[allow(dead_code, unused_must_use)]
fn setup() -> (TempDir, Path) {
    use std::rand;

    let tmpdir = match TempDir::new("txtdb-tests") {
        Ok(dir) => dir,
        Err(..) => panic!("Cannot create test directory. Tests will fail."),
    };

    let final_dir = tmpdir.path().join(rand::random::<usize>().to_string());

    let mut file = File::create(&final_dir.clone());
    file.write_str("2\n10 11\n20 21\n");

    (tmpdir, final_dir)
}
<|endoftext|>


<commit_before>//! A DNS query.

use futures::{Async, Future, Poll};
use futures::task::TaskRc;
use rand::random;
use ::bits::{AsDName, ComposeMode, ComposeResult, MessageBuilder,
             MessageBuf, Question};
use ::iana::{Class, RRType};
use super::ResolverTask;
use super::conf::ResolvOptions;
use super::core::Core;
use super::error::Error;
use super::request::QueryRequest;

//------------ Query ---------------------------------------------------------

pub struct Query(State);

enum State {
    Real(RealQuery),
    Failed(Option<Error>),
}

impl Query {
    pub fn new<N: AsDName>(resolv: &ResolverTask, name: N, rtype: RRType,
                       class: Class) -> Self {
        let core = resolv.core.clone();
        let message = core.with(|core| {
            Self::build_message(name, rtype, class, core.options())
        });
        let message = match message {
            Ok(message) => message,
            Err(err) => return Query(State::Failed(Some(err.into())))
        };
        let dgram = core.with(|core| core.conf().options.use_vc);
        let (index, request) = core.with(|c| RealQuery::start(c, dgram,
                                                              message));
        Query(State::Real(RealQuery {
            core: core, request: request,
            dgram: dgram, start_index: index, curr_index: index,
            attempt: 0
        }))
    }

    fn build_message<N: AsDName>(name: N, rtype: RRType, class: Class,
                                 opts: &ResolvOptions)
                                 -> ComposeResult<MessageBuilder> {
        let mut res = try!(MessageBuilder::new(ComposeMode::Stream, true));
        res.header_mut().set_rd(opts.recurse);
        try!(Question::push(&mut res, &name, rtype, class));
        Ok(res)
    }
}

//--- Future

impl Future for Query {
    type Item = MessageBuf;
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match self.0 {
            State::Real(ref mut query) => query.poll(),
            State::Failed(ref mut err) => {
                match err.take() {
                    Some(err) => Err(err),
                    None => panic!("polling a resolved Query")
                }
            }
        }
    }
}

//------------ RealQuery -----------------------------------------------------

/// The future of an ongoing query.
struct RealQuery {
    /// The resolver core we are working on.
    core: TaskRc<Core>,

    /// The request we are currently processing.
    request: QueryRequest,

    /// Are we still in datagram stage?
    ///
    /// Assuming the resolver config allows using datagram services at all,
    /// we’ll start with `true`. Only if a response is truncated do we have
    /// to switch to `false` and go through the stream services.
    dgram: bool,

    /// The index of the service we started at.
    ///
    /// The index references either `core.udp` or `core.tcp`, depending on
    /// the value of `dgram`. We need to keep the index we started at
    /// because of the rotate option which makes us start at a random
    /// service.
    start_index: usize,

    /// The index of the service we currently are using.
    curr_index: usize,

    /// The how-many-th attempt is this, starting at attempt 0.
    attempt: usize
}

impl RealQuery {
    fn start(core: &Core, dgram: bool, message: MessageBuilder)
             -> (usize, QueryRequest) {
        let track = if dgram { core.udp() }
                    else { core.tcp() };
        let index = if core.conf().options.rotate {
            random::<usize>() % track.len()
        }
        else { 0 };
        let request = QueryRequest::new(message, &track[index]);
        (index, request)
    }

    /// Processes a response.
    ///
    /// This will either resolve the future or switch to stream mode.
    fn response(&mut self, response: MessageBuf, message: MessageBuilder)
                -> Poll<MessageBuf, Error> {
        if response.header().tc() && self.dgram
                && !self.core.with(|core| core.options().ign_tc)
        {
            self.start_stream(message)
        }
        else { Ok(response.into()) }
    }

    /// Proceeds to the next request or errors out.
    fn next_request(&mut self, message: MessageBuilder)
                    -> Poll<MessageBuf, Error> {
        self.curr_index += 1;
        if (self.curr_index % self.track_len()) == self.start_index {
            self.attempt += 1;
            if self.attempt == self.core.with(|core| core.conf().attempts) {
                return Err(Error::Timeout)
            }
            let dgram = self.dgram;
            let (index, request) = self.core.with(|core| {
                Self::start(core, dgram, message)
            });
            self.start_index = index;
            self.curr_index = index;
            self.request = request;
        }
        else {
            let dgram = self.dgram;
            let curr_index = self.curr_index;
            self.request = self.core.with(|core| {
                let track = if dgram { core.udp() }
                            else { core.tcp() };
                QueryRequest::new(message, &track[curr_index])
            });
        }
        self.poll()
    }

    /// Switches to stream mode and starts the first request or errors out.
    fn start_stream(&mut self, message: MessageBuilder)
                    -> Poll<MessageBuf, Error> {
        self.dgram = false;
        let (index, request) = self.core.with(|core| {
            Self::start(core, false, message)
        });
        self.start_index = index;
        self.curr_index = index;
        self.request = request;
        self.poll()
    }

    fn track_len(&self) -> usize {
        if self.dgram { self.core.with(|core| core.udp().len()) }
        else { self.core.with(|core| core.tcp().len()) }
    }
}

//--- Future

impl Future for RealQuery {
    type Item = MessageBuf;
    type Error = Error;

    /// Polls for completion.
    ///
    /// Polls the current request. If that succeeded, returns the result. If
    /// it failed fatally, returns an error. If it failed non-fatally,
    /// proceeds to the next request.
    fn poll(&mut self) -> Poll<MessageBuf, Error> {
        match self.request.poll() {
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Ok(Async::Ready((Ok(response), message))) => {
                self.response(response, message)
            }
            Ok(Async::Ready((Err(_), message))) => {
                self.next_request(message)
            }
            Err(err) => Err(err.into())
        }
    }
}

<commit_msg>Fix evaluation of use_vc option.<commit_after>//! A DNS query.

use futures::{Async, Future, Poll};
use futures::task::TaskRc;
use rand::random;
use ::bits::{AsDName, ComposeMode, ComposeResult, MessageBuilder,
             MessageBuf, Question};
use ::iana::{Class, RRType};
use super::ResolverTask;
use super::conf::ResolvOptions;
use super::core::Core;
use super::error::Error;
use super::request::QueryRequest;

//------------ Query ---------------------------------------------------------

pub struct Query(State);

enum State {
    Real(RealQuery),
    Failed(Option<Error>),
}

impl Query {
    pub fn new<N: AsDName>(resolv: &ResolverTask, name: N, rtype: RRType,
                       class: Class) -> Self {
        let core = resolv.core.clone();
        let message = core.with(|core| {
            Self::build_message(name, rtype, class, core.options())
        });
        let message = match message {
            Ok(message) => message,
            Err(err) => return Query(State::Failed(Some(err.into())))
        };
        let dgram = core.with(|core| !core.conf().options.use_vc);
        let (index, request) = core.with(|c| RealQuery::start(c, dgram,
                                                              message));
        Query(State::Real(RealQuery {
            core: core, request: request,
            dgram: dgram, start_index: index, curr_index: index,
            attempt: 0
        }))
    }

    fn build_message<N: AsDName>(name: N, rtype: RRType, class: Class,
                                 opts: &ResolvOptions)
                                 -> ComposeResult<MessageBuilder> {
        let mut res = try!(MessageBuilder::new(ComposeMode::Stream, true));
        res.header_mut().set_rd(opts.recurse);
        try!(Question::push(&mut res, &name, rtype, class));
        Ok(res)
    }
}

//--- Future

impl Future for Query {
    type Item = MessageBuf;
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match self.0 {
            State::Real(ref mut query) => query.poll(),
            State::Failed(ref mut err) => {
                match err.take() {
                    Some(err) => Err(err),
                    None => panic!("polling a resolved Query")
                }
            }
        }
    }
}

//------------ RealQuery -----------------------------------------------------

/// The future of an ongoing query.
struct RealQuery {
    /// The resolver core we are working on.
    core: TaskRc<Core>,

    /// The request we are currently processing.
    request: QueryRequest,

    /// Are we still in datagram stage?
    ///
    /// Assuming the resolver config allows using datagram services at all,
    /// we’ll start with `true`. Only if a response is truncated do we have
    /// to switch to `false` and go through the stream services.
    dgram: bool,

    /// The index of the service we started at.
    ///
    /// The index references either `core.udp` or `core.tcp`, depending on
    /// the value of `dgram`. We need to keep the index we started at
    /// because of the rotate option which makes us start at a random
    /// service.
    start_index: usize,

    /// The index of the service we currently are using.
    curr_index: usize,

    /// The how-many-th attempt is this, starting at attempt 0.
    attempt: usize
}

impl RealQuery {
    fn start(core: &Core, dgram: bool, message: MessageBuilder)
             -> (usize, QueryRequest) {
        let track = if dgram { core.udp() }
                    else { core.tcp() };
        let index = if core.conf().options.rotate {
            random::<usize>() % track.len()
        }
        else { 0 };
        let request = QueryRequest::new(message, &track[index]);
        (index, request)
    }

    /// Processes a response.
    ///
    /// This will either resolve the future or switch to stream mode.
    fn response(&mut self, response: MessageBuf, message: MessageBuilder)
                -> Poll<MessageBuf, Error> {
        if response.header().tc() && self.dgram
                && !self.core.with(|core| core.options().ign_tc)
        {
            self.start_stream(message)
        }
        else { Ok(response.into()) }
    }

    /// Proceeds to the next request or errors out.
    fn next_request(&mut self, message: MessageBuilder)
                    -> Poll<MessageBuf, Error> {
        self.curr_index += 1;
        if (self.curr_index % self.track_len()) == self.start_index {
            self.attempt += 1;
            if self.attempt == self.core.with(|core| core.conf().attempts) {
                return Err(Error::Timeout)
            }
            let dgram = self.dgram;
            let (index, request) = self.core.with(|core| {
                Self::start(core, dgram, message)
            });
            self.start_index = index;
            self.curr_index = index;
            self.request = request;
        }
        else {
            let dgram = self.dgram;
            let curr_index = self.curr_index;
            self.request = self.core.with(|core| {
                let track = if dgram { core.udp() }
                            else { core.tcp() };
                QueryRequest::new(message, &track[curr_index])
            });
        }
        self.poll()
    }

    /// Switches to stream mode and starts the first request or errors out.
    fn start_stream(&mut self, message: MessageBuilder)
                    -> Poll<MessageBuf, Error> {
        self.dgram = false;
        let (index, request) = self.core.with(|core| {
            Self::start(core, false, message)
        });
        self.start_index = index;
        self.curr_index = index;
        self.request = request;
        self.poll()
    }

    fn track_len(&self) -> usize {
        if self.dgram { self.core.with(|core| core.udp().len()) }
        else { self.core.with(|core| core.tcp().len()) }
    }
}

//--- Future

impl Future for RealQuery {
    type Item = MessageBuf;
    type Error = Error;

    /// Polls for completion.
    ///
    /// Polls the current request. If that succeeded, returns the result. If
    /// it failed fatally, returns an error. If it failed non-fatally,
    /// proceeds to the next request.
    fn poll(&mut self) -> Poll<MessageBuf, Error> {
        match self.request.poll() {
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Ok(Async::Ready((Ok(response), message))) => {
                self.response(response, message)
            }
            Ok(Async::Ready((Err(_), message))) => {
                self.next_request(message)
            }
            Err(err) => Err(err.into())
        }
    }
}

<|endoftext|>


<commit_before>#![feature(catch_panic)]
mod curses;

use std::thread;
use std::sync::mpsc::Sender;

use event::InputEvent;

pub use self::curses::CursesHost;

pub trait Host {
    fn new() -> Self;

    fn setup(&self);
    fn teardown(&self);
    fn sender(&self) -> Sender;
    fn poll(&self) -> InputEvent;

    fn run(&self) -> i32 {
        self.setup();
        let res = thread::catch_panic(self._run);
        self.teardown();

        if res.is_ok() {
            return 0;
        }
        return -1;
    }

    fn _run(&self) {
        loop {
            self.sender().Send(self.poll())
        }
    }
}
<commit_msg>Fix type signatures<commit_after>#![feature(catch_panic)]
mod curses;

use std::thread;
use std::sync::Arc;
use std::sync::RwLock;
use std::sync::mpsc::Sender;

use buffer::Buffer;
use event::InputEvent;
pub use self::curses::CursesHost;

pub trait Host {
    fn new(Arc<RwLock<Vec<Buffer>>>, Sender<InputEvent>) -> Self;

    fn setup(&self);
    fn teardown(&self);
    fn sender(&self) -> Sender<InputEvent>;
    fn poll(&self) -> InputEvent;

    fn run(&self) -> i32 {
        self.setup();
        let res = thread::catch_panic(|| self._run());
        self.teardown();

        if res.is_ok() {
            return 0;
        }
        return -1;
    }

    fn _run(&self) {
        loop {
            self.sender().send(self.poll())
        };
        return
    }
}
<|endoftext|>


<commit_before>// STD Dependencies -----------------------------------------------------------
use std::thread;
use std::sync::{Arc, Mutex};
use std::collections::VecDeque;

// Discord Dependencies -------------------------------------------------------
use discord::voice::VoiceConnection;
use discord::{Connection, Discord, Error, State};
use discord::model::{
    ChannelId, MessageId, UserId, ServerId,
    Event as DiscordEvent,
    PrivateChannel
};

// Low Level Event Abstraction ------------------------------------------------
#[derive(Debug)]
pub enum Event {
    Reconnected,
    Disconnected,
    Received(DiscordEvent),
    SendMessageFailure(ChannelId, String),
    DeleteMessageFailure(ChannelId, MessageId)
}

// Low Level Event Queue ------------------------------------------------------
pub struct EventQueue {
    events: Arc<Mutex<VecDeque<Event>>>,
    sender: DiscordHandle,
    receiver: thread::JoinHandle<()>
}

// Public Interface -----------------------------------------------------------
impl EventQueue {

    pub fn new(token: String) -> EventQueue {

        let events = Arc::new(Mutex::new(VecDeque::new()));
        let receiver = DiscordHandle::from_token(token.clone()).expect("[EL] Initial connection failed.");

        EventQueue {
            events: events.clone(),
            sender: DiscordHandle::from_token(
                token.clone()

            ).expect("[EL] Initial connection failed."),
            receiver: EventQueue::receiver_thread(receiver, events)
        }

    }

    pub fn events(&mut self) -> Vec<Event> {

        let events = if let Ok(mut events) = self.events.lock() {
            events.drain(0..).collect()

        } else {
            vec![]
        };

        for e in &events {
            match e {
                &Event::Received(ref e) => self.sender.update(e),
                &Event::Reconnected => {
                    self.sender =self.sender.reconnect().expect("[EL] Sender reconnect failed!");
                },
                _ => {}
            }
        }

        events

    }

    pub fn connect_server_voice<C: FnOnce(&mut VoiceConnection)>(
        &mut self,
        server_id: ServerId,
        channel_id: ChannelId,
        callback: C
    ) {
        let voice_connection = self.sender.connection.voice(Some(server_id));
        info!("[EL] Create voice connection for Channel#{} on Server#{}", channel_id, server_id);
        voice_connection.connect(channel_id);
        callback(voice_connection);
    }

    pub fn disconnect_server_voice(&mut self, server_id: ServerId) {
        self.sender.connection.drop_voice(Some(server_id));
    }

    pub fn shutdown(self) {
        self.receiver.join().ok();
    }

}

// Message Interface ----------------------------------------------------------
impl EventQueue {

    pub fn send_message_to_user(&self, user_id: &UserId, content: String) {
        if let Some(channel) = self.private_channel_for_user(user_id) {
            self.send_message_to_channel(&channel.id, content);
        }
    }

    pub fn send_message_to_channel(&self, channel_id: &ChannelId, content: String) {

        if let Err(_) = self.sender.discord.send_message(channel_id, content.as_str(), "", false) {
            warn!("[EL] Failed to sent message.");
            if let Ok(mut events) = self.events.lock() {
                events.push_back(Event::SendMessageFailure(*channel_id, content));
            }

        } else {
            info!("[EL] Message sent.");
        }

    }

    pub fn delete_message(&self, message_id: MessageId, channel_id: ChannelId) {
        if let Err(_) = self.sender.discord.delete_message(&channel_id, &message_id) {
            warn!("[EL] Failed to delete message.");
            if let Ok(mut events) = self.events.lock() {
                events.push_back(Event::DeleteMessageFailure(channel_id, message_id));
            }

        } else {
            info!("[EL] Message deleted.");
        }
    }

}

// Internal Interface ---------------------------------------------------------
impl EventQueue {

    fn receiver_thread(
        mut receiver: DiscordHandle,
        events: Arc<Mutex<VecDeque<Event>>>

    ) -> thread::JoinHandle<()> {
        thread::spawn(move || {

            loop {
                match receiver.recv_event() {
                    Ok(event) => {

                        receiver.update(&event);

                        if let Ok(mut queue) = events.lock() {
                            queue.push_back(Event::Received(event));
                        }

                    },
                    Err(err) => {
                        if let Error::WebSocket(..) = err {
                            warn!("[EL] [Receiver] WebSocket closed...");
                            match receiver.reconnect() {
                                Ok(r) => {
                                    warn!("[EL] [Receiver] Reconnected.!");
                                    if let Ok(mut queue) = events.lock() {
                                        queue.push_back(Event::Reconnected);
                                    }
                                    receiver = r;
                                },
                                Err(_) => {
                                    warn!("[EL] [Receiver] Connection failed!");
                                    if let Ok(mut queue) = events.lock() {
                                        queue.push_back(Event::Disconnected);
                                    }
                                    break;
                                }
                            }

                        } else if let Error::Closed(..) = err {
                            warn!("[EL] [Receiver] Connection closed.");
                            if let Ok(mut queue) = events.lock() {
                                queue.push_back(Event::Disconnected);
                            }
                            break;
                        }
                    }
                }
            }

        })
    }

    fn private_channel_for_user(&self, user_id: &UserId) -> Option<PrivateChannel> {
        self.sender.discord.create_private_channel(user_id).ok()
    }

}

// Discord Abstraction --------------------------------------------------------
pub struct DiscordHandle {
    token: String,
    discord: Discord,
    connection: Connection,
    state: State
}

impl DiscordHandle {

    fn from_token(token: String) -> Result<DiscordHandle, String> {

        let discord = Discord::from_bot_token(&token).expect("Discord login failed.");
        match discord.connect() {
            Ok((conn, ready)) => Ok(DiscordHandle {
                token: token,
                discord: discord,
                connection: conn,
                state: State::new(ready)
            }),
            Err(err) => Err(err.to_string())
        }

    }

    fn reconnect(&self) -> Result<DiscordHandle, String> {
        DiscordHandle::from_token(self.token.clone())
    }

    fn update(&mut self, event: &DiscordEvent) {
        self.state.update(event);
    }

    fn recv_event(&mut self) -> Result<DiscordEvent, Error> {
        self.connection.recv_event()
    }

}

<commit_msg>Switch back to synchronous discord handle for the time being.<commit_after>// STD Dependencies -----------------------------------------------------------
use std::collections::VecDeque;

// Discord Dependencies -------------------------------------------------------
use discord::voice::VoiceConnection;
use discord::{Connection, Discord, Error, State};
use discord::model::{
    ChannelId, MessageId, UserId, ServerId,
    Event as DiscordEvent,
    PrivateChannel
};

// Low Level Event Abstraction ------------------------------------------------
#[derive(Debug)]
pub enum Event {
    Reconnected,
    Disconnected,
    Received(DiscordEvent),
    SendMessageFailure(ChannelId, String),
    DeleteMessageFailure(ChannelId, MessageId)
}

// Low Level Event Queue ------------------------------------------------------
pub struct EventQueue {
    events: VecDeque<Event>,
    receiver: DiscordHandle
}

// Public Interface -----------------------------------------------------------
impl EventQueue {

    pub fn new(token: String) -> EventQueue {
        EventQueue {
            events: VecDeque::new(),
            receiver: DiscordHandle::from_token(
                token.clone()

            ).expect("[EL] Initial connection failed.")
        }
    }

    pub fn events(&mut self) -> Vec<Event> {

        match self.receiver.recv_event() {
            Ok(event) => {
                self.receiver.update(&event);
                self.events.push_back(Event::Received(event));
            },
            Err(err) => {
                if let Error::WebSocket(..) = err {
                    warn!("[EL] [Receiver] WebSocket closed...");
                    match self.receiver.reconnect() {
                        Ok(r) => {
                            warn!("[EL] [Receiver] Reconnected.!");
                            self.events.push_back(Event::Reconnected);
                            self.receiver = r;
                        },
                        Err(_) => {
                            warn!("[EL] [Receiver] Connection failed!");
                            self.events.push_back(Event::Disconnected);
                        }
                    }

                } else if let Error::Closed(..) = err {
                    warn!("[EL] [Receiver] Connection closed.");
                    self.events.push_back(Event::Disconnected);
                }
            }

        }

        self.events.drain(0..).collect()

    }

    pub fn connect_server_voice<C: FnOnce(&mut VoiceConnection)>(
        &mut self,
        server_id: ServerId,
        channel_id: ChannelId,
        callback: C
    ) {
        let voice_connection = self.receiver.connection.voice(Some(server_id));
        info!("[EL] Create voice connection for Channel#{} on Server#{}", channel_id, server_id);
        voice_connection.connect(channel_id);
        callback(voice_connection);
    }

    pub fn disconnect_server_voice(&mut self, server_id: ServerId) {
        self.receiver.connection.drop_voice(Some(server_id));
    }

    pub fn shutdown(self) {

    }

}

// Message Interface ----------------------------------------------------------
impl EventQueue {

    pub fn send_message_to_user(&mut self, user_id: &UserId, content: String) {
        if let Some(channel) = self.private_channel_for_user(user_id) {
            self.send_message_to_channel(&channel.id, content);
        }
    }

    pub fn send_message_to_channel(&mut self, channel_id: &ChannelId, content: String) {

        if let Err(_) = self.receiver.discord.send_message(channel_id, content.as_str(), "", false) {
            warn!("[EL] Failed to sent message.");
            self.events.push_back(Event::SendMessageFailure(*channel_id, content));

        } else {
            info!("[EL] Message sent.");
        }

    }

    pub fn delete_message(&mut self, message_id: MessageId, channel_id: ChannelId) {
        if let Err(_) = self.receiver.discord.delete_message(&channel_id, &message_id) {
            warn!("[EL] Failed to delete message.");
            self.events.push_back(Event::DeleteMessageFailure(channel_id, message_id));

        } else {
            info!("[EL] Message deleted.");
        }
    }

}

// Internal Interface ---------------------------------------------------------
impl EventQueue {

    fn private_channel_for_user(&self, user_id: &UserId) -> Option<PrivateChannel> {
        self.receiver.discord.create_private_channel(user_id).ok()
    }

}

// Discord Abstraction --------------------------------------------------------
pub struct DiscordHandle {
    token: String,
    discord: Discord,
    connection: Connection,
    state: State
}

impl DiscordHandle {

    fn from_token(token: String) -> Result<DiscordHandle, String> {

        let discord = Discord::from_bot_token(&token).expect("Discord login failed.");
        match discord.connect() {
            Ok((conn, ready)) => Ok(DiscordHandle {
                token: token,
                discord: discord,
                connection: conn,
                state: State::new(ready)
            }),
            Err(err) => Err(err.to_string())
        }

    }

    fn reconnect(&self) -> Result<DiscordHandle, String> {
        DiscordHandle::from_token(self.token.clone())
    }

    fn update(&mut self, event: &DiscordEvent) {
        self.state.update(event);
    }

    fn recv_event(&mut self) -> Result<DiscordEvent, Error> {
        self.connection.recv_event()
    }

}

<|endoftext|>