<commit_before>use gl;
use gl::types::*;
use gl_context::GLContext;
use num;
use std::ffi::CString;
use std::marker::PhantomData;
use std::mem;
use std::ptr;

use shader::*;

/// 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 {
  let c_str = CString::new(name.as_bytes()).unwrap();
  let ptr = c_str.as_ptr() as *const i8;
  unsafe {
    gl::GetAttribLocation(shader_program, ptr)
  }
}

pub struct BufferHandle<'a> {
  pub gl_id: GLuint,
  phantom: PhantomData<&'a ()>,
}

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

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

    assert!(gl_id != 0);

    BufferHandle {
      gl_id: gl_id,
      phantom: PhantomData,
    }
  }
}

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: usize,
  /// maximum number of bytes in the buffer.
  pub capacity: usize,
}

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<'b:'a>(
    gl: &'a mut GLContext,
    capacity: usize,
  ) -> GLByteBuffer<'b> {
    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.get_error() {
      gl::NO_ERROR => {},
      gl::OUT_OF_MEMORY => panic!("Out of VRAM"),
      err => warn!("OpenGL error 0x{:x}", err),
    }

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

  pub fn bind(&self, _: &mut GLContext) {
    unsafe {
      gl::BindBuffer(gl::ARRAY_BUFFER, self.handle.gl_id);
    }
  }

  /// Add more data into this buffer.
  /// Returns false and does nothing if this would exceed the capacity of the buffer.
  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub unsafe fn push(&mut self, gl: &mut GLContext, vs: *const u8, count: usize) -> bool {
    if self.length + count > self.capacity {
      // This would overflow the buffer.
      return false;
    }

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

    true
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn swap_remove(&mut self, _gl: &mut GLContext, i: usize, count: usize) {
    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::CopyBufferSubData(
          gl::ARRAY_BUFFER,
          gl::ARRAY_BUFFER,
          self.length as GLintptr,
          i as GLintptr,
          count as GLsizeiptr,
        );
      }
    }
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub unsafe fn update(&self, gl: &mut GLContext, idx: usize, vs: *const u8, count: usize) {
    assert!(idx + count <= self.length);
    self.update_inner(gl, idx, vs, count);
  }

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

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

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

impl<'a, T> GLBuffer<'a, T> {
  pub fn new<'b:'a>(
    gl: &'a mut GLContext,
    capacity: usize,
  ) -> GLBuffer<'b, T> {
    GLBuffer {
      byte_buffer: GLByteBuffer::new(gl, capacity * mem::size_of::<T>()),
      phantom: PhantomData,
    }
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn push(&mut self, gl: &mut GLContext, vs: &[T]) -> bool {
    unsafe {
      self.byte_buffer.push(
        gl,
        mem::transmute(vs.as_ptr()),
        mem::size_of::<T>() * vs.len()
      )
    }
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn update(&mut self, gl: &mut GLContext, idx: usize, vs: &[T]) {
    unsafe {
      self.byte_buffer.update(
        gl,
        mem::size_of::<T>() * idx,
        mem::transmute(vs.as_ptr()),
        mem::size_of::<T>() * vs.len(),
      );
    }
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn swap_remove(&mut self, gl: &mut GLContext, idx: usize, count: usize) {
    self.byte_buffer.swap_remove(
      gl,
      mem::size_of::<T>() * idx,
      mem::size_of::<T>() * count,
    );
  }
}

#[derive(Debug)]
#[derive(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,
    }
  }
}

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

impl GLType {
  pub fn size(&self) -> u32 {
    num::NumCast::from(
      match *self {
        GLType::Float => mem::size_of::<GLfloat>(),
        GLType::UInt  => mem::size_of::<GLuint>(),
        GLType::Int   => mem::size_of::<GLint>(),
      })
    .unwrap()
  }

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

#[derive(Debug)]
/// 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: u32,
  pub unit: GLType,
  pub divisor: u32,
}

impl<'a> VertexAttribData<'a> {
  pub fn apply(attribs: &[VertexAttribData<'a>], _gl: &mut GLContext, shader: &Shader) -> u32 {
    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 {
      let shader_attrib =
        glGetAttribLocation(
          shader.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);
        gl::VertexAttribDivisor(shader_attrib, attrib.divisor);

        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 isize;
    }

    attrib_span
  }
}

pub struct ArrayHandle<'a> {
  pub gl_id: GLuint,
  phantom: PhantomData<&'a ()>,
}

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

    ArrayHandle {
      gl_id: gl_id,
      phantom: PhantomData,
    }
  }
}

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: usize,
}

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<'b:'a>(
    gl: &'a mut GLContext,
    shader_program: &Shader<'b>,
    attribs: &[VertexAttribData],
    mode: DrawMode,
    buffer: GLBuffer<'b, T>,
  ) -> GLArray<'b, T> {
    let handle = ArrayHandle::new(gl);

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

    let attrib_span = VertexAttribData::apply(attribs, gl, shader_program);
    if attrib_span as usize != mem::size_of::<T>() {
      panic!("GLArray attribs don't describe the right number of bytes");
    }

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

    let length = buffer.byte_buffer.length / mem::size_of::<T>();

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

  pub fn bind(&self, _: &mut GLContext) {
    unsafe {
      gl::BindVertexArray(self.handle.gl_id);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.buffer.byte_buffer.handle.gl_id);
    }
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  /// The array doesn't need to be bound.
  pub fn push(&mut self, gl: &mut GLContext, vs: &[T]) -> bool {
    let r = self.buffer.push(gl, vs);
    if r {
      self.length += vs.len();
    }
    r
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  /// The array doesn't need to be bound.
  pub fn swap_remove(&mut self, gl: &mut GLContext, idx: usize, count: usize) {
    self.buffer.swap_remove(gl, idx, count);
    self.length -= count;
  }

  /// Draws all the queued triangles to the screen.
  /// N.B. For performance reasons, this does NOT bind the array.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn draw(&self, gl: &mut GLContext) {
    self.draw_slice(gl, 0, self.length);
  }

  /// Draw some subset of the triangle array.
  /// N.B. For performance reasons, this does NOT bind the array.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn draw_slice(&self, _gl: &mut GLContext, start: usize, len: usize) {
    assert!(start + len <= self.length);

    unsafe {
      gl::DrawArrays(self.mode, start as i32, len as i32);
    }
  }
}
<commit_msg>Fix for current nightly<commit_after>use gl;
use gl::types::*;
use gl_context::GLContext;
use num;
use std::ffi::CString;
use std::os::raw::c_void;
use std::marker::PhantomData;
use std::mem;
use std::ptr;

use shader::*;

/// 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 {
  let c_str = CString::new(name.as_bytes()).unwrap();
  let ptr = c_str.as_ptr() as *const i8;
  unsafe {
    gl::GetAttribLocation(shader_program, ptr)
  }
}

pub struct BufferHandle<'a> {
  pub gl_id: GLuint,
  phantom: PhantomData<&'a ()>,
}

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

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

    assert!(gl_id != 0);

    BufferHandle {
      gl_id: gl_id,
      phantom: PhantomData,
    }
  }
}

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: usize,
  /// maximum number of bytes in the buffer.
  pub capacity: usize,
}

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<'b:'a>(
    gl: &'a mut GLContext,
    capacity: usize,
  ) -> GLByteBuffer<'b> {
    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.get_error() {
      gl::NO_ERROR => {},
      gl::OUT_OF_MEMORY => panic!("Out of VRAM"),
      err => warn!("OpenGL error 0x{:x}", err),
    }

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

  pub fn bind(&self, _: &mut GLContext) {
    unsafe {
      gl::BindBuffer(gl::ARRAY_BUFFER, self.handle.gl_id);
    }
  }

  /// Add more data into this buffer.
  /// Returns false and does nothing if this would exceed the capacity of the buffer.
  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub unsafe fn push(&mut self, gl: &mut GLContext, vs: *const u8, count: usize) -> bool {
    if self.length + count > self.capacity {
      // This would overflow the buffer.
      return false;
    }

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

    true
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn swap_remove(&mut self, _gl: &mut GLContext, i: usize, count: usize) {
    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::CopyBufferSubData(
          gl::ARRAY_BUFFER,
          gl::ARRAY_BUFFER,
          self.length as GLintptr,
          i as GLintptr,
          count as GLsizeiptr,
        );
      }
    }
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub unsafe fn update(&self, gl: &mut GLContext, idx: usize, vs: *const u8, count: usize) {
    assert!(idx + count <= self.length);
    self.update_inner(gl, idx, vs, count);
  }

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

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

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

impl<'a, T> GLBuffer<'a, T> {
  pub fn new<'b:'a>(
    gl: &'a mut GLContext,
    capacity: usize,
  ) -> GLBuffer<'b, T> {
    GLBuffer {
      byte_buffer: GLByteBuffer::new(gl, capacity * mem::size_of::<T>()),
      phantom: PhantomData,
    }
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn push(&mut self, gl: &mut GLContext, vs: &[T]) -> bool {
    unsafe {
      self.byte_buffer.push(
        gl,
        mem::transmute(vs.as_ptr()),
        mem::size_of::<T>() * vs.len()
      )
    }
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn update(&mut self, gl: &mut GLContext, idx: usize, vs: &[T]) {
    unsafe {
      self.byte_buffer.update(
        gl,
        mem::size_of::<T>() * idx,
        mem::transmute(vs.as_ptr()),
        mem::size_of::<T>() * vs.len(),
      );
    }
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn swap_remove(&mut self, gl: &mut GLContext, idx: usize, count: usize) {
    self.byte_buffer.swap_remove(
      gl,
      mem::size_of::<T>() * idx,
      mem::size_of::<T>() * count,
    );
  }
}

#[derive(Debug)]
#[derive(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,
    }
  }
}

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

