<commit_before>use std::marker::PhantomData;
use super::context::Context;
use super::vertex_data::{VertexData, VertexBytes, VertexAttribBinder};
use super::index_data::{IndexData, IndexDatum};
use super::buffer::{Buffer, BufferBinding,
                    ArrayBufferBinding, ElementArrayBufferBinding};
use super::types::DrawingMode;

pub struct VertexBuffer<T: VertexData> {
    pub attrib_binder: Option<T::Binder>,
    buffer: Buffer,
    count: usize,
    phantom: PhantomData<*const T>
}

impl<T: VertexData> VertexBuffer<T> {
    pub fn build_attrib_binder(&self)
        -> <T::Binder as VertexAttribBinder>::Builder
    {
        T::build_attrib_binder()
    }

    pub fn bind(&self, gl_buffer: &ArrayBufferBinding) -> Result<(), ()> {
        match self.attrib_binder {
            Some(ref binder) => {
                binder.bind(gl_buffer);
                Ok(())
            },
            None => { Err(()) }
        }
    }

    pub fn buffer(&self) -> &Buffer {
        &self.buffer
    }

    pub fn buffer_mut(&mut self) -> &mut Buffer {
        &mut self.buffer
    }
}

pub struct VertexBufferBinding<'a, T: VertexData>
    where T: 'a, T::Binder: 'a
{
    gl_buffer: ArrayBufferBinding<'a>,
    vbo: &'a mut VertexBuffer<T>
}

impl<'a, T: VertexData> VertexBufferBinding<'a, T>
    where T: 'a, T::Binder: 'a
{
    pub fn new(gl_buffer: ArrayBufferBinding<'a>, vbo: &'a mut VertexBuffer<T>)
        -> Self
    {
        VertexBufferBinding {
            gl_buffer: gl_buffer,
            vbo: vbo
        }
    }

    pub fn buffer_data(&mut self, data: &[T], usage: super::BufferDataUsage)
        where [T]: VertexBytes
    {
        self.vbo.count = data.len();
        self.gl_buffer.buffer_bytes(data.vertex_bytes(), usage);
    }

    pub fn draw_arrays_range(&self,
                             mode: DrawingMode,
                             start: u32,
                             length: usize)
    {
        debug_assert!((start as usize) + length <= self.vbo.count);

        unsafe {
            self.gl_buffer.draw_arrays_range(mode, start, length);
        }
    }

    pub fn draw_arrays(&self, mode: DrawingMode) {
        unsafe {
            self.gl_buffer.draw_arrays_range(mode, 0, self.vbo.count);
        }
    }
}

impl Context {
    pub fn new_vertex_buffer<T: VertexData>(&self) -> VertexBuffer<T> {
        VertexBuffer {
            attrib_binder: None,
            buffer: self.gen_buffer(),
            count: 0,
            phantom: PhantomData
        }
    }
}

pub struct IndexBuffer<T: IndexDatum> {
    buffer: Buffer,
    count: usize,
    phantom: PhantomData<*const T>
}

impl<T: IndexDatum> IndexBuffer<T> {
    pub fn buffer(&self) -> &Buffer {
        &self.buffer
    }

    pub fn buffer_mut(&mut self) -> &mut Buffer {
        &mut self.buffer
    }
}

pub struct IndexBufferBinding<'a, T: IndexDatum + 'a> {
    gl_buffer: ElementArrayBufferBinding<'a>,
    ibo: &'a mut IndexBuffer<T>
}

impl<'a, T: IndexDatum + 'a> IndexBufferBinding<'a, T> {
    pub fn new(gl_buffer: ElementArrayBufferBinding<'a>,
               ibo: &'a mut IndexBuffer<T>)
        -> Self
    {
        IndexBufferBinding {
            gl_buffer: gl_buffer,
            ibo: ibo
        }
    }

    pub fn buffer_data(&mut self, data: &[T], usage: super::BufferDataUsage)
        where [T]: IndexData
    {
        self.ibo.count = data.len();
        self.gl_buffer.buffer_bytes(data.index_bytes(), usage);
    }
}

impl Context {
    pub fn new_index_buffer<T: IndexDatum>(&self) -> IndexBuffer<T> {
        IndexBuffer {
            buffer: self.gen_buffer(),
            count: 0,
            phantom: PhantomData
        }
    }
}

#[macro_export]
macro_rules! bind_attrib_pointers {
    ($gl:expr, $vbo:expr, {
        $($field_name:ident => $field_attrib:expr),*
    }) => {
        {
            let vbo = $vbo;
            let binder = vbo.build_attrib_binder()
                            $(.$field_name($field_attrib))*
                            .unwrap($gl);
            vbo.attrib_binder = Some(binder)
        }
    }
}

#[macro_export]
macro_rules! bind_vertex_buffer {
    ($gl:expr, $vbo:expr) => {
        {
            let vbo = $vbo;

            let gl_buffer = bind_array_buffer!($gl, vbo.buffer_mut());
            vbo.bind(&gl_buffer).unwrap();
            $crate::VertexBufferBinding::new(gl_buffer, vbo)
        }
    }
}

#[macro_export]
macro_rules! bind_index_buffer {
    ($gl:expr, $ibo:expr) => {
        {
            let ibo = $ibo;

            let gl_buffer = bind_element_array_buffer!($gl, ibo.buffer_mut());
            $crate::IndexBufferBinding::new(gl_buffer, ibo)
        }
    }
}
<commit_msg>Add `VertexBufferBinding.draw_n_elements()`<commit_after>use std::marker::PhantomData;
use super::context::Context;
use super::vertex_data::{VertexData, VertexBytes, VertexAttribBinder};
use super::index_data::{IndexData, IndexDatum};
use super::buffer::{Buffer, BufferBinding,
                    ArrayBufferBinding, ElementArrayBufferBinding};
use super::types::DrawingMode;

pub struct VertexBuffer<T: VertexData> {
    pub attrib_binder: Option<T::Binder>,
    buffer: Buffer,
    count: usize,
    phantom: PhantomData<*const T>
}

impl<T: VertexData> VertexBuffer<T> {
    pub fn build_attrib_binder(&self)
        -> <T::Binder as VertexAttribBinder>::Builder
    {
        T::build_attrib_binder()
    }

    pub fn bind(&self, gl_buffer: &ArrayBufferBinding) -> Result<(), ()> {
        match self.attrib_binder {
            Some(ref binder) => {
                binder.bind(gl_buffer);
                Ok(())
            },
            None => { Err(()) }
        }
    }

    pub fn buffer(&self) -> &Buffer {
        &self.buffer
    }

    pub fn buffer_mut(&mut self) -> &mut Buffer {
        &mut self.buffer
    }
}

pub struct VertexBufferBinding<'a, T: VertexData>
    where T: 'a, T::Binder: 'a
{
    gl_buffer: ArrayBufferBinding<'a>,
    vbo: &'a mut VertexBuffer<T>
}

impl<'a, T: VertexData> VertexBufferBinding<'a, T>
    where T: 'a, T::Binder: 'a
{
    pub fn new(gl_buffer: ArrayBufferBinding<'a>, vbo: &'a mut VertexBuffer<T>)
        -> Self
    {
        VertexBufferBinding {
            gl_buffer: gl_buffer,
            vbo: vbo
        }
    }

    pub fn buffer_data(&mut self, data: &[T], usage: super::BufferDataUsage)
        where [T]: VertexBytes
    {
        self.vbo.count = data.len();
        self.gl_buffer.buffer_bytes(data.vertex_bytes(), usage);
    }

    pub fn draw_arrays_range(&self,
                             mode: DrawingMode,
                             start: u32,
                             length: usize)
    {
        debug_assert!((start as usize) + length <= self.vbo.count);

        unsafe {
            self.gl_buffer.draw_arrays_range(mode, start, length);
        }
    }

    pub fn draw_arrays(&self, mode: DrawingMode) {
        unsafe {
            self.gl_buffer.draw_arrays_range(mode, 0, self.vbo.count);
        }
    }

    pub fn draw_n_elements<I>(&self,
                              mode: DrawingMode,
                              count: usize,
                              indicies: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        unsafe {
            self.gl_buffer.draw_n_elements(mode, count, indicies);
        }
    }
}

impl Context {
    pub fn new_vertex_buffer<T: VertexData>(&self) -> VertexBuffer<T> {
        VertexBuffer {
            attrib_binder: None,
            buffer: self.gen_buffer(),
            count: 0,
            phantom: PhantomData
        }
    }
}

pub struct IndexBuffer<T: IndexDatum> {
    buffer: Buffer,
    count: usize,
    phantom: PhantomData<*const T>
}

impl<T: IndexDatum> IndexBuffer<T> {
    pub fn buffer(&self) -> &Buffer {
        &self.buffer
    }

    pub fn buffer_mut(&mut self) -> &mut Buffer {
        &mut self.buffer
    }
}

pub struct IndexBufferBinding<'a, T: IndexDatum + 'a> {
    gl_buffer: ElementArrayBufferBinding<'a>,
    ibo: &'a mut IndexBuffer<T>
}

impl<'a, T: IndexDatum + 'a> IndexBufferBinding<'a, T> {
    pub fn new(gl_buffer: ElementArrayBufferBinding<'a>,
               ibo: &'a mut IndexBuffer<T>)
        -> Self
    {
        IndexBufferBinding {
            gl_buffer: gl_buffer,
            ibo: ibo
        }
    }

    pub fn buffer_data(&mut self, data: &[T], usage: super::BufferDataUsage)
        where [T]: IndexData
    {
        self.ibo.count = data.len();
        self.gl_buffer.buffer_bytes(data.index_bytes(), usage);
    }
}

impl Context {
    pub fn new_index_buffer<T: IndexDatum>(&self) -> IndexBuffer<T> {
        IndexBuffer {
            buffer: self.gen_buffer(),
            count: 0,
            phantom: PhantomData
        }
    }
}

#[macro_export]
macro_rules! bind_attrib_pointers {
    ($gl:expr, $vbo:expr, {
        $($field_name:ident => $field_attrib:expr),*
    }) => {
        {
            let vbo = $vbo;
            let binder = vbo.build_attrib_binder()
                            $(.$field_name($field_attrib))*
                            .unwrap($gl);
            vbo.attrib_binder = Some(binder)
        }
    }
}

#[macro_export]
macro_rules! bind_vertex_buffer {
    ($gl:expr, $vbo:expr) => {
        {
            let vbo = $vbo;

            let gl_buffer = bind_array_buffer!($gl, vbo.buffer_mut());
            vbo.bind(&gl_buffer).unwrap();
            $crate::VertexBufferBinding::new(gl_buffer, vbo)
        }
    }
}

#[macro_export]
macro_rules! bind_index_buffer {
    ($gl:expr, $ibo:expr) => {
        {
            let ibo = $ibo;

            let gl_buffer = bind_element_array_buffer!($gl, ibo.buffer_mut());
            $crate::IndexBufferBinding::new(gl_buffer, ibo)
        }
    }
}
<|endoftext|>


<commit_before>use std::borrow::BorrowMut;
use std::marker::PhantomData;
use std::collections::{HashMap, HashSet};
use context::ContextOf;
use framebuffer::FramebufferBinding;
use program::ProgramAttrib;
use vertex_data::{VertexData, VertexBytes, VertexAttribute};
use index_data::{IndexData, IndexDatum};
use buffer::{Buffer, BufferBinderOf, BufferBinding,
             ArrayBufferBinder, ArrayBufferBinding,
             ElementArrayBufferBinding, ElementArrayBufferContext};
use types::DrawingMode;

#[derive(Debug)]
pub enum AttribAddError {
    DuplicateAttrib(String)
}

#[derive(Debug)]
pub struct AttribError {
    missing_attribs: Vec<String>,
    unknown_attribs: Vec<String>
}

pub struct AttribBinder {
    attribs: HashMap<String, ProgramAttrib>
}

impl AttribBinder {
    pub fn new() -> Self {
        AttribBinder {
            attribs: HashMap::new()
        }
    }

    pub fn add(&mut self, name: &str, attrib: ProgramAttrib)
        -> Result<(), AttribAddError>
    {
        match self.attribs.insert(name.into(), attrib) {
            None => Ok(()),
            Some(_) => Err(AttribAddError::DuplicateAttrib(name.into()))
        }
    }

