<commit_before>use gl;
use gl::types::*;
use gl_context::{GLContext, GLContextExistence};
use shader::*;
use std::cell::RefCell;
use std::kinds::marker::ContravariantLifetime;
use std::mem;
use std::ptr;
use std::rc::Rc;

/// Gets the id number for a given input of the shader program.
#[allow(non_snake_case)]
pub fn glGetAttribLocation(shader_program: GLuint, name: &str) -> GLint {
  name.with_c_str(|ptr| unsafe { gl::GetAttribLocation(shader_program, ptr) })
}

pub struct BufferHandle<'a> {
  pub gl_id: GLuint,
  pub lifetime: ContravariantLifetime<'a>,
}

impl<'a> BufferHandle<'a> {
  pub fn new(_gl: &'a GLContextExistence) -> BufferHandle<'a> {
    let mut gl_id = 0;

    unsafe {
      gl::GenBuffers(1, &mut gl_id);
    }

    assert!(gl_id != 0);

    BufferHandle {
      gl_id: gl_id,
      lifetime: ContravariantLifetime,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for BufferHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteBuffers(1, &self.gl_id);
    }
  }
}

/// Fixed-size VRAM buffer for individual bytes.
pub struct GLByteBuffer<'a> {
  pub handle: BufferHandle<'a>,
  /// number of bytes in the buffer.
  pub length: uint,
  /// maximum number of bytes in the buffer.
  pub capacity: uint,
}

impl<'a> GLByteBuffer<'a> {
  /// Creates a new array of objects on the GPU.
  /// capacity is provided in units of size slice_span.
  pub fn new(
    gl: &'a GLContextExistence,
    gl_context: &mut GLContext,
    capacity: uint,
  ) -> GLByteBuffer<'a> {
    let handle = BufferHandle::new(gl);

    unsafe {
      gl::BindBuffer(gl::ARRAY_BUFFER, handle.gl_id);

      gl::BufferData(
        gl::ARRAY_BUFFER,
        capacity as GLsizeiptr,
        ptr::null(),
        gl::DYNAMIC_DRAW,
      );
    }

    match gl_context.get_error() {
      gl::NO_ERROR => {},
      gl::OUT_OF_MEMORY => panic!("Out of VRAM"),
      err => panic!("OpenGL error 0x{:x}", err),
    }

    GLByteBuffer {
      handle: handle,
      length: 0,
      capacity: capacity,
    }
  }

  /// Add more data into this buffer.
  pub unsafe fn push(&mut self, gl: &mut GLContext, vs: *const u8, count: uint) {
    assert!(
      self.length + count <= self.capacity,
      "GLByteBuffer::push {} into a {}/{} full GLByteBuffer",
      count,
      self.length,
      self.capacity
    );

    self.update_inner(gl, self.length, vs, count);
    self.length += count;
  }

  pub fn swap_remove(&mut self, _gl: &mut GLContext, i: uint, count: uint) {
    assert!(count <= self.length);
    self.length -= count;
    assert!(i <= self.length);

    // In the `i == self.length` case, we don't bother with the swap;
    // decreasing `self.length` is enough.

    if i < self.length {
      assert!(
        i <= self.length - count,
        "GLByteBuffer::swap_remove would cause copy in overlapping regions"
      );

      unsafe {
        gl::BindBuffer(gl::ARRAY_BUFFER, self.handle.gl_id);

        gl::CopyBufferSubData(
          gl::ARRAY_BUFFER,
          gl::ARRAY_BUFFER,
          self.length as i64,
          i as i64,
          count as i64,
        );
      }
    }
  }

  pub unsafe fn update(&self, gl: &mut GLContext, idx: uint, vs: *const u8, count: uint) {
    assert!(idx + count <= self.length);
    self.update_inner(gl, idx, vs, count);
  }

  unsafe fn update_inner(
    &self,
    _gl: &mut GLContext,
    idx: uint,
    vs: *const u8,
    count: uint,
  ) {
    assert!(idx + count <= self.capacity);

    gl::BindBuffer(gl::ARRAY_BUFFER, self.handle.gl_id);

    gl::BufferSubData(
      gl::ARRAY_BUFFER,
      idx as i64,
      count as i64,
      mem::transmute(vs)
    );
  }
}

/// Fixed-size typed VRAM buffer, optimized for bulk inserts.
pub struct GLBuffer<'a, T> {
  pub byte_buffer: GLByteBuffer<'a>,
  pub length: uint,
}

impl<'a, T> GLBuffer<'a, T> {
  pub fn new(
    gl: &'a GLContextExistence,
    gl_context: &mut GLContext,
    capacity: uint,
  ) -> GLBuffer<'a, T> {
    GLBuffer {
      byte_buffer: GLByteBuffer::new(gl, gl_context, capacity * mem::size_of::<T>()),
      length: 0,
    }
  }

  pub fn push(&mut self, gl: &mut GLContext, vs: &[T]) {
    unsafe {
      self.byte_buffer.push(
        gl,
        mem::transmute(vs.as_ptr()),
        mem::size_of::<T>() * vs.len()
      );
    }
    self.length += vs.len();
  }

  pub fn update(&mut self, gl: &mut GLContext, idx: uint, vs: &[T]) {
    unsafe {
      self.byte_buffer.update(
        gl,
        mem::size_of::<T>() * idx,
        mem::transmute(vs.as_ptr()),
        mem::size_of::<T>() * vs.len(),
      );
    }
  }

  pub fn swap_remove(&mut self, gl: &mut GLContext, idx: uint, count: uint) {
    self.byte_buffer.swap_remove(
      gl,
      mem::size_of::<T>() * idx,
      mem::size_of::<T>() * count,
    );
    self.length -= count;
  }
}

#[deriving(Show)]
#[deriving(Copy, Clone)]
pub enum DrawMode {
  Lines,
  Triangles,
  Points,
}

impl DrawMode {
  fn to_enum(&self) -> GLenum {
    match *self {
      DrawMode::Lines     => gl::LINES,
      DrawMode::Triangles => gl::TRIANGLES,
      DrawMode::Points    => gl::POINTS,
    }
  }
}

#[deriving(Show)]
#[deriving(Copy, Clone)]
pub enum GLType {
  Float,
  UInt,
  Int,
}

impl GLType {
  pub fn size(&self) -> uint {
    match *self {
      GLType::Float => mem::size_of::<GLfloat>(),
      GLType::UInt  => mem::size_of::<GLuint>(),
      GLType::Int   => mem::size_of::<GLint>(),
    }
  }

  pub fn gl_enum(&self) -> GLenum {
    match *self {
      GLType::Float => gl::FLOAT,
      GLType::UInt  => gl::UNSIGNED_INT,
      GLType::Int   => gl::INT,
    }
  }

  pub fn is_integral(&self) -> bool {
    match *self {
      GLType::Float => false,
      GLType::UInt  => true,
      GLType::Int   => true,
    }
  }
}

#[deriving(Show)]
/// Specifies how to pass data from OpenGL to the vertex shaders.
pub struct VertexAttribData<'a> {
  /// Cooresponds to the shader's `input variable`.
  pub name: &'a str,
  /// The size of this attribute, in the provided units.
  pub size: uint,
  pub unit: GLType,
}

pub struct ArrayHandle<'a> {
  pub lifetime: ContravariantLifetime<'a>,
  pub gl_id: GLuint,
}

impl<'a> ArrayHandle<'a> {
  pub fn new(_gl: &'a GLContextExistence) -> ArrayHandle<'a> {
    let mut gl_id = 0;
    unsafe {
      gl::GenVertexArrays(1, &mut gl_id);
    }

    ArrayHandle {
      gl_id: gl_id,
      lifetime: ContravariantLifetime,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for ArrayHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteVertexArrays(1, &self.gl_id);
    }
  }
}

/// A fixed-capacity array of bytes passed to OpenGL.
pub struct GLArray<'a, T> {
  pub buffer: GLBuffer<'a, T>,
  pub handle: ArrayHandle<'a>,
  /// How to draw this buffer. Ex: gl::LINES, gl::TRIANGLES, etc.
  pub mode: GLenum,
  /// size of T in vertices
  pub attrib_span: uint,
  /// length in vertices
  pub length: uint,
}

impl<'a, T> GLArray<'a, T> {
  /// Creates a new array of objects on the GPU.
  /// capacity is provided in units of size slice_span.
  pub fn new(
    gl: &'a GLContextExistence,
    _gl_context: &mut GLContext,
    shader_program: Rc<RefCell<Shader>>,
    attribs: &[VertexAttribData],
    mode: DrawMode,
    buffer: GLBuffer<'a, T>,
  ) -> GLArray<'a, T> {
    let handle = ArrayHandle::new(gl);

    unsafe {
      gl::BindVertexArray(handle.gl_id);
    }

