<commit_before>extern crate serialize;

use serialize::{Encoder, Decoder};
use std::io;
use std::io::{IoResult, Reader, Writer, IoError};
use std::char::from_u32;

pub struct BinaryDecoder<R: Reader> { reader: R }

impl<R: Reader> serialize::Decoder<io::IoError> for BinaryDecoder<R>
{
    fn read_nil(&mut self)  -> IoResult<()> { Ok(()) }

    fn read_uint(&mut self) -> IoResult<uint>   { self.reader.read_le_uint() }
    fn read_u64(&mut self)  -> IoResult<u64>    { self.reader.read_le_u64() }
    fn read_u32(&mut self)  -> IoResult<u32>    { self.reader.read_le_u32() }
    fn read_u16(&mut self)  -> IoResult<u16>    { self.reader.read_le_u16() }
    fn read_u8(&mut self)   -> IoResult<u8>     { self.reader.read_u8() }

    fn read_int(&mut self)  -> IoResult<int>    { self.reader.read_le_int() }
    fn read_i64(&mut self)  -> IoResult<i64>    { self.reader.read_le_i64() }
    fn read_i32(&mut self)  -> IoResult<i32>    { self.reader.read_le_i32() }
    fn read_i16(&mut self)  -> IoResult<i16>    { self.reader.read_le_i16() }
    fn read_i8(&mut self)   -> IoResult<i8>     { self.reader.read_i8() }
    fn read_bool(&mut self) -> IoResult<bool>   { Ok(try!(self.reader.read_u8()) != 0) }

    fn read_f64(&mut self)  -> IoResult<f64>    { self.reader.read_le_f64() }
    fn read_f32(&mut self)  -> IoResult<f32>    { self.reader.read_le_f32() }

    fn read_char(&mut self) -> IoResult<char>   { self.reader.read_le_u32().map(|x| from_u32(x).unwrap()) }
    fn read_str(&mut self)  -> IoResult<String> { self.reader.read_to_string() }

    fn read_enum<T>(&mut self, _name: &str, f: |&mut BinaryDecoder<R>| -> IoResult<T>) -> IoResult<T> { f(self) }
    fn read_enum_variant<T>(&mut self, _names: &[&str], f: |&mut BinaryDecoder<R>, uint| -> IoResult<T>) -> IoResult<T>
        { let variant = try!(self.reader.read_le_uint()); f(self, variant) }
    fn read_enum_variant_arg<T>(&mut self, _a_idx: uint, f: |&mut BinaryDecoder<R>| -> IoResult<T>) -> IoResult<T> { f(self) }
    fn read_enum_struct_variant<T>(&mut self, _names: &[&str], f: |&mut BinaryDecoder<R>, uint| -> IoResult<T>) -> IoResult<T>
        { let variant = try!(self.reader.read_le_uint()); f(self, variant) }
    fn read_enum_struct_variant_field<T>(&mut self, _f_name: &str, _f_idx: uint, f: |&mut BinaryDecoder<R>| -> IoResult<T>) -> IoResult<T>
        { f(self) }

    fn read_struct<T>(&mut self, _s_name: &str, _len: uint, f: |&mut BinaryDecoder<R>| -> IoResult<T>) -> IoResult<T> { f(self) }
    fn read_struct_field<T>(&mut self, _f_name: &str, _f_idx: uint, f: |&mut BinaryDecoder<R>| -> IoResult<T>) -> IoResult<T> { f(self) }

    fn read_tuple<T>(&mut self, _len: uint, f: |&mut BinaryDecoder<R>| -> IoResult<T>) -> IoResult<T> { f(self) }
    fn read_tuple_arg<T>(&mut self, _a_idx: uint, f: |&mut BinaryDecoder<R>| -> IoResult<T>) -> IoResult<T> { f(self) }
    fn read_tuple_struct<T>(&mut self, _s_name: &str, _len: uint, f: |&mut BinaryDecoder<R>| -> IoResult<T>) -> IoResult<T> { f(self) }
    fn read_tuple_struct_arg<T>(&mut self, _a_idx: uint, f: |&mut BinaryDecoder<R>| -> IoResult<T>) -> IoResult<T> { f(self) }

    fn read_option<T>(&mut self, f: |&mut BinaryDecoder<R>, bool| -> IoResult<T>) -> IoResult<T>
        { let some = try!(self.reader.read_u8()); f(self, some != 0) }

    fn read_seq<T>(&mut self, f: |&mut BinaryDecoder<R>, uint| -> IoResult<T>) -> IoResult<T>
        { let len = try!(self.reader.read_le_uint()); f(self, len) }
    fn read_seq_elt<T>(&mut self, _idx: uint, f: |&mut BinaryDecoder<R>| -> IoResult<T>) -> IoResult<T> { f(self) }

    fn read_map<T>(&mut self, f: |&mut BinaryDecoder<R>, uint| -> IoResult<T>) -> IoResult<T>
        { let len = try!(self.reader.read_le_uint()); f(self, len) }
    fn read_map_elt_key<T>(&mut self, _idx: uint, f: |&mut BinaryDecoder<R>| -> IoResult<T>) -> IoResult<T> { f(self) }
    fn read_map_elt_val<T>(&mut self, _idx: uint, f: |&mut BinaryDecoder<R>| -> IoResult<T>) -> IoResult<T> { f(self) }

    fn error(&mut self, _err: &str) -> io::IoError { IoError::last_error() }
}

pub struct BinaryEncoder<R: Writer> { writer: R }

impl<R: Writer> serialize::Encoder<IoError> for BinaryEncoder<R>
{
    fn emit_nil(&mut self)            -> IoResult<()> { Ok(()) }

    fn emit_uint(&mut self, v: uint)  -> IoResult<()> { self.writer.write_le_uint(v) }
    fn emit_u64(&mut self, v: u64)    -> IoResult<()> { self.writer.write_le_u64(v) }
    fn emit_u32(&mut self, v: u32)    -> IoResult<()> { self.writer.write_le_u32(v) }
    fn emit_u16(&mut self, v: u16)    -> IoResult<()> { self.writer.write_le_u16(v) }
    fn emit_u8(&mut self, v: u8)      -> IoResult<()> { self.writer.write_u8(v) }

    fn emit_int(&mut self, v: int)    -> IoResult<()> { self.writer.write_le_int(v) }
    fn emit_i64(&mut self, v: i64)    -> IoResult<()> { self.writer.write_le_i64(v) }
    fn emit_i32(&mut self, v: i32)    -> IoResult<()> { self.writer.write_le_i32(v) }
    fn emit_i16(&mut self, v: i16)    -> IoResult<()> { self.writer.write_le_i16(v) }
    fn emit_i8(&mut self, v: i8)      -> IoResult<()> { self.writer.write_i8(v) }

    fn emit_bool(&mut self, v: bool)  -> IoResult<()> { self.writer.write_u8(if v { 1 } else { 0 }) }

    fn emit_f64(&mut self, v: f64)    -> IoResult<()> { self.writer.write_le_f64(v) }
    fn emit_f32(&mut self, v: f32)    -> IoResult<()> { self.writer.write_le_f32(v) }

    fn emit_char(&mut self, _v: char) -> IoResult<()> { self.writer.write_le_u32(_v as u32) }
    fn emit_str(&mut self, v: &str)   -> IoResult<()> { self.writer.write_str(v) }

    fn emit_enum(&mut self, _name: &str, f: |&mut BinaryEncoder<R>| -> IoResult<()>) -> IoResult<()> { f(self) }
    fn emit_enum_variant(&mut self, _v_name: &str, v_id: uint, _len: uint, f: |&mut BinaryEncoder<R>| -> IoResult<()>) -> IoResult<()>
        { try!(self.writer.write_le_uint(v_id)); f(self) }
    fn emit_enum_variant_arg(&mut self, _a_idx: uint, f: |&mut BinaryEncoder<R>| -> IoResult<()>) -> IoResult<()> { f(self) }
    fn emit_enum_struct_variant(&mut self, _v_name: &str, v_id: uint, _len: uint, f: |&mut BinaryEncoder<R>| -> IoResult<()>) -> IoResult<()>
        { try!(self.writer.write_le_uint(v_id)); f(self) }
    fn emit_enum_struct_variant_field(&mut self, _f_name: &str, _f_idx: uint, f: |&mut BinaryEncoder<R>| -> IoResult<()>) -> IoResult<()>
        { f(self) }

    fn emit_struct(&mut self, _name: &str, _len: uint, f: |&mut BinaryEncoder<R>| -> IoResult<()>) -> IoResult<()> { f(self) }
    fn emit_struct_field(&mut self, _f_name: &str, _f_idx: uint, f: |&mut BinaryEncoder<R>| -> IoResult<()>) -> IoResult<()> { f(self) }

    fn emit_tuple(&mut self, _len: uint, f: |&mut BinaryEncoder<R>| -> IoResult<()>) -> IoResult<()> { f(self) }
    fn emit_tuple_arg(&mut self, _idx: uint, f: |&mut BinaryEncoder<R>| -> IoResult<()>) -> IoResult<()> { f(self) }
    fn emit_tuple_struct(&mut self, _name: &str, _len: uint, f: |&mut BinaryEncoder<R>| -> IoResult<()>) -> IoResult<()> { f(self) }
    fn emit_tuple_struct_arg(&mut self, _f_idx: uint, f: |&mut BinaryEncoder<R>| -> IoResult<()>) -> IoResult<()> { f(self) }

    fn emit_option(&mut self, f: |&mut BinaryEncoder<R>| -> IoResult<()>) -> IoResult<()>  { f(self) }
    fn emit_option_none(&mut self) -> IoResult<()> { try!(self.writer.write_u8(0)); Ok(()) }
    fn emit_option_some(&mut self, f: |&mut BinaryEncoder<R>| -> IoResult<()>) -> IoResult<()> { try!(self.writer.write_u8(1)); f(self) }

    fn emit_seq(&mut self,     _len: uint, f: |this: &mut BinaryEncoder<R>| -> IoResult<()>) -> IoResult<()>
        { try!(self.writer.write_le_uint(_len)); f(self) }
    fn emit_seq_elt(&mut self, _idx: uint, f: |this: &mut BinaryEncoder<R>| -> IoResult<()>) -> IoResult<()> { f(self) }

    fn emit_map(&mut self,         _len: uint, f: |&mut BinaryEncoder<R>| -> IoResult<()>) -> IoResult<()>
        { try!(self.writer.write_le_uint(_len)); f(self) }
    fn emit_map_elt_key(&mut self, _idx: uint, f: |&mut BinaryEncoder<R>| -> IoResult<()>) -> IoResult<()> { f(self) }
    fn emit_map_elt_val(&mut self, _idx: uint, f: |&mut BinaryEncoder<R>| -> IoResult<()>) -> IoResult<()> { f(self) }
}
<commit_msg>Update for change in `serialize::Decoder` and `serialize::Encoder`.<commit_after>extern crate serialize;

use serialize::{Encoder, Decoder};
use std::io;
use std::io::{IoResult, Reader, Writer, IoError};
use std::char::from_u32;

pub struct BinaryDecoder<R: Reader> { reader: R }

impl<R: Reader> serialize::Decoder for BinaryDecoder<R>
{
    pub type Error = IoError;

    fn read_nil(&mut self)  -> IoResult<()> { Ok(()) }

    fn read_uint(&mut self) -> IoResult<uint>   { self.reader.read_le_uint() }
    fn read_u64(&mut self)  -> IoResult<u64>    { self.reader.read_le_u64() }
    fn read_u32(&mut self)  -> IoResult<u32>    { self.reader.read_le_u32() }
    fn read_u16(&mut self)  -> IoResult<u16>    { self.reader.read_le_u16() }
    fn read_u8(&mut self)   -> IoResult<u8>     { self.reader.read_u8() }

    fn read_int(&mut self)  -> IoResult<int>    { self.reader.read_le_int() }
    fn read_i64(&mut self)  -> IoResult<i64>    { self.reader.read_le_i64() }
    fn read_i32(&mut self)  -> IoResult<i32>    { self.reader.read_le_i32() }
    fn read_i16(&mut self)  -> IoResult<i16>    { self.reader.read_le_i16() }
    fn read_i8(&mut self)   -> IoResult<i8>     { self.reader.read_i8() }
    fn read_bool(&mut self) -> IoResult<bool>   { Ok(try!(self.reader.read_u8()) != 0) }

    fn read_f64(&mut self)  -> IoResult<f64>    { self.reader.read_le_f64() }
    fn read_f32(&mut self)  -> IoResult<f32>    { self.reader.read_le_f32() }

    fn read_char(&mut self) -> IoResult<char>   { self.reader.read_le_u32().map(|x| from_u32(x).unwrap()) }
    fn read_str(&mut self)  -> IoResult<String> { self.reader.read_to_string() }