    fn for_each<T, F>(&self, mut f: F) -> Result<(), AttribError>
        where T: VertexData, F: FnMut(VertexAttribute, ProgramAttrib)
    {
        // TODO: Avoid heap allocations
        // TODO: Avoid redundant calls to T::visit_attributes
        let mut attribs =
            HashMap::<String, (VertexAttribute, ProgramAttrib)>::new();
        let mut missing = Vec::<String>::new();

        T::visit_attributes(|vertex_attrib| {
            match self.attribs.get(&vertex_attrib.name) {
                Some(program_attrib) => {
                    let pair = (vertex_attrib.clone(), *program_attrib);
                    attribs.insert(vertex_attrib.name, pair);
                },
                None => {
                    missing.push(vertex_attrib.name);
                }
            }
        });

        let unknown: Vec<_> = {
            let expected: HashSet<_> = self.attribs.keys().collect();
            let actual: HashSet<_> = attribs.keys().collect();
            expected.difference(&actual).cloned().cloned().collect()
        };

        if missing.is_empty() && unknown.is_empty() {
            for (_, (vertex_attrib, program_attrib)) in attribs.into_iter() {
                f(vertex_attrib, program_attrib);
            }
            Ok(())
        }
        else {
            Err(AttribError {
                missing_attribs: missing,
                unknown_attribs: unknown
            })
        }
    }

    pub fn enable<V, B, F, P, R, T>(&self, gl: &ContextOf<B, F, P, R, T>)
        -> Result<(), AttribError>
        where V: VertexData
    {
        self.for_each::<V, _>(|_, program_attrib| {
            gl.enable_vertex_attrib_array(program_attrib);
        })
    }

    pub fn bind<V: VertexData>(&self, gl_buffer: &ArrayBufferBinding)
        -> Result<(), AttribError>
    {
        self.for_each::<V, _>(|vertex_attrib, program_attrib| {
            unsafe {
                gl_buffer.vertex_attrib_pointer(
                    program_attrib,
                    vertex_attrib.ty.components,
                    vertex_attrib.ty.data,
                    vertex_attrib.ty.normalize,
                    vertex_attrib.stride,
                    vertex_attrib.offset
                );
            }
        })
    }
}

#[derive(Debug)]
pub enum VertexBindError {
    BindingError(AttribError),
    NoAttributeBindings
}

impl From<AttribError> for VertexBindError {
    fn from(attrib_error: AttribError) -> VertexBindError {
        VertexBindError::BindingError(attrib_error)
    }
}

pub struct VertexBuffer<T: VertexData> {
    attrib_binder: Option<AttribBinder>,
    buffer: Buffer,
    count: usize,
    phantom: PhantomData<*const T>
}

impl<V: VertexData> VertexBuffer<V> {
    pub fn bind_attrib_pointers(&mut self, binder: AttribBinder) {
        self.attrib_binder = Some(binder);
    }

    pub fn bind<BA, BE, F, P, R, T>(&mut self,
                                    gl: ContextOf<BufferBinderOf<BA, BE>,
                                                  F,
                                                  P,
                                                  R,
                                                  T>)
        -> Result<(), VertexBindError>
        where BA: BorrowMut<ArrayBufferBinder>
    {
        match self.attrib_binder {
            Some(ref binder) => {
                let (mut ba_binder, mut gl) = gl.split_array_buffer();
                let mut ba_binder = ba_binder.borrow_mut();
                let gl_buffer = ba_binder.bind(&mut self.buffer);
                try!(binder.enable::<V, _, _, _, _, _>(&mut gl));
                try!(binder.bind::<V>(&gl_buffer));
                Ok(())
            },
            None => { Err(VertexBindError::NoAttributeBindings) }
        }
    }

    pub fn buffer(&self) -> &Buffer {
        &self.buffer
    }

    pub fn buffer_mut(&mut self) -> &mut Buffer {
        &mut self.buffer
    }
}

pub struct VertexBufferBinding<'a, T: VertexData + 'a> {
    gl_buffer: ArrayBufferBinding<'a>,
    count: &'a mut usize,
    _phantom: PhantomData<*const VertexBuffer<T>>
}

impl<'a, T: VertexData + 'a> VertexBufferBinding<'a, T> {
    pub fn buffer_data(&mut self, data: &[T], usage: super::BufferDataUsage)
        where [T]: VertexBytes
    {
        *self.count = data.len();
        self.gl_buffer.buffer_bytes(data.vertex_bytes(), usage);
    }
}

impl<'a> FramebufferBinding<'a> {
    pub fn draw_arrays_range_vbo<V>(&mut self,
                                    gl_vbo: &VertexBufferBinding<V>,
                                    mode: DrawingMode,
                                    start: u32,
                                    length: usize)
        where V: VertexData
    {
        debug_assert!((start as usize) + length <= *gl_vbo.count);

        unsafe {
            self.draw_arrays_range(&gl_vbo.gl_buffer, mode, start, length);
        }
    }

    pub fn draw_arrays_vbo<V>(&mut self,
                              gl_vbo: &VertexBufferBinding<V>,
                              mode: DrawingMode)
        where V: VertexData
    {
        unsafe {
            self.draw_arrays_range(&gl_vbo.gl_buffer,
                                   mode,
                                   0,
                                   *gl_vbo.count);
        }
    }

    pub fn draw_n_elements_buffered_vbo<V, I>(&mut self,
                                              gl_vbo: &VertexBufferBinding<V>,
                                              gl_ibo: &IndexBufferBinding<I>,
                                              mode: DrawingMode,
                                              length: usize)
        where V: VertexData, I: IndexDatum
    {
        debug_assert!(length <= *gl_ibo.count);

        unsafe {
            self.draw_n_elements_buffered(&gl_vbo.gl_buffer,
                                          &gl_ibo.gl_buffer,
                                          mode,
                                          length,
                                          I::index_datum_type());
        }
    }

    pub fn draw_elements_buffered_vbo<V, I>(&mut self,
                                            gl_vbo: &VertexBufferBinding<V>,
                                            gl_ibo: &IndexBufferBinding<I>,
                                            mode: DrawingMode)
        where V: VertexData, I: IndexDatum
    {
        unsafe {
            self.draw_n_elements_buffered(&gl_vbo.gl_buffer,
                                          &gl_ibo.gl_buffer,
                                          mode,
                                          *gl_ibo.count,
                                          I::index_datum_type());
        }
    }

    pub fn draw_n_elements_vbo<V, I>(&mut self,
                                     gl_vbo: &VertexBufferBinding<'a, V>,
                                     mode: DrawingMode,
                                     count: usize,
                                     indices: &[I])
        where V: VertexData, I: IndexDatum, [I]: IndexData
    {
        unsafe {
            self.draw_n_elements(&gl_vbo.gl_buffer, mode, count, indices);
        }
    }

    pub fn draw_elements_vbo<V, I>(&mut self,
                                   gl_vbo: &VertexBufferBinding<'a, V>,
                                   mode: DrawingMode,
                                   indices: &[I])
        where V: VertexData, I: IndexDatum, [I]: IndexData
    {
        unsafe {
            self.draw_elements(&gl_vbo.gl_buffer, mode, indices);
        }
    }
}

impl<B, F, P, R, T> ContextOf<B, F, P, R, T> {
    pub fn new_vertex_buffer<V: VertexData>(&self) -> VertexBuffer<V> {
        VertexBuffer {
            attrib_binder: None,
            buffer: self.gen_buffer(),
            count: 0,
            phantom: PhantomData
        }
    }
}

pub trait VertexBufferContext {
    type Rest;

    fn bind_vertex_buffer<'a, V>(self, vbo: &'a mut VertexBuffer<V>)
        -> (VertexBufferBinding<V>, Self::Rest)
        where V: VertexData;
}

// TODO: Refactor to work with less restrictive generic params
impl<BA, BE, F, P, R, T> VertexBufferContext
    for ContextOf<BufferBinderOf<BA, BE>, F, P, R, T>
    where BA: BorrowMut<ArrayBufferBinder>
{
    type Rest = ContextOf<BufferBinderOf<(), BE>, F, P, R, T>;

    fn bind_vertex_buffer<'a, V>(mut self, vbo: &'a mut VertexBuffer<V>)
        -> (VertexBufferBinding<V>, Self::Rest)
        where V: VertexData
    {
        {
            let gl = self.borrowed_mut().map_buffers(|b| b.borrowed_mut());

            vbo.bind(gl).unwrap();
        }
        let (mut ba_binder, rest) = self.split_array_buffer();
        let mut ba_binder = ba_binder.borrow_mut();
        let gl_array_buffer = ba_binder.bind(&mut vbo.buffer);
        (
            VertexBufferBinding {
                gl_buffer: gl_array_buffer,
                count: &mut vbo.count,
                _phantom: PhantomData
            },
            rest
        )
    }
}

pub trait IndexBufferContext {
    type Rest;

    fn bind_index_buffer<'a, I>(self, ibo: &'a mut IndexBuffer<I>)
        -> (IndexBufferBinding<I>, Self::Rest)
        where I: IndexDatum;
}

impl<C> IndexBufferContext for C
    where C: ElementArrayBufferContext
{
    type Rest = C::Rest;

    fn bind_index_buffer<'a, I>(self, ibo: &'a mut IndexBuffer<I>)
        -> (IndexBufferBinding<I>, Self::Rest)
        where I: IndexDatum
    {
        let (gl_be, rest) = self.bind_element_array_buffer(&mut ibo.buffer);
        (
            IndexBufferBinding {
                gl_buffer: gl_be,
                count: &mut ibo.count,
                _phantom: PhantomData
            },
            rest
        )
    }
}

pub struct IndexBuffer<T: IndexDatum> {
    buffer: Buffer,
    count: usize,
    phantom: PhantomData<*const T>
}

impl<T: IndexDatum> IndexBuffer<T> {
    pub fn buffer(&self) -> &Buffer {
        &self.buffer
    }

    pub fn buffer_mut(&mut self) -> &mut Buffer {
        &mut self.buffer
    }
}

pub struct IndexBufferBinding<'a, T: IndexDatum + 'a> {
    gl_buffer: ElementArrayBufferBinding<'a>,
    count: &'a mut usize,
    _phantom: PhantomData<*const IndexBuffer<T>>
}

impl<'a, T: IndexDatum + 'a> IndexBufferBinding<'a, T> {
    pub fn buffer_data(&mut self, data: &[T], usage: super::BufferDataUsage)
        where [T]: IndexData
    {
        *self.count = data.len();
        self.gl_buffer.buffer_bytes(data.index_bytes(), usage);
    }
}

impl<B, F, P, R, T> ContextOf<B, F, P, R, T> {
    pub fn new_index_buffer<I: IndexDatum>(&self) -> IndexBuffer<I> {
        IndexBuffer {
            buffer: self.gen_buffer(),
            count: 0,
            phantom: PhantomData
        }
    }
}

#[macro_export]
macro_rules! attrib_pointers {
    ($gl:expr, $vbo:expr, {
        $($field_name:ident => $field_attrib:expr),*
    }) => {
        {
            let mut binder = $crate::AttribBinder::new();
            $(binder.add(stringify!($field_name), $field_attrib).unwrap());*;
            binder
        }
    }
}

#[macro_export]
macro_rules! bind_attrib_pointers {
    ($gl:expr, $vbo:expr, {
        $($field_name:ident => $field_attrib:expr),*
    }) => {
        {
            let vbo = $vbo;
            let binder = {
                attrib_pointers!($gl, vbo, {
                    $($field_name => $field_attrib),*
                })
            };
            vbo.bind_attrib_pointers(binder);
        }
    }
}

#[macro_export]
macro_rules! bind_vertex_buffer {
    ($gl:expr, $vbo:expr) => {
        {
            use std::borrow::BorrowMut;
            let mut vbo = $vbo;

            let (gl_vbo, _) = $gl.bind_vertex_buffer(vbo.borrow_mut());
            gl_vbo
        }
    }
}

#[macro_export]
macro_rules! bind_index_buffer {
    ($gl:expr, $ibo:expr) => {
        {
            use std::borrow::BorrowMut;
            let mut ibo = $ibo;

            let (gl_ibo, _) = $gl.bind_index_buffer(ibo.borrow_mut());
            gl_ibo
        }
    }
}
<commit_msg>Add `VertexBufferContext` impl for `&mut ContextOf<...>`<commit_after>use std::borrow::BorrowMut;
use std::marker::PhantomData;
use std::collections::{HashMap, HashSet};
use context::ContextOf;
use framebuffer::FramebufferBinding;
use program::ProgramAttrib;
use vertex_data::{VertexData, VertexBytes, VertexAttribute};
use index_data::{IndexData, IndexDatum};
use buffer::{Buffer, BufferBinderOf, BufferBinding,
             ArrayBufferBinder, ArrayBufferBinding,
             ElementArrayBufferBinding, ElementArrayBufferContext};
use types::DrawingMode;

#[derive(Debug)]
pub enum AttribAddError {
    DuplicateAttrib(String)
}

#[derive(Debug)]
pub struct AttribError {
    missing_attribs: Vec<String>,
    unknown_attribs: Vec<String>
}

pub struct AttribBinder {
    attribs: HashMap<String, ProgramAttrib>
}

impl AttribBinder {
    pub fn new() -> Self {
        AttribBinder {
            attribs: HashMap::new()
        }
    }