impl GLType {
  pub fn size(&self) -> u32 {
    num::NumCast::from(
      match *self {
        GLType::Float => mem::size_of::<GLfloat>(),
        GLType::UInt  => mem::size_of::<GLuint>(),
        GLType::Int   => mem::size_of::<GLint>(),
      })
    .unwrap()
  }

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

#[derive(Debug)]
/// 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: u32,
  pub unit: GLType,
  pub divisor: u32,
}

impl<'a> VertexAttribData<'a> {
  pub fn apply(attribs: &[VertexAttribData<'a>], _gl: &mut GLContext, shader: &Shader) -> u32 {
    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 {
      let shader_attrib =
        glGetAttribLocation(
          shader.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);
        gl::VertexAttribDivisor(shader_attrib, attrib.divisor);

        if attrib.unit.is_integral() {
          gl::VertexAttribIPointer(
            shader_attrib,
            attrib.size as i32,
            attrib.unit.gl_enum(),
            attrib_span as i32,
            (ptr::null() as *const c_void).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() as *const c_void).offset(offset),
          );
        }
      }
      offset += (attrib.size * attrib.unit.size()) as isize;
    }

    attrib_span
  }
}

pub struct ArrayHandle<'a> {
  pub gl_id: GLuint,
  phantom: PhantomData<&'a ()>,
}

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

    ArrayHandle {
      gl_id: gl_id,
      phantom: PhantomData,
    }
  }
}

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: usize,
}

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<'b:'a>(
    gl: &'a mut GLContext,
    shader_program: &Shader<'b>,
    attribs: &[VertexAttribData],
    mode: DrawMode,
    buffer: GLBuffer<'b, T>,
  ) -> GLArray<'b, T> {
    let handle = ArrayHandle::new(gl);

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

    let attrib_span = VertexAttribData::apply(attribs, gl, shader_program);
    if attrib_span as usize != mem::size_of::<T>() {
      panic!("GLArray attribs don't describe the right number of bytes");
    }

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

    let length = buffer.byte_buffer.length / mem::size_of::<T>();

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

  pub fn bind(&self, _: &mut GLContext) {
    unsafe {
      gl::BindVertexArray(self.handle.gl_id);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.buffer.byte_buffer.handle.gl_id);
    }
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  /// The array doesn't need to be bound.
  pub fn push(&mut self, gl: &mut GLContext, vs: &[T]) -> bool {
    let r = self.buffer.push(gl, vs);
    if r {
      self.length += vs.len();
    }
    r
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  /// The array doesn't need to be bound.
  pub fn swap_remove(&mut self, gl: &mut GLContext, idx: usize, count: usize) {
    self.buffer.swap_remove(gl, idx, count);
    self.length -= count;
  }

  /// Draws all the queued triangles to the screen.
  /// N.B. For performance reasons, this does NOT bind the array.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn draw(&self, gl: &mut GLContext) {
    self.draw_slice(gl, 0, self.length);
  }

  /// Draw some subset of the triangle array.
  /// N.B. For performance reasons, this does NOT bind the array.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn draw_slice(&self, _gl: &mut GLContext, start: usize, len: usize) {
    assert!(start + len <= self.length);

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


<commit_before>use dungeon::{Dungeon};
use celloption::{Tile, Occupant};
use genotype::{Genotype};
use phenotype::{Seed};
use config::{Config};

use std::collections::{HashMap};
use rand::{Rng};

#[derive(Clone, Debug)]
pub struct WallPatterns {
    seed: Seed,
    patterns: Vec<Pattern>,
    pattern_width: u32,
    pattern_height: u32,
    indices: Vec<usize>,
    occupants: Vec<(Occupant, (u32, u32))>,
}

#[derive(Clone, Debug)]
struct Pattern {
    pattern: Vec<Option<Tile>>
}

impl Pattern {
    fn from_config(mapping: &HashMap<char, &Tile>, description: Vec<String>, width: u32, height: u32) -> Pattern {
        let size = width as usize * height as usize;
        let mut pattern = Vec::with_capacity(size);
        for line in description {
            for ch in line.chars() {
                let tile = mapping.get(&(ch));
                match tile {
                    None => pattern.push(None),
                    Some(&tile) => pattern.push(Some((*tile).clone()))
                }
            }
        }
        assert!(pattern.len() == size); // sanity check
        Pattern {
            pattern: pattern
        }
    }
}

impl WallPatterns {
    pub fn new(config: &Config, seed: &Seed) -> WallPatterns {
        // read in the configurations
        let wallpatterns = config.get_table(None, "wallpatterns");
        let tile_vars = config.get_table(Some(wallpatterns), "tiles");
        let pattern_width = config.get_integer(tile_vars, "width") as u32;
        let pattern_height = config.get_integer(tile_vars, "height") as u32;
        let mut mapping = HashMap::new();
        let tiles = config.get_listing(tile_vars, vec!["width", "height"]);
        for tile in tiles {
            let name = tile.as_slice();
            let graphical_tile = seed.tiles.get(name).unwrap();
            mapping.insert(config.get_char(tile_vars, name), graphical_tile);
        }
        let room_vars = config.get_table(Some(wallpatterns), "rooms");
        let rooms = config.get_listing(room_vars, vec![]);
        let patterns: Vec<Pattern> = rooms.iter().map(|r| {
            let description = config.get_array(room_vars, r);
            Pattern::from_config(&mapping, description, pattern_width, pattern_height)
        }).collect();
        WallPatterns {
            seed: seed.clone(),
            patterns: patterns,
            pattern_width: pattern_width,
            pattern_height: pattern_height,
            indices: vec![],
            occupants: vec![],
        }
    }

}

impl Genotype for WallPatterns {
    fn initialize<T: Rng>(&self, rng: &mut T) -> WallPatterns {
        let n = self.patterns.len();
        assert!(n != 0);
        let indices = rng.gen_iter::<usize>().take(n).map(|v| v % n).collect();
        let occupants = self.seed.random_occupants(rng);
        WallPatterns {
            seed: self.seed.clone(),
            patterns: self.patterns.clone(),
            pattern_width: self.pattern_width,
            pattern_height: self.pattern_height,
            indices: indices,
            occupants: occupants,
        }
    }

    fn mutate<T: Rng>(&mut self, rng: &mut T, percentage: f64) {
        let length = self.patterns.len();
        let n = (length as f64 * percentage) as u32;
        for _ in range(0, n) {
            let index = rng.gen_range(1, length);
            self.indices[index] = index;
        }
        self.occupants = self.seed.random_occupants(rng);
    }

    fn generate(&self) -> Dungeon {
        // draw the patterns according to the indices we have.
        let w = self.seed.width;
        let h = self.seed.height;
        let n = self.patterns.len();
        let mut dungeon = Dungeon::new(w, h, None);
        for i in 0..w {
            let x: u32 = i / self.pattern_width;
            let inner_x = i % self.pattern_width;
            for j in 0..h {
                let y: u32 = j / self.pattern_height;
                let index = self.indices[(y * self.pattern_width + x) as usize % n];
                let ref pattern = self.patterns[index];
                // here, we have to invert due to a mismatch between how we draw the patterns and opengl coords
                let inner_y = self.pattern_height - (j % self.pattern_height) - 1;
                let tile_index = inner_y * self.pattern_width + inner_x;
                let tile = pattern.pattern[tile_index as usize].clone().unwrap();
                dungeon.set_tile(i, j, &tile);
            }
        }
        // draw the occupants if their tile is not otherwise occupied.
        for (occupant, coord) in self.occupants.clone() {
            let x = coord.0;
            let y = coord.1;
            if dungeon.has_attribute(x, y, "floor") {
                dungeon.set_occupant(x, y, &occupant);
            }
        }
        dungeon.clone()
    }
}
<commit_msg>Minor fix for unwrapping wall patterns.<commit_after>use dungeon::{Dungeon};
use celloption::{Tile, Occupant};
use genotype::{Genotype};
use phenotype::{Seed};
use config::{Config};

use std::collections::{HashMap};
use rand::{Rng};

#[derive(Clone, Debug)]
pub struct WallPatterns {
    seed: Seed,
    patterns: Vec<Pattern>,
    pattern_width: u32,
    pattern_height: u32,
    indices: Vec<usize>,
    occupants: Vec<(Occupant, (u32, u32))>,
}

#[derive(Clone, Debug)]
struct Pattern {
    pattern: Vec<Option<Tile>>
}

impl Pattern {
    fn from_config(mapping: &HashMap<char, &Tile>, description: Vec<String>, width: u32, height: u32) -> Pattern {
        let size = width as usize * height as usize;
        let mut pattern = Vec::with_capacity(size);
        for line in description {
            for ch in line.chars() {
                let tile = mapping.get(&(ch));
                match tile {
                    None => pattern.push(None),
                    Some(&tile) => pattern.push(Some((*tile).clone()))
                }
            }
        }
        assert!(pattern.len() == size); // sanity check
        Pattern {
            pattern: pattern
        }
    }
}