    let mut offset = 0;
    let attrib_span = {
      let mut attrib_span = 0;
      for attrib in attribs.iter() {
        attrib_span += attrib.size * attrib.unit.size();
      }
      attrib_span
    };
    for attrib in attribs.iter() {
      let shader_attrib =
        glGetAttribLocation(
          shader_program.borrow().handle.gl_id,
          attrib.name
        );
      assert!(shader_attrib != -1, "shader attribute \"{}\" not found", attrib.name);
      let shader_attrib = shader_attrib as GLuint;

      unsafe {
        gl::EnableVertexAttribArray(shader_attrib);

        if attrib.unit.is_integral() {
          gl::VertexAttribIPointer(
            shader_attrib,
            attrib.size as i32,
            attrib.unit.gl_enum(),
            attrib_span as i32,
            ptr::null().offset(offset),
          );
        } else {
          gl::VertexAttribPointer(
            shader_attrib,
            attrib.size as i32,
            attrib.unit.gl_enum(),
            gl::FALSE as GLboolean,
            attrib_span as i32,
            ptr::null().offset(offset),
          );
        }
      }
      offset += (attrib.size * attrib.unit.size()) as int;
    }

    match unsafe { gl::GetError() } {
      gl::NO_ERROR => {},
      err => panic!("OpenGL error 0x{:x}", err),
    }

    assert!(mem::size_of::<T>() % attrib_span == 0);

    GLArray {
      buffer: buffer,
      handle: handle,
      mode: mode.to_enum(),
      attrib_span: mem::size_of::<T>() / attrib_span,
      length: 0,
    }
  }

  pub fn push(&mut self, gl: &mut GLContext, vs: &[T]) {
    self.buffer.push(gl, vs);
    self.length += vs.len() * self.attrib_span;
  }

  pub fn swap_remove(&mut self, gl: &mut GLContext, idx: uint, count: uint) {
    self.buffer.swap_remove(gl, idx, count);
    self.length -= count * self.attrib_span;
  }

  /// Draws all the queued triangles to the screen.
  pub fn draw(&self, gl: &mut GLContext) {
    self.draw_slice(gl, 0, self.buffer.length);
  }

  /// Draw some subset of the triangle array.
  pub fn draw_slice(&self, _gl: &mut GLContext, start: uint, len: uint) {
    assert!(start + len <= self.length);

    unsafe {
      gl::BindVertexArray(self.handle.gl_id);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.buffer.byte_buffer.handle.gl_id);

      gl::DrawArrays(self.mode, (start * self.attrib_span) as i32, (len * self.attrib_span) as i32);
    }
  }
}
<commit_msg>GLArray assumes its type param is a single vertex.<commit_after>use gl;
use gl::types::*;
use gl_context::{GLContext, GLContextExistence};
use shader::*;
use std::cell::RefCell;
use std::kinds::marker::ContravariantLifetime;
use std::mem;
use std::ptr;
use std::rc::Rc;

/// Gets the id number for a given input of the shader program.
#[allow(non_snake_case)]
pub fn glGetAttribLocation(shader_program: GLuint, name: &str) -> GLint {
  name.with_c_str(|ptr| unsafe { gl::GetAttribLocation(shader_program, ptr) })
}

pub struct BufferHandle<'a> {
  pub gl_id: GLuint,
  pub lifetime: ContravariantLifetime<'a>,
}

impl<'a> BufferHandle<'a> {
  pub fn new(_gl: &'a GLContextExistence) -> BufferHandle<'a> {
    let mut gl_id = 0;

    unsafe {
      gl::GenBuffers(1, &mut gl_id);
    }

    assert!(gl_id != 0);

    BufferHandle {
      gl_id: gl_id,
      lifetime: ContravariantLifetime,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for BufferHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteBuffers(1, &self.gl_id);
    }
  }
}

/// Fixed-size VRAM buffer for individual bytes.
pub struct GLByteBuffer<'a> {
  pub handle: BufferHandle<'a>,
  /// number of bytes in the buffer.
  pub length: uint,
  /// maximum number of bytes in the buffer.
  pub capacity: uint,
}

impl<'a> GLByteBuffer<'a> {
  /// Creates a new array of objects on the GPU.
  /// capacity is provided in units of size slice_span.
  pub fn new(
    gl: &'a GLContextExistence,
    gl_context: &mut GLContext,
    capacity: uint,
  ) -> GLByteBuffer<'a> {
    let handle = BufferHandle::new(gl);

    unsafe {
      gl::BindBuffer(gl::ARRAY_BUFFER, handle.gl_id);

      gl::BufferData(
        gl::ARRAY_BUFFER,
        capacity as GLsizeiptr,
        ptr::null(),
        gl::DYNAMIC_DRAW,
      );
    }

    match gl_context.get_error() {
      gl::NO_ERROR => {},
      gl::OUT_OF_MEMORY => panic!("Out of VRAM"),
      err => panic!("OpenGL error 0x{:x}", err),
    }

    GLByteBuffer {
      handle: handle,
      length: 0,
      capacity: capacity,
    }
  }

  /// Add more data into this buffer.
  pub unsafe fn push(&mut self, gl: &mut GLContext, vs: *const u8, count: uint) {
    assert!(
      self.length + count <= self.capacity,
      "GLByteBuffer::push {} into a {}/{} full GLByteBuffer",
      count,
      self.length,
      self.capacity
    );

    self.update_inner(gl, self.length, vs, count);
    self.length += count;
  }

  pub fn swap_remove(&mut self, _gl: &mut GLContext, i: uint, count: uint) {
    assert!(count <= self.length);
    self.length -= count;
    assert!(i <= self.length);

    // In the `i == self.length` case, we don't bother with the swap;
    // decreasing `self.length` is enough.

    if i < self.length {
      assert!(
        i <= self.length - count,
        "GLByteBuffer::swap_remove would cause copy in overlapping regions"
      );

      unsafe {
        gl::BindBuffer(gl::ARRAY_BUFFER, self.handle.gl_id);

        gl::CopyBufferSubData(
          gl::ARRAY_BUFFER,
          gl::ARRAY_BUFFER,
          self.length as i64,
          i as i64,
          count as i64,
        );
      }
    }
  }

  pub unsafe fn update(&self, gl: &mut GLContext, idx: uint, vs: *const u8, count: uint) {
    assert!(idx + count <= self.length);
    self.update_inner(gl, idx, vs, count);
  }

  unsafe fn update_inner(
    &self,
    _gl: &mut GLContext,
    idx: uint,
    vs: *const u8,
    count: uint,
  ) {
    assert!(idx + count <= self.capacity);

    gl::BindBuffer(gl::ARRAY_BUFFER, self.handle.gl_id);

    gl::BufferSubData(
      gl::ARRAY_BUFFER,
      idx as i64,
      count as i64,
      mem::transmute(vs)
    );
  }
}

/// Fixed-size typed VRAM buffer, optimized for bulk inserts.
pub struct GLBuffer<'a, T> {
  pub byte_buffer: GLByteBuffer<'a>,
  pub length: uint,
}

impl<'a, T> GLBuffer<'a, T> {
  pub fn new(
    gl: &'a GLContextExistence,
    gl_context: &mut GLContext,
    capacity: uint,
  ) -> GLBuffer<'a, T> {
    GLBuffer {
      byte_buffer: GLByteBuffer::new(gl, gl_context, capacity * mem::size_of::<T>()),
      length: 0,
    }
  }

  pub fn push(&mut self, gl: &mut GLContext, vs: &[T]) {
    unsafe {
      self.byte_buffer.push(
        gl,
        mem::transmute(vs.as_ptr()),
        mem::size_of::<T>() * vs.len()
      );
    }
    self.length += vs.len();
  }

  pub fn update(&mut self, gl: &mut GLContext, idx: uint, vs: &[T]) {
    unsafe {
      self.byte_buffer.update(
        gl,
        mem::size_of::<T>() * idx,
        mem::transmute(vs.as_ptr()),
        mem::size_of::<T>() * vs.len(),
      );
    }
  }

  pub fn swap_remove(&mut self, gl: &mut GLContext, idx: uint, count: uint) {
    self.byte_buffer.swap_remove(
      gl,
      mem::size_of::<T>() * idx,
      mem::size_of::<T>() * count,
    );
    self.length -= count;
  }
}

#[deriving(Show)]
#[deriving(Copy, Clone)]
pub enum DrawMode {
  Lines,
  Triangles,
  Points,
}

impl DrawMode {
  fn to_enum(&self) -> GLenum {
    match *self {
      DrawMode::Lines     => gl::LINES,
      DrawMode::Triangles => gl::TRIANGLES,
      DrawMode::Points    => gl::POINTS,
    }
  }
}

#[deriving(Show)]
#[deriving(Copy, Clone)]
pub enum GLType {
  Float,
  UInt,
  Int,
}

impl GLType {
  pub fn size(&self) -> uint {
    match *self {
      GLType::Float => mem::size_of::<GLfloat>(),
      GLType::UInt  => mem::size_of::<GLuint>(),
      GLType::Int   => mem::size_of::<GLint>(),
    }
  }

  pub fn gl_enum(&self) -> GLenum {
    match *self {
      GLType::Float => gl::FLOAT,
      GLType::UInt  => gl::UNSIGNED_INT,
      GLType::Int   => gl::INT,
    }
  }

  pub fn is_integral(&self) -> bool {
    match *self {
      GLType::Float => false,
      GLType::UInt  => true,
      GLType::Int   => true,
    }
  }
}

#[deriving(Show)]
/// Specifies how to pass data from OpenGL to the vertex shaders.
pub struct VertexAttribData<'a> {
  /// Cooresponds to the shader's `input variable`.
  pub name: &'a str,
  /// The size of this attribute, in the provided units.
  pub size: uint,
  pub unit: GLType,
}