    pub fn add(&mut self, name: &str, attrib: ProgramAttrib)
        -> Result<(), AttribAddError>
    {
        match self.attribs.insert(name.into(), attrib) {
            None => Ok(()),
            Some(_) => Err(AttribAddError::DuplicateAttrib(name.into()))
        }
    }

    fn for_each<T, F>(&self, mut f: F) -> Result<(), AttribError>
        where T: VertexData, F: FnMut(VertexAttribute, ProgramAttrib)
    {
        // TODO: Avoid heap allocations
        // TODO: Avoid redundant calls to T::visit_attributes
        let mut attribs =
            HashMap::<String, (VertexAttribute, ProgramAttrib)>::new();
        let mut missing = Vec::<String>::new();

        T::visit_attributes(|vertex_attrib| {
            match self.attribs.get(&vertex_attrib.name) {
                Some(program_attrib) => {
                    let pair = (vertex_attrib.clone(), *program_attrib);
                    attribs.insert(vertex_attrib.name, pair);
                },
                None => {
                    missing.push(vertex_attrib.name);
                }
            }
        });

        let unknown: Vec<_> = {
            let expected: HashSet<_> = self.attribs.keys().collect();
            let actual: HashSet<_> = attribs.keys().collect();
            expected.difference(&actual).cloned().cloned().collect()
        };

        if missing.is_empty() && unknown.is_empty() {
            for (_, (vertex_attrib, program_attrib)) in attribs.into_iter() {
                f(vertex_attrib, program_attrib);
            }
            Ok(())
        }
        else {
            Err(AttribError {
                missing_attribs: missing,
                unknown_attribs: unknown
            })
        }
    }

    pub fn enable<V, B, F, P, R, T>(&self, gl: &ContextOf<B, F, P, R, T>)
        -> Result<(), AttribError>
        where V: VertexData
    {
        self.for_each::<V, _>(|_, program_attrib| {
            gl.enable_vertex_attrib_array(program_attrib);
        })
    }

    pub fn bind<V: VertexData>(&self, gl_buffer: &ArrayBufferBinding)
        -> Result<(), AttribError>
    {
        self.for_each::<V, _>(|vertex_attrib, program_attrib| {
            unsafe {
                gl_buffer.vertex_attrib_pointer(
                    program_attrib,
                    vertex_attrib.ty.components,
                    vertex_attrib.ty.data,
                    vertex_attrib.ty.normalize,
                    vertex_attrib.stride,
                    vertex_attrib.offset
                );
            }
        })
    }
}

#[derive(Debug)]
pub enum VertexBindError {
    BindingError(AttribError),
    NoAttributeBindings
}

impl From<AttribError> for VertexBindError {
    fn from(attrib_error: AttribError) -> VertexBindError {
        VertexBindError::BindingError(attrib_error)
    }
}

pub struct VertexBuffer<T: VertexData> {
    attrib_binder: Option<AttribBinder>,
    buffer: Buffer,
    count: usize,
    phantom: PhantomData<*const T>
}

impl<V: VertexData> VertexBuffer<V> {
    pub fn bind_attrib_pointers(&mut self, binder: AttribBinder) {
        self.attrib_binder = Some(binder);
    }

    pub fn bind<BA, BE, F, P, R, T>(&mut self,
                                    gl: ContextOf<BufferBinderOf<BA, BE>,
                                                  F,
                                                  P,
                                                  R,
                                                  T>)
        -> Result<(), VertexBindError>
        where BA: BorrowMut<ArrayBufferBinder>
    {
        match self.attrib_binder {
            Some(ref binder) => {
                let (mut ba_binder, mut gl) = gl.split_array_buffer();
                let mut ba_binder = ba_binder.borrow_mut();
                let gl_buffer = ba_binder.bind(&mut self.buffer);
                try!(binder.enable::<V, _, _, _, _, _>(&mut gl));
                try!(binder.bind::<V>(&gl_buffer));
                Ok(())
            },
            None => { Err(VertexBindError::NoAttributeBindings) }
        }
    }

    pub fn buffer(&self) -> &Buffer {
        &self.buffer
    }

    pub fn buffer_mut(&mut self) -> &mut Buffer {
        &mut self.buffer
    }
}

pub struct VertexBufferBinding<'a, T: VertexData + 'a> {
    gl_buffer: ArrayBufferBinding<'a>,
    count: &'a mut usize,
    _phantom: PhantomData<*const VertexBuffer<T>>
}

impl<'a, T: VertexData + 'a> VertexBufferBinding<'a, T> {
    pub fn buffer_data(&mut self, data: &[T], usage: super::BufferDataUsage)
        where [T]: VertexBytes
    {
        *self.count = data.len();
        self.gl_buffer.buffer_bytes(data.vertex_bytes(), usage);
    }
}

impl<'a> FramebufferBinding<'a> {
    pub fn draw_arrays_range_vbo<V>(&mut self,
                                    gl_vbo: &VertexBufferBinding<V>,
                                    mode: DrawingMode,
                                    start: u32,
                                    length: usize)
        where V: VertexData
    {
        debug_assert!((start as usize) + length <= *gl_vbo.count);

        unsafe {
            self.draw_arrays_range(&gl_vbo.gl_buffer, mode, start, length);
        }
    }

    pub fn draw_arrays_vbo<V>(&mut self,
                              gl_vbo: &VertexBufferBinding<V>,
                              mode: DrawingMode)
        where V: VertexData
    {
        unsafe {
            self.draw_arrays_range(&gl_vbo.gl_buffer,
                                   mode,
                                   0,
                                   *gl_vbo.count);
        }
    }

    pub fn draw_n_elements_buffered_vbo<V, I>(&mut self,
                                              gl_vbo: &VertexBufferBinding<V>,
                                              gl_ibo: &IndexBufferBinding<I>,
                                              mode: DrawingMode,
                                              length: usize)
        where V: VertexData, I: IndexDatum
    {
        debug_assert!(length <= *gl_ibo.count);

        unsafe {
            self.draw_n_elements_buffered(&gl_vbo.gl_buffer,
                                          &gl_ibo.gl_buffer,
                                          mode,
                                          length,
                                          I::index_datum_type());
        }
    }

    pub fn draw_elements_buffered_vbo<V, I>(&mut self,
                                            gl_vbo: &VertexBufferBinding<V>,
                                            gl_ibo: &IndexBufferBinding<I>,
                                            mode: DrawingMode)
        where V: VertexData, I: IndexDatum
    {
        unsafe {
            self.draw_n_elements_buffered(&gl_vbo.gl_buffer,
                                          &gl_ibo.gl_buffer,
                                          mode,
                                          *gl_ibo.count,
                                          I::index_datum_type());
        }
    }

    pub fn draw_n_elements_vbo<V, I>(&mut self,
                                     gl_vbo: &VertexBufferBinding<'a, V>,
                                     mode: DrawingMode,
                                     count: usize,
                                     indices: &[I])
        where V: VertexData, I: IndexDatum, [I]: IndexData
    {
        unsafe {
            self.draw_n_elements(&gl_vbo.gl_buffer, mode, count, indices);
        }
    }

    pub fn draw_elements_vbo<V, I>(&mut self,
                                   gl_vbo: &VertexBufferBinding<'a, V>,
                                   mode: DrawingMode,
                                   indices: &[I])
        where V: VertexData, I: IndexDatum, [I]: IndexData
    {
        unsafe {
            self.draw_elements(&gl_vbo.gl_buffer, mode, indices);
        }
    }
}

impl<B, F, P, R, T> ContextOf<B, F, P, R, T> {
    pub fn new_vertex_buffer<V: VertexData>(&self) -> VertexBuffer<V> {
        VertexBuffer {
            attrib_binder: None,
            buffer: self.gen_buffer(),
            count: 0,
            phantom: PhantomData
        }
    }
}

pub trait VertexBufferContext {
    type Rest;

    fn bind_vertex_buffer<'a, V>(self, vbo: &'a mut VertexBuffer<V>)
        -> (VertexBufferBinding<V>, Self::Rest)
        where V: VertexData;
}

impl<BA, BE, F, P, R, T> VertexBufferContext
    for ContextOf<BufferBinderOf<BA, BE>, F, P, R, T>
    where BA: BorrowMut<ArrayBufferBinder>
{
    type Rest = ContextOf<BufferBinderOf<(), BE>, F, P, R, T>;

    fn bind_vertex_buffer<'a, V>(mut self, vbo: &'a mut VertexBuffer<V>)
        -> (VertexBufferBinding<V>, Self::Rest)
        where V: VertexData
    {
        {
            let gl = self.borrowed_mut().map_buffers(|b| b.borrowed_mut());

            vbo.bind(gl).unwrap();
        }
        let (mut ba_binder, rest) = self.split_array_buffer();
        let mut ba_binder = ba_binder.borrow_mut();
        let gl_array_buffer = ba_binder.bind(&mut vbo.buffer);
        (
            VertexBufferBinding {
                gl_buffer: gl_array_buffer,
                count: &mut vbo.count,
                _phantom: PhantomData
            },
            rest
        )
    }
}

impl<'b, BA, BE, F, P, R, T> VertexBufferContext
    for &'b mut ContextOf<BufferBinderOf<BA, BE>, F, P, R, T>
    where BA: BorrowMut<ArrayBufferBinder>
{
    type Rest = ContextOf<BufferBinderOf<(), &'b mut BE>,
                          &'b mut F,
                          &'b mut P,
                          &'b mut R,
                          &'b mut T>;

    fn bind_vertex_buffer<'a, V>(mut self, vbo: &'a mut VertexBuffer<V>)
        -> (VertexBufferBinding<V>, Self::Rest)
        where V: VertexData
    {
        {
            let gl = self.borrowed_mut().map_buffers(|b| b.borrowed_mut());

            vbo.bind(gl).unwrap();
        }
        let gl: ContextOf<BufferBinderOf<&mut BA, &mut BE>, _, _, _, _> = self.mut_into();
        let (mut ba_binder, rest): (&mut BA, _) = gl.split_array_buffer();
        let mut ba_binder = ba_binder.borrow_mut();
        let gl_array_buffer = ba_binder.bind(&mut vbo.buffer);
        (
            VertexBufferBinding {
                gl_buffer: gl_array_buffer,
                count: &mut vbo.count,
                _phantom: PhantomData
            },
            rest
        )
    }
}

pub trait IndexBufferContext {
    type Rest;

    fn bind_index_buffer<'a, I>(self, ibo: &'a mut IndexBuffer<I>)
        -> (IndexBufferBinding<I>, Self::Rest)
        where I: IndexDatum;
}

impl<C> IndexBufferContext for C
    where C: ElementArrayBufferContext
{
    type Rest = C::Rest;

    fn bind_index_buffer<'a, I>(self, ibo: &'a mut IndexBuffer<I>)
        -> (IndexBufferBinding<I>, Self::Rest)
        where I: IndexDatum
    {
        let (gl_be, rest) = self.bind_element_array_buffer(&mut ibo.buffer);
        (
            IndexBufferBinding {
                gl_buffer: gl_be,
                count: &mut ibo.count,
                _phantom: PhantomData
            },
            rest
        )
    }
}

pub struct IndexBuffer<T: IndexDatum> {
    buffer: Buffer,
    count: usize,
    phantom: PhantomData<*const T>
}

impl<T: IndexDatum> IndexBuffer<T> {
    pub fn buffer(&self) -> &Buffer {
        &self.buffer
    }

    pub fn buffer_mut(&mut self) -> &mut Buffer {
        &mut self.buffer
    }
}

pub struct IndexBufferBinding<'a, T: IndexDatum + 'a> {
    gl_buffer: ElementArrayBufferBinding<'a>,
    count: &'a mut usize,
    _phantom: PhantomData<*const IndexBuffer<T>>
}

impl<'a, T: IndexDatum + 'a> IndexBufferBinding<'a, T> {
    pub fn buffer_data(&mut self, data: &[T], usage: super::BufferDataUsage)
        where [T]: IndexData
    {
        *self.count = data.len();
        self.gl_buffer.buffer_bytes(data.index_bytes(), usage);
    }
}

impl<B, F, P, R, T> ContextOf<B, F, P, R, T> {
    pub fn new_index_buffer<I: IndexDatum>(&self) -> IndexBuffer<I> {
        IndexBuffer {
            buffer: self.gen_buffer(),
            count: 0,
            phantom: PhantomData
        }
    }
}

#[macro_export]
macro_rules! attrib_pointers {
    ($gl:expr, $vbo:expr, {
        $($field_name:ident => $field_attrib:expr),*
    }) => {
        {
            let mut binder = $crate::AttribBinder::new();
            $(binder.add(stringify!($field_name), $field_attrib).unwrap());*;
            binder
        }
    }
}

#[macro_export]
macro_rules! bind_attrib_pointers {
    ($gl:expr, $vbo:expr, {
        $($field_name:ident => $field_attrib:expr),*
    }) => {
        {
            let vbo = $vbo;
            let binder = {
                attrib_pointers!($gl, vbo, {
                    $($field_name => $field_attrib),*
                })
            };
            vbo.bind_attrib_pointers(binder);
        }
    }
}