impl WallPatterns {
    pub fn new(config: &Config, seed: &Seed) -> WallPatterns {
        // read in the configurations
        let wallpatterns = config.get_table(None, "wallpatterns");
        let tile_vars = config.get_table(Some(wallpatterns), "tiles");
        let pattern_width = config.get_integer(tile_vars, "width") as u32;
        let pattern_height = config.get_integer(tile_vars, "height") as u32;
        let mut mapping = HashMap::new();
        let tiles = config.get_listing(tile_vars, vec!["width", "height"]);
        for tile in tiles {
            let name = tile.as_slice();
            let graphical_tile = seed.tiles.get(name).unwrap();
            mapping.insert(config.get_char(tile_vars, name), graphical_tile);
        }
        let room_vars = config.get_table(Some(wallpatterns), "rooms");
        let rooms = config.get_listing(room_vars, vec![]);
        let patterns: Vec<Pattern> = rooms.iter().map(|r| {
            let description = config.get_array(room_vars, r);
            Pattern::from_config(&mapping, description, pattern_width, pattern_height)
        }).collect();
        WallPatterns {
            seed: seed.clone(),
            patterns: patterns,
            pattern_width: pattern_width,
            pattern_height: pattern_height,
            indices: vec![],
            occupants: vec![],
        }
    }

}

impl Genotype for WallPatterns {
    fn initialize<T: Rng>(&self, rng: &mut T) -> WallPatterns {
        let n = self.patterns.len();
        assert!(n != 0);
        let indices = rng.gen_iter::<usize>().take(n).map(|v| v % n).collect();
        let occupants = self.seed.random_occupants(rng);
        WallPatterns {
            seed: self.seed.clone(),
            patterns: self.patterns.clone(),
            pattern_width: self.pattern_width,
            pattern_height: self.pattern_height,
            indices: indices,
            occupants: occupants,
        }
    }

    fn mutate<T: Rng>(&mut self, rng: &mut T, percentage: f64) {
        let length = self.patterns.len();
        let n = (length as f64 * percentage) as u32;
        for _ in range(0, n) {
            let index = rng.gen_range(1, length);
            self.indices[index] = index;
        }
        self.occupants = self.seed.random_occupants(rng);
    }

    fn generate(&self) -> Dungeon {
        // draw the patterns according to the indices we have.
        let w = self.seed.width;
        let h = self.seed.height;
        let n = self.patterns.len();
        let mut dungeon = Dungeon::new(w, h, None);
        for i in 0..w {
            let x: u32 = i / self.pattern_width;
            let inner_x = i % self.pattern_width;
            for j in 0..h {
                let y: u32 = j / self.pattern_height;
                let index = self.indices[(y * self.pattern_width + x) as usize % n];
                let ref pattern = self.patterns[index];
                // here, we have to invert due to a mismatch between how we draw the patterns and opengl coords
                let inner_y = self.pattern_height - (j % self.pattern_height) - 1;
                let tile_index = inner_y * self.pattern_width + inner_x;
                if let Some(tile) = pattern.pattern[tile_index as usize].clone() {
                    dungeon.set_tile(i, j, &tile);
                }
            }
        }
        // draw the occupants if their tile is not otherwise occupied.
        for (occupant, coord) in self.occupants.clone() {
            let x = coord.0;
            let y = coord.1;
            if dungeon.has_attribute(x, y, "floor") {
                dungeon.set_occupant(x, y, &occupant);
            }
        }
        dungeon.clone()
    }
}
<|endoftext|>


<commit_before>#![crate_type = "dylib"]
#![feature(plugin_registrar, quote, box_syntax, core, collections, rustc_private, io, unicode, path)]

extern crate rustc;
extern crate syntax;

use syntax::ast;
use syntax::codemap;
use syntax::ext::base::{ExtCtxt, MacResult, MacItems, DummyResult};
use syntax::parse;
use syntax::parse::token;
use syntax::fold::Folder;
use rustc::plugin::Registry;
use std::old_io::fs::File;
use std::str;

use rustast::{AstBuilder, DUMMY_SP};

mod translate;
mod grammar;
mod rustast;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
            token::intern("peg"),
            syntax::ext::base::IdentTT(box expand_peg_str, None));

    reg.register_syntax_extension(
            token::intern("peg_file"),
            syntax::ext::base::IdentTT(box expand_peg_file, None));
}

fn expand_peg_str<'s>(cx: &'s mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<ast::TokenTree>) -> Box<MacResult + 's> {
    let source = match parse_arg(cx, tts.as_slice()) {
        Some(source) => source,
        None => return DummyResult::any(sp),
    };

    expand_peg(cx, sp, ident, source.as_slice())
}

fn expand_peg_file<'s>(cx: &'s mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<ast::TokenTree>) -> Box<MacResult + 's> {
    let fname = match parse_arg(cx, tts.as_slice()) {
        Some(fname) => fname,
        None => return DummyResult::any(sp),
    };

    let path = Path::new(cx.codemap().span_to_filename(sp)).dir_path().join(fname);

    let source_utf8 = match File::open(&path).read_to_end() {
      Ok(source_utf8) => source_utf8,
      Err(e) => {
        cx.span_err(sp, e.to_string().as_slice());
        return DummyResult::any(sp)
      }
    };

    let source = str::from_utf8(source_utf8.as_slice()).unwrap();

    cx.codemap().new_filemap(path.as_str().unwrap().to_string(), "".to_string());

    expand_peg(cx, sp, ident, source.as_slice())
}

fn expand_peg(cx: &mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, source: &str) -> Box<MacResult + 'static> {
    let grammar_def = grammar::grammar(source);

    let grammar_def = match grammar_def {
      Ok(grammar_def) => grammar_def,
      Err(msg) => {
        cx.span_err(sp, msg.as_slice());
        return DummyResult::any(sp)
      }
    };

    let ast = translate::compile_grammar(cx, &grammar_def);

    // #![allow(non_snake_case, unused)]
    let allow = cx.attribute(DUMMY_SP, cx.meta_list(DUMMY_SP, token::InternedString::new("allow"), vec![
        cx.meta_word(DUMMY_SP, token::InternedString::new("non_snake_case")),
        cx.meta_word(DUMMY_SP, token::InternedString::new("unused")),
    ]));

    MacItems::new(Some(cx.item_mod(sp, sp, ident, vec![allow], ast.items.clone())).into_iter())
}

fn parse_arg(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Option<String> {
    use syntax::print::pprust;

    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                tts.to_vec());
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.
    let arg = cx.expander().fold_expr(parser.parse_expr());
    match arg.node {
        ast::ExprLit(ref spanned) => {
            match spanned.node {
                ast::LitStr(ref n, _) => {
                    if !parser.eat(&token::Eof) {
                        cx.span_err(parser.span,
                                    "expected only one string literal");
                        return None
                    }
                    return Some(n.get().to_string())
                }
                _ => {}
            }
        }
        _ => {}
    }

    let err = format!("expected string literal but got `{}`",
                      pprust::expr_to_string(&*arg));
    cx.span_err(parser.span, err.as_slice());
    None
}
<commit_msg>Remove obsolete crate_type: Fixes #42<commit_after>#![feature(plugin_registrar, quote, box_syntax, core, collections, rustc_private, io, unicode, path)]

extern crate rustc;
extern crate syntax;

use syntax::ast;
use syntax::codemap;
use syntax::ext::base::{ExtCtxt, MacResult, MacItems, DummyResult};
use syntax::parse;
use syntax::parse::token;
use syntax::fold::Folder;
use rustc::plugin::Registry;
use std::old_io::fs::File;
use std::str;

use rustast::{AstBuilder, DUMMY_SP};

mod translate;
mod grammar;
mod rustast;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
            token::intern("peg"),
            syntax::ext::base::IdentTT(box expand_peg_str, None));

    reg.register_syntax_extension(
            token::intern("peg_file"),
            syntax::ext::base::IdentTT(box expand_peg_file, None));
}

fn expand_peg_str<'s>(cx: &'s mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<ast::TokenTree>) -> Box<MacResult + 's> {
    let source = match parse_arg(cx, tts.as_slice()) {
        Some(source) => source,
        None => return DummyResult::any(sp),
    };

    expand_peg(cx, sp, ident, source.as_slice())
}

fn expand_peg_file<'s>(cx: &'s mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<ast::TokenTree>) -> Box<MacResult + 's> {
    let fname = match parse_arg(cx, tts.as_slice()) {
        Some(fname) => fname,
        None => return DummyResult::any(sp),
    };

    let path = Path::new(cx.codemap().span_to_filename(sp)).dir_path().join(fname);

    let source_utf8 = match File::open(&path).read_to_end() {
      Ok(source_utf8) => source_utf8,
      Err(e) => {
        cx.span_err(sp, e.to_string().as_slice());
        return DummyResult::any(sp)
      }
    };

    let source = str::from_utf8(source_utf8.as_slice()).unwrap();

    cx.codemap().new_filemap(path.as_str().unwrap().to_string(), "".to_string());

    expand_peg(cx, sp, ident, source.as_slice())
}

fn expand_peg(cx: &mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, source: &str) -> Box<MacResult + 'static> {
    let grammar_def = grammar::grammar(source);

    let grammar_def = match grammar_def {
      Ok(grammar_def) => grammar_def,
      Err(msg) => {
        cx.span_err(sp, msg.as_slice());
        return DummyResult::any(sp)
      }
    };

    let ast = translate::compile_grammar(cx, &grammar_def);

    // #![allow(non_snake_case, unused)]
    let allow = cx.attribute(DUMMY_SP, cx.meta_list(DUMMY_SP, token::InternedString::new("allow"), vec![
        cx.meta_word(DUMMY_SP, token::InternedString::new("non_snake_case")),
        cx.meta_word(DUMMY_SP, token::InternedString::new("unused")),
    ]));

    MacItems::new(Some(cx.item_mod(sp, sp, ident, vec![allow], ast.items.clone())).into_iter())
}