    fn read_enum<T, F>(&mut self, _name: &str, f: F) -> IoResult<T>
        where F: FnOnce(&mut BinaryDecoder<R>) -> IoResult<T> { f(self) }
    fn read_enum_variant<T, F>(&mut self, _names: &[&str], f: F) -> IoResult<T>
        where F: FnOnce(&mut BinaryDecoder<R>, uint) -> IoResult<T>
        { let variant = try!(self.reader.read_le_uint()); f(self, variant) }
    fn read_enum_variant_arg<T, F>(&mut self, _a_idx: uint, f: F) -> IoResult<T>
        where F: FnOnce(&mut BinaryDecoder<R>) -> IoResult<T> { f(self) }
    fn read_enum_struct_variant<T, F>(&mut self, _names: &[&str], f: F) -> IoResult<T>
        where F: FnOnce(&mut BinaryDecoder<R>, uint) -> IoResult<T>
        { let variant = try!(self.reader.read_le_uint()); f(self, variant) }
    fn read_enum_struct_variant_field<T, F>(&mut self, _f_name: &str, _f_idx: uint, f: F) -> IoResult<T>
        where F: FnOnce(&mut BinaryDecoder<R>) -> IoResult<T>
        { f(self) }

    fn read_struct<T, F>(&mut self, _s_name: &str, _len: uint, f: F) -> IoResult<T>
        where F: FnOnce(&mut BinaryDecoder<R>) -> IoResult<T>
        { f(self) }
    fn read_struct_field<T, F>(&mut self, _f_name: &str, _f_idx: uint, f: F) -> IoResult<T>
        where F: FnOnce(&mut BinaryDecoder<R>) -> IoResult<T> { f(self) }

    fn read_tuple<T, F>(&mut self, _len: uint, f: F) -> IoResult<T>
        where F: FnOnce(&mut BinaryDecoder<R>) -> IoResult<T> { f(self) }
    fn read_tuple_arg<T, F>(&mut self, _a_idx: uint, f: F) -> IoResult<T>
        where F: FnOnce(&mut BinaryDecoder<R>) -> IoResult<T> { f(self) }
    fn read_tuple_struct<T, F>(&mut self, _s_name: &str, _len: uint, f: F) -> IoResult<T>
        where F: FnOnce(&mut BinaryDecoder<R>) -> IoResult<T> { f(self) }
    fn read_tuple_struct_arg<T, F>(&mut self, _a_idx: uint, f: F) -> IoResult<T>
        where F: FnOnce(&mut BinaryDecoder<R>) -> IoResult<T> { f(self) }

    fn read_option<T, F>(&mut self, f: F) -> IoResult<T>
        where F: FnOnce(&mut BinaryDecoder<R>, bool) -> IoResult<T>
        { let some = try!(self.reader.read_u8()); f(self, some != 0) }

    fn read_seq<T, F>(&mut self, f: F) -> IoResult<T>
        where F: FnOnce(&mut BinaryDecoder<R>, uint) -> IoResult<T>
        { let len = try!(self.reader.read_le_uint()); f(self, len) }
    fn read_seq_elt<T, F>(&mut self, _idx: uint, f: F) -> IoResult<T>
        where F: FnOnce(&mut BinaryDecoder<R>) -> IoResult<T> { f(self) }

    fn read_map<T, F>(&mut self, f: F) -> IoResult<T>
        where F: FnOnce(&mut BinaryDecoder<R>, uint) -> IoResult<T>
        { let len = try!(self.reader.read_le_uint()); f(self, len) }
    fn read_map_elt_key<T, F>(&mut self, _idx: uint, f: F) -> IoResult<T>
        where F: FnOnce(&mut BinaryDecoder<R>) -> IoResult<T> { f(self) }
    fn read_map_elt_val<T, F>(&mut self, _idx: uint, f: F) -> IoResult<T>
        where F: FnOnce(&mut BinaryDecoder<R>) -> IoResult<T> { f(self) }

    fn error(&mut self, _err: &str) -> io::IoError { IoError::last_error() }
}

pub struct BinaryEncoder<R: Writer> { writer: R }

impl<R: Writer> serialize::Encoder for BinaryEncoder<R>
{
    pub type Error = IoError;

    fn emit_nil(&mut self)            -> IoResult<()> { Ok(()) }

    fn emit_uint(&mut self, v: uint)  -> IoResult<()> { self.writer.write_le_uint(v) }
    fn emit_u64(&mut self, v: u64)    -> IoResult<()> { self.writer.write_le_u64(v) }
    fn emit_u32(&mut self, v: u32)    -> IoResult<()> { self.writer.write_le_u32(v) }
    fn emit_u16(&mut self, v: u16)    -> IoResult<()> { self.writer.write_le_u16(v) }
    fn emit_u8(&mut self, v: u8)      -> IoResult<()> { self.writer.write_u8(v) }

    fn emit_int(&mut self, v: int)    -> IoResult<()> { self.writer.write_le_int(v) }
    fn emit_i64(&mut self, v: i64)    -> IoResult<()> { self.writer.write_le_i64(v) }
    fn emit_i32(&mut self, v: i32)    -> IoResult<()> { self.writer.write_le_i32(v) }
    fn emit_i16(&mut self, v: i16)    -> IoResult<()> { self.writer.write_le_i16(v) }
    fn emit_i8(&mut self, v: i8)      -> IoResult<()> { self.writer.write_i8(v) }

    fn emit_bool(&mut self, v: bool)  -> IoResult<()> { self.writer.write_u8(if v { 1 } else { 0 }) }

    fn emit_f64(&mut self, v: f64)    -> IoResult<()> { self.writer.write_le_f64(v) }
    fn emit_f32(&mut self, v: f32)    -> IoResult<()> { self.writer.write_le_f32(v) }

    fn emit_char(&mut self, _v: char) -> IoResult<()> { self.writer.write_le_u32(_v as u32) }
    fn emit_str(&mut self, v: &str)   -> IoResult<()> { self.writer.write_str(v) }

    fn emit_enum<F>(&mut self, _name: &str, f: F) -> IoResult<()>
        where F: FnOnce(&mut BinaryEncoder<R>) -> IoResult<()> { f(self) }
    fn emit_enum_variant<F>(&mut self, _v_name: &str, v_id: uint, _len: uint, f: F) -> IoResult<()>
        where F: FnOnce(&mut BinaryEncoder<R>) -> IoResult<()>
        { try!(self.writer.write_le_uint(v_id)); f(self) }
    fn emit_enum_variant_arg<F>(&mut self, _a_idx: uint, f: F) -> IoResult<()>
        where F: FnOnce(&mut BinaryEncoder<R>) -> IoResult<()> { f(self) }
    fn emit_enum_struct_variant<F>(&mut self, _v_name: &str, v_id: uint, _len: uint, f: F) -> IoResult<()>
        where F: FnOnce(&mut BinaryEncoder<R>) -> IoResult<()>
        { try!(self.writer.write_le_uint(v_id)); f(self) }
    fn emit_enum_struct_variant_field<F>(&mut self, _f_name: &str, _f_idx: uint, f: F) -> IoResult<()>
        where F: FnOnce(&mut BinaryEncoder<R>) -> IoResult<()>
        { f(self) }

    fn emit_struct<F>(&mut self, _name: &str, _len: uint, f: F) -> IoResult<()>
        where F: FnOnce(&mut BinaryEncoder<R>) -> IoResult<()> { f(self) }
    fn emit_struct_field<F>(&mut self, _f_name: &str, _f_idx: uint, f: F) -> IoResult<()>
        where F: FnOnce(&mut BinaryEncoder<R>) -> IoResult<()> { f(self) }

    fn emit_tuple<F>(&mut self, _len: uint, f: F) -> IoResult<()>
        where F: FnOnce(&mut BinaryEncoder<R>) -> IoResult<()> { f(self) }
    fn emit_tuple_arg<F>(&mut self, _idx: uint, f: F) -> IoResult<()>
        where F: FnOnce(&mut BinaryEncoder<R>) -> IoResult<()> { f(self) }
    fn emit_tuple_struct<F>(&mut self, _name: &str, _len: uint, f: F) -> IoResult<()>
        where F: FnOnce(&mut BinaryEncoder<R>) -> IoResult<()> { f(self) }
    fn emit_tuple_struct_arg<F>(&mut self, _f_idx: uint, f: F) -> IoResult<()>
        where F: FnOnce(&mut BinaryEncoder<R>) -> IoResult<()> { f(self) }

    fn emit_option<F>(&mut self, f: F) -> IoResult<()>
        where F: FnOnce(&mut BinaryEncoder<R>) -> IoResult<()> { f(self) }
    fn emit_option_none(&mut self) -> IoResult<()> { try!(self.writer.write_u8(0)); Ok(()) }
    fn emit_option_some<F>(&mut self, f: F) -> IoResult<()>
        where F: FnOnce(&mut BinaryEncoder<R>) -> IoResult<()>
        { try!(self.writer.write_u8(1)); f(self) }

    fn emit_seq<F>(&mut self, _len: uint, f: F) -> IoResult<()>
        where F: FnOnce(&mut BinaryEncoder<R>) -> IoResult<()>
        { try!(self.writer.write_le_uint(_len)); f(self) }
    fn emit_seq_elt<F>(&mut self, _idx: uint, f: F) -> IoResult<()>
        where F: FnOnce(&mut BinaryEncoder<R>) -> IoResult<()> { f(self) }

    fn emit_map<F>(&mut self, _len: uint, f: F) -> IoResult<()>
        where F: FnOnce(&mut BinaryEncoder<R>) -> IoResult<()>
        { try!(self.writer.write_le_uint(_len)); f(self) }
    fn emit_map_elt_key<F>(&mut self, _idx: uint, f: F) -> IoResult<()>
        where F: FnOnce(&mut BinaryEncoder<R>) -> IoResult<()> { f(self) }
    fn emit_map_elt_val<F>(&mut self, _idx: uint, f: F) -> IoResult<()>
        where F: FnOnce(&mut BinaryEncoder<R>) -> IoResult<()> { f(self) }
}
<|endoftext|>


<commit_before>use gl;
use gl::types::*;
use types::{Color, Viewport, GLError};
use buffer::{ArrayBufferBinder, ElementArrayBufferBinder};
use program::{ProgramBinder, ProgramAttrib};
use framebuffer::FramebufferBinder;
use renderbuffer::RenderbufferBinder;
use texture_units::{TextureUnits};

pub struct Context {
    pub array_buffer: ArrayBufferBinder,
    pub element_array_buffer: ElementArrayBufferBinder,
    pub program: ProgramBinder,
    pub framebuffer: FramebufferBinder,
    pub renderbuffer: RenderbufferBinder,
    pub tex_units: TextureUnits
}

impl Context {
    pub unsafe fn current_context() -> Self {
        Context {
            array_buffer: ArrayBufferBinder,
            element_array_buffer: ElementArrayBufferBinder,
            program: ProgramBinder,
            framebuffer: FramebufferBinder,
            renderbuffer: RenderbufferBinder,
            tex_units: TextureUnits::current()
        }
    }

    pub fn clear_color(&mut self, color: Color) {
        unsafe {
            gl::ClearColor(color.r, color.g, color.b, color.a);
        }
    }

    pub fn enable_vertex_attrib_array(&self, attrib: ProgramAttrib) {
        unsafe {
            gl::EnableVertexAttribArray(attrib.gl_index);
            dbg_gl_error! {
                GLError::InvalidValue => "`index` is >= GL_MAX_VERTEX_ATTRIBS",
                _ => "Unknown error"
            }
        }
    }

    pub fn viewport(&self, viewport: Viewport) {
        unsafe {
            gl::Viewport(viewport.x as GLint,
                         viewport.y as GLint,
                         viewport.width as GLsizei,
                         viewport.height as GLsizei);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`width` or `height` is negative",
                _ => "Unknown error"
            }
        }
    }

    pub fn get_error() -> Option<GLError> {
        unsafe {
            match gl::GetError() {
                gl::INVALID_ENUM =>
                    Some(GLError::InvalidEnum),
                gl::INVALID_VALUE =>
                    Some(GLError::InvalidValue),
                gl::INVALID_OPERATION =>
                    Some(GLError::InvalidOperation),
                gl::INVALID_FRAMEBUFFER_OPERATION =>
                    Some(GLError::InvalidFramebufferOperation),
                gl::OUT_OF_MEMORY =>
                    Some(GLError::OutOfMemory),
                _ =>
                    None
            }
        }
    }
}

#[macro_export]
macro_rules! bind_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! bind_element_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.element_array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! use_program {
    ($gl:expr, $program:expr) => {
        $gl.program.bind($program)
    }
}

#[macro_export]
macro_rules! bind_framebuffer {
    ($gl:expr, $fbo:expr) => {
        $gl.framebuffer.bind($fbo)
    }
}

#[macro_export]
macro_rules! bind_renderbuffer {
    ($gl:expr, $renderbuffer:expr) => {
        $gl.renderbuffer.bind($renderbuffer)
    }
}

// HACK: Workaround for issue described here:
// https://www.reddit.com/r/rust/comments/339yj3/tuple_indexing_in_a_macro/cqiyv4n
#[macro_export]
macro_rules! _glitter_expr {
    ($x:expr) => ($x)
}

#[macro_export]
macro_rules! active_texture {
    ($gl:expr, $idx:tt) => {
        _glitter_expr!($gl.tex_units.$idx.active())
    }
}