#[macro_export]
macro_rules! bind_vertex_buffer {
    ($gl:expr, $vbo:expr) => {
        {
            use std::borrow::BorrowMut;
            let mut vbo = $vbo;

            let (gl_vbo, _) = $gl.bind_vertex_buffer(vbo.borrow_mut());
            gl_vbo
        }
    }
}

#[macro_export]
macro_rules! bind_index_buffer {
    ($gl:expr, $ibo:expr) => {
        {
            use std::borrow::BorrowMut;
            let mut ibo = $ibo;

            let (gl_ibo, _) = $gl.bind_index_buffer(ibo.borrow_mut());
            gl_ibo
        }
    }
}
<|endoftext|>


<commit_before>extern crate alsa;
extern crate libc;
extern crate nix;

use std;
use std::ffi::CString;
use std::error;
use time::{Time, TimeDelta};
use base::*;

use super::input::*;

const CHANNELS: usize = 2;

const ACCEPTED_RATES: [usize; 4] = [44100, 48000, 88200, 96000];
const MAX_SAMPLE_RATE_ERROR: f32 = 1000.0;

enum State {
    Inactive,
    Active { silent_samples: usize },
}

pub struct AlsaInput {
    spec: DeviceSpec,
    pcm: alsa::PCM,
    sample_rate: usize,
    format: SampleFormat,
    period_size: usize,
    rate_detector: RateDetector,
    exact_rate_detector: RateDetector,
    state: State,
    current_rate: DetectedRate,
    last_rate_update: Time,
}

// Deactivate input after 5 seconds of silence.
const SILENCE_PERIOD_SECONDS: usize = 5;

impl AlsaInput {
    pub fn open(spec: DeviceSpec, period_duration: TimeDelta) -> Result<Box<AlsaInput>> {
        let pcm = try!(alsa::PCM::open(
            &*CString::new(&spec.id[..]).unwrap(),
            alsa::Direction::Capture,
            false
        ));

        let mut sample_rate = spec.sample_rate.unwrap_or(48000);
        let period_size;
        let format;
        {
            let hwp = try!(alsa::pcm::HwParams::any(&pcm));
            try!(hwp.set_channels(CHANNELS as u32));
            try!(hwp.set_rate(sample_rate as u32, alsa::ValueOr::Nearest));

            for fmt in [
                alsa::pcm::Format::S32LE,
                alsa::pcm::Format::S243LE,
                alsa::pcm::Format::S24LE,
                alsa::pcm::Format::S16LE,
            ].iter()
            {
                match hwp.set_format(*fmt) {
                    Ok(_) => break,
                    Err(_) => (),
                }
            }

            let target_period_size = period_duration * sample_rate as i64 / TimeDelta::seconds(1);
            try!(hwp.set_period_size_near(
                target_period_size as alsa::pcm::Frames,
                alsa::ValueOr::Nearest
            ));
            try!(hwp.set_periods(8, alsa::ValueOr::Nearest));
            try!(hwp.set_rate_resample(false));
            try!(hwp.set_access(alsa::pcm::Access::RWInterleaved));
            try!(pcm.hw_params(&hwp));

            sample_rate = try!(hwp.get_rate()) as usize;
            period_size = try!(hwp.get_period_size()) as usize;
            format = match try!(hwp.get_format()) {
                alsa::pcm::Format::S16LE => SampleFormat::S16LE,
                alsa::pcm::Format::S243LE => SampleFormat::S24LE3,
                alsa::pcm::Format::S24LE => SampleFormat::S24LE4,
                alsa::pcm::Format::S32LE => SampleFormat::S32LE,
                fmt => return Err(Error::new(&format!("Unknown format: {:?}", fmt))),
            };

            println!(
                "INFO: Reading {} ({}). Buffer size: {}x{}. {} {}",
                spec.id,
                &spec.name,
                period_size,
                try!(hwp.get_periods()),
                sample_rate,
                format
            );
        }

        Ok(Box::new(AlsaInput {
            spec: spec,
            pcm: pcm,
            sample_rate: sample_rate,
            format: format,
            period_size: period_size,
            rate_detector: RateDetector::new(MAX_SAMPLE_RATE_ERROR),
            exact_rate_detector: RateDetector::new(1.0),
            state: State::Inactive,
            current_rate: DetectedRate { rate: sample_rate as f32, error: sample_rate as f32 },
            last_rate_update: Time::now(),
        }))
    }
}

impl Input for AlsaInput {
    fn read(&mut self) -> Result<Option<Frame>> {
        let mut buf = vec![0u8; self.period_size * CHANNELS * self.format.bytes_per_sample()];
        let read_result = self.pcm.io().readi(&mut buf[..]);
        let samples = match read_result {
            Ok(0) => return Ok(None),
            Ok(r) => r,
            Err(e) => {
                if e.errno().unwrap_or(nix::Errno::UnknownErrno) == nix::errno::EWOULDBLOCK {
                    return Ok(None);
                }
                println!("Recovering AlsaInput {}: {:?}", &self.spec.name, e.errno());
                match self.pcm
                    .recover(e.errno().unwrap_or(nix::Errno::UnknownErrno) as i32, true)
                {
                    Ok(_) => return self.read(),
                    Err(_) => return Err(Error::new(error::Error::description(&e))),
                }
            }
        };

        assert!(samples > 0);

        let now = Time::now();
        let rate = self.rate_detector.update(samples, now);
        if (self.sample_rate as f32 - rate.rate).abs() > MAX_SAMPLE_RATE_ERROR &&
           rate.error < MAX_SAMPLE_RATE_ERROR {
            let mut new_rate = 0;
            for r in &ACCEPTED_RATES[..] {
                if (rate.rate - *r as f32).abs() < MAX_SAMPLE_RATE_ERROR {
                    new_rate = *r;
                }
            }

            if new_rate > 0 {
                println!(
                    "INFO: rate changed for input device {}: {}",
                    &self.spec.name, new_rate
                );
                self.sample_rate = new_rate;
                self.current_rate = DetectedRate { rate: new_rate as f32, error: MAX_SAMPLE_RATE_ERROR };
                self.exact_rate_detector.reset();
            } else if rate.error < 100.0 {
                println!(
                    "WARNING: Unknown sample rate for {}: {}",
                    &self.spec.name, rate.rate
                );
            }
        }

        if self.spec.exact_sample_rate {
            let rate = self.exact_rate_detector.update(samples, now);

            if (now - self.last_rate_update) > TimeDelta::milliseconds(500) {
               self.last_rate_update = now;
               if rate.error < 10.0 {
                    self.current_rate = rate;
               }
            }
        }

        let bytes = samples * CHANNELS * self.format.bytes_per_sample();

        let mut all_zeros = true;
        for i in 0..bytes {
            if buf[i] != 0 {
                all_zeros = false;
                break;
            }
        }

        self.state = match (&self.state, all_zeros) {
            (_, false) => State::Active { silent_samples: 0 },
            (&State::Active { silent_samples }, true) => {
                let silence = silent_samples + samples;
                if silence > SILENCE_PERIOD_SECONDS * self.sample_rate {
                    State::Inactive
                } else {
                    State::Active {
                        silent_samples: silence,
                    }
                }
            }
            (&State::Inactive, true) => State::Inactive,
        };

        match self.state {
            State::Inactive => return Ok(None),
            _ => (),
        }

        let mut frame = Frame::from_buffer_stereo(
            self.format, self.current_rate.rate, &buf[0..bytes], Time::now());
        frame.timestamp -= frame.duration();

        Ok(Some(frame))
    }

    fn min_delay(&self) -> TimeDelta {
        samples_to_timedelta(self.sample_rate as f32, self.period_size as i64)
    }
}

const TARGET_SAMPLE_RATES: [usize; 2] = [44100, 48000];

const RETRY_PERIOD_MS: i64 = 3000;
const PROBE_TIME_MS: i64 = 500;

pub struct ResilientAlsaInput {
    spec: DeviceSpec,
    period_duration: TimeDelta,
    input: Option<Box<AlsaInput>>,
    last_open_attempt: Time,
    probe_sample_rate: bool,
    last_active: Time,
    next_sample_rate_to_probe: usize,
}

impl ResilientAlsaInput {
    pub fn new(spec: DeviceSpec, period_duration: TimeDelta, probe_sample_rate: bool) -> Box<ResilientAlsaInput> {
        Box::new(ResilientAlsaInput {
            spec: spec,
            period_duration: period_duration,
            input: None,
            probe_sample_rate: probe_sample_rate,
            last_open_attempt: Time::now(),
            last_active: Time::now(),
            next_sample_rate_to_probe: 0,
        })
    }

    fn try_reopen(&mut self) {
        let now = Time::now();
        if now - self.last_open_attempt >= TimeDelta::milliseconds(RETRY_PERIOD_MS) {
            self.last_open_attempt = now;
            let mut spec = self.spec.clone();
            if spec.sample_rate.is_none() {
                spec.sample_rate = Some(TARGET_SAMPLE_RATES[self.next_sample_rate_to_probe]);
                self.next_sample_rate_to_probe =
                    (self.next_sample_rate_to_probe + 1) % TARGET_SAMPLE_RATES.len();
            }
            match AlsaInput::open(spec, self.period_duration) {
                Ok(input) => {
                    self.input = Some(input);
                    self.last_active = now;
                }
                Err(_) => (),
            };
        }
    }
}

impl Input for ResilientAlsaInput {
    fn read(&mut self) -> Result<Option<Frame>> {
        if self.input.is_none() {
            self.try_reopen()
        }
        let mut reset = false;
        let result = match self.input.as_mut() {
            Some(input) => match input.read() {
                Ok(Some(frame)) => {
                    self.last_active = Time::now();
                    Some(frame)
                }
                Ok(None) => {
                    if self.probe_sample_rate &&
                       Time::now() - self.last_active > TimeDelta::milliseconds(PROBE_TIME_MS) {
                        reset = true;
                    }
                    None
                }
                Err(e) => {
                    println!("WARNING: input read from {} failed: {}", &self.spec.name, e);
                    reset = true;
                    None
                }
            },
            None => None,
        };
        if reset {
            self.input = None;
        }
        if self.input.is_none() {
            std::thread::sleep(self.period_duration.as_duration());
        }

        Ok(result)
    }

    fn min_delay(&self) -> TimeDelta {
        match self.input.as_ref() {
            Some(input) => input.min_delay(),
            None => self.period_duration,
        }
    }
}
<commit_msg>Reset input rate detector on overflow<commit_after>extern crate alsa;
extern crate libc;
extern crate nix;

use std;
use std::ffi::CString;
use std::error;
use time::{Time, TimeDelta};
use base::*;

use super::input::*;

const CHANNELS: usize = 2;

const ACCEPTED_RATES: [usize; 4] = [44100, 48000, 88200, 96000];
const MAX_SAMPLE_RATE_ERROR: f32 = 1000.0;

enum State {
    Inactive,
    Active { silent_samples: usize },
}

pub struct AlsaInput {
    spec: DeviceSpec,
    pcm: alsa::PCM,
    sample_rate: usize,
    format: SampleFormat,
    period_size: usize,
    rate_detector: RateDetector,
    exact_rate_detector: RateDetector,
    state: State,
    current_rate: DetectedRate,
    last_rate_update: Time,
}

// Deactivate input after 5 seconds of silence.
const SILENCE_PERIOD_SECONDS: usize = 5;