pub struct ArrayHandle<'a> {
  pub lifetime: ContravariantLifetime<'a>,
  pub gl_id: GLuint,
}

impl<'a> ArrayHandle<'a> {
  pub fn new(_gl: &'a GLContextExistence) -> ArrayHandle<'a> {
    let mut gl_id = 0;
    unsafe {
      gl::GenVertexArrays(1, &mut gl_id);
    }

    ArrayHandle {
      gl_id: gl_id,
      lifetime: ContravariantLifetime,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for ArrayHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteVertexArrays(1, &self.gl_id);
    }
  }
}

/// A fixed-capacity array of bytes passed to OpenGL.
pub struct GLArray<'a, T> {
  pub buffer: GLBuffer<'a, T>,
  pub handle: ArrayHandle<'a>,
  /// How to draw this buffer. Ex: gl::LINES, gl::TRIANGLES, etc.
  pub mode: GLenum,
  /// length in `T`s.
  pub length: uint,
}

impl<'a, T> GLArray<'a, T> {
  /// Creates a new array of objects on the GPU.
  /// capacity is provided in units of size slice_span.
  pub fn new(
    gl: &'a GLContextExistence,
    _gl_context: &mut GLContext,
    shader_program: Rc<RefCell<Shader>>,
    attribs: &[VertexAttribData],
    mode: DrawMode,
    buffer: GLBuffer<'a, T>,
  ) -> GLArray<'a, T> {
    let handle = ArrayHandle::new(gl);

    unsafe {
      gl::BindVertexArray(handle.gl_id);
    }

    let mut offset = 0;
    let attrib_span = {
      let mut attrib_span = 0;
      for attrib in attribs.iter() {
        attrib_span += attrib.size * attrib.unit.size();
      }
      attrib_span
    };
    for attrib in attribs.iter() {
      let shader_attrib =
        glGetAttribLocation(
          shader_program.borrow().handle.gl_id,
          attrib.name
        );
      assert!(shader_attrib != -1, "shader attribute \"{}\" not found", attrib.name);
      let shader_attrib = shader_attrib as GLuint;

      unsafe {
        gl::EnableVertexAttribArray(shader_attrib);

        if attrib.unit.is_integral() {
          gl::VertexAttribIPointer(
            shader_attrib,
            attrib.size as i32,
            attrib.unit.gl_enum(),
            attrib_span as i32,
            ptr::null().offset(offset),
          );
        } else {
          gl::VertexAttribPointer(
            shader_attrib,
            attrib.size as i32,
            attrib.unit.gl_enum(),
            gl::FALSE as GLboolean,
            attrib_span as i32,
            ptr::null().offset(offset),
          );
        }
      }
      offset += (attrib.size * attrib.unit.size()) as int;
    }

    match unsafe { gl::GetError() } {
      gl::NO_ERROR => {},
      err => panic!("OpenGL error 0x{:x}", err),
    }

    assert_eq!(attrib_span, mem::size_of::<T>());

    GLArray {
      buffer: buffer,
      handle: handle,
      mode: mode.to_enum(),
      length: 0,
    }
  }

  pub fn push(&mut self, gl: &mut GLContext, vs: &[T]) {
    self.buffer.push(gl, vs);
    self.length += vs.len();
  }

  pub fn swap_remove(&mut self, gl: &mut GLContext, idx: uint, count: uint) {
    self.buffer.swap_remove(gl, idx, count);
    self.length -= count;
  }

  /// Draws all the queued triangles to the screen.
  pub fn draw(&self, gl: &mut GLContext) {
    self.draw_slice(gl, 0, self.buffer.length);
  }

  /// Draw some subset of the triangle array.
  pub fn draw_slice(&self, _gl: &mut GLContext, start: uint, len: uint) {
    assert!(start + len <= self.length);

    unsafe {
      gl::BindVertexArray(self.handle.gl_id);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.buffer.byte_buffer.handle.gl_id);

      gl::DrawArrays(self.mode, start as i32, len as i32);
    }
  }
}
<|endoftext|>


<commit_before>use std::mem;
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, ElementArrayBufferBinder,
             ArrayBufferBinding, ElementArrayBufferBinding};
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>,
    vbo: &'a mut VertexBuffer<T>
}

impl<'a, T: VertexData + 'a> VertexBufferBinding<'a, T> {
    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);
    }
}

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.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.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.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.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
        }
    }
}

// TODO: Refactor to work with less restrictive generic params
impl<BA, BE, F, P, R, T> ContextOf<BufferBinderOf<BA, BE>, F, P, R, T> {
    pub fn bind_vertex_buffer<'a, V>(mut self, vbo: &'a mut VertexBuffer<V>)
        -> (
            VertexBufferBinding<V>,
            ContextOf<BufferBinderOf<(), BE>, F, P, R, T>
        )
        where V: VertexData,
              BA: BorrowMut<ArrayBufferBinder>
    {
        // NOTE: The mem::transmute here unsafely extends the borrow of
        //       ibo.buffer_mut()
        // TODO: Find a safe(r) way to do this
        {
            let gl = self.borrowed_mut().map_buffers(|b| b.borrowed_mut());

            vbo.bind(gl).unwrap();
        }
        let (mut ba_binder, gl) = self.split_array_buffer();
        let mut ba_binder = ba_binder.borrow_mut();
        let buffer = unsafe { mem::transmute(vbo.buffer_mut() as *mut Buffer) };
        let gl_array_buffer = ba_binder.bind(buffer);
        (
            VertexBufferBinding {
                gl_buffer: gl_array_buffer,
                vbo: vbo
            },
            gl
        )
    }

    pub fn bind_index_buffer<'a, I>(self, ibo: &'a mut IndexBuffer<I>)
        -> (
            IndexBufferBinding<I>,
            ContextOf<BufferBinderOf<BA, ()>, F, P, R, T>
        )
        where I: IndexDatum + 'a,
              BE: BorrowMut<ElementArrayBufferBinder> + 'a
    {
        // NOTE: The mem::transmute here unsafely extends the borrow of
        //       ibo.buffer_mut()
        // TODO: Find a safe(r) way to do this
        let (mut be_binder, gl) = self.split_element_array_buffer();
        let be_binder = be_binder.borrow_mut();
        let buffer = unsafe { mem::transmute(ibo.buffer_mut() as *mut Buffer) };
        let gl_be = be_binder.bind(buffer);
        (IndexBufferBinding::new(gl_be, ibo), gl)
    }
}

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<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>Remove `VertexBufferBinding::new()`<commit_after>use std::mem;
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, ElementArrayBufferBinder,
             ArrayBufferBinding, ElementArrayBufferBinding};
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>,
    vbo: &'a mut 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.vbo.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.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.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.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.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
        }
    }
}