fn parse_arg(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Option<String> {
    use syntax::print::pprust;

    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                tts.to_vec());
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.
    let arg = cx.expander().fold_expr(parser.parse_expr());
    match arg.node {
        ast::ExprLit(ref spanned) => {
            match spanned.node {
                ast::LitStr(ref n, _) => {
                    if !parser.eat(&token::Eof) {
                        cx.span_err(parser.span,
                                    "expected only one string literal");
                        return None
                    }
                    return Some(n.get().to_string())
                }
                _ => {}
            }
        }
        _ => {}
    }

    let err = format!("expected string literal but got `{}`",
                      pprust::expr_to_string(&*arg));
    cx.span_err(parser.span, err.as_slice());
    None
}
<|endoftext|>


<commit_before>use std::{
    cell::{Cell, RefCell},
    collections::BTreeMap,
};

use dces::prelude::Entity;

use crate::{prelude::*, render::RenderContext2D, tree::Tree, utils::prelude::*};

use super::Layout;

/// Stacks visual the children widgets vertical or horizontal.
#[derive(Default)]
pub struct StackLayout {
    desired_size: RefCell<DirtySize>,
    old_alignment: Cell<(Alignment, Alignment)>,
}

impl StackLayout {
    pub fn new() -> Self {
        StackLayout::default()
    }
}

impl Layout for StackLayout {
    fn measure(
        &self,
        render_context_2_d: &mut RenderContext2D,
        entity: Entity,
        ecm: &mut EntityComponentManager<Tree, StringComponentStore>,

        layouts: &BTreeMap<Entity, Box<dyn Layout>>,
        theme: &ThemeValue,
    ) -> DirtySize {
        if *ecm
            .component_store()
            .get::<Visibility>("visibility", entity)
            .unwrap()
            == Visibility::Collapsed
        {
            self.desired_size.borrow_mut().set_size(0.0, 0.0);
            return *self.desired_size.borrow();
        }

        let horizontal_alignment: Alignment = *ecm
            .component_store()
            .get("horizontal_alignment", entity)
            .unwrap();
        let vertical_alignment: Alignment = *ecm
            .component_store()
            .get("vertical_alignment", entity)
            .unwrap();

        if horizontal_alignment != self.old_alignment.get().1
            || vertical_alignment != self.old_alignment.get().0
        {
            self.desired_size.borrow_mut().set_dirty(true);
        }

        let orientation: Orientation = *ecm.component_store().get("orientation", entity).unwrap();
        let mut desired_size: (f64, f64) = (0.0, 0.0);
        let nchildren = ecm.entity_store().children[&entity].len();
        let spacing = spacing(ecm, entity);

        for index in 0..nchildren {
            let child = ecm.entity_store().children[&entity][index];

            if let Some(child_layout) = layouts.get(&child) {
                let child_desired_size =
                    child_layout.measure(render_context_2_d, child, ecm, layouts, theme);

                let mut child_margin = {
                    if child_desired_size.width() > 0.0 && child_desired_size.height() > 0.0 {
                        *ecm.component_store()
                            .get::<Thickness>("margin", child)
                            .unwrap()
                    } else {
                        Thickness::default()
                    }
                };

                if spacing != 0.0 && nchildren > 1 {
                    apply_spacing(&mut child_margin, spacing, orientation, index, nchildren);
                }

                match orientation {
                    Orientation::Horizontal => {
                        desired_size.0 +=
                            child_desired_size.width() + child_margin.left() + child_margin.right();
                        desired_size.1 = desired_size.1.max(
                            child_desired_size.height()
                                + child_margin.top()
                                + child_margin.bottom(),
                        );
                    }
                    _ => {
                        desired_size.0 = desired_size.0.max(
                            child_desired_size.width() + child_margin.left() + child_margin.right(),
                        );
                        desired_size.1 += child_desired_size.height()
                            + child_margin.top()
                            + child_margin.bottom();
                    }
                }

                let dirty = child_desired_size.dirty() || self.desired_size.borrow().dirty();
                self.desired_size.borrow_mut().set_dirty(dirty);
            }
        }

        self.desired_size
            .borrow_mut()
            .set_size(desired_size.0, desired_size.1);
        *self.desired_size.borrow()
    }

    fn arrange(
        &self,
        render_context_2_d: &mut RenderContext2D,
        parent_size: (f64, f64),
        entity: Entity,
        ecm: &mut EntityComponentManager<Tree, StringComponentStore>,
        layouts: &BTreeMap<Entity, Box<dyn Layout>>,
        theme: &ThemeValue,
    ) -> (f64, f64) {
        if *ecm
            .component_store()
            .get::<Visibility>("visibility", entity)
            .unwrap()
            == Visibility::Collapsed
        {
            self.desired_size.borrow_mut().set_size(0.0, 0.0);
            return (0.0, 0.0);
        }

        if !self.desired_size.borrow().dirty() {
            return self.desired_size.borrow().size();
        }

        let horizontal_alignment: Alignment = *ecm
            .component_store()
            .get("horizontal_alignment", entity)
            .unwrap();
        let vertical_alignment: Alignment = *ecm
            .component_store()
            .get("vertical_alignment", entity)
            .unwrap();
        let margin: Thickness = *ecm.component_store().get("margin", entity).unwrap();
        let constraint = *ecm
            .component_store()
            .get::<Constraint>("constraint", entity)
            .unwrap();
        let orientation: Orientation = *ecm.component_store().get("orientation", entity).unwrap();
        let mut size_counter = 0.0;

        let size = constraint.perform((
            horizontal_alignment.align_measure(
                parent_size.0,
                self.desired_size.borrow().width(),
                margin.left(),
                margin.right(),
            ),
            vertical_alignment.align_measure(
                parent_size.1,
                self.desired_size.borrow().height(),
                margin.top(),
                margin.bottom(),
            ),
        ));

        if let Ok(bounds) = ecm
            .component_store_mut()
            .get_mut::<Rectangle>("bounds", entity)
        {
            bounds.set_width(size.0);
            bounds.set_height(size.1);
        }

        let available_size = size;
        let nchildren = ecm.entity_store().children[&entity].len();
        let spacing = spacing(ecm, entity);

        for index in 0..nchildren {
            let child = ecm.entity_store().children[&entity][index];

            let mut child_desired_size = (0.0, 0.0);
            if let Some(child_layout) = layouts.get(&child) {
                match orientation {
                    Orientation::Horizontal => {
                        // set width to 0.0 to shrink width of the child
                        child_desired_size = child_layout.arrange(
                            render_context_2_d,
                            (0.0, size.1),
                            child,
                            ecm,
                            layouts,
                            theme,
                        );
                    }
                    // set height to 0.0 to shrink height of the child
                    Orientation::Vertical => {
                        child_desired_size = child_layout.arrange(
                            render_context_2_d,
                            (size.0, 0.0),
                            child,
                            ecm,
                            layouts,
                            theme,
                        );
                    }
                }
            }

            let mut child_margin = {
                if child_desired_size.0 > 0.0 && child_desired_size.1 > 0.0 {
                    *ecm.component_store()
                        .get::<Thickness>("margin", child)
                        .unwrap()
                } else {
                    Thickness::default()
                }
            };

            if spacing != 0.0 && nchildren > 1 {
                apply_spacing(&mut child_margin, spacing, orientation, index, nchildren);
            }

            let child_horizontal_alignment: Alignment = *ecm
                .component_store()
                .get("horizontal_alignment", child)
                .unwrap();
            let child_vertical_alignment: Alignment = *ecm
                .component_store()
                .get("vertical_alignment", child)
                .unwrap();

            if let Ok(child_bounds) = ecm
                .component_store_mut()
                .get_mut::<Rectangle>("bounds", child)
            {
                match orientation {
                    Orientation::Horizontal => {
                        child_bounds.set_x(
                            size_counter
                                + child_horizontal_alignment.align_position(
                                    available_size.0,
                                    child_bounds.width(),
                                    child_margin.left(),
                                    child_margin.right(),
                                ),
                        );
                        child_bounds.set_y(child_vertical_alignment.align_position(
                            available_size.1,
                            child_bounds.height(),
                            child_margin.top(),
                            child_margin.bottom(),
                        ));
                        size_counter +=
                            child_bounds.width() + child_margin.left() + child_margin.right();
                    }
                    _ => {
                        child_bounds.set_x(child_horizontal_alignment.align_position(
                            available_size.0,
                            child_bounds.width(),
                            child_margin.left(),
                            child_margin.right(),
                        ));
                        child_bounds.set_y(
                            size_counter
                                + child_vertical_alignment.align_position(
                                    available_size.1,
                                    child_bounds.height(),
                                    child_margin.top(),
                                    child_margin.bottom(),
                                ),
                        );
                        size_counter +=
                            child_bounds.height() + child_margin.top() + child_margin.bottom();
                    }
                }
            }
        }

        self.desired_size.borrow_mut().set_dirty(false);
        size
    }
}

impl Into<Box<dyn Layout>> for StackLayout {
    fn into(self) -> Box<dyn Layout> {
        Box::new(self)
    }
}

/// Applies spacing to widgets in a stack, depending upon their position, and the orientation.
fn apply_spacing(margins: &mut Thickness, spacing: f64, orientation: Orientation, index: usize, nchildren: usize) {
    let start =  if index == 0 { 0.0 } else { spacing / 2.0 };
    let end = if index == nchildren - 1 { 0.0 } else { spacing / 2.0 };

    match orientation {
        Orientation::Vertical => {
            margins.top += start;
            margins.bottom += end;
        }
        Orientation::Horizontal => {
            margins.left += start;
            margins.right += end;
        }
    }
}