#[macro_export]
macro_rules! active_texture_n {
    ($gl:expr, $idx:expr) => {
        $gl.tex_units.nth_unit($idx).active()
    }
}
<commit_msg>Add `current_framebuffer_binding!` macro<commit_after>use gl;
use gl::types::*;
use types::{Color, Viewport, GLError};
use buffer::{ArrayBufferBinder, ElementArrayBufferBinder};
use program::{ProgramBinder, ProgramAttrib};
use framebuffer::FramebufferBinder;
use renderbuffer::RenderbufferBinder;
use texture_units::{TextureUnits};

pub struct Context {
    pub array_buffer: ArrayBufferBinder,
    pub element_array_buffer: ElementArrayBufferBinder,
    pub program: ProgramBinder,
    pub framebuffer: FramebufferBinder,
    pub renderbuffer: RenderbufferBinder,
    pub tex_units: TextureUnits
}

impl Context {
    pub unsafe fn current_context() -> Self {
        Context {
            array_buffer: ArrayBufferBinder,
            element_array_buffer: ElementArrayBufferBinder,
            program: ProgramBinder,
            framebuffer: FramebufferBinder,
            renderbuffer: RenderbufferBinder,
            tex_units: TextureUnits::current()
        }
    }

    pub fn clear_color(&mut self, color: Color) {
        unsafe {
            gl::ClearColor(color.r, color.g, color.b, color.a);
        }
    }

    pub fn enable_vertex_attrib_array(&self, attrib: ProgramAttrib) {
        unsafe {
            gl::EnableVertexAttribArray(attrib.gl_index);
            dbg_gl_error! {
                GLError::InvalidValue => "`index` is >= GL_MAX_VERTEX_ATTRIBS",
                _ => "Unknown error"
            }
        }
    }

    pub fn viewport(&self, viewport: Viewport) {
        unsafe {
            gl::Viewport(viewport.x as GLint,
                         viewport.y as GLint,
                         viewport.width as GLsizei,
                         viewport.height as GLsizei);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`width` or `height` is negative",
                _ => "Unknown error"
            }
        }
    }

    pub fn get_error() -> Option<GLError> {
        unsafe {
            match gl::GetError() {
                gl::INVALID_ENUM =>
                    Some(GLError::InvalidEnum),
                gl::INVALID_VALUE =>
                    Some(GLError::InvalidValue),
                gl::INVALID_OPERATION =>
                    Some(GLError::InvalidOperation),
                gl::INVALID_FRAMEBUFFER_OPERATION =>
                    Some(GLError::InvalidFramebufferOperation),
                gl::OUT_OF_MEMORY =>
                    Some(GLError::OutOfMemory),
                _ =>
                    None
            }
        }
    }
}

#[macro_export]
macro_rules! bind_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! bind_element_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.element_array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! use_program {
    ($gl:expr, $program:expr) => {
        $gl.program.bind($program)
    }
}

#[macro_export]
macro_rules! bind_framebuffer {
    ($gl:expr, $fbo:expr) => {
        $gl.framebuffer.bind($fbo)
    }
}

#[macro_export]
macro_rules! current_framebuffer_binding {
    ($gl:expr) => {
        $gl.framebuffer.current_binding()
    }
}

#[macro_export]
macro_rules! bind_renderbuffer {
    ($gl:expr, $renderbuffer:expr) => {
        $gl.renderbuffer.bind($renderbuffer)
    }
}

// HACK: Workaround for issue described here:
// https://www.reddit.com/r/rust/comments/339yj3/tuple_indexing_in_a_macro/cqiyv4n
#[macro_export]
macro_rules! _glitter_expr {
    ($x:expr) => ($x)
}

#[macro_export]
macro_rules! active_texture {
    ($gl:expr, $idx:tt) => {
        _glitter_expr!($gl.tex_units.$idx.active())
    }
}

#[macro_export]
macro_rules! active_texture_n {
    ($gl:expr, $idx:expr) => {
        $gl.tex_units.nth_unit($idx).active()
    }
}
<|endoftext|>


<commit_before>use ordered_float::OrderedFloat;
use rayon::prelude::*;

use super::CharIndex;
use super::enigma::Enigma;

lazy_static! {
    static ref QGRAMS: Vec<f64> = {
        let f = include_str!("data/quadgrams.txt");
        let mut qgrams = vec![0.0; 456_976];  // 26^4 = 456,976

        for line in f.lines() {
            let line: Vec<_> = line.split(' ').collect();
            let qgram: &str = line[0];
            let count: f64 = line[1].parse().unwrap();

            let index = qgram.chars().fold(0, |acc, c| 26 * acc + c.index());
            qgrams[index] = count.ln();
        }

        qgrams
    };

    static ref ALPHAS: Vec<String> = {
        // Construct the vector ["AAA", "AAB", ..., "ZZY", "ZZZ"]
        iproduct!(b'A'..b'[', b'A'..b'[', b'A'..b'[')
            .map(|(a, b, c)| String::from_utf8(vec![a, b, c]).unwrap())
            .collect()
    };

    static ref ROTORS: Vec<String> = {
        // Create all permutations of rotors 1 through 5
        iproduct!(b'1'..b'6', b'1'..b'6', b'1'..b'6')
            .filter(|&(r1, r2, r3)| (r1 != r2) && (r1 != r3) && (r2 != r3))
            .map(|(r1, r2, r3)| String::from_utf8(vec![r1, r2, r3]).unwrap())
            .collect()
    };
}

/// Decrypts the given string by iterating through multiple possible Enigma
/// configurations, returning the tuple `(plaintext, rotor, key, ring)`
/// corresponding to the most probable plaintext.
pub fn decrypt(msg: &str) -> (String, String, String, String) {
    // Try all rotor/key permutations (60*26^3 == 1,054,560 decryptions)
    let (rotor, key) = iproduct!(ROTORS.iter(), ALPHAS.iter())
        .collect::<Vec<_>>()
        .into_par_iter()
        .max_by_key(|&(rotor, key)| {
            let mut enigma = Enigma::new(rotor, key, "AAA", 'B', "");
            let plaintext = enigma.encrypt(msg);
            OrderedFloat(qgram_score(&plaintext))
        }).unwrap();

    // Keep the best rotor configuration found previously, and use the same
    // key setting for the first (slow) rotor. The ring setting for the first
    // rotor doesn't matter, so fix it to 'A', and try all key/ring settings
    // for the remaining two rotors (26^4 == 456,976 decryptions)
    let key_offset = key.chars().nth(0).unwrap().index() * 676;

    let (_, msg, key, ring) = iproduct!(key_offset..(key_offset + 676), 0..676)
        .collect::<Vec<_>>()
        .par_iter()
        .map(|&(key_index, ring_index)| {
            let key = &ALPHAS[key_index];
            let ring = &ALPHAS[ring_index];

            let mut enigma = Enigma::new(rotor, key, ring, 'B', "");
            let plaintext = enigma.encrypt(msg);
            let score = qgram_score(&plaintext);
            (OrderedFloat(score), plaintext, key, ring)
        }).max().unwrap();

    (msg, rotor.clone(), key.clone(), ring.clone())
}

/// Strips all non-alphabetic characters from the given message string and
/// returns the sum of the log-probabilities of each quadgram substring.
pub fn qgram_score(msg: &str) -> f64 {
    let char_indices: Vec<usize> = msg.chars()
        .filter(|&c| c.is_alphabetic())
        .map(|c| c.index())
        .collect();

    if char_indices.len() < 4 {
        panic!("Message must contain 4 or more alphabetic characters.");
    }

    char_indices.windows(4)
        .map(|w| w.iter().fold(0, |acc, x| 26 * acc + x))
        .map(|i| QGRAMS[i])
        .sum()
}

#[cfg(test)]
mod tests {
    use super::{QGRAMS, qgram_score};

    macro_rules! assert_approx_eq {
        ($a:expr, $b:expr) => {
            let (a, b) = (&$a, &$b);
            assert!((*a - *b).abs() < 1.0e-6, "{} is not approximately equal to {}", *a, *b);
        }
    }

    #[test]
    fn qgram_estimates() {
        assert_approx_eq!(QGRAMS[0], 8.81060879);
        assert_approx_eq!(qgram_score("THE QUICK BROWN FOX"), 149.80102862);
    }

    #[test]
    fn sensible_qgram_scores() {
        assert!(qgram_score("AN ENGLISH PHRASE") > qgram_score("ESARHP HSILGNE NA"));
    }

    #[test]
    #[should_panic]
    fn invalid_qgram_check() {
        qgram_score("ABC");
    }
}
<commit_msg>Optimize ciphertext decryption algorithm<commit_after>use itertools::Itertools;
use ordered_float::OrderedFloat;
use rayon::prelude::*;

use super::CharIndex;
use super::enigma::Enigma;

lazy_static! {
    static ref QGRAMS: Vec<f64> = {
        let f = include_str!("data/quadgrams.txt");
        let mut qgrams = vec![0.0; 456_976];  // 26^4 = 456,976

        for line in f.lines() {
            let line: Vec<_> = line.split(' ').collect();
            let qgram: &str = line[0];
            let count: f64 = line[1].parse().unwrap();

            let index = qgram.chars().fold(0, |acc, c| 26 * acc + c.index());
            qgrams[index] = count.ln();
        }

        qgrams
    };

    static ref ALPHAS: Vec<String> = {
        // Construct the vector ["AAA", "AAB", ..., "ZZY", "ZZZ"]
        iproduct!(b'A'..b'[', b'A'..b'[', b'A'..b'[')
            .map(|(a, b, c)| String::from_utf8(vec![a, b, c]).unwrap())
            .collect()
    };

    static ref ROTORS: Vec<String> = {
        // Create all permutations of rotors 1 through 5
        iproduct!(b'1'..b'6', b'1'..b'6', b'1'..b'6')
            .filter(|&(r1, r2, r3)| (r1 != r2) && (r1 != r3) && (r2 != r3))
            .map(|(r1, r2, r3)| String::from_utf8(vec![r1, r2, r3]).unwrap())
            .collect()
    };
}

/// Decrypts the given string by iterating through multiple possible Enigma
/// configurations, returning the tuple `(plaintext, rotor, key, ring)`
/// corresponding to the most probable plaintext.
pub fn decrypt(msg: &str) -> (String, String, String, String) {
    // Try all rotor/key permutations (60*26^3 == 1,054,560 decryptions).
    let (rotor, key) = iproduct!(ROTORS.iter(), ALPHAS.iter())
        .collect::<Vec<_>>()
        .into_par_iter()
        .max_by_key(|&(rotor, key)| {
            let mut enigma = Enigma::new(rotor, key, "AAA", 'B', "");
            let plaintext = enigma.encrypt(msg);
            OrderedFloat(qgram_score(&plaintext))
        }).unwrap();

    // Use the best rotor/key settings found previously, and iterate through
    // ring settings for the latter two rotors (the ring setting for the slow
    // rotor doesn't matter, so fix it to 'A'), shifting the key setting to
    // match the corresponding ring setting (26^2 == 676 decryptions).
    let (k1, k2, k3) = key.chars().map(|c| c.index()).next_tuple().unwrap();

    let (_, msg, key, ring) = iproduct!(0..26, 0..26).map(|(r2, r3)| {
        let key = &ALPHAS[k1 * 676 + ((k2 + r2) % 26) * 26 + (k3 + r3) % 26];
        let ring = &ALPHAS[r2 * 26 + r3];

        let mut enigma = Enigma::new(rotor, key, ring, 'B', "");
        let plaintext = enigma.encrypt(msg);
        let score = qgram_score(&plaintext);
        (OrderedFloat(score), plaintext, key, ring)
    }).max().unwrap();

    (msg, rotor.clone(), key.clone(), ring.clone())
}

/// Strips all non-alphabetic characters from the given message string and
/// returns the sum of the log-probabilities of each quadgram substring.
pub fn qgram_score(msg: &str) -> f64 {
    let char_indices: Vec<usize> = msg.chars()
        .filter(|&c| c.is_alphabetic())
        .map(|c| c.index())
        .collect();

    if char_indices.len() < 4 {
        panic!("Message must contain 4 or more alphabetic characters.");
    }

    char_indices.windows(4)
        .map(|w| w.iter().fold(0, |acc, x| 26 * acc + x))
        .map(|i| QGRAMS[i])
        .sum()
}

#[cfg(test)]
mod tests {
    use super::{QGRAMS, qgram_score};

    macro_rules! assert_approx_eq {
        ($a:expr, $b:expr) => {
            let (a, b) = (&$a, &$b);
            assert!((*a - *b).abs() < 1.0e-6, "{} is not approximately equal to {}", *a, *b);
        }
    }

    #[test]
    fn qgram_estimates() {
        assert_approx_eq!(QGRAMS[0], 8.81060879);
        assert_approx_eq!(qgram_score("THE QUICK BROWN FOX"), 149.80102862);
    }

    #[test]
    fn sensible_qgram_scores() {
        assert!(qgram_score("AN ENGLISH PHRASE") > qgram_score("ESARHP HSILGNE NA"));
    }