// TODO: Refactor to work with less restrictive generic params
impl<BA, BE, F, P, R, T> ContextOf<BufferBinderOf<BA, BE>, F, P, R, T> {
    pub fn bind_vertex_buffer<'a, V>(mut self, vbo: &'a mut VertexBuffer<V>)
        -> (
            VertexBufferBinding<V>,
            ContextOf<BufferBinderOf<(), BE>, F, P, R, T>
        )
        where V: VertexData,
              BA: BorrowMut<ArrayBufferBinder>
    {
        // NOTE: The mem::transmute here unsafely extends the borrow of
        //       ibo.buffer_mut()
        // TODO: Find a safe(r) way to do this
        {
            let gl = self.borrowed_mut().map_buffers(|b| b.borrowed_mut());

            vbo.bind(gl).unwrap();
        }
        let (mut ba_binder, gl) = self.split_array_buffer();
        let mut ba_binder = ba_binder.borrow_mut();
        let buffer = unsafe { mem::transmute(vbo.buffer_mut() as *mut Buffer) };
        let gl_array_buffer = ba_binder.bind(buffer);
        (
            VertexBufferBinding {
                gl_buffer: gl_array_buffer,
                vbo: vbo
            },
            gl
        )
    }

    pub fn bind_index_buffer<'a, I>(self, ibo: &'a mut IndexBuffer<I>)
        -> (
            IndexBufferBinding<I>,
            ContextOf<BufferBinderOf<BA, ()>, F, P, R, T>
        )
        where I: IndexDatum + 'a,
              BE: BorrowMut<ElementArrayBufferBinder> + 'a
    {
        // NOTE: The mem::transmute here unsafely extends the borrow of
        //       ibo.buffer_mut()
        // TODO: Find a safe(r) way to do this
        let (mut be_binder, gl) = self.split_element_array_buffer();
        let be_binder = be_binder.borrow_mut();
        let buffer = unsafe { mem::transmute(ibo.buffer_mut() as *mut Buffer) };
        let gl_be = be_binder.bind(buffer);
        (IndexBufferBinding::new(gl_be, ibo), gl)
    }
}

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<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>//! Cranelift IR builder library.
//!
//! Provides a straightforward way to create a Cranelift IR function and fill it with instructions
//! translated from another language. Contains an SSA construction module that lets you translate
//! your non-SSA variables into SSA Cranelift IR values via `use_var` and `def_var` calls.
//!
//! To get started, create an [`FunctionBuilderContext`](struct.FunctionBuilderContext.html) and
//! pass it as an argument to a [`FunctionBuilder`](struct.FunctionBuilder.html).
//!
//! # Example
//!
//! Here is a pseudo-program we want to transform into Cranelift IR:
//!
//! ```clif
//! function(x) {
//! x, y, z : i32
//! block0:
//!    y = 2;
//!    z = x + y;
//!    jump block1
//! block1:
//!    z = z + y;
//!    brnz y, block2;
//!    z = z - x;
//!    return y
//! block2:
//!    y = y - x
//!    jump block1
//! }
//! ```
//!
//! Here is how you build the corresponding Cranelift IR function using `FunctionBuilderContext`:
//!
//! ```rust
//! extern crate cranelift_codegen;
//! extern crate cranelift_frontend;
//!
//! use cranelift_codegen::entity::EntityRef;
//! use cranelift_codegen::ir::{ExternalName, Function, Signature, AbiParam, InstBuilder};
//! use cranelift_codegen::ir::types::*;
//! use cranelift_codegen::settings::{self, CallConv};
//! use cranelift_frontend::{FunctionBuilderContext, FunctionBuilder, Variable};
//! use cranelift_codegen::verifier::verify_function;
//!
//! fn main() {
//!     let mut sig = Signature::new(CallConv::SystemV);
//!     sig.returns.push(AbiParam::new(I32));
//!     sig.params.push(AbiParam::new(I32));
//!     let mut fn_builder_ctx = FunctionBuilderContext::<Variable>::new();
//!     let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig);
//!     {
//!         let mut builder = FunctionBuilder::<Variable>::new(&mut func, &mut fn_builder_ctx);
//!
//!         let block0 = builder.create_ebb();
//!         let block1 = builder.create_ebb();
//!         let block2 = builder.create_ebb();
//!         let x = Variable::new(0);
//!         let y = Variable::new(1);
//!         let z = Variable::new(2);
//!         builder.declare_var(x, I32);
//!         builder.declare_var(y, I32);
//!         builder.declare_var(z, I32);
//!         builder.append_ebb_params_for_function_params(block0);
//!
//!         builder.switch_to_block(block0);
//!         builder.seal_block(block0);
//!         {
//!             let tmp = builder.ebb_params(block0)[0]; // the first function parameter
//!             builder.def_var(x, tmp);
//!         }
//!         {
//!             let tmp = builder.ins().iconst(I32, 2);
//!             builder.def_var(y, tmp);
//!         }
//!         {
//!             let arg1 = builder.use_var(x);
//!             let arg2 = builder.use_var(y);
//!             let tmp = builder.ins().iadd(arg1, arg2);
//!             builder.def_var(z, tmp);
//!         }
//!         builder.ins().jump(block1, &[]);
//!
//!         builder.switch_to_block(block1);
//!         {
//!             let arg1 = builder.use_var(y);
//!             let arg2 = builder.use_var(z);
//!             let tmp = builder.ins().iadd(arg1, arg2);
//!             builder.def_var(z, tmp);
//!         }
//!         {
//!             let arg = builder.use_var(y);
//!             builder.ins().brnz(arg, block2, &[]);
//!         }
//!         {
//!             let arg1 = builder.use_var(z);
//!             let arg2 = builder.use_var(x);
//!             let tmp = builder.ins().isub(arg1, arg2);
//!             builder.def_var(z, tmp);
//!         }
//!         {
//!             let arg = builder.use_var(y);
//!             builder.ins().return_(&[arg]);
//!         }
//!
//!         builder.switch_to_block(block2);
//!         builder.seal_block(block2);
//!
//!         {
//!             let arg1 = builder.use_var(y);
//!             let arg2 = builder.use_var(x);
//!             let tmp = builder.ins().isub(arg1, arg2);
//!             builder.def_var(y, tmp);
//!         }
//!         builder.ins().jump(block1, &[]);
//!         builder.seal_block(block1);
//!
//!         builder.finalize();
//!     }
//!
//!     let flags = settings::Flags::new(settings::builder());
//!     let res = verify_function(&func, &flags);
//!     println!("{}", func.display(None));
//!     if let Err(errors) = res {
//!         panic!("{}", errors);
//!     }
//! }
//! ```

#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
#![warn(unused_import_braces)]
#![cfg_attr(feature = "std", deny(unstable_features))]
#![cfg_attr(feature = "cargo-clippy", allow(new_without_default))]
#![cfg_attr(
    feature = "cargo-clippy",
    warn(
        float_arithmetic, mut_mut, nonminimal_bool, option_map_unwrap_or, option_map_unwrap_or_else,
        print_stdout, unicode_not_nfc, use_self
    )
)]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), feature(alloc))]

extern crate cranelift_codegen;

pub use frontend::{FunctionBuilder, FunctionBuilderContext};
pub use variable::Variable;

mod frontend;
mod ssa;
mod variable;

#[cfg(not(feature = "std"))]
mod std {
    extern crate alloc;

    pub use self::alloc::vec;
    pub use core::*;
}
<commit_msg>Better explanation for how to use FunctionBuilder to deal with variable translation<commit_after>//! Cranelift IR builder library.
//!
//! Provides a straightforward way to create a Cranelift IR function and fill it with instructions
//! corresponding to your source program written in another language.
//!
//! To get started, create an [`FunctionBuilderContext`](struct.FunctionBuilderContext.html) and
//! pass it as an argument to a [`FunctionBuilder`](struct.FunctionBuilder.html).
//!
//! # Source Language Variables and Cranelift IR values
//!
//! The most interesting feature of this API is that it provides a single way to deal with all your
//! variable problems. Indeed, the [`FunctionBuilder`](struct.FunctionBuilder.html) struct has a
//! type parameter `Variable` that should be instantiated with the type of your Source Language
//! Variables (SLV). Then, through calling the functions
//! [`declare_var`](struct.FunctionBuilder.html#method.declare_var),
//! [`def_var`](struct.FunctionBuilder.html#method.def_var) and
//! [`use_var`](struct.FunctionBuilder.html#method.use_var), the
//! [`FunctionBuilder`](struct.FunctionBuilder.html) will create for you all the Cranelift IR
//! values corresponding to your SLVs.
//!
//! If a SLV is immutable (defined only once), then it will get mapped to one and only Cranelift IR
//! value. If a SLV is mutable ([`def_var`](struct.FunctionBuilder.html#method.def_var) multiple
//! times), then internally a [`SSA`](https://en.wikipedia.org/wiki/Static_single_assignment_form)
//! construction algorithm will automatically create multiple Cranelift IR values that will be
//! returned to you by [`use_var`](struct.FunctionBuilder.html#method.use_var) depending on where
//! you want to use your SLV.
//!
//! The morality is that you should use these three functions to handle all your SLVs, even those
//! that are not present in the source code but artefacts of the translation. For instance, if your
//! source language is expression-based, then you will need to introduce artifical SLVs to store
//! intermediate results of the computation of your expressions. Hence The `Variable` type that you
//! would pass to [`FunctionBuilder`](struct.FunctionBuilder.html) could look like this
//!
//! ```
//! enum Variable {
//!     OriginalSourceVariable(String),
//!     IntermediateExpressionVariable(u32)
//! }
//! ```
//!
//! # Example
//!
//! Here is a pseudo-program we want to transform into Cranelift IR:
//!
//! ```clif
//! function(x) {
//! x, y, z : i32
//! block0:
//!    y = 2;
//!    z = x + y;
//!    jump block1
//! block1:
//!    z = z + y;
//!    brnz y, block2;
//!    z = z - x;
//!    return y
//! block2:
//!    y = y - x
//!    jump block1
//! }
//! ```
//!
//! Here is how you build the corresponding Cranelift IR function using `FunctionBuilderContext`:
//!
//! ```rust
//! extern crate cranelift_codegen;
//! extern crate cranelift_frontend;
//!
//! use cranelift_codegen::entity::EntityRef;
//! use cranelift_codegen::ir::{ExternalName, Function, Signature, AbiParam, InstBuilder};
//! use cranelift_codegen::ir::types::*;
//! use cranelift_codegen::settings::{self, CallConv};
//! use cranelift_frontend::{FunctionBuilderContext, FunctionBuilder, Variable};
//! use cranelift_codegen::verifier::verify_function;
//!
//! fn main() {
//!     let mut sig = Signature::new(CallConv::SystemV);
//!     sig.returns.push(AbiParam::new(I32));
//!     sig.params.push(AbiParam::new(I32));
//!     let mut fn_builder_ctx = FunctionBuilderContext::<Variable>::new();
//!     let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig);
//!     {
//!         let mut builder = FunctionBuilder::<Variable>::new(&mut func, &mut fn_builder_ctx);
//!
//!         let block0 = builder.create_ebb();
//!         let block1 = builder.create_ebb();
//!         let block2 = builder.create_ebb();
//!         let x = Variable::new(0);
//!         let y = Variable::new(1);
//!         let z = Variable::new(2);
//!         builder.declare_var(x, I32);
//!         builder.declare_var(y, I32);
//!         builder.declare_var(z, I32);
//!         builder.append_ebb_params_for_function_params(block0);
//!
//!         builder.switch_to_block(block0);
//!         builder.seal_block(block0);
//!         {
//!             let tmp = builder.ebb_params(block0)[0]; // the first function parameter
//!             builder.def_var(x, tmp);
//!         }
//!         {
//!             let tmp = builder.ins().iconst(I32, 2);
//!             builder.def_var(y, tmp);
//!         }
//!         {
//!             let arg1 = builder.use_var(x);
//!             let arg2 = builder.use_var(y);
//!             let tmp = builder.ins().iadd(arg1, arg2);
//!             builder.def_var(z, tmp);
//!         }
//!         builder.ins().jump(block1, &[]);
//!
//!         builder.switch_to_block(block1);
//!         {
//!             let arg1 = builder.use_var(y);
//!             let arg2 = builder.use_var(z);
//!             let tmp = builder.ins().iadd(arg1, arg2);
//!             builder.def_var(z, tmp);
//!         }
//!         {
//!             let arg = builder.use_var(y);
//!             builder.ins().brnz(arg, block2, &[]);
//!         }
//!         {
//!             let arg1 = builder.use_var(z);
//!             let arg2 = builder.use_var(x);
//!             let tmp = builder.ins().isub(arg1, arg2);
//!             builder.def_var(z, tmp);
//!         }
//!         {
//!             let arg = builder.use_var(y);
//!             builder.ins().return_(&[arg]);
//!         }
//!
//!         builder.switch_to_block(block2);
//!         builder.seal_block(block2);
//!
//!         {
//!             let arg1 = builder.use_var(y);
//!             let arg2 = builder.use_var(x);
//!             let tmp = builder.ins().isub(arg1, arg2);
//!             builder.def_var(y, tmp);
//!         }
//!         builder.ins().jump(block1, &[]);
//!         builder.seal_block(block1);
//!
//!         builder.finalize();
//!     }
//!
//!     let flags = settings::Flags::new(settings::builder());
//!     let res = verify_function(&func, &flags);
//!     println!("{}", func.display(None));
//!     if let Err(errors) = res {
//!         panic!("{}", errors);
//!     }
//! }
//! ```