/// Fetch the spacing property, which is guaranteed to exist on a stack.
fn spacing(ecm: &mut EntityComponentManager<Tree, StringComponentStore>, entity: Entity) -> f64 {
    ecm.component_store()
        .get::<f64>("spacing", entity)
        .expect("stack layout missing spacing property")
        .clone()
}<commit_msg>improvement(tests): Add unit tests for stack spacing<commit_after>use std::{
    cell::{Cell, RefCell},
    collections::BTreeMap,
};

use dces::prelude::Entity;

use crate::{prelude::*, render::RenderContext2D, tree::Tree, utils::prelude::*};

use super::Layout;

/// Stacks visual the children widgets vertical or horizontal.
#[derive(Default)]
pub struct StackLayout {
    desired_size: RefCell<DirtySize>,
    old_alignment: Cell<(Alignment, Alignment)>,
}

impl StackLayout {
    pub fn new() -> Self {
        StackLayout::default()
    }
}

impl Layout for StackLayout {
    fn measure(
        &self,
        render_context_2_d: &mut RenderContext2D,
        entity: Entity,
        ecm: &mut EntityComponentManager<Tree, StringComponentStore>,

        layouts: &BTreeMap<Entity, Box<dyn Layout>>,
        theme: &ThemeValue,
    ) -> DirtySize {
        if *ecm
            .component_store()
            .get::<Visibility>("visibility", entity)
            .unwrap()
            == Visibility::Collapsed
        {
            self.desired_size.borrow_mut().set_size(0.0, 0.0);
            return *self.desired_size.borrow();
        }

        let horizontal_alignment: Alignment = *ecm
            .component_store()
            .get("horizontal_alignment", entity)
            .unwrap();
        let vertical_alignment: Alignment = *ecm
            .component_store()
            .get("vertical_alignment", entity)
            .unwrap();

        if horizontal_alignment != self.old_alignment.get().1
            || vertical_alignment != self.old_alignment.get().0
        {
            self.desired_size.borrow_mut().set_dirty(true);
        }

        let orientation: Orientation = *ecm.component_store().get("orientation", entity).unwrap();
        let mut desired_size: (f64, f64) = (0.0, 0.0);
        let nchildren = ecm.entity_store().children[&entity].len();
        let spacing = spacing(ecm, entity);

        for index in 0..nchildren {
            let child = ecm.entity_store().children[&entity][index];

            if let Some(child_layout) = layouts.get(&child) {
                let child_desired_size =
                    child_layout.measure(render_context_2_d, child, ecm, layouts, theme);

                let mut child_margin = {
                    if child_desired_size.width() > 0.0 && child_desired_size.height() > 0.0 {
                        *ecm.component_store()
                            .get::<Thickness>("margin", child)
                            .unwrap()
                    } else {
                        Thickness::default()
                    }
                };

                if spacing != 0.0 && nchildren > 1 {
                    apply_spacing(&mut child_margin, spacing, orientation, index, nchildren);
                }

                match orientation {
                    Orientation::Horizontal => {
                        desired_size.0 +=
                            child_desired_size.width() + child_margin.left() + child_margin.right();
                        desired_size.1 = desired_size.1.max(
                            child_desired_size.height()
                                + child_margin.top()
                                + child_margin.bottom(),
                        );
                    }
                    _ => {
                        desired_size.0 = desired_size.0.max(
                            child_desired_size.width() + child_margin.left() + child_margin.right(),
                        );
                        desired_size.1 += child_desired_size.height()
                            + child_margin.top()
                            + child_margin.bottom();
                    }
                }

                let dirty = child_desired_size.dirty() || self.desired_size.borrow().dirty();
                self.desired_size.borrow_mut().set_dirty(dirty);
            }
        }

        self.desired_size
            .borrow_mut()
            .set_size(desired_size.0, desired_size.1);
        *self.desired_size.borrow()
    }

    fn arrange(
        &self,
        render_context_2_d: &mut RenderContext2D,
        parent_size: (f64, f64),
        entity: Entity,
        ecm: &mut EntityComponentManager<Tree, StringComponentStore>,
        layouts: &BTreeMap<Entity, Box<dyn Layout>>,
        theme: &ThemeValue,
    ) -> (f64, f64) {
        if *ecm
            .component_store()
            .get::<Visibility>("visibility", entity)
            .unwrap()
            == Visibility::Collapsed
        {
            self.desired_size.borrow_mut().set_size(0.0, 0.0);
            return (0.0, 0.0);
        }

        if !self.desired_size.borrow().dirty() {
            return self.desired_size.borrow().size();
        }

        let horizontal_alignment: Alignment = *ecm
            .component_store()
            .get("horizontal_alignment", entity)
            .unwrap();
        let vertical_alignment: Alignment = *ecm
            .component_store()
            .get("vertical_alignment", entity)
            .unwrap();
        let margin: Thickness = *ecm.component_store().get("margin", entity).unwrap();
        let constraint = *ecm
            .component_store()
            .get::<Constraint>("constraint", entity)
            .unwrap();
        let orientation: Orientation = *ecm.component_store().get("orientation", entity).unwrap();
        let mut size_counter = 0.0;

        let size = constraint.perform((
            horizontal_alignment.align_measure(
                parent_size.0,
                self.desired_size.borrow().width(),
                margin.left(),
                margin.right(),
            ),
            vertical_alignment.align_measure(
                parent_size.1,
                self.desired_size.borrow().height(),
                margin.top(),
                margin.bottom(),
            ),
        ));

        if let Ok(bounds) = ecm
            .component_store_mut()
            .get_mut::<Rectangle>("bounds", entity)
        {
            bounds.set_width(size.0);
            bounds.set_height(size.1);
        }

        let available_size = size;
        let nchildren = ecm.entity_store().children[&entity].len();
        let spacing = spacing(ecm, entity);

        for index in 0..nchildren {
            let child = ecm.entity_store().children[&entity][index];

            let mut child_desired_size = (0.0, 0.0);
            if let Some(child_layout) = layouts.get(&child) {
                match orientation {
                    Orientation::Horizontal => {
                        // set width to 0.0 to shrink width of the child
                        child_desired_size = child_layout.arrange(
                            render_context_2_d,
                            (0.0, size.1),
                            child,
                            ecm,
                            layouts,
                            theme,
                        );
                    }
                    // set height to 0.0 to shrink height of the child
                    Orientation::Vertical => {
                        child_desired_size = child_layout.arrange(
                            render_context_2_d,
                            (size.0, 0.0),
                            child,
                            ecm,
                            layouts,
                            theme,
                        );
                    }
                }
            }

            let mut child_margin = {
                if child_desired_size.0 > 0.0 && child_desired_size.1 > 0.0 {
                    *ecm.component_store()
                        .get::<Thickness>("margin", child)
                        .unwrap()
                } else {
                    Thickness::default()
                }
            };

            if spacing != 0.0 && nchildren > 1 {
                apply_spacing(&mut child_margin, spacing, orientation, index, nchildren);
            }

            let child_horizontal_alignment: Alignment = *ecm
                .component_store()
                .get("horizontal_alignment", child)
                .unwrap();
            let child_vertical_alignment: Alignment = *ecm
                .component_store()
                .get("vertical_alignment", child)
                .unwrap();

            if let Ok(child_bounds) = ecm
                .component_store_mut()
                .get_mut::<Rectangle>("bounds", child)
            {
                match orientation {
                    Orientation::Horizontal => {
                        child_bounds.set_x(
                            size_counter
                                + child_horizontal_alignment.align_position(
                                    available_size.0,
                                    child_bounds.width(),
                                    child_margin.left(),
                                    child_margin.right(),
                                ),
                        );
                        child_bounds.set_y(child_vertical_alignment.align_position(
                            available_size.1,
                            child_bounds.height(),
                            child_margin.top(),
                            child_margin.bottom(),
                        ));
                        size_counter +=
                            child_bounds.width() + child_margin.left() + child_margin.right();
                    }
                    _ => {
                        child_bounds.set_x(child_horizontal_alignment.align_position(
                            available_size.0,
                            child_bounds.width(),
                            child_margin.left(),
                            child_margin.right(),
                        ));
                        child_bounds.set_y(
                            size_counter
                                + child_vertical_alignment.align_position(
                                    available_size.1,
                                    child_bounds.height(),
                                    child_margin.top(),
                                    child_margin.bottom(),
                                ),
                        );
                        size_counter +=
                            child_bounds.height() + child_margin.top() + child_margin.bottom();
                    }
                }
            }
        }

        self.desired_size.borrow_mut().set_dirty(false);
        size
    }
}

impl Into<Box<dyn Layout>> for StackLayout {
    fn into(self) -> Box<dyn Layout> {
        Box::new(self)
    }
}

/// Applies spacing to widgets in a stack, depending upon their position, and the orientation.
fn apply_spacing(margins: &mut Thickness, spacing: f64, orientation: Orientation, index: usize, nchildren: usize) {
    let start =  if index == 0 { 0.0 } else { spacing / 2.0 };
    let end = if index == nchildren - 1 { 0.0 } else { spacing / 2.0 };

    match orientation {
        Orientation::Vertical => {
            margins.top += start;
            margins.bottom += end;
        }
        Orientation::Horizontal => {
            margins.left += start;
            margins.right += end;
        }
    }
}