impl AlsaInput {
    pub fn open(spec: DeviceSpec, period_duration: TimeDelta) -> Result<Box<AlsaInput>> {
        let pcm = try!(alsa::PCM::open(
            &*CString::new(&spec.id[..]).unwrap(),
            alsa::Direction::Capture,
            false
        ));

        let mut sample_rate = spec.sample_rate.unwrap_or(48000);
        let period_size;
        let format;
        {
            let hwp = try!(alsa::pcm::HwParams::any(&pcm));
            try!(hwp.set_channels(CHANNELS as u32));
            try!(hwp.set_rate(sample_rate as u32, alsa::ValueOr::Nearest));

            for fmt in [
                alsa::pcm::Format::S32LE,
                alsa::pcm::Format::S243LE,
                alsa::pcm::Format::S24LE,
                alsa::pcm::Format::S16LE,
            ].iter()
            {
                match hwp.set_format(*fmt) {
                    Ok(_) => break,
                    Err(_) => (),
                }
            }

            let target_period_size = period_duration * sample_rate as i64 / TimeDelta::seconds(1);
            try!(hwp.set_period_size_near(
                target_period_size as alsa::pcm::Frames,
                alsa::ValueOr::Nearest
            ));
            try!(hwp.set_periods(8, alsa::ValueOr::Nearest));
            try!(hwp.set_rate_resample(false));
            try!(hwp.set_access(alsa::pcm::Access::RWInterleaved));
            try!(pcm.hw_params(&hwp));

            sample_rate = try!(hwp.get_rate()) as usize;
            period_size = try!(hwp.get_period_size()) as usize;
            format = match try!(hwp.get_format()) {
                alsa::pcm::Format::S16LE => SampleFormat::S16LE,
                alsa::pcm::Format::S243LE => SampleFormat::S24LE3,
                alsa::pcm::Format::S24LE => SampleFormat::S24LE4,
                alsa::pcm::Format::S32LE => SampleFormat::S32LE,
                fmt => return Err(Error::new(&format!("Unknown format: {:?}", fmt))),
            };

            println!(
                "INFO: Reading {} ({}). Buffer size: {}x{}. {} {}",
                spec.id,
                &spec.name,
                period_size,
                try!(hwp.get_periods()),
                sample_rate,
                format
            );
        }

        Ok(Box::new(AlsaInput {
            spec: spec,
            pcm: pcm,
            sample_rate: sample_rate,
            format: format,
            period_size: period_size,
            rate_detector: RateDetector::new(MAX_SAMPLE_RATE_ERROR),
            exact_rate_detector: RateDetector::new(1.0),
            state: State::Inactive,
            current_rate: DetectedRate { rate: sample_rate as f32, error: sample_rate as f32 },
            last_rate_update: Time::now(),
        }))
    }
}

impl Input for AlsaInput {
    fn read(&mut self) -> Result<Option<Frame>> {
        let mut buf = vec![0u8; self.period_size * CHANNELS * self.format.bytes_per_sample()];
        let read_result = self.pcm.io().readi(&mut buf[..]);
        let samples = match read_result {
            Ok(0) => return Ok(None),
            Ok(r) => r,
            Err(e) => {
                if e.errno().unwrap_or(nix::Errno::UnknownErrno) == nix::errno::EWOULDBLOCK {
                    return Ok(None);
                }
                println!("Recovering AlsaInput {}: {:?}", &self.spec.name, e.errno());
                self.rate_detector.reset();
                self.exact_rate_detector.reset();
                match self.pcm
                    .recover(e.errno().unwrap_or(nix::Errno::UnknownErrno) as i32, true)
                {
                    Ok(_) => return self.read(),
                    Err(_) => return Err(Error::new(error::Error::description(&e))),
                }
            }
        };

        assert!(samples > 0);

        let now = Time::now();
        let rate = self.rate_detector.update(samples, now);
        if (self.sample_rate as f32 - rate.rate).abs() > MAX_SAMPLE_RATE_ERROR &&
           rate.error < MAX_SAMPLE_RATE_ERROR {
            let mut new_rate = 0;
            for r in &ACCEPTED_RATES[..] {
                if (rate.rate - *r as f32).abs() < MAX_SAMPLE_RATE_ERROR {
                    new_rate = *r;
                }
            }

            if new_rate > 0 {
                println!(
                    "INFO: rate changed for input device {}: {}",
                    &self.spec.name, new_rate
                );
                self.sample_rate = new_rate;
                self.current_rate = DetectedRate { rate: new_rate as f32, error: MAX_SAMPLE_RATE_ERROR };
                self.exact_rate_detector.reset();
            } else if rate.error < 100.0 {
                println!(
                    "WARNING: Unknown sample rate for {}: {}",
                    &self.spec.name, rate.rate
                );
            }
        }

        if self.spec.exact_sample_rate {
            let rate = self.exact_rate_detector.update(samples, now);

            if (now - self.last_rate_update) > TimeDelta::milliseconds(500) {
               self.last_rate_update = now;
               if rate.error < 10.0 {
                    self.current_rate = rate;
               }
            }
        }

        let bytes = samples * CHANNELS * self.format.bytes_per_sample();

        let mut all_zeros = true;
        for i in 0..bytes {
            if buf[i] != 0 {
                all_zeros = false;
                break;
            }
        }

        self.state = match (&self.state, all_zeros) {
            (_, false) => State::Active { silent_samples: 0 },
            (&State::Active { silent_samples }, true) => {
                let silence = silent_samples + samples;
                if silence > SILENCE_PERIOD_SECONDS * self.sample_rate {
                    State::Inactive
                } else {
                    State::Active {
                        silent_samples: silence,
                    }
                }
            }
            (&State::Inactive, true) => State::Inactive,
        };

        match self.state {
            State::Inactive => return Ok(None),
            _ => (),
        }

        let mut frame = Frame::from_buffer_stereo(
            self.format, self.current_rate.rate, &buf[0..bytes], Time::now());
        frame.timestamp -= frame.duration();

        Ok(Some(frame))
    }

    fn min_delay(&self) -> TimeDelta {
        samples_to_timedelta(self.sample_rate as f32, self.period_size as i64)
    }
}

const TARGET_SAMPLE_RATES: [usize; 2] = [44100, 48000];

const RETRY_PERIOD_MS: i64 = 3000;
const PROBE_TIME_MS: i64 = 500;

pub struct ResilientAlsaInput {
    spec: DeviceSpec,
    period_duration: TimeDelta,
    input: Option<Box<AlsaInput>>,
    last_open_attempt: Time,
    probe_sample_rate: bool,
    last_active: Time,
    next_sample_rate_to_probe: usize,
}

impl ResilientAlsaInput {
    pub fn new(spec: DeviceSpec, period_duration: TimeDelta, probe_sample_rate: bool) -> Box<ResilientAlsaInput> {
        Box::new(ResilientAlsaInput {
            spec: spec,
            period_duration: period_duration,
            input: None,
            probe_sample_rate: probe_sample_rate,
            last_open_attempt: Time::now(),
            last_active: Time::now(),
            next_sample_rate_to_probe: 0,
        })
    }

    fn try_reopen(&mut self) {
        let now = Time::now();
        if now - self.last_open_attempt >= TimeDelta::milliseconds(RETRY_PERIOD_MS) {
            self.last_open_attempt = now;
            let mut spec = self.spec.clone();
            if spec.sample_rate.is_none() {
                spec.sample_rate = Some(TARGET_SAMPLE_RATES[self.next_sample_rate_to_probe]);
                self.next_sample_rate_to_probe =
                    (self.next_sample_rate_to_probe + 1) % TARGET_SAMPLE_RATES.len();
            }
            match AlsaInput::open(spec, self.period_duration) {
                Ok(input) => {
                    self.input = Some(input);
                    self.last_active = now;
                }
                Err(_) => (),
            };
        }
    }
}

impl Input for ResilientAlsaInput {
    fn read(&mut self) -> Result<Option<Frame>> {
        if self.input.is_none() {
            self.try_reopen()
        }
        let mut reset = false;
        let result = match self.input.as_mut() {
            Some(input) => match input.read() {
                Ok(Some(frame)) => {
                    self.last_active = Time::now();
                    Some(frame)
                }
                Ok(None) => {
                    if self.probe_sample_rate &&
                       Time::now() - self.last_active > TimeDelta::milliseconds(PROBE_TIME_MS) {
                        reset = true;
                    }
                    None
                }
                Err(e) => {
                    println!("WARNING: input read from {} failed: {}", &self.spec.name, e);
                    reset = true;
                    None
                }
            },
            None => None,
        };
        if reset {
            self.input = None;
        }
        if self.input.is_none() {
            std::thread::sleep(self.period_duration.as_duration());
        }

        Ok(result)
    }

    fn min_delay(&self) -> TimeDelta {
        match self.input.as_ref() {
            Some(input) => input.min_delay(),
            None => self.period_duration,
        }
    }
}
<|endoftext|>


<commit_before>use futures::{Async, Future, Poll, Sink};
use futures::stream::Stream;
use futures::sink::Send;
use futures_state_stream::{StateStream, StreamEvent};

use native_tls::TlsConnector;

use std::io;
use std::net::ToSocketAddrs;

use tokio::net::{ConnectFuture, TcpStream};
use tokio_io::AsyncRead;
use tokio_tls::{ConnectAsync, TlsConnectorExt};

use imap_proto::{Request, RequestId, State};
use imap_proto::builders::command::Command;
use proto::{ImapCodec, ImapTransport, ResponseData};

pub mod builder {
    pub use imap_proto::builders::command::{CommandBuilder, FetchBuilderAttributes,
                                            FetchBuilderMessages, FetchBuilderModifiers,
                                            FetchCommand, FetchCommandAttributes,
                                            FetchCommandMessages};
}

pub struct Client {
    transport: ImapTransport,
    state: ClientState,
}

impl Client {
    pub fn connect(server: &str) -> io::Result<ImapConnectFuture> {
        let addr = (server, 993).to_socket_addrs()?.next().ok_or_else(|| {
            io::Error::new(io::ErrorKind::Other, format!("no IP addresses found for {}", server))
        })?;
        Ok(ImapConnectFuture::TcpConnecting(TcpStream::connect(&addr), server.to_string()))
    }

    pub fn call(self, cmd: Command) -> ResponseStream {
        let Self { transport, mut state } = self;
        let request_id = state.request_ids.next().unwrap(); // safe: never returns Err
        let (cmd_bytes, next_state) = cmd.into_parts();
        let future = transport.send(Request(request_id.clone(), cmd_bytes));
        ResponseStream::new(future, state, request_id, next_state)
    }
}

pub struct ResponseStream {
    future: Option<Send<ImapTransport>>,
    transport: Option<ImapTransport>,
    state: Option<ClientState>,
    request_id: RequestId,
    next_state: Option<State>,
    done: bool,
}

impl ResponseStream {
    pub fn new(future: Send<ImapTransport>, state: ClientState,
               request_id: RequestId, next_state: Option<State>) -> Self {
        Self {
            future: Some(future),
            transport: None,
            state: Some(state),
            request_id: request_id,
            next_state: next_state,
            done: false,
        }
    }
}

impl StateStream for ResponseStream {
    type Item = ResponseData;
    type State = Client;
    type Error = io::Error;
    fn poll(&mut self) -> Poll<StreamEvent<Self::Item, Self::State>, Self::Error> {
        match self.future.take() {
            Some(mut future) => match future.poll() {
                Ok(Async::Ready(transport)) => {
                    self.transport = Some(transport);
                },
                Ok(Async::NotReady) => {
                    self.future = Some(future);
                    return Ok(Async::NotReady);
                },
                Err(e) => {
                    return Err(e);
                },
            },
            None => {},
        }
        let mut transport = match self.transport.take() {
            None => return Ok(Async::NotReady),
            Some(mut transport) => transport,
        };
        if self.done {
            let mut state = self.state.take().unwrap();
            if self.next_state.is_some() {
                state.state = self.next_state.take().unwrap();
            }
            let client = Client { transport, state };
            return Ok(Async::Ready(StreamEvent::Done(client)));
        }
        match transport.poll() {
            Ok(Async::Ready(Some(rsp))) => {
                if let Some(req_id) = rsp.request_id() {
                    self.done = *req_id == self.request_id;
                };
                self.transport = Some(transport);
                return Ok(Async::Ready(StreamEvent::Next(rsp)));
            },
            Err(e) => {
                return Err(e);
            },
            _ => (),
        }
        self.transport = Some(transport);
        Ok(Async::NotReady)
    }
}

pub enum ImapConnectFuture {
    #[doc(hidden)] TcpConnecting(ConnectFuture, String),
    #[doc(hidden)] TlsHandshake(ConnectAsync<TcpStream>),
    #[doc(hidden)] ServerGreeting(Option<ImapTransport>),
}

impl Future for ImapConnectFuture {
    type Item = (Client, ResponseData);
    type Error = io::Error;
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let mut new = None;
        if let ImapConnectFuture::TcpConnecting(ref mut future, ref domain) = *self {
            let stream = try_ready!(future.poll());
            let ctx = TlsConnector::builder().unwrap().build().unwrap();
            let future = ctx.connect_async(domain, stream);
            new = Some(ImapConnectFuture::TlsHandshake(future));
        }
        if new.is_some() {
            *self = new.take().unwrap();
        }
        if let ImapConnectFuture::TlsHandshake(ref mut future) = *self {
            let transport = try_ready!(future.map_err(|e| {
                io::Error::new(io::ErrorKind::Other, e)
            }).poll()).framed(ImapCodec::default());
            new = Some(ImapConnectFuture::ServerGreeting(Some(transport)));
        }
        if new.is_some() {
            *self = new.take().unwrap();
        }
        if let ImapConnectFuture::ServerGreeting(ref mut wrapped) = *self {
            let msg = try_ready!(wrapped.as_mut().unwrap().poll()).unwrap();
            return Ok(Async::Ready((Client {
                transport: wrapped.take().unwrap(),
                state: ClientState::new(),
            }, msg)));
        }
        Ok(Async::NotReady)
    }
}

pub struct ClientState {
    state: State,
    request_ids: IdGenerator,
}