#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
#![warn(unused_import_braces)]
#![cfg_attr(feature = "std", deny(unstable_features))]
#![cfg_attr(feature = "cargo-clippy", allow(new_without_default))]
#![cfg_attr(
    feature = "cargo-clippy",
    warn(
        float_arithmetic, mut_mut, nonminimal_bool, option_map_unwrap_or, option_map_unwrap_or_else,
        print_stdout, unicode_not_nfc, use_self
    )
)]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), feature(alloc))]

extern crate cranelift_codegen;

pub use frontend::{FunctionBuilder, FunctionBuilderContext};
pub use variable::Variable;

mod frontend;
mod ssa;
mod variable;

#[cfg(not(feature = "std"))]
mod std {
    extern crate alloc;

    pub use self::alloc::vec;
    pub use core::*;
}
<|endoftext|>


<commit_before>use {Timer, TimeSpan, TimingMethod};

pub fn calculate(timer: &Timer) -> TimeSpan {
    let mut total_playtime = TimeSpan::zero();

    for attempt in timer.run().attempt_history() {
        if let Some(duration) = attempt.duration() {
            // Either >= 1.6.0 or a finished run
            total_playtime += duration;
        } else {
            // Must be < 1.6.0 and a reset
            // Calculate the sum of the segments for that run
            for segment in timer.run().segments() {
                if let Some(segment_time) =
                    segment
                        .segment_history()
                        .get(attempt.index())
                        .and_then(|s| s[TimingMethod::RealTime]) {
                    total_playtime += segment_time;
                }
            }
        }
    }

    total_playtime += timer.current_attempt_duration() - timer.get_pause_time().unwrap_or_default();

    total_playtime
}
<commit_msg>Take Attempt History Pause Time into account for Total Playtime<commit_after>use {Timer, TimeSpan, TimingMethod};

pub fn calculate(timer: &Timer) -> TimeSpan {
    let mut total_playtime = TimeSpan::zero();

    for attempt in timer.run().attempt_history() {
        if let Some(duration) = attempt.duration() {
            // Either >= 1.6.0 or a finished run
            total_playtime += duration;
            if let Some(pause_time) = attempt.pause_time() {
                total_playtime -= pause_time;
            }
        } else {
            // Must be < 1.6.0 and a reset
            // Calculate the sum of the segments for that run
            for segment in timer.run().segments() {
                if let Some(segment_time) =
                    segment
                        .segment_history()
                        .get(attempt.index())
                        .and_then(|s| s[TimingMethod::RealTime]) {
                    total_playtime += segment_time;
                }
            }
        }
    }

    total_playtime += timer.current_attempt_duration() - timer.get_pause_time().unwrap_or_default();

    total_playtime
}
<|endoftext|>


<commit_before>extern crate onmf;
use onmf::helpers::{ToImage, Normalize, magnify};
use onmf::testimage_generator;

extern crate nalgebra;
use self::nalgebra::{DMat};

extern crate rand;
use rand::{StdRng, SeedableRng};

extern crate num;
use num::{Float};

fn main() {
    let mag_factor = 10;

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);

    let steps = 12;
    let per_step = 1000;
    let nsamples = steps * per_step;
    let nobserved = 10 * 10;
    let nhidden = 20 + steps;
    // let nhidden = 40;

    let mut data = DMat::<f64>::new_zeros(nsamples, nobserved);

    // write one testimage into each row of data
    for (horizontal, vertical, i, factor) in testimage_generator::testimages::<f64, _>(per_step, &mut rng) {
        let row = (horizontal + vertical) * i;
        for (col, val) in factor.as_vec().iter().enumerate() {
            data[(row, col)] = val.clone();
        }
    }

    let mut nmf = onmf::OrthogonalNMF::<f64>::init_random01(
        nhidden, nobserved, nsamples, &mut rng);

    let mut iteration: i32 = 0;
    loop {
        // alpha gets larger and larger with each iteration
        // 0.1, 0.101, 0.102, 0.103, ...
        // at iteration 232 alpha first goes above 1.0
        // iteration = 232 -> alpha = 1.005
        let alpha = 0.1 * 1.01.powi(iteration);
        // TODO this could converge faster
        // let alpha = 0.1 * 1.001.powi(iteration);

        // let alpha = 0.1;

        // TODO maybe try an even smaller alpha
        // let alpha = 0.01;

        println!("iteration = {} alpha = {}", iteration, alpha);

        nmf.iterate(alpha, &data);

        // read testimage out of each row of nmf.hidden
        for irow in 0..nhidden {
            let mut column = Vec::<f64>::new();
            for icol in 0..nobserved {
                column.push(nmf.hidden[(irow, icol)]);
            }
            let image = DMat::<f64>::from_col_vec(10, 10, &column[..]);
            // println!("image {}", irow);
            // println!("{:?}", image);
            magnify(image.normalize(), mag_factor).save_to_png(&format!("orthogonal-nmf-hidden-{}.png", irow)[..]).unwrap();
        }

        iteration += 1;
    }
}
<commit_msg>nmf -> ortho_nmf<commit_after>extern crate onmf;
use onmf::helpers::{ToImage, Normalize, magnify};
use onmf::testimage_generator;

extern crate nalgebra;
use self::nalgebra::{DMat};

extern crate rand;
use rand::{StdRng, SeedableRng};

extern crate num;
use num::{Float};

fn main() {
    let mag_factor = 10;

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);

    let steps = 12;
    let per_step = 1000;
    let nsamples = steps * per_step;
    let nobserved = 10 * 10;
    let nhidden = 20 + steps;
    // let nhidden = 40;

    let mut data = DMat::<f64>::new_zeros(nsamples, nobserved);

    // write one testimage into each row of data
    for (horizontal, vertical, i, factor) in testimage_generator::testimages::<f64, _>(per_step, &mut rng) {
        let row = (horizontal + vertical) * i;
        for (col, val) in factor.as_vec().iter().enumerate() {
            data[(row, col)] = val.clone();
        }
    }

    let mut ortho_nmf = onmf::OrthogonalNMF::<f64>::init_random01(
        nhidden, nobserved, nsamples, &mut rng);

    let mut iteration: i32 = 0;
    loop {
        // alpha gets larger and larger with each iteration
        // 0.1, 0.101, 0.102, 0.103, ...
        // at iteration 232 alpha first goes above 1.0
        // iteration = 232 -> alpha = 1.005
        let alpha = 0.1 * 1.01.powi(iteration);
        // TODO this could converge faster
        // let alpha = 0.1 * 1.001.powi(iteration);

        // let alpha = 0.1;

        // TODO maybe try an even smaller alpha
        // let alpha = 0.01;

        println!("iteration = {} alpha = {}", iteration, alpha);

        ortho_nmf.iterate(alpha, &data);

        // read testimage out of each row of nmf.hidden
        for irow in 0..nhidden {
            let mut column = Vec::<f64>::new();
            for icol in 0..nobserved {
                column.push(ortho_nmf.hidden[(irow, icol)]);
            }
            let image = DMat::<f64>::from_col_vec(10, 10, &column[..]);
            // println!("image {}", irow);
            // println!("{:?}", image);
            magnify(image.normalize(), mag_factor).save_to_png(&format!("orthogonal-nmf-hidden-{}.png", irow)[..]).unwrap();
        }

        iteration += 1;
    }
}
<|endoftext|>


<commit_before>//! # ACPI
//! Code to parse the ACPI tables

use core::intrinsics::{atomic_load, atomic_store};
use core::sync::atomic::Ordering;
use collections::btree_map::BTreeMap;
use collections::string::String;

use syscall::io::{Io, Pio};

use spin::RwLock;