    #[test]
    #[should_panic]
    fn invalid_qgram_check() {
        qgram_score("ABC");
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

#[cfg(target_os = "linux")]
extern crate i2cdev;
extern crate termion;

#[cfg(target_os = "linux")]
use self::i2cdev::core::I2CDevice;
#[cfg(target_os = "linux")]
use self::i2cdev::linux::LinuxI2CDevice;

use std;
use shared::*;

const MODE_REGISTER: u8 = 0x00;
const FRAME_REGISTER: u8 = 0x01;
const AUTOPLAY1_REGISTER: u8 = 0x02;
const AUTOPLAY2_REGISTER: u8 = 0x03;
const BLINK_REGISTER: u8 = 0x05;
const AUDIOSYNC_REGISTER: u8 = 0x06;
const BREATH1_REGISTER: u8 = 0x08;
const BREATH2_REGISTER: u8 = 0x09;
const SHUTDOWN_REGISTER: u8 = 0x0A;
const GAIN_REGISTER: u8 = 0x0B;
const ADC_REGISTER: u8 = 0x0C;

const CONFIG_BANK: u8 = 0x0B;
const BANK_ADDRESS: u8 = 0xFD;

const PICTURE_MODE: u8 = 0x00;
const AUTOPLAY_MODE: u8 = 0x08;
const AUDIOPLAY_MODE: u8 = 0x18;

const ENABLE_OFFSET: u8 = 0x00;
const BLINK_OFFSET: u8 = 0x12;
const COLOR_OFFSET: u8 = 0x24;

const ADDRESS: u16 = 0x74;

/// Represents a device capable of displaying a rectangular bitmap buffer.
pub trait Display {
    fn show(&mut self, buffer: &[Column]);
}

#[cfg(target_os = "linux")]
/// A Scroll pHAT HD device connected over I2C bus (e.g. on a Raspberry Pi).
pub struct I2CDisplay {
    device: LinuxI2CDevice,
    frame: u8,
}

#[cfg(target_os = "linux")]
impl I2CDisplay {
    /// Creates a new I2CDisplay device using the I2C device identified by the provided
    /// `device_id` (normally 1 or 2).
    pub fn new(device_id: u8) -> I2CDisplay {
        let device_path = format!("/dev/i2c-{}", device_id);
        let d = LinuxI2CDevice::new(device_path, ADDRESS).unwrap();
        let mut display = I2CDisplay {
            device: d,
            frame: 0,
        };

        display.init_display();

        display
    }

    fn bank(&mut self, bank: u8) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.device.smbus_write_byte_data(BANK_ADDRESS, bank)
    }

    fn register(
        &mut self,
        bank: u8,
        register: u8,
        value: u8,
    ) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.bank(bank);
        self.device.smbus_write_byte_data(register, value)
    }

    fn frame(&mut self, frame: u8) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.register(CONFIG_BANK, FRAME_REGISTER, frame)
    }

    fn reset_display(&mut self) {
        self.sleep(true);
        std::thread::sleep(std::time::Duration::from_millis(10));
        self.sleep(false);
    }

    fn init_display(&mut self) {
        self.reset_display();

        self.device.smbus_write_byte_data(BANK_ADDRESS, CONFIG_BANK);
        // Switch to Picture Mode
        self.device
            .smbus_write_byte_data(MODE_REGISTER, PICTURE_MODE);
        // Disable audio sync
        self.device.smbus_write_byte_data(AUDIOSYNC_REGISTER, 0);

        // Initialize frame 1
        self.device.smbus_write_byte_data(BANK_ADDRESS, 1);
        // Turn off blinking for all LEDs
        for i in 0..17 {
            self.device.smbus_write_byte_data(BLINK_OFFSET + i, 0);
        }
        // Set the PWM duty cycle for all LEDs to 0%
        for i in 0..17 {
            for j in 0..7 {
                self.device
                    .smbus_write_byte_data(COLOR_OFFSET + (i * 8) + j, 0);
            }
        }
        // Turn all LEDs "on"
        for i in 0..17 {
            self.device.smbus_write_byte_data(ENABLE_OFFSET + i, 127);
        }

        // Initialize frame 0
        self.device.smbus_write_byte_data(BANK_ADDRESS, 0);
        // Turn off blinking for all LEDs
        for i in 0..17 {
            self.device.smbus_write_byte_data(BLINK_OFFSET + i, 0);
        }
        // Set the PWM duty cycle for all LEDs to 0%
        for i in 0..17 {
            for j in 0..7 {
                self.device
                    .smbus_write_byte_data(COLOR_OFFSET + (i * 8) + j, 0);
            }
        }
        // Turn all LEDs "on"
        for i in 0..17 {
            self.device.smbus_write_byte_data(ENABLE_OFFSET + i, 127);
        }
    }

    fn sleep(&mut self, value: bool) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.register(CONFIG_BANK, SHUTDOWN_REGISTER, if value { 0 } else { 1 })
    }
}

#[cfg(target_os = "linux")]
impl Display for I2CDisplay {
    fn show(&mut self, buffer: &[Column]) {
        let new_frame = (self.frame + 1) % 2;
        self.bank(new_frame);
        for y in 0..DISPLAY_HEIGHT {
            for x in 0..DISPLAY_WIDTH {
                let offset = if x >= 8 {
                    (x - 8) * 16 + y
                } else {
                    (8 - x) * 16 - (y + 2)
                };
                let value = match buffer.get(x as usize) {
                    Some(column) => column[y as usize],
                    None => 0,
                };
                self.device
                    .smbus_write_byte_data(COLOR_OFFSET + offset as u8, value);
            }
        }
        self.frame(new_frame);
        self.frame = new_frame;
    }
}

/// A virtual display that outputs its buffer to the terminal from which the binary is attached.
///
/// Useful for debugging or prototyping, as it does not require a physical display to be connected.
pub struct TermDisplay {}

impl TermDisplay {
    pub fn new() -> TermDisplay {
        TermDisplay {}
    }
}

impl Display for TermDisplay {
    fn show(&mut self, buffer: &[Column]) {
        print!("{}", termion::clear::All);
        for x in 0..buffer.len() {
            let col = &buffer[x];
            for y in 0..col.len() {
                let c = col[y];
                let v = if c == 0 { ' ' } else { '#' };
                println!("{}{}", termion::cursor::Goto(x as u16 + 1, y as u16 + 1), v);
            }
        }
    }
}

/// A virtual display that outputs its buffer to the terminal from which the binary is attached.
///
/// Useful for debugging or prototyping, as it does not require a physical display to be connected.
pub struct UnicodeDisplay {}

impl UnicodeDisplay {
    pub fn new() -> UnicodeDisplay {
        UnicodeDisplay {}
    }
}

impl Display for UnicodeDisplay {
    fn show(&mut self, buffer: &[Column]) {
        print!("{}", termion::clear::All);

        let col = &buffer[0];

        println!("{}╔", termion::cursor::Goto(1, 1));
        for y in 0..col.len() {
            println!("{}║", termion::cursor::Goto(1, y as u16 + 2));
        }
        println!("{}╚", termion::cursor::Goto(1, col.len() as u16 + 2));

        for x in 0..buffer.len() {
            let col = &buffer[x];
            println!("{}═", termion::cursor::Goto(x as u16 + 2, 1));
            for y in 0..col.len() {
                let c = col[y];
                let v = if c == 0 { '░' } else { '▓' };
                println!("{}{}", termion::cursor::Goto(x as u16 + 2, y as u16 + 2), v);
            }
            println!(
                "{}═",
                termion::cursor::Goto(x as u16 + 2, col.len() as u16 + 2)
            );
        }

        println!("{}╗", termion::cursor::Goto(buffer.len() as u16 + 1, 1));
        for y in 0..col.len() {
            println!(
                "{}║",
                termion::cursor::Goto(buffer.len() as u16 + 1, y as u16 + 2)
            );
        }
        println!(
            "{}╝",
            termion::cursor::Goto(buffer.len() as u16 + 1, col.len() as u16 + 2)
        );
    }
}
<commit_msg>Use write_data everywhere<commit_after>#![allow(dead_code)]

#[cfg(target_os = "linux")]
extern crate i2cdev;
extern crate termion;

#[cfg(target_os = "linux")]
use self::i2cdev::core::I2CDevice;
#[cfg(target_os = "linux")]
use self::i2cdev::linux::LinuxI2CDevice;

use std;
use shared::*;

const MODE_REGISTER: u8 = 0x00;
const FRAME_REGISTER: u8 = 0x01;
const AUTOPLAY1_REGISTER: u8 = 0x02;
const AUTOPLAY2_REGISTER: u8 = 0x03;
const BLINK_REGISTER: u8 = 0x05;
const AUDIOSYNC_REGISTER: u8 = 0x06;
const BREATH1_REGISTER: u8 = 0x08;
const BREATH2_REGISTER: u8 = 0x09;
const SHUTDOWN_REGISTER: u8 = 0x0A;
const GAIN_REGISTER: u8 = 0x0B;
const ADC_REGISTER: u8 = 0x0C;

const CONFIG_BANK: u8 = 0x0B;
const BANK_ADDRESS: u8 = 0xFD;

const PICTURE_MODE: u8 = 0x00;
const AUTOPLAY_MODE: u8 = 0x08;
const AUDIOPLAY_MODE: u8 = 0x18;

const ENABLE_OFFSET: u8 = 0x00;
const BLINK_OFFSET: u8 = 0x12;
const COLOR_OFFSET: u8 = 0x24;

const ADDRESS: u16 = 0x74;

/// Represents a device capable of displaying a rectangular bitmap buffer.
pub trait Display {
    fn show(&mut self, buffer: &[Column]);
}

#[cfg(target_os = "linux")]
/// A Scroll pHAT HD device connected over I2C bus (e.g. on a Raspberry Pi).
pub struct I2CDisplay {
    device: LinuxI2CDevice,
    frame: u8,
}

#[cfg(target_os = "linux")]
impl I2CDisplay {
    /// Creates a new I2CDisplay device using the I2C device identified by the provided
    /// `device_id` (normally 1 or 2).
    pub fn new(device_id: u8) -> I2CDisplay {
        let device_path = format!("/dev/i2c-{}", device_id);
        let d = LinuxI2CDevice::new(device_path, ADDRESS).unwrap();
        let mut display = I2CDisplay {
            device: d,
            frame: 0,
        };

        display.init_display();

        display
    }

    fn bank(&mut self, bank: u8) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.write_data(BANK_ADDRESS, &[bank])
    }

    fn register(
        &mut self,
        bank: u8,
        register: u8,
        value: u8,
    ) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.bank(bank);
        self.write_data(register, &[value])
    }

    fn frame(&mut self, frame: u8) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.register(CONFIG_BANK, FRAME_REGISTER, frame)
    }

    fn write_data(
        &mut self,
        base_address: u8,
        data: &[u8],
    ) -> Result<(), i2cdev::linux::LinuxI2CError> {
        for i in 0..data.len() {
            self.device
                .smbus_write_byte_data(base_address + (i as u8), data[i])?;
        }
        Ok(())
    }

    fn reset_display(&mut self) {
        self.sleep(true);
        std::thread::sleep(std::time::Duration::from_millis(10));
        self.sleep(false);
    }

    fn init_display(&mut self) {
        self.reset_display();

        // Switch to Picture Mode.
        self.register(CONFIG_BANK, MODE_REGISTER, PICTURE_MODE);

        // Disable audio sync.
        self.register(CONFIG_BANK, AUDIOSYNC_REGISTER, 0);

        // Initialize frame 1.
        self.write_data(BANK_ADDRESS, &[1]);

        // Turn off blinking for all LEDs.
        self.write_data(BLINK_OFFSET, &[0; 17]);

        // Set the PWM duty cycle for all LEDs to 0%.
        self.write_data(COLOR_OFFSET, &[0; 17 * 7]);

        // Turn all LEDs "on".
        self.write_data(ENABLE_OFFSET, &[127; 17]);

        // Initialize frame 0.
        self.write_data(BANK_ADDRESS, &[0]);

        // Turn off blinking for all LEDs.
        self.write_data(BLINK_OFFSET, &[0; 17]);

        // Set the PWM duty cycle for all LEDs to 0%.
        self.write_data(COLOR_OFFSET, &[0; 17 * 7]);

        // Turn all LEDs "on".
        self.write_data(ENABLE_OFFSET, &[127; 17]);
    }

    fn sleep(&mut self, value: bool) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.register(CONFIG_BANK, SHUTDOWN_REGISTER, if value { 0 } else { 1 })
    }
}

#[cfg(target_os = "linux")]
impl Display for I2CDisplay {
    fn show(&mut self, buffer: &[Column]) {
        let new_frame = (self.frame + 1) % 2;
        self.bank(new_frame);
        for y in 0..DISPLAY_HEIGHT {
            for x in 0..DISPLAY_WIDTH {
                let offset = if x >= 8 {
                    (x - 8) * 16 + y
                } else {
                    (8 - x) * 16 - (y + 2)
                };
                let value = match buffer.get(x as usize) {
                    Some(column) => column[y as usize],
                    None => 0,
                };
                self.write_data(COLOR_OFFSET + offset as u8, &[value]);
            }
        }
        self.frame(new_frame);
        self.frame = new_frame;
    }
}