impl ClientState {
    pub fn new() -> Self {
        Self {
            state: State::NotAuthenticated,
            request_ids: IdGenerator::new(),
        }
    }
}

impl Default for ClientState {
    fn default() -> Self {
        Self::new()
    }
}

pub struct IdGenerator {
    next: u64,
}

impl IdGenerator {
    pub fn new() -> Self {
        Self { next: 0 }
    }
}

impl Default for IdGenerator {
    fn default() -> Self {
        Self::new()
    }
}

impl Iterator for IdGenerator {
    type Item = RequestId;
    fn next(&mut self) -> Option<Self::Item> {
        self.next += 1;
        Some(RequestId(format!("A{:04}", self.next % 10_000)))
    }
}
<commit_msg>Use pattern matching for setting next state<commit_after>use futures::{Async, Future, Poll, Sink};
use futures::stream::Stream;
use futures::sink::Send;
use futures_state_stream::{StateStream, StreamEvent};

use native_tls::TlsConnector;

use std::io;
use std::net::ToSocketAddrs;

use tokio::net::{ConnectFuture, TcpStream};
use tokio_io::AsyncRead;
use tokio_tls::{ConnectAsync, TlsConnectorExt};

use imap_proto::{Request, RequestId, State};
use imap_proto::builders::command::Command;
use proto::{ImapCodec, ImapTransport, ResponseData};

pub mod builder {
    pub use imap_proto::builders::command::{CommandBuilder, FetchBuilderAttributes,
                                            FetchBuilderMessages, FetchBuilderModifiers,
                                            FetchCommand, FetchCommandAttributes,
                                            FetchCommandMessages};
}

pub struct Client {
    transport: ImapTransport,
    state: ClientState,
}

impl Client {
    pub fn connect(server: &str) -> io::Result<ImapConnectFuture> {
        let addr = (server, 993).to_socket_addrs()?.next().ok_or_else(|| {
            io::Error::new(io::ErrorKind::Other, format!("no IP addresses found for {}", server))
        })?;
        Ok(ImapConnectFuture::TcpConnecting(TcpStream::connect(&addr), server.to_string()))
    }

    pub fn call(self, cmd: Command) -> ResponseStream {
        let Self { transport, mut state } = self;
        let request_id = state.request_ids.next().unwrap(); // safe: never returns Err
        let (cmd_bytes, next_state) = cmd.into_parts();
        let future = transport.send(Request(request_id.clone(), cmd_bytes));
        ResponseStream::new(future, state, request_id, next_state)
    }
}

pub struct ResponseStream {
    future: Option<Send<ImapTransport>>,
    transport: Option<ImapTransport>,
    state: Option<ClientState>,
    request_id: RequestId,
    next_state: Option<State>,
    done: bool,
}

impl ResponseStream {
    pub fn new(future: Send<ImapTransport>, state: ClientState,
               request_id: RequestId, next_state: Option<State>) -> Self {
        Self {
            future: Some(future),
            transport: None,
            state: Some(state),
            request_id: request_id,
            next_state: next_state,
            done: false,
        }
    }
}

impl StateStream for ResponseStream {
    type Item = ResponseData;
    type State = Client;
    type Error = io::Error;
    fn poll(&mut self) -> Poll<StreamEvent<Self::Item, Self::State>, Self::Error> {
        match self.future.take() {
            Some(mut future) => match future.poll() {
                Ok(Async::Ready(transport)) => {
                    self.transport = Some(transport);
                },
                Ok(Async::NotReady) => {
                    self.future = Some(future);
                    return Ok(Async::NotReady);
                },
                Err(e) => {
                    return Err(e);
                },
            },
            None => {},
        }
        let mut transport = match self.transport.take() {
            None => return Ok(Async::NotReady),
            Some(mut transport) => transport,
        };
        if self.done {
            let mut state = self.state.take().unwrap();
            if let Some(next_state) = self.next_state.take() {
                state.state = next_state;
            }
            let client = Client { transport, state };
            return Ok(Async::Ready(StreamEvent::Done(client)));
        }
        match transport.poll() {
            Ok(Async::Ready(Some(rsp))) => {
                if let Some(req_id) = rsp.request_id() {
                    self.done = *req_id == self.request_id;
                };
                self.transport = Some(transport);
                return Ok(Async::Ready(StreamEvent::Next(rsp)));
            },
            Err(e) => {
                return Err(e);
            },
            _ => (),
        }
        self.transport = Some(transport);
        Ok(Async::NotReady)
    }
}

pub enum ImapConnectFuture {
    #[doc(hidden)] TcpConnecting(ConnectFuture, String),
    #[doc(hidden)] TlsHandshake(ConnectAsync<TcpStream>),
    #[doc(hidden)] ServerGreeting(Option<ImapTransport>),
}

impl Future for ImapConnectFuture {
    type Item = (Client, ResponseData);
    type Error = io::Error;
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let mut new = None;
        if let ImapConnectFuture::TcpConnecting(ref mut future, ref domain) = *self {
            let stream = try_ready!(future.poll());
            let ctx = TlsConnector::builder().unwrap().build().unwrap();
            let future = ctx.connect_async(domain, stream);
            new = Some(ImapConnectFuture::TlsHandshake(future));
        }
        if new.is_some() {
            *self = new.take().unwrap();
        }
        if let ImapConnectFuture::TlsHandshake(ref mut future) = *self {
            let transport = try_ready!(future.map_err(|e| {
                io::Error::new(io::ErrorKind::Other, e)
            }).poll()).framed(ImapCodec::default());
            new = Some(ImapConnectFuture::ServerGreeting(Some(transport)));
        }
        if new.is_some() {
            *self = new.take().unwrap();
        }
        if let ImapConnectFuture::ServerGreeting(ref mut wrapped) = *self {
            let msg = try_ready!(wrapped.as_mut().unwrap().poll()).unwrap();
            return Ok(Async::Ready((Client {
                transport: wrapped.take().unwrap(),
                state: ClientState::new(),
            }, msg)));
        }
        Ok(Async::NotReady)
    }
}

pub struct ClientState {
    state: State,
    request_ids: IdGenerator,
}

impl ClientState {
    pub fn new() -> Self {
        Self {
            state: State::NotAuthenticated,
            request_ids: IdGenerator::new(),
        }
    }
}

impl Default for ClientState {
    fn default() -> Self {
        Self::new()
    }
}

pub struct IdGenerator {
    next: u64,
}

impl IdGenerator {
    pub fn new() -> Self {
        Self { next: 0 }
    }
}

impl Default for IdGenerator {
    fn default() -> Self {
        Self::new()
    }
}

impl Iterator for IdGenerator {
    type Item = RequestId;
    fn next(&mut self) -> Option<Self::Item> {
        self.next += 1;
        Some(RequestId(format!("A{:04}", self.next % 10_000)))
    }
}
<|endoftext|>


<commit_before>extern crate udt;

use std::net::{UdpSocket, SocketAddr, IpAddr};
use std::str;
use std::fmt;
use udt::{UdtSocket, UdtError, UdtOpts, SocketType, SocketFamily};
use sodiumoxide::crypto::secretbox::xsalsa20poly1305::Key;

// TODO config
const UDT_BUF_SIZE: i32 = 1024000;
const MAX_MESSAGE_SIZE: usize = 1024 * 1024; // 1 MB max datagram

mod crypto {
    use sodiumoxide::crypto::secretbox;
    use sodiumoxide::crypto::secretbox::xsalsa20poly1305::{NONCEBYTES, Key, Nonce};

    pub fn seal(buf: &[u8], key: &Key) -> Vec<u8> {
        assert!(NONCEBYTES < u8::max_value() as usize,
                "Uh, why is the nonce size this big?");

        let nonce = secretbox::gen_nonce();
        let Nonce(noncebytes) = nonce;
        let mut hdr = vec![0u8; 1 + NONCEBYTES];
        hdr[0] = NONCEBYTES as u8;
        hdr[1..].clone_from_slice(&noncebytes);

        let mut sealed = secretbox::seal(&buf[..], &nonce, key);
        let mut msg = Vec::with_capacity(hdr.len() + sealed.len());
        msg.extend_from_slice(&hdr);
        msg.append(&mut sealed);
        msg
    }

    pub fn open(buf: &[u8], key: &Key) -> Result<Vec<u8>, String> {
        let noncelen = buf[0] as usize;
        if noncelen != NONCEBYTES {
            return Err(String::from("nonce length not recognized"));
        }
        if buf.len() < (1 + noncelen) {
            return Err(String::from("msg not long enough to contain nonce"));
        }
        let mut noncebytes = [0u8; NONCEBYTES];
        noncebytes.copy_from_slice(&buf[1..1 + noncelen]);
        let nonce = Nonce(noncebytes);

        secretbox::open(&buf[1 + noncelen..], &nonce, key)
            .map_err(|_| String::from("failed to decrypt"))
    }

    // Tests for the crypto module
    #[cfg(test)]
    mod test {
        use ::rand;
        use ::rand::distributions::{IndependentSample, Range};

        #[test]
        fn roundtrip() {
            use sodiumoxide::crypto::secretbox;
            // generate some data, seal it, and then make sure it unseals to the same thing
            let mut rng = rand::thread_rng();
            let between = Range::new(10, 10000);

            let key = secretbox::gen_key();
            let data_size: usize = between.ind_sample(&mut rng);
            let mut data = Vec::with_capacity(data_size);
            for _ in 0..data_size {
                data.push(rand::random());
            }

            let cipher_text = super::seal(&data, &key);
            let decrypted_text = super::open(&cipher_text, &key).unwrap();
            assert_eq!(decrypted_text, data);
        }
    }
}

fn new_udt_socket() -> UdtSocket {
    udt::init();
    let sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap();
    sock.setsockopt(UdtOpts::UDP_RCVBUF, UDT_BUF_SIZE).unwrap();
    sock.setsockopt(UdtOpts::UDP_SNDBUF, UDT_BUF_SIZE).unwrap();
    sock
}

fn send(sock: &UdtSocket, key: &Key, buf: &[u8]) -> Result<(), UdtError> {
    // FIXME don't unwrap, create an Error struct that can handle everything
    sock.sendmsg(&crypto::seal(buf, key)[..]).map(|_| ())
}

fn recv(sock: &UdtSocket, key: &Key) -> Result<Vec<u8>, UdtError> {
    crypto::open(&try!(sock.recvmsg(MAX_MESSAGE_SIZE))[..], key).map_err(|_| {
        UdtError {
            err_code: -1,
            err_msg: String::from("decryption failure"),
        }
    })
}

pub struct PortRange {
    start: u16,
    end: u16,
}

pub struct Server {
    pub ip_addr: IpAddr,
    pub port: u16,
    key: Key,
    sock: UdtSocket,
}

pub struct Client {
    addr: SocketAddr,
    sock: UdtSocket,
    key: Key,
}

pub struct ServerConnection<'a> {
    key: &'a Key,
    sock: UdtSocket,
}

impl Client {
    pub fn new(addr: SocketAddr, key: Key) -> Client {
        let sock = new_udt_socket();
        Client {
            addr: addr,
            sock: sock,
            key: key,
        }
    }

    pub fn connect(&self) -> Result<(), UdtError> {
        self.sock.connect(self.addr)
    }

    pub fn send(&self, buf: &[u8]) -> Result<(), UdtError> {
        send(&self.sock, &self.key, buf)
    }

    pub fn recv(&self) -> Result<Vec<u8>, UdtError> {
        recv(&self.sock, &self.key)
    }

    pub fn close(&self) -> Result<(), UdtError> {
        self.sock.close()
    }
}

impl Server {
    pub fn get_open_port(range: &PortRange) -> Result<u16, ()> {
        for p in range.start..range.end {
            if let Ok(_) = UdpSocket::bind(&format!("0.0.0.0:{}", p)[..]) {
                return Ok(p);
            }
        }
        Err(())
    }

    pub fn new(ip_addr: IpAddr, port: u16, key: Key) -> Server {
        let sock = new_udt_socket();
        sock.bind(SocketAddr::new(ip_addr, port)).unwrap();
        Server {
            sock: sock,
            ip_addr: ip_addr,
            port: port,
            key: key,
        }
    }

    pub fn listen(&self) -> Result<(), UdtError> {
        self.sock.listen(1)
    }

    pub fn accept(&self) -> Result<ServerConnection, UdtError> {
        self.sock.accept().map(|(sock, _)| {
            ServerConnection {
                key: &self.key,
                sock: sock,
            }
        })
    }
}

impl<'a> ServerConnection<'a> {
    pub fn send(&self, buf: &[u8]) -> Result<(), UdtError> {
        send(&self.sock, self.key, buf)
    }

    pub fn recv(&self) -> Result<Vec<u8>, UdtError> {
        recv(&self.sock, self.key)
    }

    pub fn close(&self) -> Result<(), UdtError> {
        self.sock.close()
    }
}