/// Fetch the spacing property, which is guaranteed to exist on a stack.
fn spacing(ecm: &mut EntityComponentManager<Tree, StringComponentStore>, entity: Entity) -> f64 {
    ecm.component_store()
        .get::<f64>("spacing", entity)
        .expect("stack layout missing spacing property")
        .clone()
}

#[cfg(test)]
mod tests {
    use orbtk_utils::{Thickness, Orientation};
    use std::iter;

    use super::apply_spacing;

    const NUM_WIDGETS: usize = 5;

    #[test]
    fn spacing_vertical() {
        let expected = iter::once(Thickness { left: 0.0, right: 0.0, top: 0.0, bottom: 2.0 })
            .chain(iter::repeat(Thickness { left: 0.0, right: 0.0, top: 2.0, bottom: 2.0 }).take(3))
            .chain(iter::once(Thickness { left: 0.0, right: 0.0, top: 2.0, bottom: 0.0 }));

        spacing(Orientation::Vertical, 4.0, expected);
    }

    #[test]
    fn spacing_horizontal() {
        let expected = iter::once(Thickness { left: 0.0, right: 4.0, top: 0.0, bottom: 0.0 })
            .chain(iter::repeat(Thickness { left: 4.0, right: 4.0, top: 0.0, bottom: 0.0 }).take(3))
            .chain(iter::once(Thickness { left: 4.0, right: 0.0, top: 0.0, bottom: 0.0 }));

        spacing(Orientation::Horizontal, 8.0, expected);
    }

    fn spacing(orientation: Orientation, spacing: f64, expected: impl Iterator<Item = Thickness>) {
        let inputs = (0..NUM_WIDGETS).map(|id| (id, Thickness::default()));

        for ((index, mut input), expected) in inputs.zip(expected) {
            apply_spacing(&mut input, spacing, orientation, index, NUM_WIDGETS);
            assert_eq!(input, expected);
        }
    }
}<|endoftext|>


<commit_before>use {Credentials, Error, FileType, DataTransferMode};
use {server, protocol};

use std::path::PathBuf;

/// The state of a client.
#[derive(Clone, Debug)]
pub enum Session
{
    /// We need to send them a welcome message.
    PendingWelcome,
    /// We are waiting for (or in the middle of) the user to login.
    Login(Login),
    /// We are connected and logged in as a user.
    Ready(Ready),
}

#[derive(Clone, Debug)]
pub enum Login
{
    /// The client needs to initiate login by sending 'USER <name>'.
    WaitingForUsername,
    /// The client has initiated login, and we are waiting for their password.
    WaitingForPassword {
        username: String,
    },
}

#[derive(Clone, Debug)]
pub struct Ready
{
    /// The credentials of the current user.
    pub credentials: Credentials,
    /// The current working directory.
    pub working_dir: PathBuf,
    /// The current data transfer file mode.
    pub transfer_type: FileType,
    /// The current state of the data connection.
    pub data_connection: DataConnection,
    /// Whether the connection is active or passive.
    pub data_transfer_mode: DataTransferMode,
    /// The port given by the 'PORT' command.
    pub port: Option<u16>,
    /// The data transfer operations we have queued.
    pub active_transfer: Option<server::Transfer>,
}

/// The current state of the data connection.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DataConnection
{
    /// Not sure if we want a data connection yet.
    None,
    /// We need to send an outbound connection to the client.
    PendingOutbound{ port: u16 },
    /// We need to receive an inbound connection from the client.
    PendingInbound { port: u16},
    /// We have successfully made a data protocol connection.
    Connected,
}

impl Session
{
    pub fn expect_ready(&self) -> Result<&Ready, Error> {
        if let Session::Ready(ref ready) = *self {
            Ok(ready)
        } else {
            Err(Error::Protocol(protocol::Error::Client(protocol::ClientError::NotLoggedIn)))
        }
    }

    pub fn expect_ready_mut(&mut self) -> Result<&mut Ready, Error> {
        if let Session::Ready(ref mut ready) = *self {
            Ok(ready)
        } else {
            Err(Error::Protocol(protocol::Error::Client(protocol::ClientError::NotLoggedIn)))
        }
    }

    pub fn expect_login(&self) -> Result<&Login, Error> {
        if let Session::Login(ref login) = *self {
            Ok(login)
        } else {
            // FIXME: return a more appropriate error.
            Err(Error::Protocol(protocol::Error::Client(protocol::ClientError::NotLoggedIn)))
        }
    }

    pub fn expect_login_mut(&mut self) -> Result<&mut Login, Error> {
        if let Session::Login(ref mut login) = *self {
            Ok(login)
        } else {
            // FIXME: return a more appropriate error.
            Err(Error::Protocol(protocol::Error::Client(protocol::ClientError::NotLoggedIn)))
        }
    }
}

impl Ready
{
    pub fn new(credentials: Credentials) -> Self {
        Ready {
            credentials: credentials,
            working_dir: "/".into(),
            transfer_type: FileType::Binary,
            data_connection: DataConnection::None,
            data_transfer_mode: DataTransferMode::default(),
            port: None,
            active_transfer: None,
        }
    }
}

impl Default for Session
{
    fn default() -> Self { Session::PendingWelcome }
}
<commit_msg>Remove an unused type<commit_after>use {Credentials, Error, FileType, DataTransferMode};
use {server, protocol};

use std::path::PathBuf;

/// The state of a client.
#[derive(Clone, Debug)]
pub enum Session
{
    /// We need to send them a welcome message.
    PendingWelcome,
    /// We are waiting for (or in the middle of) the user to login.
    Login(Login),
    /// We are connected and logged in as a user.
    Ready(Ready),
}

#[derive(Clone, Debug)]
pub enum Login
{
    /// The client needs to initiate login by sending 'USER <name>'.
    WaitingForUsername,
    /// The client has initiated login, and we are waiting for their password.
    WaitingForPassword {
        username: String,
    },
}

#[derive(Clone, Debug)]
pub struct Ready
{
    /// The credentials of the current user.
    pub credentials: Credentials,
    /// The current working directory.
    pub working_dir: PathBuf,
    /// The current data transfer file mode.
    pub transfer_type: FileType,
    /// Whether the connection is active or passive.
    pub data_transfer_mode: DataTransferMode,
    /// The port given by the 'PORT' command.
    pub port: Option<u16>,
    /// The data transfer operations we have queued.
    pub active_transfer: Option<server::Transfer>,
}

impl Session
{
    pub fn expect_ready(&self) -> Result<&Ready, Error> {
        if let Session::Ready(ref ready) = *self {
            Ok(ready)
        } else {
            Err(Error::Protocol(protocol::Error::Client(protocol::ClientError::NotLoggedIn)))
        }
    }

    pub fn expect_ready_mut(&mut self) -> Result<&mut Ready, Error> {
        if let Session::Ready(ref mut ready) = *self {
            Ok(ready)
        } else {
            Err(Error::Protocol(protocol::Error::Client(protocol::ClientError::NotLoggedIn)))
        }
    }

    pub fn expect_login(&self) -> Result<&Login, Error> {
        if let Session::Login(ref login) = *self {
            Ok(login)
        } else {
            // FIXME: return a more appropriate error.
            Err(Error::Protocol(protocol::Error::Client(protocol::ClientError::NotLoggedIn)))
        }
    }

    pub fn expect_login_mut(&mut self) -> Result<&mut Login, Error> {
        if let Session::Login(ref mut login) = *self {
            Ok(login)
        } else {
            // FIXME: return a more appropriate error.
            Err(Error::Protocol(protocol::Error::Client(protocol::ClientError::NotLoggedIn)))
        }
    }
}

impl Ready
{
    pub fn new(credentials: Credentials) -> Self {
        Ready {
            credentials: credentials,
            working_dir: "/".into(),
            transfer_type: FileType::Binary,
            data_transfer_mode: DataTransferMode::default(),
            port: None,
            active_transfer: None,
        }
    }
}

impl Default for Session
{
    fn default() -> Self { Session::PendingWelcome }
}
<|endoftext|>


<commit_before>pub use lapin_async::channel::BasicProperties;
pub use lapin_async::channel::options::*;

use futures::{Future, future};
use lapin_async;
use lapin_async::channel::Channel as InnerChannel;
use lapin_async::connection::Connection;
use lapin_async::queue::Queue;
use log::trace;

use crate::confirmation::ConfirmationFuture;
use crate::consumer::Consumer;
use crate::error::Error;
use crate::message::{BasicGetMessage, BasicReturnMessage};
use crate::types::*;

/// `Channel` provides methods to act on a channel, such as managing queues
#[derive(Clone)]
pub struct Channel {
  conn:  Connection,
  inner: InnerChannel,
}

impl Channel {
    /// create a channel
    pub fn create(conn: Connection) -> impl Future<Item = Self, Error = Error> {
        future::result(conn.create_channel().map(|inner| Channel { inner, conn })).and_then(|channel| {
          let confirmation: ConfirmationFuture<()> = channel.inner.channel_open().into();
          confirmation.map(|_| channel)
        })
    }

    pub fn id(&self) -> u16 {
      self.inner.id()
    }

    /// request access
    ///
    /// returns a future that resolves once the access is granted
    pub fn access_request(&self, realm: &str, options: AccessRequestOptions) -> ConfirmationFuture<()> {
        self.inner.access_request(realm, options).into()
    }

    /// declares an exchange
    ///
    /// returns a future that resolves once the exchange is available
    pub fn exchange_declare(&self, name: &str, exchange_type: &str, options: ExchangeDeclareOptions, arguments: FieldTable) -> ConfirmationFuture<()> {
        self.inner.exchange_declare(name, exchange_type, options, arguments).into()
    }