/// A virtual display that outputs its buffer to the terminal from which the binary is attached.
///
/// Useful for debugging or prototyping, as it does not require a physical display to be connected.
pub struct TermDisplay {}

impl TermDisplay {
    pub fn new() -> TermDisplay {
        TermDisplay {}
    }
}

impl Display for TermDisplay {
    fn show(&mut self, buffer: &[Column]) {
        print!("{}", termion::clear::All);
        for x in 0..buffer.len() {
            let col = &buffer[x];
            for y in 0..col.len() {
                let c = col[y];
                let v = if c == 0 { ' ' } else { '#' };
                println!("{}{}", termion::cursor::Goto(x as u16 + 1, y as u16 + 1), v);
            }
        }
    }
}

/// A virtual display that outputs its buffer to the terminal from which the binary is attached.
///
/// Useful for debugging or prototyping, as it does not require a physical display to be connected.
pub struct UnicodeDisplay {}

impl UnicodeDisplay {
    pub fn new() -> UnicodeDisplay {
        UnicodeDisplay {}
    }
}

impl Display for UnicodeDisplay {
    fn show(&mut self, buffer: &[Column]) {
        print!("{}", termion::clear::All);

        let col = &buffer[0];

        println!("{}╔", termion::cursor::Goto(1, 1));
        for y in 0..col.len() {
            println!("{}║", termion::cursor::Goto(1, y as u16 + 2));
        }
        println!("{}╚", termion::cursor::Goto(1, col.len() as u16 + 2));

        for x in 0..buffer.len() {
            let col = &buffer[x];
            println!("{}═", termion::cursor::Goto(x as u16 + 2, 1));
            for y in 0..col.len() {
                let c = col[y];
                let v = if c == 0 { '░' } else { '▓' };
                println!("{}{}", termion::cursor::Goto(x as u16 + 2, y as u16 + 2), v);
            }
            println!(
                "{}═",
                termion::cursor::Goto(x as u16 + 2, col.len() as u16 + 2)
            );
        }

        println!("{}╗", termion::cursor::Goto(buffer.len() as u16 + 1, 1));
        for y in 0..col.len() {
            println!(
                "{}║",
                termion::cursor::Goto(buffer.len() as u16 + 1, y as u16 + 2)
            );
        }
        println!(
            "{}╝",
            termion::cursor::Goto(buffer.len() as u16 + 1, col.len() as u16 + 2)
        );
    }
}
<|endoftext|>


<commit_before>use std::path::Path;
use std::fs::File;
use std::f64;

use image::{ DynamicImage, GenericImage, ImageFormat };
use image;

use bitreader::BitReader;

use num_traits::float::Float;

pub struct CoverImage {
    cover_image: DynamicImage
}

impl CoverImage {
    pub fn new(file_path: &str) -> CoverImage {
        CoverImage {
            cover_image: image::open(&Path::new(&file_path)).unwrap()
        }
    }

    pub fn encode_with(&self, message: &str) {
        let bit_vector = get_bit_vec(message);

        encode(&self.cover_image, &bit_vector);

        let ref mut fout = File::create(&Path::new("/home/hugh/Pictures/yurt.png")).unwrap();

        let _ = self.cover_image.save(fout, ImageFormat::PNG).unwrap();
    }
}

// Get a Vector of Bits to Encode the Image with
fn get_bit_vec(message: &str) -> Vec<u8> {
    let mut bit_vector = Vec::new();
    let mut reader = BitReader::new(&message.as_bytes());

    // Multiplied by 8 because it's a Vec of bits not bytes
    for _ in 0..message.len() * 8 {
        bit_vector.push(reader.read_u8(1).unwrap());
    }

    bit_vector
}

// Encode the image with the Vector of Bits
fn encode(c_image: &DynamicImage, bit_vec: &Vec<u8>) {
    let mut tiled_image_vec = tile_image(&c_image);

    //let (width, height) = c_image.dimensions();

    let encoded_image = encode_image(&mut tiled_image_vec, bit_vec);
}

fn tile_image(c_image: &DynamicImage) -> Vec<image::Rgba<u8>> {
    let (width, height) = c_image.dimensions();

    let mut image_blocks = Vec::new();

    for row_index in 0..(height / 8) as u32 {
        for col_index in 0..(width / 8) as u32 {
            for row in 0..8 {
                for column in 0..8 {
                    image_blocks.push(c_image.get_pixel(column + (col_index * 8), row + (row_index * 8)));
                }
            }
        }
    }

    image_blocks
}

fn encode_image(tiled_image: &mut Vec<image::Rgba<u8>>, message: &Vec<u8>) {
    let mut cu = 0.0;
    let mut cv = 0.0;
    let mut total = 0.0;
    let mut inverse_total = 0.0;
    let mut index: usize = 0;
    let mut count = 0;
    let mut dct_coeffs: Vec<f64> = Vec::new();
    let mut colour_value: u8 = 0;

    let num_of_iterations = if message.len() / 3 == 0 {
                                    (message.len() / 3) as u32
                                } else {
                                    ((message.len() / 3) + 1) as u32
                                };

    for iteration in 0..num_of_iterations {
        for channel in 0..3 {
            for v in 0..8 {
                for u in 0..8 {
                    // Forward transform
                    for y in 0..8 {
                        for x in 0..8 {
                            index = u + (v * 8) + (iteration * 64) as usize;

                            colour_value = tiled_image[index].data[channel];

                            if u == 0 {
                                cu = 1.0 / 2.0.sqrt()
                            } else {
                                cu = 1.0
                            }

                            if v == 0 {
                                cv = 1.0 / 2.0.sqrt()
                            } else {
                                cv = 0.0
                            }

                            total = total + (v as f64 * f64::consts::PI * (2.0 * (y as f64) + 1.0) / 16.0).cos()
                                          * (u as f64 * f64::consts::PI * (2.0 * (x as f64) + 1.0) / 16.0).cos()
                                          * colour_value as f64;
                        }
                    }

                    // 0.25, Cu and Cv are scaling factors
                    total = total * 0.25 * cu * cv;

                    dct_coeffs.push(total);
                }
            }

            // Encode the message
            let coeff_to_mod = (27 + (iteration * 64)) as usize;

            if dct_coeffs[coeff_to_mod].trunc() % 2.0 == 0.0 {
                if message[count] == 1 {
                    dct_coeffs[coeff_to_mod] = dct_coeffs[coeff_to_mod] + 1.0
                }
            } else {
                if message[count] == 0 {
                    dct_coeffs[coeff_to_mod] = dct_coeffs[coeff_to_mod] + 1.0
                }
            }

            // Inverse transform
            for v in 0..8 {
                for u in 0..8 {
                    for y in 0..8 {
                        for x in 0..8 {
                            index = u + (v * 8) + (iteration * 64) as usize;

                            colour_value = tiled_image[index].data[channel];

                            if u == 0 {
                                cu = 1.0 / 2.0.sqrt()
                            } else {
                                cu = 1.0
                            }

                            if v == 0 {
                                cv = 1.0 / 2.0.sqrt()
                            } else {
                                cv = 0.0
                            }

                            inverse_total = inverse_total * cu * cv + (v as f64 * f64::consts::PI * (2.0 * (y as f64) + 1.0) / 16.0).cos()
                                                                    * (u as f64 * f64::consts::PI * (2.0 * (x as f64) + 1.0) / 16.0).cos()
                                                                    * colour_value as f64;
                        }
                    }
                }
            }

            inverse_total = inverse_total * 0.25;
        }
    }
}

/**************************************************************************************************
 *                                                                                *
 *                                         Tests                                                  *
 *                                                                                *
 **************************************************************************************************/

#[cfg(test)]
#[test]
fn test_get_bit_vec_len() {
    let bits = get_bit_vec("h");

    assert_eq!(8, bits.len());
}

#[cfg(test)]
#[test]
fn test_get_bit_vec() {
    let test_bits = vec![0, 1, 1, 0, 1, 0, 0, 0];
    let bits = get_bit_vec("h");

    assert_eq!(bits, test_bits);
}

#[cfg(test)]
#[test]
fn test_encode_red_channel_lsb_set() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img, &bit_vec);

    let pixel = img.get_pixel(0, 0);

    assert_eq!(pixel.data[0] % 2, bit_vec[0]);
}

#[cfg(test)]
#[test]
fn test_encode_green_channel_lsb_set() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img, &bit_vec);

    let pixel = img.get_pixel(0, 0);

    assert_eq!(pixel.data[1] % 2, bit_vec[1]);
}

#[cfg(test)]
#[test]
fn test_encode_blue_channel_lsb_set() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img, &bit_vec);

    let pixel = img.get_pixel(0, 0);

    assert_eq!(pixel.data[2] % 2 as u8, bit_vec[2]);
}

#[cfg(test)]
#[test]
fn test_full_byte_is_encoded() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let mut encoded_bit_vec = Vec::new();
    let mut count = 0;

    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img, &bit_vec);

    'outer: for x_co_ord in 0..3 {
        let pixel = img.get_pixel(x_co_ord, 0);

        for channel in 0..3 {
            if count >= 8 {
                break 'outer;
            }

            encoded_bit_vec.push(pixel.data[channel] % 2);

            count += 1;
        }
    }

    assert_eq!(encoded_bit_vec, bit_vec);
}

#[cfg(test)]
#[test]
fn test_tile_image_length() {
    let img = image::open(&Path::new("/home/hugh/Pictures/colour.jpg")).unwrap();

    let vec = tile_image(&img);

    assert_eq!(vec.len(), 91200);
}

#[cfg(test)]
#[test]
fn test_tile_image_first_pixel() {
    let img = image::open(&Path::new("/home/hugh/Pictures/project.jpg")).unwrap();

    let pixel = img.get_pixel(0, 0);

    let vec = tile_image(&img);

    assert_eq!(vec[0], pixel);
}

#[cfg(test)]
#[test]
fn test_tile_image_random_pixel1() {
    let img = image::open(&Path::new("/home/hugh/Pictures/project.jpg")).unwrap();

    let pixel = img.get_pixel(15, 7);

    let vec = tile_image(&img);

    assert_eq!(vec[127], pixel);
}

#[cfg(test)]
#[test]
fn test_tile_image_random_pixel2() {
    let img = image::open(&Path::new("/home/hugh/Pictures/project.jpg")).unwrap();

    let pixel = img.get_pixel(40, 16);

    let vec = tile_image(&img);

    assert_eq!(vec[6720], pixel);
}

#[cfg(test)]
#[test]
fn test_tile_image_random_pixel3() {
    let img = image::open(&Path::new("/home/hugh/Pictures/project.jpg")).unwrap();

    let pixel = img.get_pixel(15, 7);

    let vec = tile_image(&img);

    assert_eq!(vec[127], pixel);
}

#[cfg(test)]
#[test]
fn test_tile_image_last_pixel() {
    let img = image::open(&Path::new("/home/hugh/Pictures/project.jpg")).unwrap();

    let pixel = img.get_pixel(399, 399);

    let vec = tile_image(&img);

    assert_eq!(vec[159999], pixel);
}
<commit_msg>idct finished<commit_after>use std::path::Path;
use std::fs::File;
use std::f64;

use image::{ DynamicImage, GenericImage, ImageFormat };
use image;

use bitreader::BitReader;

use num_traits::float::Float;

pub struct CoverImage {
    cover_image: DynamicImage
}

impl CoverImage {
    pub fn new(file_path: &str) -> CoverImage {
        CoverImage {
            cover_image: image::open(&Path::new(&file_path)).unwrap()
        }
    }

    pub fn encode_with(&self, message: &str) {
        let bit_vector = get_bit_vec(message);

        encode(&self.cover_image, &bit_vector);

        let ref mut fout = File::create(&Path::new("/home/hugh/Pictures/yurt.png")).unwrap();

        let _ = self.cover_image.save(fout, ImageFormat::PNG).unwrap();
    }
}

// Get a Vector of Bits to Encode the Image with
fn get_bit_vec(message: &str) -> Vec<u8> {
    let mut bit_vector = Vec::new();
    let mut reader = BitReader::new(&message.as_bytes());

    // Multiplied by 8 because it's a Vec of bits not bytes
    for _ in 0..message.len() * 8 {
        bit_vector.push(reader.read_u8(1).unwrap());
    }

    bit_vector
}

// Encode the image with the Vector of Bits
fn encode(c_image: &DynamicImage, bit_vec: &Vec<u8>) {
    let mut tiled_image_vec = tile_image(&c_image);

    //let (width, height) = c_image.dimensions();

    let encoded_image = encode_image(&mut tiled_image_vec, bit_vec);
}

fn tile_image(c_image: &DynamicImage) -> Vec<image::Rgba<u8>> {
    let (width, height) = c_image.dimensions();

    let mut image_blocks = Vec::new();

    for row_index in 0..(height / 8) as u32 {
        for col_index in 0..(width / 8) as u32 {
            for row in 0..8 {
                for column in 0..8 {
                    image_blocks.push(c_image.get_pixel(column + (col_index * 8), row + (row_index * 8)));
                }
            }
        }
    }

    image_blocks
}