impl<'a> PortRange {
    fn new(start: u16, end: u16) -> Result<PortRange, &'a str> {
        if start > end {
            Err("range end must be greater than or equal to start")
        } else {
            Ok(PortRange {
                start: start,
                end: end,
            })
        }
    }

    pub fn from(s: &str) -> Result<PortRange, &'a str> {
        let sections: Vec<&str> = s.split('-').collect();
        if sections.len() != 2 {
            return Err("Range must be specified in the form of \"<start>-<end>\"");
        }
        let (start, end) = (sections[0].parse::<u16>(), sections[1].parse::<u16>());
        if start.is_err() || end.is_err() {
            return Err("improperly formatted port range");
        }
        PortRange::new(start.unwrap(), end.unwrap())
    }
}

impl fmt::Display for PortRange {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}-{}", self.start, self.end)
    }
}
<commit_msg>add some more sanity tests<commit_after>extern crate udt;

use std::net::{UdpSocket, SocketAddr, IpAddr};
use std::str;
use std::fmt;
use udt::{UdtSocket, UdtError, UdtOpts, SocketType, SocketFamily};
use sodiumoxide::crypto::secretbox::xsalsa20poly1305::Key;

// TODO config
const UDT_BUF_SIZE: i32 = 1024000;
const MAX_MESSAGE_SIZE: usize = 1024 * 1024; // 1 MB max datagram

mod crypto {
    use sodiumoxide::crypto::secretbox;
    use sodiumoxide::crypto::secretbox::xsalsa20poly1305::{NONCEBYTES, Key, Nonce};

    pub fn seal(buf: &[u8], key: &Key) -> Vec<u8> {
        assert!(NONCEBYTES < u8::max_value() as usize,
                "Uh, why is the nonce size this big?");

        let nonce = secretbox::gen_nonce();
        let Nonce(noncebytes) = nonce;
        let mut hdr = vec![0u8; 1 + NONCEBYTES];
        hdr[0] = NONCEBYTES as u8;
        hdr[1..].clone_from_slice(&noncebytes);

        let mut sealed = secretbox::seal(&buf[..], &nonce, key);
        let mut msg = Vec::with_capacity(hdr.len() + sealed.len());
        msg.extend_from_slice(&hdr);
        msg.append(&mut sealed);
        msg
    }

    pub fn open(buf: &[u8], key: &Key) -> Result<Vec<u8>, String> {
        let noncelen = buf[0] as usize;
        if noncelen != NONCEBYTES {
            return Err(String::from("nonce length not recognized"));
        }
        if buf.len() < (1 + noncelen) {
            return Err(String::from("msg not long enough to contain nonce"));
        }
        let mut noncebytes = [0u8; NONCEBYTES];
        noncebytes.copy_from_slice(&buf[1..1 + noncelen]);
        let nonce = Nonce(noncebytes);

        secretbox::open(&buf[1 + noncelen..], &nonce, key)
            .map_err(|_| String::from("failed to decrypt"))
    }

    // Tests for the crypto module
    #[cfg(test)]
    mod test {
        use ::rand;
        use ::rand::distributions::{IndependentSample, Range};

        #[test]
        fn roundtrip() {
            use sodiumoxide::crypto::secretbox;
            // generate some data, seal it, and then make sure it unseals to the same thing
            let mut rng = rand::thread_rng();
            let between = Range::new(10, 10000);

            let key = secretbox::gen_key();
            let data_size: usize = between.ind_sample(&mut rng);
            let mut data = Vec::with_capacity(data_size);
            for _ in 0..data_size {
                data.push(rand::random());
            }

            let cipher_text = super::seal(&data, &key);
            let decrypted_text = super::open(&cipher_text, &key).unwrap();
            assert_eq!(decrypted_text, data);
        }

        #[test]
        fn key_sanity() {
            use std::collections::HashSet;
            use sodiumoxide::crypto::secretbox;
            use sodiumoxide::crypto::secretbox::xsalsa20poly1305::Key;

            let mut set: HashSet<[u8;32]> = HashSet::with_capacity(10000);

            for _ in 0..10000 {
                let key = secretbox::gen_key();
                let Key(keybytes) = key;
                assert!(set.insert(keybytes));
            }
        }

        #[test]
        fn nonce_sanity() {
            use std::collections::HashSet;
            use sodiumoxide::crypto::secretbox;
            use sodiumoxide::crypto::secretbox::xsalsa20poly1305::Nonce;

            let mut set: HashSet<[u8;24]> = HashSet::with_capacity(10000);

            for _ in 0..10000 {
                let nonce = secretbox::gen_nonce();
                let Nonce(noncebytes) = nonce;
                assert!(set.insert(noncebytes));
            }
        }
    }
}

fn new_udt_socket() -> UdtSocket {
    udt::init();
    let sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap();
    sock.setsockopt(UdtOpts::UDP_RCVBUF, UDT_BUF_SIZE).unwrap();
    sock.setsockopt(UdtOpts::UDP_SNDBUF, UDT_BUF_SIZE).unwrap();
    sock
}

fn send(sock: &UdtSocket, key: &Key, buf: &[u8]) -> Result<(), UdtError> {
    // FIXME don't unwrap, create an Error struct that can handle everything
    sock.sendmsg(&crypto::seal(buf, key)[..]).map(|_| ())
}

fn recv(sock: &UdtSocket, key: &Key) -> Result<Vec<u8>, UdtError> {
    crypto::open(&try!(sock.recvmsg(MAX_MESSAGE_SIZE))[..], key).map_err(|_| {
        UdtError {
            err_code: -1,
            err_msg: String::from("decryption failure"),
        }
    })
}

pub struct PortRange {
    start: u16,
    end: u16,
}

pub struct Server {
    pub ip_addr: IpAddr,
    pub port: u16,
    key: Key,
    sock: UdtSocket,
}

pub struct Client {
    addr: SocketAddr,
    sock: UdtSocket,
    key: Key,
}

pub struct ServerConnection<'a> {
    key: &'a Key,
    sock: UdtSocket,
}

impl Client {
    pub fn new(addr: SocketAddr, key: Key) -> Client {
        let sock = new_udt_socket();
        Client {
            addr: addr,
            sock: sock,
            key: key,
        }
    }

    pub fn connect(&self) -> Result<(), UdtError> {
        self.sock.connect(self.addr)
    }

    pub fn send(&self, buf: &[u8]) -> Result<(), UdtError> {
        send(&self.sock, &self.key, buf)
    }

    pub fn recv(&self) -> Result<Vec<u8>, UdtError> {
        recv(&self.sock, &self.key)
    }

    pub fn close(&self) -> Result<(), UdtError> {
        self.sock.close()
    }
}

impl Server {
    pub fn get_open_port(range: &PortRange) -> Result<u16, ()> {
        for p in range.start..range.end {
            if let Ok(_) = UdpSocket::bind(&format!("0.0.0.0:{}", p)[..]) {
                return Ok(p);
            }
        }
        Err(())
    }

    pub fn new(ip_addr: IpAddr, port: u16, key: Key) -> Server {
        let sock = new_udt_socket();
        sock.bind(SocketAddr::new(ip_addr, port)).unwrap();
        Server {
            sock: sock,
            ip_addr: ip_addr,
            port: port,
            key: key,
        }
    }

    pub fn listen(&self) -> Result<(), UdtError> {
        self.sock.listen(1)
    }

    pub fn accept(&self) -> Result<ServerConnection, UdtError> {
        self.sock.accept().map(|(sock, _)| {
            ServerConnection {
                key: &self.key,
                sock: sock,
            }
        })
    }
}

impl<'a> ServerConnection<'a> {
    pub fn send(&self, buf: &[u8]) -> Result<(), UdtError> {
        send(&self.sock, self.key, buf)
    }

    pub fn recv(&self) -> Result<Vec<u8>, UdtError> {
        recv(&self.sock, self.key)
    }

    pub fn close(&self) -> Result<(), UdtError> {
        self.sock.close()
    }
}

impl<'a> PortRange {
    fn new(start: u16, end: u16) -> Result<PortRange, &'a str> {
        if start > end {
            Err("range end must be greater than or equal to start")
        } else {
            Ok(PortRange {
                start: start,
                end: end,
            })
        }
    }

    pub fn from(s: &str) -> Result<PortRange, &'a str> {
        let sections: Vec<&str> = s.split('-').collect();
        if sections.len() != 2 {
            return Err("Range must be specified in the form of \"<start>-<end>\"");
        }
        let (start, end) = (sections[0].parse::<u16>(), sections[1].parse::<u16>());
        if start.is_err() || end.is_err() {
            return Err("improperly formatted port range");
        }
        PortRange::new(start.unwrap(), end.unwrap())
    }
}

impl fmt::Display for PortRange {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}-{}", self.start, self.end)
    }
}
<|endoftext|>


<commit_before>//! CHIP-8 emulator backend.
//! You can develop your own frontends for it.
//!
//! The reference frontend is
//! [crusty-chip-sfml](https://github.com/crumblingstatue/crusty-chip-sfml).

use std::slice::bytes::copy_memory;

static START_ADDR: u16 = 0x200;
static MEM_SIZE: uint = 4096;
pub static DISPLAY_WIDTH: uint = 64;
pub static DISPLAY_HEIGHT: uint = 32;

static fontset: [[u8, .. 5], .. 0x10] = [
    [0xF0, 0x90, 0x90, 0x90, 0xF0], // 0
    [0x20, 0x60, 0x20, 0x20, 0x70], // 1
    [0xF0, 0x10, 0xF0, 0x80, 0xF0], // 2
    [0xF0, 0x10, 0xF0, 0x10, 0xF0], // 3
    [0x90, 0x90, 0xF0, 0x10, 0x10], // 4
    [0xF0, 0x80, 0xF0, 0x10, 0xF0], // 5
    [0xF0, 0x80, 0xF0, 0x90, 0xF0], // 6
    [0xF0, 0x10, 0x20, 0x40, 0x40], // 7
    [0xF0, 0x90, 0xF0, 0x90, 0xF0], // 8
    [0xF0, 0x90, 0xF0, 0x10, 0xF0], // 9
    [0xF0, 0x90, 0xF0, 0x90, 0x90], // A
    [0xE0, 0x90, 0xE0, 0x90, 0xE0], // B
    [0xF0, 0x80, 0x80, 0x80, 0xF0], // C
    [0xE0, 0x90, 0x90, 0x90, 0xE0], // D
    [0xF0, 0x80, 0xF0, 0x80, 0xF0], // E
    [0xF0, 0x80, 0xF0, 0x80, 0x80], // F
];

type DrawCallback<'a> = |pixels: &[u8]|: 'a;

/// CHIP-8 virtual machine
pub struct Chip8<'a> {
    ram: [u8, .. MEM_SIZE],
    v: [u8, .. 16],
    i: u16,
    delay_timer: u8,
    sound_timer: u8,
    pc: u16,
    sp: u8,
    stack: [u16, .. 16],
    display: [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT],
    draw_callback: DrawCallback<'a>
}

impl <'a> Chip8 <'a> {