use device::local_apic::LOCAL_APIC;
use interrupt;
use memory::{allocate_frames, Frame};
use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress};
use start::{kstart_ap, CPU_COUNT, AP_READY};

use self::dmar::{Dmar, DmarEntry};
use self::fadt::Fadt;
use self::madt::{Madt, MadtEntry};
use self::rsdt::Rsdt;
use self::sdt::Sdt;
use self::xsdt::Xsdt;
use self::hpet::Hpet;

use self::aml::{is_aml_table, parse_aml_table, AmlError, AmlValue};

pub mod hpet;
mod dmar;
mod fadt;
mod madt;
mod rsdt;
mod sdt;
mod xsdt;
mod aml;

const TRAMPOLINE: usize = 0x7E00;
const AP_STARTUP: usize = TRAMPOLINE + 512;

fn get_sdt(sdt_address: usize, active_table: &mut ActivePageTable) -> &'static Sdt {
    {
        let page = Page::containing_address(VirtualAddress::new(sdt_address));
        if active_table.translate_page(page).is_none() {
            let frame = Frame::containing_address(PhysicalAddress::new(page.start_address().get()));
            let result = active_table.map_to(page, frame, entry::PRESENT | entry::NO_EXECUTE);
            result.flush(active_table);
        }
    }

    let sdt = unsafe { &*(sdt_address as *const Sdt) };

    // Map extra SDT frames if required
    {
        let start_page = Page::containing_address(VirtualAddress::new(sdt_address + 4096));
        let end_page = Page::containing_address(VirtualAddress::new(sdt_address + sdt.length as usize));
        for page in Page::range_inclusive(start_page, end_page) {
            if active_table.translate_page(page).is_none() {
                let frame = Frame::containing_address(PhysicalAddress::new(page.start_address().get()));
                let result = active_table.map_to(page, frame, entry::PRESENT | entry::NO_EXECUTE);
                result.flush(active_table);
            }
        }
    }

    sdt
}

fn parse_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) {
    print!("  ");
    for &c in sdt.signature.iter() {
        print!("{}", c as char);
    }

    if let Some(fadt) = Fadt::new(sdt) {
        println!(": {:X}", fadt.dsdt);

        let dsdt = get_sdt(fadt.dsdt as usize, active_table);
        parse_sdt(dsdt, active_table);

        let mut fadt_t = ACPI_TABLE.fadt.write();
        *fadt_t = Some(fadt);
    } else if let Some(madt) = Madt::new(sdt) {
        println!(": {:>08X}: {}", madt.local_address, madt.flags);

        let local_apic = unsafe { &mut LOCAL_APIC };

        let me = local_apic.id() as u8;

        if local_apic.x2 {
            println!("    X2APIC {}", me);
        } else {
            println!("    XAPIC {}: {:>08X}", me, local_apic.address);
        }

        if cfg!(feature = "multi_core"){
            let trampoline_frame = Frame::containing_address(PhysicalAddress::new(TRAMPOLINE));
            let trampoline_page = Page::containing_address(VirtualAddress::new(TRAMPOLINE));

            // Map trampoline
            let result = active_table.map_to(trampoline_page, trampoline_frame, entry::PRESENT | entry::WRITABLE);
            result.flush(active_table);

            for madt_entry in madt.iter() {
                println!("      {:?}", madt_entry);
                match madt_entry {
                    MadtEntry::LocalApic(ap_local_apic) => if ap_local_apic.id == me {
                        println!("        This is my local APIC");
                    } else {
                        if ap_local_apic.flags & 1 == 1 {
                            // Increase CPU ID
                            CPU_COUNT.fetch_add(1, Ordering::SeqCst);

                            // Allocate a stack
                            let stack_start = allocate_frames(64).expect("no more frames in acpi stack_start").start_address().get() + ::KERNEL_OFFSET;
                            let stack_end = stack_start + 64 * 4096;

                            let ap_ready = TRAMPOLINE as *mut u64;
                            let ap_cpu_id = unsafe { ap_ready.offset(1) };
                            let ap_page_table = unsafe { ap_ready.offset(2) };
                            let ap_stack_start = unsafe { ap_ready.offset(3) };
                            let ap_stack_end = unsafe { ap_ready.offset(4) };
                            let ap_code = unsafe { ap_ready.offset(5) };

                            // Set the ap_ready to 0, volatile
                            unsafe { atomic_store(ap_ready, 0) };
                            unsafe { atomic_store(ap_cpu_id, ap_local_apic.id as u64) };
                            unsafe { atomic_store(ap_page_table, active_table.address() as u64) };
                            unsafe { atomic_store(ap_stack_start, stack_start as u64) };
                            unsafe { atomic_store(ap_stack_end, stack_end as u64) };
                            unsafe { atomic_store(ap_code, kstart_ap as u64) };
                            AP_READY.store(false, Ordering::SeqCst);

                            print!("        AP {}:", ap_local_apic.id);

                            // Send INIT IPI
                            {
                                let mut icr = 0x4500;
                                if local_apic.x2 {
                                    icr |= (ap_local_apic.id as u64) << 32;
                                } else {
                                    icr |= (ap_local_apic.id as u64) << 56;
                                }
                                print!(" IPI...");
                                local_apic.set_icr(icr);
                            }

                            // Send START IPI
                            {
                                //Start at 0x0800:0000 => 0x8000. Hopefully the bootloader code is still there
                                let ap_segment = (AP_STARTUP >> 12) & 0xFF;
                                let mut icr = 0x4600 | ap_segment as u64;

                                if local_apic.x2 {
                                    icr |= (ap_local_apic.id as u64) << 32;
                                } else {
                                    icr |= (ap_local_apic.id as u64) << 56;
                                }

                                print!(" SIPI...");
                                local_apic.set_icr(icr);
                            }

                            // Wait for trampoline ready
                            print!(" Wait...");
                            while unsafe { atomic_load(ap_ready) } == 0 {
                                interrupt::pause();
                            }
                            print!(" Trampoline...");
                            while ! AP_READY.load(Ordering::SeqCst) {
                                interrupt::pause();
                            }
                            println!(" Ready");

                            active_table.flush_all();
                        } else {
                            println!("        CPU Disabled");
                        }
                    },
                    _ => ()
                }
            }

            // Unmap trampoline
            let (result, _frame) = active_table.unmap_return(trampoline_page, false);
            result.flush(active_table);
        }
    } else if let Some(dmar) = Dmar::new(sdt) {
        println!(": {}: {}", dmar.addr_width, dmar.flags);

        for dmar_entry in dmar.iter() {
            println!("      {:?}", dmar_entry);
            match dmar_entry {
                DmarEntry::Drhd(dmar_drhd) => {
                    let drhd = dmar_drhd.get(active_table);

                    println!("VER: {:X}", drhd.version);
                    println!("CAP: {:X}", drhd.cap);
                    println!("EXT_CAP: {:X}", drhd.ext_cap);
                    println!("GCMD: {:X}", drhd.gl_cmd);
                    println!("GSTS: {:X}", drhd.gl_sts);
                    println!("RT: {:X}", drhd.root_table);
                },
                _ => ()
            }
        }
    } else if let Some(hpet) = Hpet::new(sdt, active_table) {
        println!(": {}", hpet.hpet_number);

        let mut hpet_t = ACPI_TABLE.hpet.write();
        *hpet_t = Some(hpet);
    } else if is_aml_table(sdt) {
        match parse_aml_table(sdt) {
            Ok(()) => println!(": Parsed"),
            Err(AmlError::AmlParseError(e)) => println!(": {}", e),
            Err(AmlError::AmlInvalidOpCode) => println!(": Invalid opcode"),
            Err(AmlError::AmlValueError) => println!(": Type constraints or value bounds not met"),
            Err(AmlError::AmlDeferredLoad) => println!(": Deferred load reached top level"),
            Err(AmlError::AmlFatalError(_, _, _)) => println!(": Fatal error occurred"),
            Err(AmlError::AmlHardFatal) => println!(": Fatal error occurred")
        };
    } else {
        println!(": Unknown");
    }
}

/// Parse the ACPI tables to gather CPU, interrupt, and timer information
pub unsafe fn init(active_table: &mut ActivePageTable) {
    {
        let mut namespace = ACPI_TABLE.namespace.write();
        *namespace = Some(BTreeMap::new());
    }

    let start_addr = 0xE0000;
    let end_addr = 0xFFFFF;

    // Map all of the ACPI RSDP space
    {
        let start_frame = Frame::containing_address(PhysicalAddress::new(start_addr));
        let end_frame = Frame::containing_address(PhysicalAddress::new(end_addr));
        for frame in Frame::range_inclusive(start_frame, end_frame) {
            let page = Page::containing_address(VirtualAddress::new(frame.start_address().get()));
            let result = active_table.map_to(page, frame, entry::PRESENT | entry::NO_EXECUTE);
            result.flush(active_table);
        }
    }

    // Search for RSDP
    if let Some(rsdp) = RSDP::search(start_addr, end_addr) {
        let rxsdt = get_sdt(rsdp.sdt_address(), active_table);

        for &c in rxsdt.signature.iter() {
            print!("{}", c as char);
        }
        println!(":");
        if let Some(rsdt) = Rsdt::new(rxsdt) {
            for sdt_address in rsdt.iter() {
                let sdt = get_sdt(sdt_address, active_table);
                parse_sdt(sdt, active_table);
            }
        } else if let Some(xsdt) = Xsdt::new(rxsdt) {
            for sdt_address in xsdt.iter() {
                let sdt = get_sdt(sdt_address, active_table);
                parse_sdt(sdt, active_table);
            }
        } else {
            println!("UNKNOWN RSDT OR XSDT SIGNATURE");
        }
    } else {
        println!("NO RSDP FOUND");
    }

    /* TODO: Cleanup mapping when looking for RSDP
    // Unmap all of the ACPI RSDP space
    {
        let start_frame = Frame::containing_address(PhysicalAddress::new(start_addr));
        let end_frame = Frame::containing_address(PhysicalAddress::new(end_addr));
        for frame in Frame::range_inclusive(start_frame, end_frame) {
            let page = Page::containing_address(VirtualAddress::new(frame.start_address().get()));
            let result = active_table.unmap(page);
            result.flush(active_table);
        }
    }
    */
}