fn encode_image(tiled_image: &mut Vec<image::Rgba<u8>>, message: &Vec<u8>) {
    let mut cu = 0.0;
    let mut cv = 0.0;
    let mut total = 0.0;
    let mut inverse_total = 0.0;
    let mut index: usize = 0;
    let mut count = 0;
    let mut dct_coeffs: Vec<f64> = Vec::new();
    let mut idct_coeffs: Vec<f64> = Vec::new();
    let mut colour_value: u8 = 0;
    let mut freq_value: f64 = 0.0;

    let num_of_iterations = if message.len() / 3 == 0 {
                                    (message.len() / 3) as u32
                                } else {
                                    ((message.len() / 3) + 1) as u32
                                };

    for iteration in 0..num_of_iterations {
        for channel in 0..3 {

            // Forward Transform
            for v in 0..8 {
                for u in 0..8 {
                    for y in 0..8 {
                        for x in 0..8 {
                            index = u + (v * 8) + (iteration * 64) as usize;

                            colour_value = tiled_image[index].data[channel];

                            if u == 0 {
                                cu = 1.0 / 2.0.sqrt()
                            } else {
                                cu = 1.0
                            }

                            if v == 0 {
                                cv = 1.0 / 2.0.sqrt()
                            } else {
                                cv = 0.0
                            }

                            total = total + (v as f64 * f64::consts::PI * (2.0 * (y as f64) + 1.0) / 16.0).cos()
                                          * (u as f64 * f64::consts::PI * (2.0 * (x as f64) + 1.0) / 16.0).cos()
                                          * colour_value as f64;
                        }
                    }

                    // 0.25, Cu and Cv are scaling factors
                    total = total * 0.25 * cu * cv;

                    dct_coeffs.push(total);
                }
            }

            // Encode the message
            let coeff_to_mod = (27 + (iteration * 64)) as usize;

            if dct_coeffs[coeff_to_mod].trunc() % 2.0 == 0.0 {
                if message[count] == 1 {
                    dct_coeffs[coeff_to_mod] = dct_coeffs[coeff_to_mod] + 1.0
                }
            } else {
                if message[count] == 0 {
                    dct_coeffs[coeff_to_mod] = dct_coeffs[coeff_to_mod] + 1.0
                }
            }

            // Inverse Transform
            for v in 0..8 {
                for u in 0..8 {
                    for y in 0..8 {
                        for x in 0..8 {
                            index = u + (v * 8) + (iteration * 64) as usize;

                            freq_value = dct_coeffs[index];

                            if u == 0 {
                                cu = 1.0 / 2.0.sqrt()
                            } else {
                                cu = 1.0
                            }

                            if v == 0 {
                                cv = 1.0 / 2.0.sqrt()
                            } else {
                                cv = 0.0
                            }

                            inverse_total = inverse_total * cu * cv + (v as f64 * f64::consts::PI * (2.0 * (y as f64) + 1.0) / 16.0).cos()
                                                                    * (u as f64 * f64::consts::PI * (2.0 * (x as f64) + 1.0) / 16.0).cos()
                                                                    * freq_value as f64;
                        }
                    }

                    inverse_total = inverse_total * 0.25;

                    idct_coeffs.push(inverse_total);
                }
            }

            // Set modified coefficient
            let modded_coeff = (27 + (iteration * 64)) as usize;

            tiled_image[modded_coeff].data[channel];
        }
    }
}

/**************************************************************************************************
 *                                                                                *
 *                                         Tests                                                  *
 *                                                                                *
 **************************************************************************************************/

#[cfg(test)]
#[test]
fn test_get_bit_vec_len() {
    let bits = get_bit_vec("h");

    assert_eq!(8, bits.len());
}

#[cfg(test)]
#[test]
fn test_get_bit_vec() {
    let test_bits = vec![0, 1, 1, 0, 1, 0, 0, 0];
    let bits = get_bit_vec("h");

    assert_eq!(bits, test_bits);
}

#[cfg(test)]
#[test]
fn test_encode_red_channel_lsb_set() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img, &bit_vec);

    let pixel = img.get_pixel(0, 0);

    assert_eq!(pixel.data[0] % 2, bit_vec[0]);
}

#[cfg(test)]
#[test]
fn test_encode_green_channel_lsb_set() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img, &bit_vec);

    let pixel = img.get_pixel(0, 0);

    assert_eq!(pixel.data[1] % 2, bit_vec[1]);
}

#[cfg(test)]
#[test]
fn test_encode_blue_channel_lsb_set() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img, &bit_vec);

    let pixel = img.get_pixel(0, 0);

    assert_eq!(pixel.data[2] % 2 as u8, bit_vec[2]);
}

#[cfg(test)]
#[test]
fn test_full_byte_is_encoded() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let mut encoded_bit_vec = Vec::new();
    let mut count = 0;

    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img, &bit_vec);

    'outer: for x_co_ord in 0..3 {
        let pixel = img.get_pixel(x_co_ord, 0);

        for channel in 0..3 {
            if count >= 8 {
                break 'outer;
            }

            encoded_bit_vec.push(pixel.data[channel] % 2);

            count += 1;
        }
    }

    assert_eq!(encoded_bit_vec, bit_vec);
}

#[cfg(test)]
#[test]
fn test_tile_image_length() {
    let img = image::open(&Path::new("/home/hugh/Pictures/colour.jpg")).unwrap();

    let vec = tile_image(&img);

    assert_eq!(vec.len(), 91200);
}

#[cfg(test)]
#[test]
fn test_tile_image_first_pixel() {
    let img = image::open(&Path::new("/home/hugh/Pictures/project.jpg")).unwrap();

    let pixel = img.get_pixel(0, 0);

    let vec = tile_image(&img);

    assert_eq!(vec[0], pixel);
}

#[cfg(test)]
#[test]
fn test_tile_image_random_pixel1() {
    let img = image::open(&Path::new("/home/hugh/Pictures/project.jpg")).unwrap();

    let pixel = img.get_pixel(15, 7);

    let vec = tile_image(&img);

    assert_eq!(vec[127], pixel);
}

#[cfg(test)]
#[test]
fn test_tile_image_random_pixel2() {
    let img = image::open(&Path::new("/home/hugh/Pictures/project.jpg")).unwrap();

    let pixel = img.get_pixel(40, 16);

    let vec = tile_image(&img);

    assert_eq!(vec[6720], pixel);
}

#[cfg(test)]
#[test]
fn test_tile_image_random_pixel3() {
    let img = image::open(&Path::new("/home/hugh/Pictures/project.jpg")).unwrap();

    let pixel = img.get_pixel(15, 7);

    let vec = tile_image(&img);

    assert_eq!(vec[127], pixel);
}

#[cfg(test)]
#[test]
fn test_tile_image_last_pixel() {
    let img = image::open(&Path::new("/home/hugh/Pictures/project.jpg")).unwrap();

    let pixel = img.get_pixel(399, 399);

    let vec = tile_image(&img);

    assert_eq!(vec[159999], pixel);
}
<|endoftext|>


<commit_before>use std::cell::UnsafeCell;
use std::cmp;
use std::fmt;
use std::mem;
use std::mem::MaybeUninit;
use std::sync::atomic::{AtomicUsize, Ordering};

use crate::errors::InvalidThreadAccess;

fn next_thread_id() -> usize {
    static mut COUNTER: AtomicUsize = AtomicUsize::new(0);
    unsafe { COUNTER.fetch_add(1, Ordering::SeqCst) }
}

pub(crate) fn get_thread_id() -> usize {
    thread_local!(static THREAD_ID: usize = next_thread_id());
    THREAD_ID.with(|&x| x)
}

/// A `Fragile<T>` wraps a non sendable `T` to be safely send to other threads.
///
/// Once the value has been wrapped it can be sent to other threads but access
/// to the value on those threads will fail.
///
/// If the value needs destruction and the fragile wrapper is on another thread
/// the destructor will panic.  Alternatively you can use `Sticky<T>` which is
/// not going to panic but might temporarily leak the value.
pub struct Fragile<T> {
    value: MaybeUninit<UnsafeCell<Box<T>>>,
    thread_id: usize,
}

impl<T> Fragile<T> {
    /// Creates a new `Fragile` wrapping a `value`.
    ///
    /// The value that is moved into the `Fragile` can be non `Send` and
    /// will be anchored to the thread that created the object.  If the
    /// fragile wrapper type ends up being send from thread to thread
    /// only the original thread can interact with the value.
    pub fn new(value: T) -> Self {
        Fragile {
            value: MaybeUninit::new(UnsafeCell::new(Box::new(value))),
            thread_id: get_thread_id(),
        }
    }

    /// Returns `true` if the access is valid.
    ///
    /// This will be `false` if the value was sent to another thread.
    pub fn is_valid(&self) -> bool {
        get_thread_id() == self.thread_id
    }

    #[inline(always)]
    fn assert_thread(&self) {
        if !self.is_valid() {
            panic!("trying to access wrapped value in fragile container from incorrect thread.");
        }
    }

    /// Consumes the `Fragile`, returning the wrapped value.
    ///
    /// # Panics
    ///
    /// Panics if called from a different thread than the one where the
    /// original value was created.
    pub fn into_inner(mut self) -> T {
        self.assert_thread();
        unsafe {
            let rv = mem::replace(&mut self.value, MaybeUninit::uninit());
            mem::forget(self);
            *rv.assume_init().into_inner()
        }
    }

    /// Consumes the `Fragile`, returning the wrapped value if successful.
    ///
    /// The wrapped value is returned if this is called from the same thread
    /// as the one where the original value was created, otherwise the
    /// `Fragile` is returned as `Err(self)`.
    pub fn try_into_inner(self) -> Result<T, Self> {
        if get_thread_id() == self.thread_id {
            Ok(self.into_inner())
        } else {
            Err(self)
        }
    }

    /// Immutably borrows the wrapped value.
    ///
    /// # Panics
    ///
    /// Panics if the calling thread is not the one that wrapped the value.
    /// For a non-panicking variant, use [`try_get`](#method.try_get`).
    pub fn get(&self) -> &T {
        self.assert_thread();
        unsafe { &*(*self.value.as_ptr()).get() }
    }

    /// Mutably borrows the wrapped value.
    ///
    /// # Panics
    ///
    /// Panics if the calling thread is not the one that wrapped the value.
    /// For a non-panicking variant, use [`try_get_mut`](#method.try_get_mut`).
    pub fn get_mut(&mut self) -> &mut T {
        self.assert_thread();
        unsafe { &mut *(*self.value.as_ptr()).get() }
    }

    /// Tries to immutably borrow the wrapped value.
    ///
    /// Returns `None` if the calling thread is not the one that wrapped the value.
    pub fn try_get(&self) -> Result<&T, InvalidThreadAccess> {
        if get_thread_id() == self.thread_id {
            unsafe { Ok(&*(*self.value.as_ptr()).get()) }
        } else {
            Err(InvalidThreadAccess)
        }
    }

    /// Tries to mutably borrow the wrapped value.
    ///
    /// Returns `None` if the calling thread is not the one that wrapped the value.
    pub fn try_get_mut(&mut self) -> Result<&mut T, InvalidThreadAccess> {
        if get_thread_id() == self.thread_id {
            unsafe { Ok(&mut *(*self.value.as_ptr()).get()) }
        } else {
            Err(InvalidThreadAccess)
        }
    }
}

impl<T> Drop for Fragile<T> {
    fn drop(&mut self) {
        if mem::needs_drop::<T>() {
            if get_thread_id() == self.thread_id {
                unsafe {
                    let rv = mem::replace(&mut self.value, MaybeUninit::uninit());
                    rv.assume_init();
                }
            } else {
                panic!("destructor of fragile object ran on wrong thread");
            }
        }
    }
}

impl<T> From<T> for Fragile<T> {
    #[inline]
    fn from(t: T) -> Fragile<T> {
        Fragile::new(t)
    }
}

impl<T: Clone> Clone for Fragile<T> {
    #[inline]
    fn clone(&self) -> Fragile<T> {
        Fragile::new(self.get().clone())
    }
}

impl<T: Default> Default for Fragile<T> {
    #[inline]
    fn default() -> Fragile<T> {
        Fragile::new(T::default())
    }
}

impl<T: PartialEq> PartialEq for Fragile<T> {
    #[inline]
    fn eq(&self, other: &Fragile<T>) -> bool {
        *self.get() == *other.get()
    }
}

impl<T: Eq> Eq for Fragile<T> {}

impl<T: PartialOrd> PartialOrd for Fragile<T> {
    #[inline]
    fn partial_cmp(&self, other: &Fragile<T>) -> Option<cmp::Ordering> {
        self.get().partial_cmp(&*other.get())
    }

    #[inline]
    fn lt(&self, other: &Fragile<T>) -> bool {
        *self.get() < *other.get()
    }

    #[inline]
    fn le(&self, other: &Fragile<T>) -> bool {
        *self.get() <= *other.get()
    }

    #[inline]
    fn gt(&self, other: &Fragile<T>) -> bool {
        *self.get() > *other.get()
    }