    /// deletes an exchange
    ///
    /// returns a future that resolves once the exchange is deleted
    pub fn exchange_delete(&self, name: &str, options: ExchangeDeleteOptions) -> ConfirmationFuture<()> {
        self.inner.exchange_delete(name, options).into()
    }

    /// binds an exchange to another exchange
    ///
    /// returns a future that resolves once the exchanges are bound
    pub fn exchange_bind(&self, destination: &str, source: &str, routing_key: &str, options: ExchangeBindOptions, arguments: FieldTable) -> ConfirmationFuture<()> {
        self.inner.exchange_bind(destination, source, routing_key, options, arguments).into()
    }

    /// unbinds an exchange from another one
    ///
    /// returns a future that resolves once the exchanges are unbound
    pub fn exchange_unbind(&self, destination: &str, source: &str, routing_key: &str, options: ExchangeUnbindOptions, arguments: FieldTable) -> ConfirmationFuture<()> {
        self.inner.exchange_unbind(destination, source, routing_key, options, arguments).into()
    }

    /// declares a queue
    ///
    /// returns a future that resolves once the queue is available
    ///
    /// the `mandatory` and `ìmmediate` options can be set to true,
    /// but the return message will not be handled
    pub fn queue_declare(&self, name: &str, options: QueueDeclareOptions, arguments: FieldTable) -> ConfirmationFuture<Queue> {
        self.inner.queue_declare(name, options, arguments).into()
    }

    /// binds a queue to an exchange
    ///
    /// returns a future that resolves once the queue is bound to the exchange
    pub fn queue_bind(&self, name: &str, exchange: &str, routing_key: &str, options: QueueBindOptions, arguments: FieldTable) -> ConfirmationFuture<()> {
        self.inner.queue_bind(name, exchange, routing_key, options, arguments).into()
    }

    /// unbinds a queue from the exchange
    ///
    /// returns a future that resolves once the queue is unbound from the exchange
    pub fn queue_unbind(&self, name: &str, exchange: &str, routing_key: &str, arguments: FieldTable) -> ConfirmationFuture<()> {
        self.inner.queue_unbind(name, exchange, routing_key, arguments).into()
    }

    /// sets up confirm extension for this channel
    pub fn confirm_select(&self, options: ConfirmSelectOptions) -> ConfirmationFuture<()> {
        self.inner.confirm_select(options).into()
    }

    /// specifies quality of service for a channel
    pub fn basic_qos(&self, prefetch_count: ShortUInt, options: BasicQosOptions) -> ConfirmationFuture<()> {
        self.inner.basic_qos(prefetch_count, options).into()
    }

    /// publishes a message on a queue
    ///
    /// the future's result is:
    /// - `Some(true)` if we're on a confirm channel and the message was ack'd
    /// - `Some(false)` if we're on a confirm channel and the message was nack'd
    /// - `None` if we're not on a confirm channel
    pub fn basic_publish(&self, exchange: &str, routing_key: &str, payload: Vec<u8>, options: BasicPublishOptions, properties: BasicProperties) -> ConfirmationFuture<()> {
      self.inner.basic_publish(exchange, routing_key, options, payload, properties).into()
    }

    /// creates a consumer stream
    ///
    /// returns a future of a `Consumer` that resolves once the method succeeds
    ///
    /// `Consumer` implements `futures::Stream`, so it can be used with any of
    /// the usual combinators
    pub fn basic_consume(&self, queue: &Queue, consumer_tag: &str, options: BasicConsumeOptions, arguments: FieldTable) -> impl Future<Item = Consumer, Error = Error> {
        let mut consumer = Consumer::new(self.id(), queue.name.clone(), consumer_tag.into());
        let subscriber = consumer.subscriber();
        let confirmation: ConfirmationFuture<ShortString> = self.inner.basic_consume(queue.name.as_str(), consumer_tag, options, arguments, Box::new(subscriber)).into();
        confirmation.map(|consumer_tag| {
            trace!("basic_consume received response, returning consumer");
            consumer.update_consumer_tag(consumer_tag);
            consumer
        })
    }

    pub fn basic_cancel(&self, consumer_tag: &str, options: BasicCancelOptions) -> ConfirmationFuture<()> {
        self.inner.basic_cancel(consumer_tag, options).into()
    }

    pub fn basic_recover(&self, options: BasicRecoverOptions) -> ConfirmationFuture<()> {
        self.inner.basic_recover(options).into()
    }

    pub fn basic_recover_async(&self, options: BasicRecoverAsyncOptions) -> ConfirmationFuture<()> {
        self.inner.basic_recover_async(options).into()
    }

    /// acks a message
    pub fn basic_ack(&self, delivery_tag: u64, multiple: bool) -> ConfirmationFuture<()> {
        self.inner.basic_ack(delivery_tag, BasicAckOptions { multiple }).into()
    }

    /// nacks a message
    pub fn basic_nack(&self, delivery_tag: u64, multiple: bool, requeue: bool) -> ConfirmationFuture<()> {
        self.inner.basic_nack(delivery_tag, BasicNackOptions { multiple, requeue }).into()
    }

    /// rejects a message
    pub fn basic_reject(&self, delivery_tag: u64, options: BasicRejectOptions) -> ConfirmationFuture<()> {
        self.inner.basic_reject(delivery_tag, options).into()
    }

    /// gets a message
    pub fn basic_get(&self, queue: &str, options: BasicGetOptions) -> ConfirmationFuture<Option<BasicGetMessage>> {
        self.inner.basic_get(queue, options).into()
    }

    /// Purge a queue.
    ///
    /// This method removes all messages from a queue which are not awaiting acknowledgment.
    pub fn queue_purge(&self, queue_name: &str, options: QueuePurgeOptions) -> ConfirmationFuture<LongUInt> {
        self.inner.queue_purge(queue_name, options).into()
    }

    /// Delete a queue.
    ///
    /// This method deletes a queue. When a queue is deleted any pending messages are sent to a dead-letter queue
    /// if this is defined in the server configuration, and all consumers on the queue are cancelled.
    ///
    /// If `if_unused` is set, the server will only delete the queue if it has no consumers.
    /// If the queue has consumers the server does not delete it but raises a channel exception instead.
    ///
    /// If `if_empty` is set, the server will only delete the queue if it has no messages.
    pub fn queue_delete(&self, queue_name: &str, options: QueueDeleteOptions) -> ConfirmationFuture<LongUInt> {
        self.inner.queue_delete(queue_name, options).into()
    }

    /// closes the channel
    pub fn close(&self, code: u16, message: &str) -> ConfirmationFuture<()> {
        self.inner.channel_close(code, message, 0, 0).into()
    }

    /// ack a channel close
    pub fn close_ok(&self) -> ConfirmationFuture<()> {
        self.inner.channel_close_ok().into()
    }

    /// update a channel flow
    pub fn channel_flow(&self, options: ChannelFlowOptions) -> ConfirmationFuture<Boolean> {
        self.inner.channel_flow(options).into()
    }

    /// ack an update to a channel flow
    pub fn channel_flow_ok(&self, options: ChannelFlowOkOptions) -> ConfirmationFuture<()> {
        self.inner.channel_flow_ok(options).into()
    }

    pub fn tx_select(&self) -> ConfirmationFuture<()> {
        self.inner.tx_select().into()
    }

    pub fn tx_commit(&self) -> ConfirmationFuture<()> {
        self.inner.tx_commit().into()
    }

    pub fn tx_rollback(&self) -> ConfirmationFuture<()> {
        self.inner.tx_rollback().into()
    }

    pub fn wait_for_confirms(&self) -> impl Future<Item = Vec<BasicReturnMessage>, Error = Error> {
        // TODO: make async
        future::ok(self.inner.wait_for_confirms())
    }
}
<commit_msg>futures: reindent channel<commit_after>pub use lapin_async::channel::BasicProperties;
pub use lapin_async::channel::options::*;

use futures::{Future, future};
use lapin_async;
use lapin_async::channel::Channel as InnerChannel;
use lapin_async::connection::Connection;
use lapin_async::queue::Queue;
use log::trace;

use crate::confirmation::ConfirmationFuture;
use crate::consumer::Consumer;
use crate::error::Error;
use crate::message::{BasicGetMessage, BasicReturnMessage};
use crate::types::*;

/// `Channel` provides methods to act on a channel, such as managing queues
#[derive(Clone)]
pub struct Channel {
  conn:  Connection,
  inner: InnerChannel,
}

impl Channel {
  /// create a channel
  pub fn create(conn: Connection) -> impl Future<Item = Self, Error = Error> {
    future::result(conn.create_channel().map(|inner| Channel { inner, conn })).and_then(|channel| {
      let confirmation: ConfirmationFuture<()> = channel.inner.channel_open().into();
      confirmation.map(|_| channel)
    })
  }

  pub fn id(&self) -> u16 {
    self.inner.id()
  }

  /// request access
  ///
  /// returns a future that resolves once the access is granted
  pub fn access_request(&self, realm: &str, options: AccessRequestOptions) -> ConfirmationFuture<()> {
    self.inner.access_request(realm, options).into()
  }

  /// declares an exchange
  ///
  /// returns a future that resolves once the exchange is available
  pub fn exchange_declare(&self, name: &str, exchange_type: &str, options: ExchangeDeclareOptions, arguments: FieldTable) -> ConfirmationFuture<()> {
    self.inner.exchange_declare(name, exchange_type, options, arguments).into()
  }