    /// Create a new Chip8 VM
    ///
    /// ## Arguments ##
    /// * draw_callback - Callback used when drawing
    pub fn new(draw_callback: DrawCallback<'a>) -> Chip8<'a> {
        Chip8 {
            ram: [0u8, .. MEM_SIZE],
            v: [0u8, .. 16],
            i: 0u16,
            delay_timer: 0u8,
            sound_timer: 0u8,
            pc: START_ADDR,
            sp: 0,
            stack: [0u16, .. 16],
            display: [0u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT],
            draw_callback: draw_callback
        }
    }

    /// Load a ROM
    ///
    /// ## Arguments ##
    /// * rom - ROM to load
    pub fn load_rom(&mut self, rom: &[u8]) {
        let len = self.ram.len();
        copy_memory(self.ram.mut_slice(START_ADDR as uint, len), rom);
    }

    /// Do an emulation cycle.
    pub fn do_cycle(&mut self) {
        let ins = self.get_ins();
        self.pc += 2;

        match ins & 0xF000 {
            0x1000 => self.jump_addr(ins & 0x0FFF),
            0x3000 => self.skip_next_vx_eq(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0x5000 => match ins & 0x000F {
                0x0000 => self.skip_next_vx_eq_vy(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint),
                _ => fail!("Unknown 0x5XXX instruction: {:x}", ins)
            },
            0x6000 => self.set_vx_byte(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0x7000 => self.add_vx_byte(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0x8000 => match ins & 0x000F {
                0x0000 => self.set_vx_to_vy(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint),
                0x0004 => self.add_vx_vy(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint),
                0x0005 => self.sub_vx_vy(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint),
                _ => fail!("Unknown 0x8XXX instruction: {:x}", ins)
            },
            0x9000 => match ins & 0x000F {
                0x0000 => self.skip_next_vx_ne_vy(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint),
                _ => fail!("Unknown 0x9XXX instruction: {:x}", ins)
            },
            0xA000 => self.set_i(ins & 0x0FFF),
            0xC000 => self.set_vx_rand_and(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0xD000 => self.display_sprite(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint, ((ins & 0x000F)) as uint),
            0xF000 => match ins & 0x00FF {
                0x0055 => self.copy_v0_through_vx_to_mem(((ins & 0x0F00) >> 8) as uint),
                0x0065 => self.read_v0_through_vx_from_mem(((ins & 0x0F00) >> 8) as uint),
                0x001E => self.add_vx_to_i(((ins & 0x0F00) >> 8) as uint),
                _ => fail!("Unknown 0xFXXX instruction: {:x}", ins)
            },
            _ => fail!("Unknown instruction: {:04x}", ins)
        }
    }

    fn get_ins(&self) -> u16 {
        let b1 = self.ram[self.pc as uint];
        let b2 = self.ram[(self.pc + 1) as uint];
        b1 as u16 << 8 | b2 as u16
    }

    fn set_i(&mut self, to: u16) {
        self.i = to;
    }

    fn set_vx_rand_and(&mut self, x: uint, to: u8) {
        use std::rand::{task_rng, Rng};
        let mut rgen = task_rng();
        self.v[x] = rgen.gen::<u8>() & to;
    }

    fn skip_next_vx_eq(&mut self, x: uint, to: u8) {
        if self.v[x] == to {
            self.pc += 2;
        }
    }

    fn display_sprite(&mut self, vx: uint, vy: uint, n: uint) {
        let x_off = self.v[vx] as uint;
        let y_off = self.v[vy] as uint * DISPLAY_WIDTH;
        let offset = x_off + y_off;

        for mut y in range(0u, n) {
            if y >= DISPLAY_HEIGHT {
                y = y - DISPLAY_HEIGHT;
            }
            let b = self.ram[self.i as uint + y];
            for mut x in range(0u, 8) {
                if x >= DISPLAY_WIDTH {
                    x = x - DISPLAY_WIDTH;
                }
                let idx = offset + (y * DISPLAY_WIDTH) + x;
                if idx < DISPLAY_WIDTH * DISPLAY_HEIGHT {
                    self.display[idx] ^= b & (0b10000000 >> x);
                } else {
                    println!("Warning: Out of bounds VRAM write: {}", idx);
                }
            }
        }

        (self.draw_callback)(self.display);
    }

    fn add_vx_byte(&mut self, x: uint, byte: u8) {
        self.v[x] += byte;
    }

    fn set_vx_byte(&mut self, x: uint, byte: u8) {
        self.v[x] = byte;
    }

    fn jump_addr(&mut self, addr: u16) {
        self.pc = addr;
    }

    fn set_vx_to_vy(&mut self, x: uint, y: uint) {
        self.v[x] = self.v[y];
    }

    fn add_vx_vy(&mut self, x: uint, y: uint) {
        let result = (self.v[x] + self.v[y]) as u16;
        self.v[0xF] = (result > 255) as u8;
        self.v[x] = result as u8;
    }

    fn sub_vx_vy(&mut self, x: uint, y: uint) {
        self.v[0xF] = (self.v[x] > self.v[y]) as u8;
        self.v[x] -= self.v[y];
    }

    fn add_vx_to_i(&mut self, x: uint) {
        self.i += x as u16;
    }

    fn copy_v0_through_vx_to_mem(&mut self, x: uint) {
        if x == 0 {
            return;
        }
        copy_memory(self.ram.mut_slice(self.i as uint, self.i as uint + x), self.v.slice(0, x));
    }

    fn read_v0_through_vx_from_mem(&mut self, x: uint) {
        if x == 0 {
            return;
        }
        copy_memory(self.v.mut_slice(0, x), self.ram.slice(self.i as uint, self.i as uint + x));
    }

    fn skip_next_vx_eq_vy(&mut self, x: uint, y: uint) {
        if self.v[x] == self.v[y] {
            self.pc += 2;
        }
    }

    fn skip_next_vx_ne_vy(&mut self, x: uint, y: uint) {
        if self.v[x] != self.v[y] {
            self.pc += 2;
        }
    }
}
<commit_msg>Implement clear_display<commit_after>//! CHIP-8 emulator backend.
//! You can develop your own frontends for it.
//!
//! The reference frontend is
//! [crusty-chip-sfml](https://github.com/crumblingstatue/crusty-chip-sfml).

use std::slice::bytes::copy_memory;

static START_ADDR: u16 = 0x200;
static MEM_SIZE: uint = 4096;
pub static DISPLAY_WIDTH: uint = 64;
pub static DISPLAY_HEIGHT: uint = 32;

static fontset: [[u8, .. 5], .. 0x10] = [
    [0xF0, 0x90, 0x90, 0x90, 0xF0], // 0
    [0x20, 0x60, 0x20, 0x20, 0x70], // 1
    [0xF0, 0x10, 0xF0, 0x80, 0xF0], // 2
    [0xF0, 0x10, 0xF0, 0x10, 0xF0], // 3
    [0x90, 0x90, 0xF0, 0x10, 0x10], // 4
    [0xF0, 0x80, 0xF0, 0x10, 0xF0], // 5
    [0xF0, 0x80, 0xF0, 0x90, 0xF0], // 6
    [0xF0, 0x10, 0x20, 0x40, 0x40], // 7
    [0xF0, 0x90, 0xF0, 0x90, 0xF0], // 8
    [0xF0, 0x90, 0xF0, 0x10, 0xF0], // 9
    [0xF0, 0x90, 0xF0, 0x90, 0x90], // A
    [0xE0, 0x90, 0xE0, 0x90, 0xE0], // B
    [0xF0, 0x80, 0x80, 0x80, 0xF0], // C
    [0xE0, 0x90, 0x90, 0x90, 0xE0], // D
    [0xF0, 0x80, 0xF0, 0x80, 0xF0], // E
    [0xF0, 0x80, 0xF0, 0x80, 0x80], // F
];

type DrawCallback<'a> = |pixels: &[u8]|: 'a;

/// CHIP-8 virtual machine
pub struct Chip8<'a> {
    ram: [u8, .. MEM_SIZE],
    v: [u8, .. 16],
    i: u16,
    delay_timer: u8,
    sound_timer: u8,
    pc: u16,
    sp: u8,
    stack: [u16, .. 16],
    display: [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT],
    draw_callback: DrawCallback<'a>
}

impl <'a> Chip8 <'a> {

    /// Create a new Chip8 VM
    ///
    /// ## Arguments ##
    /// * draw_callback - Callback used when drawing
    pub fn new(draw_callback: DrawCallback<'a>) -> Chip8<'a> {
        Chip8 {
            ram: [0u8, .. MEM_SIZE],
            v: [0u8, .. 16],
            i: 0u16,
            delay_timer: 0u8,
            sound_timer: 0u8,
            pc: START_ADDR,
            sp: 0,
            stack: [0u16, .. 16],
            display: [0u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT],
            draw_callback: draw_callback
        }
    }

    /// Load a ROM
    ///
    /// ## Arguments ##
    /// * rom - ROM to load
    pub fn load_rom(&mut self, rom: &[u8]) {
        let len = self.ram.len();
        copy_memory(self.ram.mut_slice(START_ADDR as uint, len), rom);
    }

    /// Do an emulation cycle.
    pub fn do_cycle(&mut self) {
        let ins = self.get_ins();
        self.pc += 2;

        match ins & 0xF000 {
            0x0000 => match ins & 0x0FFF {
                0x00E0 => self.clear_display(),
                _ => self.jump_to_sys_routine(0)
            },
            0x1000 => self.jump_addr(ins & 0x0FFF),
            0x3000 => self.skip_next_vx_eq(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0x5000 => match ins & 0x000F {
                0x0000 => self.skip_next_vx_eq_vy(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint),
                _ => fail!("Unknown 0x5XXX instruction: {:x}", ins)
            },
            0x6000 => self.set_vx_byte(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0x7000 => self.add_vx_byte(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0x8000 => match ins & 0x000F {
                0x0000 => self.set_vx_to_vy(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint),
                0x0004 => self.add_vx_vy(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint),
                0x0005 => self.sub_vx_vy(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint),
                _ => fail!("Unknown 0x8XXX instruction: {:x}", ins)
            },
            0x9000 => match ins & 0x000F {
                0x0000 => self.skip_next_vx_ne_vy(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint),
                _ => fail!("Unknown 0x9XXX instruction: {:x}", ins)
            },
            0xA000 => self.set_i(ins & 0x0FFF),
            0xC000 => self.set_vx_rand_and(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0xD000 => self.display_sprite(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint, ((ins & 0x000F)) as uint),
            0xF000 => match ins & 0x00FF {
                0x0055 => self.copy_v0_through_vx_to_mem(((ins & 0x0F00) >> 8) as uint),
                0x0065 => self.read_v0_through_vx_from_mem(((ins & 0x0F00) >> 8) as uint),
                0x001E => self.add_vx_to_i(((ins & 0x0F00) >> 8) as uint),
                _ => fail!("Unknown 0xFXXX instruction: {:x}", ins)
            },
            _ => fail!("Unknown instruction: {:04x}", ins)
        }
    }

    fn get_ins(&self) -> u16 {
        let b1 = self.ram[self.pc as uint];
        let b2 = self.ram[(self.pc + 1) as uint];
        b1 as u16 << 8 | b2 as u16
    }

    fn set_i(&mut self, to: u16) {
        self.i = to;
    }

    fn set_vx_rand_and(&mut self, x: uint, to: u8) {
        use std::rand::{task_rng, Rng};
        let mut rgen = task_rng();
        self.v[x] = rgen.gen::<u8>() & to;
    }

    fn skip_next_vx_eq(&mut self, x: uint, to: u8) {
        if self.v[x] == to {
            self.pc += 2;
        }
    }

    fn display_sprite(&mut self, vx: uint, vy: uint, n: uint) {
        let x_off = self.v[vx] as uint;
        let y_off = self.v[vy] as uint * DISPLAY_WIDTH;
        let offset = x_off + y_off;

        for mut y in range(0u, n) {
            if y >= DISPLAY_HEIGHT {
                y = y - DISPLAY_HEIGHT;
            }
            let b = self.ram[self.i as uint + y];
            for mut x in range(0u, 8) {
                if x >= DISPLAY_WIDTH {
                    x = x - DISPLAY_WIDTH;
                }
                let idx = offset + (y * DISPLAY_WIDTH) + x;
                if idx < DISPLAY_WIDTH * DISPLAY_HEIGHT {
                    self.display[idx] ^= b & (0b10000000 >> x);
                } else {
                    println!("Warning: Out of bounds VRAM write: {}", idx);
                }
            }
        }

        (self.draw_callback)(self.display);
    }

    fn add_vx_byte(&mut self, x: uint, byte: u8) {
        self.v[x] += byte;
    }

    fn set_vx_byte(&mut self, x: uint, byte: u8) {
        self.v[x] = byte;
    }

    fn jump_addr(&mut self, addr: u16) {
        self.pc = addr;
    }

    fn set_vx_to_vy(&mut self, x: uint, y: uint) {
        self.v[x] = self.v[y];
    }

    fn add_vx_vy(&mut self, x: uint, y: uint) {
        let result = (self.v[x] + self.v[y]) as u16;
        self.v[0xF] = (result > 255) as u8;
        self.v[x] = result as u8;
    }

    fn sub_vx_vy(&mut self, x: uint, y: uint) {
        self.v[0xF] = (self.v[x] > self.v[y]) as u8;
        self.v[x] -= self.v[y];
    }

    fn add_vx_to_i(&mut self, x: uint) {
        self.i += x as u16;
    }

    fn copy_v0_through_vx_to_mem(&mut self, x: uint) {
        if x == 0 {
            return;
        }
        copy_memory(self.ram.mut_slice(self.i as uint, self.i as uint + x), self.v.slice(0, x));
    }

    fn read_v0_through_vx_from_mem(&mut self, x: uint) {
        if x == 0 {
            return;
        }
        copy_memory(self.v.mut_slice(0, x), self.ram.slice(self.i as uint, self.i as uint + x));
    }

    fn skip_next_vx_eq_vy(&mut self, x: uint, y: uint) {
        if self.v[x] == self.v[y] {
            self.pc += 2;
        }
    }

    fn skip_next_vx_ne_vy(&mut self, x: uint, y: uint) {
        if self.v[x] != self.v[y] {
            self.pc += 2;
        }
    }

    fn clear_display(&mut self) {
        for px in self.display.mut_iter() {
            *px = 0;
        }
    }

    fn jump_to_sys_routine(&mut self, addr: uint) {
        unimplemented!();
    }
}
<|endoftext|>


<commit_before>pub struct Identifier;
<commit_msg>todo for identifier<commit_after>// TODO: Implement Identifier
pub struct Identifier;
<|endoftext|>