    #[inline]
    fn ge(&self, other: &Fragile<T>) -> bool {
        *self.get() >= *other.get()
    }
}

impl<T: Ord> Ord for Fragile<T> {
    #[inline]
    fn cmp(&self, other: &Fragile<T>) -> cmp::Ordering {
        self.get().cmp(&*other.get())
    }
}

impl<T: fmt::Display> fmt::Display for Fragile<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::Display::fmt(self.get(), f)
    }
}

impl<T: fmt::Debug> fmt::Debug for Fragile<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self.try_get() {
            Ok(value) => f.debug_struct("Fragile").field("value", value).finish(),
            Err(..) => {
                struct InvalidPlaceholder;
                impl fmt::Debug for InvalidPlaceholder {
                    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                        f.write_str("<invalid thread>")
                    }
                }

                f.debug_struct("Fragile")
                    .field("value", &InvalidPlaceholder)
                    .finish()
            }
        }
    }
}

// this type is sync because access can only ever happy from the same thread
// that created it originally.  All other threads will be able to safely
// call some basic operations on the reference and they will fail.
unsafe impl<T> Sync for Fragile<T> {}

// The entire point of this type is to be Send
unsafe impl<T> Send for Fragile<T> {}

#[test]
fn test_basic() {
    use std::thread;
    let val = Fragile::new(true);
    assert_eq!(val.to_string(), "true");
    assert_eq!(val.get(), &true);
    assert!(val.try_get().is_ok());
    thread::spawn(move || {
        assert!(val.try_get().is_err());
    })
    .join()
    .unwrap();
}

#[test]
fn test_mut() {
    let mut val = Fragile::new(true);
    *val.get_mut() = false;
    assert_eq!(val.to_string(), "false");
    assert_eq!(val.get(), &false);
}

#[test]
#[should_panic]
fn test_access_other_thread() {
    use std::thread;
    let val = Fragile::new(true);
    thread::spawn(move || {
        val.get();
    })
    .join()
    .unwrap();
}

#[test]
fn test_noop_drop_elsewhere() {
    use std::thread;
    let val = Fragile::new(true);
    thread::spawn(move || {
        // force the move
        val.try_get().ok();
    })
    .join()
    .unwrap();
}

#[test]
fn test_panic_on_drop_elsewhere() {
    use std::sync::atomic::{AtomicBool, Ordering};
    use std::sync::Arc;
    use std::thread;
    let was_called = Arc::new(AtomicBool::new(false));
    struct X(Arc<AtomicBool>);
    impl Drop for X {
        fn drop(&mut self) {
            self.0.store(true, Ordering::SeqCst);
        }
    }
    let val = Fragile::new(X(was_called.clone()));
    assert!(thread::spawn(move || {
        val.try_get().ok();
    })
    .join()
    .is_err());
    assert_eq!(was_called.load(Ordering::SeqCst), false);
}

#[test]
fn test_rc_sending() {
    use std::rc::Rc;
    use std::sync::mpsc::channel;
    use std::thread;

    let val = Fragile::new(Rc::new(true));
    let (tx, rx) = channel();

    let thread = thread::spawn(move || {
        assert!(val.try_get().is_err());
        let here = val;
        tx.send(here).unwrap();
    });

    let rv = rx.recv().unwrap();
    assert!(**rv.get());

    thread.join().unwrap();
}
<commit_msg>Remove UnsafeCell<commit_after>use std::cmp;
use std::fmt;
use std::mem;
use std::mem::MaybeUninit;
use std::sync::atomic::{AtomicUsize, Ordering};

use crate::errors::InvalidThreadAccess;

fn next_thread_id() -> usize {
    static mut COUNTER: AtomicUsize = AtomicUsize::new(0);
    unsafe { COUNTER.fetch_add(1, Ordering::SeqCst) }
}

pub(crate) fn get_thread_id() -> usize {
    thread_local!(static THREAD_ID: usize = next_thread_id());
    THREAD_ID.with(|&x| x)
}

/// A `Fragile<T>` wraps a non sendable `T` to be safely send to other threads.
///
/// Once the value has been wrapped it can be sent to other threads but access
/// to the value on those threads will fail.
///
/// If the value needs destruction and the fragile wrapper is on another thread
/// the destructor will panic.  Alternatively you can use `Sticky<T>` which is
/// not going to panic but might temporarily leak the value.
pub struct Fragile<T> {
    value: MaybeUninit<Box<T>>,
    thread_id: usize,
}

impl<T> Fragile<T> {
    /// Creates a new `Fragile` wrapping a `value`.
    ///
    /// The value that is moved into the `Fragile` can be non `Send` and
    /// will be anchored to the thread that created the object.  If the
    /// fragile wrapper type ends up being send from thread to thread
    /// only the original thread can interact with the value.
    pub fn new(value: T) -> Self {
        Fragile {
            value: MaybeUninit::new(Box::new(value)),
            thread_id: get_thread_id(),
        }
    }

    /// Returns `true` if the access is valid.
    ///
    /// This will be `false` if the value was sent to another thread.
    pub fn is_valid(&self) -> bool {
        get_thread_id() == self.thread_id
    }

    #[inline(always)]
    fn assert_thread(&self) {
        if !self.is_valid() {
            panic!("trying to access wrapped value in fragile container from incorrect thread.");
        }
    }

    /// Consumes the `Fragile`, returning the wrapped value.
    ///
    /// # Panics
    ///
    /// Panics if called from a different thread than the one where the
    /// original value was created.
    pub fn into_inner(mut self) -> T {
        self.assert_thread();
        unsafe {
            let rv = mem::replace(&mut self.value, MaybeUninit::uninit());
            mem::forget(self);
            *rv.assume_init()
        }
    }

    /// Consumes the `Fragile`, returning the wrapped value if successful.
    ///
    /// The wrapped value is returned if this is called from the same thread
    /// as the one where the original value was created, otherwise the
    /// `Fragile` is returned as `Err(self)`.
    pub fn try_into_inner(self) -> Result<T, Self> {
        if get_thread_id() == self.thread_id {
            Ok(self.into_inner())
        } else {
            Err(self)
        }
    }

    /// Immutably borrows the wrapped value.
    ///
    /// # Panics
    ///
    /// Panics if the calling thread is not the one that wrapped the value.
    /// For a non-panicking variant, use [`try_get`](#method.try_get`).
    pub fn get(&self) -> &T {
        self.assert_thread();
        unsafe { &*self.value.as_ptr() }
    }

    /// Mutably borrows the wrapped value.
    ///
    /// # Panics
    ///
    /// Panics if the calling thread is not the one that wrapped the value.
    /// For a non-panicking variant, use [`try_get_mut`](#method.try_get_mut`).
    pub fn get_mut(&mut self) -> &mut T {
        self.assert_thread();
        unsafe { &mut *self.value.as_mut_ptr() }
    }

    /// Tries to immutably borrow the wrapped value.
    ///
    /// Returns `None` if the calling thread is not the one that wrapped the value.
    pub fn try_get(&self) -> Result<&T, InvalidThreadAccess> {
        if get_thread_id() == self.thread_id {
            unsafe { Ok(&*self.value.as_ptr()) }
        } else {
            Err(InvalidThreadAccess)
        }
    }

    /// Tries to mutably borrow the wrapped value.
    ///
    /// Returns `None` if the calling thread is not the one that wrapped the value.
    pub fn try_get_mut(&mut self) -> Result<&mut T, InvalidThreadAccess> {
        if get_thread_id() == self.thread_id {
            unsafe { Ok(&mut *self.value.as_mut_ptr()) }
        } else {
            Err(InvalidThreadAccess)
        }
    }
}

impl<T> Drop for Fragile<T> {
    fn drop(&mut self) {
        if mem::needs_drop::<T>() {
            if get_thread_id() == self.thread_id {
                unsafe {
                    let rv = mem::replace(&mut self.value, MaybeUninit::uninit());
                    rv.assume_init();
                }
            } else {
                panic!("destructor of fragile object ran on wrong thread");
            }
        }
    }
}

impl<T> From<T> for Fragile<T> {
    #[inline]
    fn from(t: T) -> Fragile<T> {
        Fragile::new(t)
    }
}

impl<T: Clone> Clone for Fragile<T> {
    #[inline]
    fn clone(&self) -> Fragile<T> {
        Fragile::new(self.get().clone())
    }
}

impl<T: Default> Default for Fragile<T> {
    #[inline]
    fn default() -> Fragile<T> {
        Fragile::new(T::default())
    }
}

impl<T: PartialEq> PartialEq for Fragile<T> {
    #[inline]
    fn eq(&self, other: &Fragile<T>) -> bool {
        *self.get() == *other.get()
    }
}

impl<T: Eq> Eq for Fragile<T> {}

impl<T: PartialOrd> PartialOrd for Fragile<T> {
    #[inline]
    fn partial_cmp(&self, other: &Fragile<T>) -> Option<cmp::Ordering> {
        self.get().partial_cmp(&*other.get())
    }

    #[inline]
    fn lt(&self, other: &Fragile<T>) -> bool {
        *self.get() < *other.get()
    }

    #[inline]
    fn le(&self, other: &Fragile<T>) -> bool {
        *self.get() <= *other.get()
    }

    #[inline]
    fn gt(&self, other: &Fragile<T>) -> bool {
        *self.get() > *other.get()
    }

    #[inline]
    fn ge(&self, other: &Fragile<T>) -> bool {
        *self.get() >= *other.get()
    }
}

impl<T: Ord> Ord for Fragile<T> {
    #[inline]
    fn cmp(&self, other: &Fragile<T>) -> cmp::Ordering {
        self.get().cmp(&*other.get())
    }
}

impl<T: fmt::Display> fmt::Display for Fragile<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::Display::fmt(self.get(), f)
    }
}

impl<T: fmt::Debug> fmt::Debug for Fragile<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self.try_get() {
            Ok(value) => f.debug_struct("Fragile").field("value", value).finish(),
            Err(..) => {
                struct InvalidPlaceholder;
                impl fmt::Debug for InvalidPlaceholder {
                    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                        f.write_str("<invalid thread>")
                    }
                }

                f.debug_struct("Fragile")
                    .field("value", &InvalidPlaceholder)
                    .finish()
            }
        }
    }
}

// this type is sync because access can only ever happy from the same thread
// that created it originally.  All other threads will be able to safely
// call some basic operations on the reference and they will fail.
unsafe impl<T> Sync for Fragile<T> {}

// The entire point of this type is to be Send
unsafe impl<T> Send for Fragile<T> {}

#[test]
fn test_basic() {
    use std::thread;
    let val = Fragile::new(true);
    assert_eq!(val.to_string(), "true");
    assert_eq!(val.get(), &true);
    assert!(val.try_get().is_ok());
    thread::spawn(move || {
        assert!(val.try_get().is_err());
    })
    .join()
    .unwrap();
}

#[test]
fn test_mut() {
    let mut val = Fragile::new(true);
    *val.get_mut() = false;
    assert_eq!(val.to_string(), "false");
    assert_eq!(val.get(), &false);
}

#[test]
#[should_panic]
fn test_access_other_thread() {
    use std::thread;
    let val = Fragile::new(true);
    thread::spawn(move || {
        val.get();
    })
    .join()
    .unwrap();
}

#[test]
fn test_noop_drop_elsewhere() {
    use std::thread;
    let val = Fragile::new(true);
    thread::spawn(move || {
        // force the move
        val.try_get().ok();
    })
    .join()
    .unwrap();
}

#[test]
fn test_panic_on_drop_elsewhere() {
    use std::sync::atomic::{AtomicBool, Ordering};
    use std::sync::Arc;
    use std::thread;
    let was_called = Arc::new(AtomicBool::new(false));
    struct X(Arc<AtomicBool>);
    impl Drop for X {
        fn drop(&mut self) {
            self.0.store(true, Ordering::SeqCst);
        }
    }
    let val = Fragile::new(X(was_called.clone()));
    assert!(thread::spawn(move || {
        val.try_get().ok();
    })
    .join()
    .is_err());
    assert_eq!(was_called.load(Ordering::SeqCst), false);
}

#[test]
fn test_rc_sending() {
    use std::rc::Rc;
    use std::sync::mpsc::channel;
    use std::thread;

    let val = Fragile::new(Rc::new(true));
    let (tx, rx) = channel();

    let thread = thread::spawn(move || {
        assert!(val.try_get().is_err());
        let here = val;
        tx.send(here).unwrap();
    });

    let rv = rx.recv().unwrap();
    assert!(**rv.get());

    thread.join().unwrap();
}
<|endoftext|>


<commit_before>extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;

#[proc_macro_derive(RawSerialize)]
pub fn raw_serialize_gen(input: TokenStream) -> TokenStream {
    // Construct a string representation of the type definition
    let s = input.to_string();

    // Parse the string representation
    let ast = syn::parse_macro_input(&s).unwrap();

    // Build the impl
    let gen = impl_raw_serialize(&ast);

    // Return the generated impl
    gen.parse().unwrap()
}