pub fn set_global_s_state(state: u8) {
    if state == 5 {
        let fadt = ACPI_TABLE.fadt.read();

        if let Some(ref fadt) = *fadt {
            let port = fadt.pm1a_control_block as u16;
            let mut val = 1 << 13;

            let namespace = ACPI_TABLE.namespace.read();

            if let Some(ref namespace) = *namespace {
                if let Some(s) = namespace.get("\\_S5") {
                    if let Ok(p) = s.get_as_package() {
                        let slp_typa = p[0].get_as_integer().expect("SLP_TYPa is not an integer");
                        let slp_typb = p[1].get_as_integer().expect("SLP_TYPb is not an integer");

                        println!("Shutdown SLP_TYPa {:X}, SLP_TYPb {:X}", slp_typa, slp_typb);
                        val |= slp_typa as u16;

                        println!("Shutdown with ACPI outw(0x{:X}, 0x{:X})", port, val);
                        Pio::<u16>::new(port).write(val);
                    }
                }
            }
        }
    }
}

pub struct Acpi {
    pub fadt: RwLock<Option<Fadt>>,
    pub namespace: RwLock<Option<BTreeMap<String, AmlValue>>>,
    pub hpet: RwLock<Option<Hpet>>,
    pub next_ctx: RwLock<u64>,
}

pub static ACPI_TABLE: Acpi = Acpi {
    fadt: RwLock::new(None),
    namespace: RwLock::new(None),
    hpet: RwLock::new(None),
    next_ctx: RwLock::new(0),
};

/// RSDP
#[derive(Copy, Clone, Debug)]
#[repr(packed)]
pub struct RSDP {
    signature: [u8; 8],
    checksum: u8,
    oemid: [u8; 6],
    revision: u8,
    rsdt_address: u32,
    length: u32,
    xsdt_address: u64,
    extended_checksum: u8,
    reserved: [u8; 3]
}

impl RSDP {
    /// Search for the RSDP
    pub fn search(start_addr: usize, end_addr: usize) -> Option<RSDP> {
        for i in 0 .. (end_addr + 1 - start_addr)/16 {
            let rsdp = unsafe { &*((start_addr + i * 16) as *const RSDP) };
            if &rsdp.signature == b"RSD PTR " {
                return Some(*rsdp);
            }
        }
        None
    }

    /// Get the RSDT or XSDT address
    pub fn sdt_address(&self) -> usize {
        if self.revision >= 2 {
            self.xsdt_address as usize
        } else {
            self.rsdt_address as usize
        }
    }
}
<commit_msg>Shutdown on fatal error<commit_after>//! # ACPI
//! Code to parse the ACPI tables

use core::intrinsics::{atomic_load, atomic_store};
use core::sync::atomic::Ordering;
use collections::btree_map::BTreeMap;
use collections::string::String;

use syscall::io::{Io, Pio};

use spin::RwLock;

use stop::kstop;

use device::local_apic::LOCAL_APIC;
use interrupt;
use memory::{allocate_frames, Frame};
use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress};
use start::{kstart_ap, CPU_COUNT, AP_READY};

use self::dmar::{Dmar, DmarEntry};
use self::fadt::Fadt;
use self::madt::{Madt, MadtEntry};
use self::rsdt::Rsdt;
use self::sdt::Sdt;
use self::xsdt::Xsdt;
use self::hpet::Hpet;

use self::aml::{is_aml_table, parse_aml_table, AmlError, AmlValue};

pub mod hpet;
mod dmar;
mod fadt;
mod madt;
mod rsdt;
mod sdt;
mod xsdt;
mod aml;

const TRAMPOLINE: usize = 0x7E00;
const AP_STARTUP: usize = TRAMPOLINE + 512;

fn get_sdt(sdt_address: usize, active_table: &mut ActivePageTable) -> &'static Sdt {
    {
        let page = Page::containing_address(VirtualAddress::new(sdt_address));
        if active_table.translate_page(page).is_none() {
            let frame = Frame::containing_address(PhysicalAddress::new(page.start_address().get()));
            let result = active_table.map_to(page, frame, entry::PRESENT | entry::NO_EXECUTE);
            result.flush(active_table);
        }
    }

    let sdt = unsafe { &*(sdt_address as *const Sdt) };

    // Map extra SDT frames if required
    {
        let start_page = Page::containing_address(VirtualAddress::new(sdt_address + 4096));
        let end_page = Page::containing_address(VirtualAddress::new(sdt_address + sdt.length as usize));
        for page in Page::range_inclusive(start_page, end_page) {
            if active_table.translate_page(page).is_none() {
                let frame = Frame::containing_address(PhysicalAddress::new(page.start_address().get()));
                let result = active_table.map_to(page, frame, entry::PRESENT | entry::NO_EXECUTE);
                result.flush(active_table);
            }
        }
    }

    sdt
}

fn parse_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) {
    print!("  ");
    for &c in sdt.signature.iter() {
        print!("{}", c as char);
    }

    if let Some(fadt) = Fadt::new(sdt) {
        println!(": {:X}", fadt.dsdt);

        let dsdt = get_sdt(fadt.dsdt as usize, active_table);
        parse_sdt(dsdt, active_table);

        let mut fadt_t = ACPI_TABLE.fadt.write();
        *fadt_t = Some(fadt);
    } else if let Some(madt) = Madt::new(sdt) {
        println!(": {:>08X}: {}", madt.local_address, madt.flags);

        let local_apic = unsafe { &mut LOCAL_APIC };

        let me = local_apic.id() as u8;

        if local_apic.x2 {
            println!("    X2APIC {}", me);
        } else {
            println!("    XAPIC {}: {:>08X}", me, local_apic.address);
        }

        if cfg!(feature = "multi_core"){
            let trampoline_frame = Frame::containing_address(PhysicalAddress::new(TRAMPOLINE));
            let trampoline_page = Page::containing_address(VirtualAddress::new(TRAMPOLINE));

            // Map trampoline
            let result = active_table.map_to(trampoline_page, trampoline_frame, entry::PRESENT | entry::WRITABLE);
            result.flush(active_table);

            for madt_entry in madt.iter() {
                println!("      {:?}", madt_entry);
                match madt_entry {
                    MadtEntry::LocalApic(ap_local_apic) => if ap_local_apic.id == me {
                        println!("        This is my local APIC");
                    } else {
                        if ap_local_apic.flags & 1 == 1 {
                            // Increase CPU ID
                            CPU_COUNT.fetch_add(1, Ordering::SeqCst);

                            // Allocate a stack
                            let stack_start = allocate_frames(64).expect("no more frames in acpi stack_start").start_address().get() + ::KERNEL_OFFSET;
                            let stack_end = stack_start + 64 * 4096;

                            let ap_ready = TRAMPOLINE as *mut u64;
                            let ap_cpu_id = unsafe { ap_ready.offset(1) };
                            let ap_page_table = unsafe { ap_ready.offset(2) };
                            let ap_stack_start = unsafe { ap_ready.offset(3) };
                            let ap_stack_end = unsafe { ap_ready.offset(4) };
                            let ap_code = unsafe { ap_ready.offset(5) };

                            // Set the ap_ready to 0, volatile
                            unsafe { atomic_store(ap_ready, 0) };
                            unsafe { atomic_store(ap_cpu_id, ap_local_apic.id as u64) };
                            unsafe { atomic_store(ap_page_table, active_table.address() as u64) };
                            unsafe { atomic_store(ap_stack_start, stack_start as u64) };
                            unsafe { atomic_store(ap_stack_end, stack_end as u64) };
                            unsafe { atomic_store(ap_code, kstart_ap as u64) };
                            AP_READY.store(false, Ordering::SeqCst);

                            print!("        AP {}:", ap_local_apic.id);

                            // Send INIT IPI
                            {
                                let mut icr = 0x4500;
                                if local_apic.x2 {
                                    icr |= (ap_local_apic.id as u64) << 32;
                                } else {
                                    icr |= (ap_local_apic.id as u64) << 56;
                                }
                                print!(" IPI...");
                                local_apic.set_icr(icr);
                            }

                            // Send START IPI
                            {
                                //Start at 0x0800:0000 => 0x8000. Hopefully the bootloader code is still there
                                let ap_segment = (AP_STARTUP >> 12) & 0xFF;
                                let mut icr = 0x4600 | ap_segment as u64;

                                if local_apic.x2 {
                                    icr |= (ap_local_apic.id as u64) << 32;
                                } else {
                                    icr |= (ap_local_apic.id as u64) << 56;
                                }

                                print!(" SIPI...");
                                local_apic.set_icr(icr);
                            }

                            // Wait for trampoline ready
                            print!(" Wait...");
                            while unsafe { atomic_load(ap_ready) } == 0 {
                                interrupt::pause();
                            }
                            print!(" Trampoline...");
                            while ! AP_READY.load(Ordering::SeqCst) {
                                interrupt::pause();
                            }
                            println!(" Ready");

                            active_table.flush_all();
                        } else {
                            println!("        CPU Disabled");
                        }
                    },
                    _ => ()
                }
            }

            // Unmap trampoline
            let (result, _frame) = active_table.unmap_return(trampoline_page, false);
            result.flush(active_table);
        }
    } else if let Some(dmar) = Dmar::new(sdt) {
        println!(": {}: {}", dmar.addr_width, dmar.flags);

        for dmar_entry in dmar.iter() {
            println!("      {:?}", dmar_entry);
            match dmar_entry {
                DmarEntry::Drhd(dmar_drhd) => {
                    let drhd = dmar_drhd.get(active_table);

                    println!("VER: {:X}", drhd.version);
                    println!("CAP: {:X}", drhd.cap);
                    println!("EXT_CAP: {:X}", drhd.ext_cap);
                    println!("GCMD: {:X}", drhd.gl_cmd);
                    println!("GSTS: {:X}", drhd.gl_sts);
                    println!("RT: {:X}", drhd.root_table);
                },
                _ => ()
            }
        }
    } else if let Some(hpet) = Hpet::new(sdt, active_table) {
        println!(": {}", hpet.hpet_number);

        let mut hpet_t = ACPI_TABLE.hpet.write();
        *hpet_t = Some(hpet);
    } else if is_aml_table(sdt) {
        match parse_aml_table(sdt) {
            Ok(()) => println!(": Parsed"),
            Err(AmlError::AmlParseError(e)) => println!(": {}", e),
            Err(AmlError::AmlInvalidOpCode) => println!(": Invalid opcode"),
            Err(AmlError::AmlValueError) => println!(": Type constraints or value bounds not met"),
            Err(AmlError::AmlDeferredLoad) => println!(": Deferred load reached top level"),
            Err(AmlError::AmlFatalError(_, _, _)) => {
                println!(": Fatal error occurred");
                unsafe { kstop(); }
            },
            Err(AmlError::AmlHardFatal) => {
                println!(": Fatal error occurred");
                unsafe { kstop(); }
            }
        };
    } else {
        println!(": Unknown");
    }
}