  /// deletes an exchange
  ///
  /// returns a future that resolves once the exchange is deleted
  pub fn exchange_delete(&self, name: &str, options: ExchangeDeleteOptions) -> ConfirmationFuture<()> {
    self.inner.exchange_delete(name, options).into()
  }

  /// binds an exchange to another exchange
  ///
  /// returns a future that resolves once the exchanges are bound
  pub fn exchange_bind(&self, destination: &str, source: &str, routing_key: &str, options: ExchangeBindOptions, arguments: FieldTable) -> ConfirmationFuture<()> {
    self.inner.exchange_bind(destination, source, routing_key, options, arguments).into()
  }

  /// unbinds an exchange from another one
  ///
  /// returns a future that resolves once the exchanges are unbound
  pub fn exchange_unbind(&self, destination: &str, source: &str, routing_key: &str, options: ExchangeUnbindOptions, arguments: FieldTable) -> ConfirmationFuture<()> {
    self.inner.exchange_unbind(destination, source, routing_key, options, arguments).into()
  }

  /// declares a queue
  ///
  /// returns a future that resolves once the queue is available
  ///
  /// the `mandatory` and `ìmmediate` options can be set to true,
  /// but the return message will not be handled
  pub fn queue_declare(&self, name: &str, options: QueueDeclareOptions, arguments: FieldTable) -> ConfirmationFuture<Queue> {
    self.inner.queue_declare(name, options, arguments).into()
  }

  /// binds a queue to an exchange
  ///
  /// returns a future that resolves once the queue is bound to the exchange
  pub fn queue_bind(&self, name: &str, exchange: &str, routing_key: &str, options: QueueBindOptions, arguments: FieldTable) -> ConfirmationFuture<()> {
    self.inner.queue_bind(name, exchange, routing_key, options, arguments).into()
  }

  /// unbinds a queue from the exchange
  ///
  /// returns a future that resolves once the queue is unbound from the exchange
  pub fn queue_unbind(&self, name: &str, exchange: &str, routing_key: &str, arguments: FieldTable) -> ConfirmationFuture<()> {
    self.inner.queue_unbind(name, exchange, routing_key, arguments).into()
  }

  /// sets up confirm extension for this channel
  pub fn confirm_select(&self, options: ConfirmSelectOptions) -> ConfirmationFuture<()> {
    self.inner.confirm_select(options).into()
  }

  /// specifies quality of service for a channel
  pub fn basic_qos(&self, prefetch_count: ShortUInt, options: BasicQosOptions) -> ConfirmationFuture<()> {
    self.inner.basic_qos(prefetch_count, options).into()
  }

  /// publishes a message on a queue
  ///
  /// the future's result is:
  /// - `Some(true)` if we're on a confirm channel and the message was ack'd
  /// - `Some(false)` if we're on a confirm channel and the message was nack'd
  /// - `None` if we're not on a confirm channel
  pub fn basic_publish(&self, exchange: &str, routing_key: &str, payload: Vec<u8>, options: BasicPublishOptions, properties: BasicProperties) -> ConfirmationFuture<()> {
    self.inner.basic_publish(exchange, routing_key, options, payload, properties).into()
  }

  /// creates a consumer stream
  ///
  /// returns a future of a `Consumer` that resolves once the method succeeds
  ///
  /// `Consumer` implements `futures::Stream`, so it can be used with any of
  /// the usual combinators
  pub fn basic_consume(&self, queue: &Queue, consumer_tag: &str, options: BasicConsumeOptions, arguments: FieldTable) -> impl Future<Item = Consumer, Error = Error> {
    let mut consumer = Consumer::new(self.id(), queue.name.clone(), consumer_tag.into());
    let subscriber = consumer.subscriber();
    let confirmation: ConfirmationFuture<ShortString> = self.inner.basic_consume(queue.name.as_str(), consumer_tag, options, arguments, Box::new(subscriber)).into();
    confirmation.map(|consumer_tag| {
      trace!("basic_consume received response, returning consumer");
      consumer.update_consumer_tag(consumer_tag);
      consumer
    })
  }

  pub fn basic_cancel(&self, consumer_tag: &str, options: BasicCancelOptions) -> ConfirmationFuture<()> {
    self.inner.basic_cancel(consumer_tag, options).into()
  }

  pub fn basic_recover(&self, options: BasicRecoverOptions) -> ConfirmationFuture<()> {
    self.inner.basic_recover(options).into()
  }

  pub fn basic_recover_async(&self, options: BasicRecoverAsyncOptions) -> ConfirmationFuture<()> {
    self.inner.basic_recover_async(options).into()
  }

  /// acks a message
  pub fn basic_ack(&self, delivery_tag: u64, multiple: bool) -> ConfirmationFuture<()> {
    self.inner.basic_ack(delivery_tag, BasicAckOptions { multiple }).into()
  }

  /// nacks a message
  pub fn basic_nack(&self, delivery_tag: u64, multiple: bool, requeue: bool) -> ConfirmationFuture<()> {
    self.inner.basic_nack(delivery_tag, BasicNackOptions { multiple, requeue }).into()
  }

  /// rejects a message
  pub fn basic_reject(&self, delivery_tag: u64, options: BasicRejectOptions) -> ConfirmationFuture<()> {
    self.inner.basic_reject(delivery_tag, options).into()
  }

  /// gets a message
  pub fn basic_get(&self, queue: &str, options: BasicGetOptions) -> ConfirmationFuture<Option<BasicGetMessage>> {
    self.inner.basic_get(queue, options).into()
  }

  /// Purge a queue.
  ///
  /// This method removes all messages from a queue which are not awaiting acknowledgment.
  pub fn queue_purge(&self, queue_name: &str, options: QueuePurgeOptions) -> ConfirmationFuture<LongUInt> {
    self.inner.queue_purge(queue_name, options).into()
  }

  /// Delete a queue.
  ///
  /// This method deletes a queue. When a queue is deleted any pending messages are sent to a dead-letter queue
  /// if this is defined in the server configuration, and all consumers on the queue are cancelled.
  ///
  /// If `if_unused` is set, the server will only delete the queue if it has no consumers.
  /// If the queue has consumers the server does not delete it but raises a channel exception instead.
  ///
  /// If `if_empty` is set, the server will only delete the queue if it has no messages.
  pub fn queue_delete(&self, queue_name: &str, options: QueueDeleteOptions) -> ConfirmationFuture<LongUInt> {
    self.inner.queue_delete(queue_name, options).into()
  }

  /// closes the channel
  pub fn close(&self, code: u16, message: &str) -> ConfirmationFuture<()> {
    self.inner.channel_close(code, message, 0, 0).into()
  }

  /// ack a channel close
  pub fn close_ok(&self) -> ConfirmationFuture<()> {
    self.inner.channel_close_ok().into()
  }

  /// update a channel flow
  pub fn channel_flow(&self, options: ChannelFlowOptions) -> ConfirmationFuture<Boolean> {
    self.inner.channel_flow(options).into()
  }

  /// ack an update to a channel flow
  pub fn channel_flow_ok(&self, options: ChannelFlowOkOptions) -> ConfirmationFuture<()> {
    self.inner.channel_flow_ok(options).into()
  }

  pub fn tx_select(&self) -> ConfirmationFuture<()> {
    self.inner.tx_select().into()
  }

  pub fn tx_commit(&self) -> ConfirmationFuture<()> {
    self.inner.tx_commit().into()
  }

  pub fn tx_rollback(&self) -> ConfirmationFuture<()> {
    self.inner.tx_rollback().into()
  }

  pub fn wait_for_confirms(&self) -> impl Future<Item = Vec<BasicReturnMessage>, Error = Error> {
    // TODO: make async
    future::ok(self.inner.wait_for_confirms())
  }
}
<|endoftext|>


<commit_before>#[deriving(PartialEq, Show, Clone)]
pub enum Card {
    JokerA,
    JokerB,
    Clubs(uint),
    Diamonds(uint),
    Hearts(uint),
    Spades(uint),
}

impl Card {
    pub fn count_index(&self) -> uint {
        match *self {
            Clubs(i) => i,
            Diamonds(i) => i + 13,
            Hearts(i) => i + 26,
            Spades(i) => i + 39,
            JokerA => 53,
            JokerB => 53,
        }
    }

    //    pub fn is_joker(&self) -> bool {
    //     match *self {
    //         JokerA => true,
    //         JokerB => true,
    //         _ => false,
    //     }
    // }

    // pub fn is_red(&self) -> bool {
    //     match *self {
    //         Diamonds(_) => true,
    //         Hearts(_) => true,
    //         _ => false,
    //     }
    // }

}

#[test]
fn test_count_cut_index() {
    let a = JokerA;
    assert_eq!(a.count_index(), 53);
    let b = Hearts(4);
    assert_eq!(b.count_index(), 30);
}
<commit_msg>Clean up code<commit_after>#[deriving(PartialEq, Show, Clone)]
pub enum Card {
    JokerA,
    JokerB,
    Clubs(uint),
    Diamonds(uint),
    Hearts(uint),
    Spades(uint),
}

impl Card {
    pub fn count_index(&self) -> uint {
        match *self {
            Clubs(i) => i,
            Diamonds(i) => i + 13,
            Hearts(i) => i + 26,
            Spades(i) => i + 39,
            JokerA => 53,
            JokerB => 53,
        }
    }
}

#[test]
fn test_count_cut_index() {
    let a = JokerA;
    assert_eq!(a.count_index(), 53);
    let b = Hearts(4);
    assert_eq!(b.count_index(), 30);
}
<|endoftext|>