fn impl_raw_serialize(ast: &syn::MacroInput) -> quote::Tokens {
    match ast.body {
        syn::Body::Struct(syn::VariantData::Struct(ref data)) => {
            impl_raw_serialize_struct(data.clone(), ast)
        },
        syn::Body::Struct(syn::VariantData::Tuple(ref data)) => {
            impl_raw_serialize_tuple(data.clone(), ast)
        },
        _ => {
            panic!("Enums are not yet supported");
        }
    }
}

fn impl_raw_serialize_struct(data: Vec<syn::Field>, ast: &syn::MacroInput) -> quote::Tokens {
    let name = &ast.ident;
    for x in data.iter() {
        use syn::Ty::*;
        match x.ty {
            Rptr(_, _)  => panic!("Reference types are not supported ({:?} is a reference type)", x),
            Ptr(_)      => panic!("Pointer types are not supported ({:?} is a reference type)", x),
            BareFn(_)   => panic!("Functions cannot be serialized ({:?} is a bare function type)", x),
            _ => {}
        };
    }

    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
    let data_ty = data.into_iter().map(|x| x.ident.unwrap()).collect::<Vec<syn::Ident>>();
    let ret = quote! {
        impl #impl_generics RawSerialize #ty_generics for #name #where_clause {
            fn raw_serialize(&self, to: &mut std::io::Write) -> Result<u64, std::io::Error> {
                let mut size = 0;
                #( let size_x; check!(self.#data_ty.raw_serialize(to), size_x); size += size_x; )*
                Ok(size)
            }
        }
    };
    println!("sestr: {:?}", ret);
    ret
}

fn impl_raw_serialize_tuple(data: Vec<syn::Field>, ast: &syn::MacroInput) -> quote::Tokens {
    let name = &ast.ident;
    for x in data.iter() {
        use syn::Ty::*;
        match x.ty {
            Rptr(_, _)  => panic!("Reference types are not supported ({:?} is a reference type)", x),
            Ptr(_)      => panic!("Pointer types are not supported ({:?} is a reference type)", x),
            BareFn(_)   => panic!("Functions cannot be serialized ({:?} is a bare function type)", x),
            _ => {}
        };
    }

    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();

    let x = (0..data.len()).map(|x| syn::Ident::new(x.to_string())).collect::<Vec<syn::Ident>>();

    let ret = quote! {
        impl #impl_generics RawSerialize #ty_generics for #name #where_clause {
            fn raw_serialize(&self, to: &mut std::io::Write) -> Result<u64, std::io::Error> {
                let mut size = 0;
                #( let size_x; check!(self.#x.raw_serialize(to), size_x); size += size_x; )*
                Ok(size)
            }
        }
    };
    println!("setup: {:?}", ret);
    ret
}

#[proc_macro_derive(RawDeserialize)]
pub fn raw_deserialize_gen(input: TokenStream) -> TokenStream {
    // Construct a string representation of the type definition
    let s = input.to_string();

    // Parse the string representation
    let ast = syn::parse_macro_input(&s).unwrap();

    // Build the impl
    let gen = impl_raw_deserialize(&ast);

    // Return the generated impl
    gen.parse().unwrap()
}

fn impl_raw_deserialize(ast: &syn::MacroInput) -> quote::Tokens {
    match ast.body {
        syn::Body::Struct(syn::VariantData::Struct(ref data)) => {
            impl_raw_deserialize_struct(data.clone(), ast)
        },
        syn::Body::Struct(syn::VariantData::Tuple(ref data)) => {
            impl_raw_deserialize_tuple(data.clone(), ast)
        },
        _ => {
            panic!("Enums are not yet supported");
        }
    }
}

fn impl_raw_deserialize_struct(data: Vec<syn::Field>, ast: &syn::MacroInput) -> quote::Tokens {
    let name = &ast.ident;
    let mut data_fields: Vec<syn::Ident> = vec![];
    let mut data_ty: Vec<syn::Ty> = vec![];

    for x in data {
        use syn::Ty::*;
        match x.ty {
            Rptr(_, _)  => panic!("Reference types are not supported ({:?} is a reference type)", x),
            Ptr(_)      => panic!("Pointer types are not supported ({:?} is a reference type)", x),
            BareFn(_)   => panic!("Functions cannot be serialized ({:?} is a bare function type)", x),
            _ => {}
        };
        data_fields.push(x.ident.clone().unwrap());
        data_ty.push(x.ty.clone());
    }

    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
    let dclone_1 = data_fields.clone();
    let dclone_2 = data_fields.clone();
    let dclone_3 = data_fields.clone();
    let ret = quote! {
        impl #impl_generics RawDeserialize #ty_generics for #name #where_clause {
            fn raw_deserialize(from: &mut std::io::Read) -> Result<#name, std::io::Error> {
                #(
                    let #dclone_1;
                    check!(#data_ty::raw_deserialize(from), #dclone_2);
                )*
                Ok(#name {
                    #(#dclone_3: #data_fields),*
                })
            }
        }
    };
    ret
}

fn impl_raw_deserialize_tuple(data: Vec<syn::Field>, ast: &syn::MacroInput) -> quote::Tokens {
    let name = &ast.ident;
    let mut data_ty: Vec<syn::Ty> = vec![];

    for x in data.iter() {
        use syn::Ty::*;
        match x.ty {
            Rptr(_, _)  => panic!("Reference types are not supported ({:?} is a reference type)", x),
            Ptr(_)      => panic!("Pointer types are not supported ({:?} is a reference type)", x),
            BareFn(_)   => panic!("Functions cannot be serialized ({:?} is a bare function type)", x),
            _ => {}
        };
        data_ty.push(x.ty.clone());
    }

    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();

    let data_fields = (0..data.len()).map(|x| syn::Ident::new("__field_".to_string() + x.to_string().as_str())).collect::<Vec<syn::Ident>>();
    let dclone_1 = data_fields.clone();
    let dclone_2 = data_fields.clone();
    let dclone_3 = data_fields.clone();
    let ret = quote! {
        impl #impl_generics RawDeserialize #ty_generics for #name #where_clause {
            fn raw_deserialize(from: &mut std::io::Read) -> Result<#name, std::io::Error> {
                #(
                    let #dclone_1;
                    check!(#data_ty::raw_deserialize(from), #dclone_2);
                )*
                Ok(#name(
                    #(#dclone_3),*
                ))
            }
        }
    };
    println!("detup: {:?}", ret);
    ret
}
<commit_msg>Fixed serialization of arrays and tuples<commit_after>extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;

#[proc_macro_derive(RawSerialize)]
pub fn raw_serialize_gen(input: TokenStream) -> TokenStream {
    // Construct a string representation of the type definition
    let s = input.to_string();

    // Parse the string representation
    let ast = syn::parse_macro_input(&s).unwrap();

    // Build the impl
    let gen = impl_raw_serialize(&ast);

    // Return the generated impl
    gen.parse().unwrap()
}

fn impl_raw_serialize(ast: &syn::MacroInput) -> quote::Tokens {
    match ast.body {
        syn::Body::Struct(syn::VariantData::Struct(ref data)) => {
            impl_raw_serialize_struct(data.clone(), ast)
        },
        syn::Body::Struct(syn::VariantData::Tuple(ref data)) => {
            impl_raw_serialize_tuple(data.clone(), ast)
        },
        _ => {
            panic!("Enums are not yet supported");
        }
    }
}

fn impl_raw_serialize_struct(data: Vec<syn::Field>, ast: &syn::MacroInput) -> quote::Tokens {
    let name = &ast.ident;
    for x in data.iter() {
        use syn::Ty::*;
        match x.ty {
            Rptr(_, _)  => panic!("Reference types are not supported ({:?} is a reference type)", x),
            Ptr(_)      => panic!("Pointer types are not supported ({:?} is a reference type)", x),
            BareFn(_)   => panic!("Functions cannot be serialized ({:?} is a bare function type)", x),
            _ => {}
        };
    }

    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
    let data_ty = data.into_iter().map(|x| x.ident.unwrap()).collect::<Vec<syn::Ident>>();
    let ret = quote! {
        impl #impl_generics RawSerialize #ty_generics for #name #where_clause {
            fn raw_serialize(&self, to: &mut std::io::Write) -> Result<u64, std::io::Error> {
                let mut size = 0;
                #( let size_x; check!(self.#data_ty.raw_serialize(to), size_x); size += size_x; )*
                Ok(size)
            }
        }
    };
    ret
}

fn impl_raw_serialize_tuple(data: Vec<syn::Field>, ast: &syn::MacroInput) -> quote::Tokens {
    let name = &ast.ident;
    for x in data.iter() {
        use syn::Ty::*;
        match x.ty {
            Rptr(_, _)  => panic!("Reference types are not supported ({:?} is a reference type)", x),
            Ptr(_)      => panic!("Pointer types are not supported ({:?} is a reference type)", x),
            BareFn(_)   => panic!("Functions cannot be serialized ({:?} is a bare function type)", x),
            _ => {}
        };
    }

    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();

    let x = (0..data.len()).map(|x| syn::Ident::new(x.to_string())).collect::<Vec<syn::Ident>>();

    let ret = quote! {
        impl #impl_generics RawSerialize #ty_generics for #name #where_clause {
            fn raw_serialize(&self, to: &mut std::io::Write) -> Result<u64, std::io::Error> {
                let mut size = 0;
                #( let size_x; check!(self.#x.raw_serialize(to), size_x); size += size_x; )*
                Ok(size)
            }
        }
    };
    ret
}

#[proc_macro_derive(RawDeserialize)]
pub fn raw_deserialize_gen(input: TokenStream) -> TokenStream {
    // Construct a string representation of the type definition
    let s = input.to_string();

    // Parse the string representation
    let ast = syn::parse_macro_input(&s).unwrap();

    // Build the impl
    let gen = impl_raw_deserialize(&ast);

    // Return the generated impl
    gen.parse().unwrap()
}

fn impl_raw_deserialize(ast: &syn::MacroInput) -> quote::Tokens {
    match ast.body {
        syn::Body::Struct(syn::VariantData::Struct(ref data)) => {
            impl_raw_deserialize_struct(data.clone(), ast)
        },
        syn::Body::Struct(syn::VariantData::Tuple(ref data)) => {
            impl_raw_deserialize_tuple(data.clone(), ast)
        },
        _ => {
            panic!("Enums are not yet supported");
        }
    }
}

fn impl_raw_deserialize_struct(data: Vec<syn::Field>, ast: &syn::MacroInput) -> quote::Tokens {
    let name = &ast.ident;
    let mut data_fields: Vec<syn::Ident> = vec![];
    let mut data_ty: Vec<syn::Ty> = vec![];

    for x in data {
        use syn::Ty::*;
        match x.ty {
            Rptr(_, _)  => panic!("Reference types are not supported ({:?} is a reference type)", x),
            Ptr(_)      => panic!("Pointer types are not supported ({:?} is a reference type)", x),
            BareFn(_)   => panic!("Functions cannot be serialized ({:?} is a bare function type)", x),
            _ => {}
        };
        data_fields.push(x.ident.clone().unwrap());
        data_ty.push(x.ty.clone());
    }

    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
    let dclone_1 = data_fields.clone();
    let dclone_2 = data_fields.clone();
    let dclone_3 = data_fields.clone();
    let dclone_4 = data_fields.clone();

    let ret = quote! {
        impl #impl_generics RawDeserialize #ty_generics for #name #where_clause {
            fn raw_deserialize(from: &mut std::io::Read) -> Result<#name, std::io::Error> {
                #(
                    let #dclone_1;
                    {
                        type __T = #data_ty;
                        check!(__T::raw_deserialize(from), #dclone_2);
                    }
                )*
                Ok(#name {
                    #(#dclone_3: #data_fields),*
                })
            }
        }
    };
    ret
}

fn impl_raw_deserialize_tuple(data: Vec<syn::Field>, ast: &syn::MacroInput) -> quote::Tokens {
    let name = &ast.ident;
    let mut data_ty: Vec<syn::Ty> = vec![];

    for x in data.iter() {
        use syn::Ty::*;
        match x.ty {
            Rptr(_, _)  => panic!("Reference types are not supported ({:?} is a reference type)", x),
            Ptr(_)      => panic!("Pointer types are not supported ({:?} is a reference type)", x),
            BareFn(_)   => panic!("Functions cannot be serialized ({:?} is a bare function type)", x),
            _ => {}
        };
        data_ty.push(x.ty.clone());
    }

    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();

    let data_fields = (0..data.len()).map(|x| syn::Ident::new("__field_".to_string() + x.to_string().as_str())).collect::<Vec<syn::Ident>>();
    let dclone_1 = data_fields.clone();
    let dclone_2 = data_fields.clone();
    let dclone_3 = data_fields.clone();
    let ret = quote! {
        impl #impl_generics RawDeserialize #ty_generics for #name #where_clause {
            fn raw_deserialize(from: &mut std::io::Read) -> Result<#name, std::io::Error> {
                #(
                    let #dclone_1;
                    {
                        type __T = #data_ty;
                        check!(__T::raw_deserialize(from), #dclone_2);
                    }
                )*
                Ok(#name(
                    #(#dclone_3),*
                ))
            }
        }
    };
    println!("detup: {:?}", ret);
    ret
}
<|endoftext|>