/// Parse the ACPI tables to gather CPU, interrupt, and timer information
pub unsafe fn init(active_table: &mut ActivePageTable) {
    {
        let mut namespace = ACPI_TABLE.namespace.write();
        *namespace = Some(BTreeMap::new());
    }

    let start_addr = 0xE0000;
    let end_addr = 0xFFFFF;

    // Map all of the ACPI RSDP space
    {
        let start_frame = Frame::containing_address(PhysicalAddress::new(start_addr));
        let end_frame = Frame::containing_address(PhysicalAddress::new(end_addr));
        for frame in Frame::range_inclusive(start_frame, end_frame) {
            let page = Page::containing_address(VirtualAddress::new(frame.start_address().get()));
            let result = active_table.map_to(page, frame, entry::PRESENT | entry::NO_EXECUTE);
            result.flush(active_table);
        }
    }

    // Search for RSDP
    if let Some(rsdp) = RSDP::search(start_addr, end_addr) {
        let rxsdt = get_sdt(rsdp.sdt_address(), active_table);

        for &c in rxsdt.signature.iter() {
            print!("{}", c as char);
        }
        println!(":");
        if let Some(rsdt) = Rsdt::new(rxsdt) {
            for sdt_address in rsdt.iter() {
                let sdt = get_sdt(sdt_address, active_table);
                parse_sdt(sdt, active_table);
            }
        } else if let Some(xsdt) = Xsdt::new(rxsdt) {
            for sdt_address in xsdt.iter() {
                let sdt = get_sdt(sdt_address, active_table);
                parse_sdt(sdt, active_table);
            }
        } else {
            println!("UNKNOWN RSDT OR XSDT SIGNATURE");
        }
    } else {
        println!("NO RSDP FOUND");
    }

    /* TODO: Cleanup mapping when looking for RSDP
    // Unmap all of the ACPI RSDP space
    {
        let start_frame = Frame::containing_address(PhysicalAddress::new(start_addr));
        let end_frame = Frame::containing_address(PhysicalAddress::new(end_addr));
        for frame in Frame::range_inclusive(start_frame, end_frame) {
            let page = Page::containing_address(VirtualAddress::new(frame.start_address().get()));
            let result = active_table.unmap(page);
            result.flush(active_table);
        }
    }
    */
}

pub fn set_global_s_state(state: u8) {
    if state == 5 {
        let fadt = ACPI_TABLE.fadt.read();

        if let Some(ref fadt) = *fadt {
            let port = fadt.pm1a_control_block as u16;
            let mut val = 1 << 13;

            let namespace = ACPI_TABLE.namespace.read();

            if let Some(ref namespace) = *namespace {
                if let Some(s) = namespace.get("\\_S5") {
                    if let Ok(p) = s.get_as_package() {
                        let slp_typa = p[0].get_as_integer().expect("SLP_TYPa is not an integer");
                        let slp_typb = p[1].get_as_integer().expect("SLP_TYPb is not an integer");

                        println!("Shutdown SLP_TYPa {:X}, SLP_TYPb {:X}", slp_typa, slp_typb);
                        val |= slp_typa as u16;

                        println!("Shutdown with ACPI outw(0x{:X}, 0x{:X})", port, val);
                        Pio::<u16>::new(port).write(val);
                    }
                }
            }
        }
    }
}

pub struct Acpi {
    pub fadt: RwLock<Option<Fadt>>,
    pub namespace: RwLock<Option<BTreeMap<String, AmlValue>>>,
    pub hpet: RwLock<Option<Hpet>>,
    pub next_ctx: RwLock<u64>,
}

pub static ACPI_TABLE: Acpi = Acpi {
    fadt: RwLock::new(None),
    namespace: RwLock::new(None),
    hpet: RwLock::new(None),
    next_ctx: RwLock::new(0),
};

/// RSDP
#[derive(Copy, Clone, Debug)]
#[repr(packed)]
pub struct RSDP {
    signature: [u8; 8],
    checksum: u8,
    oemid: [u8; 6],
    revision: u8,
    rsdt_address: u32,
    length: u32,
    xsdt_address: u64,
    extended_checksum: u8,
    reserved: [u8; 3]
}

impl RSDP {
    /// Search for the RSDP
    pub fn search(start_addr: usize, end_addr: usize) -> Option<RSDP> {
        for i in 0 .. (end_addr + 1 - start_addr)/16 {
            let rsdp = unsafe { &*((start_addr + i * 16) as *const RSDP) };
            if &rsdp.signature == b"RSD PTR " {
                return Some(*rsdp);
            }
        }
        None
    }

    /// Get the RSDT or XSDT address
    pub fn sdt_address(&self) -> usize {
        if self.revision >= 2 {
            self.xsdt_address as usize
        } else {
            self.rsdt_address as usize
        }
    }
}
<|endoftext|>


<commit_before>use quote::Tokens;
use syn::{Body, Field, Ident, Variant, VariantData, MacroInput, Ty};

pub fn expand(input: &MacroInput) -> Tokens {
    let trait_name = "Add";
    let method_name = trait_name.to_lowercase();
    let method_ident = Ident::from(method_name);
    let result = match input.body {
        Body::Struct(VariantData::Tuple(ref fields)) => {
            Some((input.ident, tuple_content(cx, span, x, fields, method_name)))
        },
        _ => None,
    };
    quote!()
}

fn tuple_content(item: Item, fields: &Vec<StructField>, method_name: String) -> Tokens {
    let type_name = item.ident;
    let mut exprs: = vec![];

    for i in 0..fields.len() {
        let i = &i.to_string();
        exprs.push(cx.parse_expr(format!("self.{}.{}(rhs.{})", i, method_name, i)));
    }

    cx.expr_call_ident(span, type_name, exprs)
}

<commit_msg>Macros 1.1: Continue with add_like<commit_after>use quote::Tokens;
use syn::{Body, Field, Ident, Variant, VariantData, MacroInput, Ty};

pub fn expand(input: &MacroInput) -> Tokens {
    let trait_name = "Add";
    let method_name = trait_name.to_lowercase();
    let method_ident = Ident::from(method_name);
    let input_type = input.ident;
    let (output_type, block) = match input.body {
        Body::Struct(VariantData::Tuple(ref fields)) => {
            (input_type, tuple_content(input_type, fields, method_name))
        },
        _ => panic!(format!("Only structs and enums can use dervie({})", trait_name))
    };
    quote!()
}

fn tuple_content(input_type: Ident, fields: &Vec<Field>, method_name: String) -> Tokens  {
    let mut exprs = vec![];

    for i in 0..fields.len() {
        let i = &i.to_string();
        exprs.push(quote!((format!("self.{}.{}(rhs.{})", i, method_name, i)));
    }

    cx.expr_call_ident(span, type_name, exprs)
}

<|endoftext|>