<commit_before>use std::marker::PhantomData;
use gl;
use gl::types::*;
use context::Context;
use renderbuffer::{Renderbuffer, RenderbufferTarget};
use texture::{Texture, TextureType, ImageTargetType};
use types::{BufferBits, GLError};

pub struct Framebuffer {
    gl_id: GLuint
}

impl Framebuffer {
    pub unsafe fn from_gl(id: GLuint) -> Self {
        Framebuffer { gl_id: id }
    }

    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Framebuffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteFramebuffers(1, &self.gl_id as *const GLuint);
        }
    }
}

impl Context {
    pub unsafe fn gen_framebuffer(&self) -> Framebuffer {
        let mut id : GLuint = 0;

        gl::GenFramebuffers(1, &mut id as *mut GLuint);
        dbg_gl_sanity_check! {
            GLError::InvalidValue => "`n` is negative",
            _ => "Unknown error"
        }

        Framebuffer {
            gl_id: id
        }
    }
}

gl_enum! {
    pub gl_enum FramebufferAttachment {
        ColorAttachment0 as COLOR_ATTACHMENT0 = gl::COLOR_ATTACHMENT0,
        DepthAttachment as DEPTH_ATTACHMENT = gl::DEPTH_ATTACHMENT,
        StencilAttachment as STENCIL_ATTACHMENT = gl::STENCIL_ATTACHMENT
    }
}

pub struct FramebufferBinding<'a> {
    phantom: PhantomData<&'a mut Framebuffer>
}

impl<'a> FramebufferBinding<'a> {
    fn target(&self) -> GLenum {
        gl::FRAMEBUFFER
    }

    pub fn renderbuffer(&mut self,
                        attachment: FramebufferAttachment,
                        renderbuffer: &mut Renderbuffer)
    {
        let renderbuffer_target = RenderbufferTarget::Renderbuffer;
        unsafe {
            gl::FramebufferRenderbuffer(self.target(),
                                        attachment.gl_enum(),
                                        renderbuffer_target.gl_enum(),
                                        renderbuffer.gl_id());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_FRAMEBUFFER`, `attachment` is not a valid attachment point, or `renderbuffer` is not `GL_RENDERBUFFER` and `renderbuffer` is not 0",
                GLError::InvalidOperation => "Framebuffer 0 is bound, or `renderbuffer` is neither 0 nor the name of an existing renderbuffer object",
                _ => "Unknown error"
            }
        }
    }

    pub fn texture_2d<T: TextureType>(&mut self,
                                      attachment: FramebufferAttachment,
                                      tex_target: T::ImageTargetType,
                                      texture: &mut Texture<T>,
                                      level: i32)
    {
        debug_assert!(level == 0);

        unsafe {
            gl::FramebufferTexture2D(self.target(),
                                     attachment.gl_enum(),
                                     tex_target.gl_enum(),
                                     texture.gl_id(),
                                     level as GLint);
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_FRAMEBUFFER`, `attachment` is not an accepted attachment point, or `textarget` is not an accepted texture target and texture is not 0",
                GLError::InvalidValue => "`level` is not 0 and `texture` is not 0",
                GLError::InvalidOperation => "Framebuffer object 0 is bound, `texture` is neither 0 nor the name of an existing texture object, or `textarget` is not a valid target for `texture`",
                _ => "Unknown error"
            }
        }
    }

    pub fn clear(&mut self, buffers: BufferBits) {
        unsafe {
            gl::Clear(buffers.bits());
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`mask` includes a bit other than an allowed value",
                _ => "Unkown error"
            }
        }
    }
}

pub struct FramebufferBinder;
impl FramebufferBinder {
    pub unsafe fn current_binding<'a>(&'a mut self) -> FramebufferBinding<'a> {
        FramebufferBinding { phantom: PhantomData }
    }

    pub fn bind<'a>(&'a mut self, fbo: &mut Framebuffer)
        -> FramebufferBinding<'a>
    {
        let binding = FramebufferBinding { phantom: PhantomData };
        unsafe {
            gl::BindFramebuffer(binding.target(), fbo.gl_id());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_FRAMEBUFFER`",
                _ => "Unknown error"
            }
        }
        binding
    }
}
<commit_msg>Add `FramebufferBinding.check_framebuffer_status()`<commit_after>use std::marker::PhantomData;
use gl;
use gl::types::*;
use context::Context;
use renderbuffer::{Renderbuffer, RenderbufferTarget};
use texture::{Texture, TextureType, ImageTargetType};
use types::{BufferBits, GLError, GLFramebufferError};

pub struct Framebuffer {
    gl_id: GLuint
}

impl Framebuffer {
    pub unsafe fn from_gl(id: GLuint) -> Self {
        Framebuffer { gl_id: id }
    }

    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Framebuffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteFramebuffers(1, &self.gl_id as *const GLuint);
        }
    }
}

impl Context {
    pub unsafe fn gen_framebuffer(&self) -> Framebuffer {
        let mut id : GLuint = 0;

        gl::GenFramebuffers(1, &mut id as *mut GLuint);
        dbg_gl_sanity_check! {
            GLError::InvalidValue => "`n` is negative",
            _ => "Unknown error"
        }

        Framebuffer {
            gl_id: id
        }
    }
}

gl_enum! {
    pub gl_enum FramebufferAttachment {
        ColorAttachment0 as COLOR_ATTACHMENT0 = gl::COLOR_ATTACHMENT0,
        DepthAttachment as DEPTH_ATTACHMENT = gl::DEPTH_ATTACHMENT,
        StencilAttachment as STENCIL_ATTACHMENT = gl::STENCIL_ATTACHMENT
    }
}

pub struct FramebufferBinding<'a> {
    phantom: PhantomData<&'a mut Framebuffer>
}

impl<'a> FramebufferBinding<'a> {
    fn target(&self) -> GLenum {
        gl::FRAMEBUFFER
    }

    pub fn check_framebuffer_status(&self) -> Option<GLFramebufferError> {
        unsafe {
            match gl::CheckFramebufferStatus(self.target()) {
                gl::FRAMEBUFFER_INCOMPLETE_ATTACHMENT => {
                    Some(GLFramebufferError::IncompleteAttachment)
                },
                // gl::FRAMEBUFFER_INCOMPLETE_DIMENSIONS => {
                //     Some(GLFramebufferError::IncompleteDimensions)
                // },
                gl::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT => {
                    Some(GLFramebufferError::IncompleteMissingAttachment)
                },
                gl::FRAMEBUFFER_UNSUPPORTED => {
                    Some(GLFramebufferError::Unsupported)
                },
                _ => { None }
            }
        }
    }

    pub fn renderbuffer(&mut self,
                        attachment: FramebufferAttachment,
                        renderbuffer: &mut Renderbuffer)
    {
        let renderbuffer_target = RenderbufferTarget::Renderbuffer;
        unsafe {
            gl::FramebufferRenderbuffer(self.target(),
                                        attachment.gl_enum(),
                                        renderbuffer_target.gl_enum(),
                                        renderbuffer.gl_id());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_FRAMEBUFFER`, `attachment` is not a valid attachment point, or `renderbuffer` is not `GL_RENDERBUFFER` and `renderbuffer` is not 0",
                GLError::InvalidOperation => "Framebuffer 0 is bound, or `renderbuffer` is neither 0 nor the name of an existing renderbuffer object",
                _ => "Unknown error"
            }
        }
    }

    pub fn texture_2d<T: TextureType>(&mut self,
                                      attachment: FramebufferAttachment,
                                      tex_target: T::ImageTargetType,
                                      texture: &mut Texture<T>,
                                      level: i32)
    {
        debug_assert!(level == 0);

        unsafe {
            gl::FramebufferTexture2D(self.target(),
                                     attachment.gl_enum(),
                                     tex_target.gl_enum(),
                                     texture.gl_id(),
                                     level as GLint);
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_FRAMEBUFFER`, `attachment` is not an accepted attachment point, or `textarget` is not an accepted texture target and texture is not 0",
                GLError::InvalidValue => "`level` is not 0 and `texture` is not 0",
                GLError::InvalidOperation => "Framebuffer object 0 is bound, `texture` is neither 0 nor the name of an existing texture object, or `textarget` is not a valid target for `texture`",
                _ => "Unknown error"
            }
        }
    }

    pub fn clear(&mut self, buffers: BufferBits) {
        unsafe {
            gl::Clear(buffers.bits());
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`mask` includes a bit other than an allowed value",
                _ => "Unkown error"
            }
        }
    }
}

pub struct FramebufferBinder;
impl FramebufferBinder {
    pub unsafe fn current_binding<'a>(&'a mut self) -> FramebufferBinding<'a> {
        FramebufferBinding { phantom: PhantomData }
    }

    pub fn bind<'a>(&'a mut self, fbo: &mut Framebuffer)
        -> FramebufferBinding<'a>
    {
        let binding = FramebufferBinding { phantom: PhantomData };
        unsafe {
            gl::BindFramebuffer(binding.target(), fbo.gl_id());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_FRAMEBUFFER`",
                _ => "Unknown error"
            }
        }
        binding
    }
}
<|endoftext|>


<commit_before>use color;
use math::{BaseNum, Point2, Point3};
use std::ops::{Deref, DerefMut};

/// Types used as vertices that can be used to describe geometric points in space.
pub trait Vertex: Clone + Copy + PartialEq {
    /// The values used to describe the vertex position.
    type Scalar: BaseNum;
}

/// Vertex types that have at least 2 dimensions.
pub trait Vertex2d: Vertex {
    /// The x, y location of the vertex.
    fn point2(self) -> Point2<Self::Scalar>;
}

/// Vertex types that have at least 3 dimensions.
pub trait Vertex3d: Vertex2d {
    /// The x, y, z location of the vertex.
    fn point3(self) -> Point3<Self::Scalar>;
}

/// If a type is not specified for a scalar along an axis, this is the default type used.
pub type DefaultScalar = f64;
/// If a type is not specified for a piece of geometry, this is the default type used.
pub type Default = Point3<DefaultScalar>;

/// An iterator yielding a vertex for each index yielded by the given indices iterator.
#[derive(Clone, Debug)]
pub struct IterFromIndices<'a, I, V: 'a = Default> {
    indices: I,
    vertices: &'a [V],
}

/// A vertex that is colored with the given linear `RGBA` color.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Rgba<V = Default>(pub V, pub color::Rgba);

/// Produce an iterator yielding a vertex for each index yielded by the given indices iterator.
pub fn iter_from_indices<I, V>(indices: I, vertices: &[V]) -> IterFromIndices<I::IntoIter, V>
where
    I: IntoIterator<Item = usize>,
{
    let indices = indices.into_iter();
    IterFromIndices { indices, vertices }
}

// Iterators

impl<'a, I, V> Iterator for IterFromIndices<'a, I, V>
where
    I: Iterator<Item = usize>,
{
    type Item = &'a V;
    fn next(&mut self) -> Option<Self::Item> {
        let IterFromIndices { ref mut indices, ref vertices } = *self;
        indices.next().map(|i| &vertices[i])
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.indices.size_hint()
    }
}

impl<'a, I, V> DoubleEndedIterator for IterFromIndices<'a, I, V>
where
    I: Iterator<Item = usize> + DoubleEndedIterator,
{
    fn next_back(&mut self) -> Option<Self::Item> {
        let IterFromIndices { ref mut indices, ref vertices } = *self;
        indices.next_back().map(|i| &vertices[i])
    }
}

impl<'a, I, V> ExactSizeIterator for IterFromIndices<'a, I, V>
where
    I: Iterator<Item = usize> + ExactSizeIterator,
{
    fn len(&self) -> usize {
        self.indices.len()
    }
}

// Rgba impls.

impl<V> Rgba<V> {
    /// A reference to the inner vertex.
    pub fn vertex(&self) -> &V {
        &self.0
    }
    /// A reference to the inner rgba.
    pub fn rgba(&self) -> &color::Rgba {
        &self.1
    }
}

impl<V> Deref for Rgba<V> {
    type Target = V;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<V> DerefMut for Rgba<V> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl<V> From<(V, color::Rgba)> for Rgba<V> {
    fn from((v, rgba): (V, color::Rgba)) -> Self {
        Rgba(v, rgba)
    }
}

impl<V> Into<(V, color::Rgba)> for Rgba<V> {
    fn into(self) -> (V, color::Rgba) {
        let Rgba(v, rgba) = self;
        (v, rgba)
    }
}

// Vertex impls

impl<S> Vertex for Point2<S>
where
    S: BaseNum,
{
    type Scalar = S;
}

impl<S> Vertex for Point3<S>
where
    S: BaseNum,
{
    type Scalar = S;
}

// impl<S> Vertex for Vector2<S>
// where
//     S: BaseNum,
// {
//     type Scalar = S;
// }
//
// impl<S> Vertex for Vector3<S>
// where
//     S: BaseNum,
// {
//     type Scalar = S;
// }

impl<V> Vertex for Rgba<V>
where
    V: Vertex,
{
    type Scalar = V::Scalar;
}

// Vertex2d impls

impl<S> Vertex2d for Point2<S>
where
    S: BaseNum,
{
    fn point2(self) -> Point2<S> {
        Point2 { x: self.x, y: self.y }
    }
}

impl<S> Vertex2d for Point3<S>
where
    S: BaseNum,
{
    fn point2(self) -> Point2<S> {
        Point2 { x: self.x, y: self.y }
    }
}

// impl<S> Vertex2d for Vector2<S>
// where
//     S: BaseNum,
// {
//     fn point2(self) -> Point2<S> {
//         self
//     }
// }
//
// impl<S> Vertex2d for Vector3<S>
// where
//     S: BaseNum,
// {
//     fn point2(self) -> Point2<S> {
//         Point2 { x: self.x, y: self.y }
//     }
// }

impl<V> Vertex2d for Rgba<V>
where
    V: Vertex2d,
{
    fn point2(self) -> Point2<V::Scalar> {
        self.0.point2()
    }
}

// Vertex3d impls

impl<S> Vertex3d for Point3<S>
where
    S: BaseNum,
{
    fn point3(self) -> Point3<S> {
        Point3 { x: self.x, y: self.y, z: self.z }
    }
}

// impl<S> Vertex3d for Vector3<S>
// where
//     S: BaseNum,
// {
//     fn point3(self) -> Point3<S> {
//         self
//     }
// }

impl<V> Vertex3d for Rgba<V>
where
    V: Vertex3d,
{
    fn point3(self) -> Point3<V::Scalar> {
        self.0.point3()
    }
}
<commit_msg>Add more geom Vertex impls<commit_after>use color;
use math::{BaseNum, Point2, Point3};
use std::ops::{Deref, DerefMut};

/// Types used as vertices that can be used to describe geometric points in space.
pub trait Vertex: Clone + Copy + PartialEq {
    /// The values used to describe the vertex position.
    type Scalar: BaseNum;
}

/// Vertex types that have at least 2 dimensions.
pub trait Vertex2d: Vertex {
    /// The x, y location of the vertex.
    fn point2(self) -> Point2<Self::Scalar>;
}

/// Vertex types that have at least 3 dimensions.
pub trait Vertex3d: Vertex2d {
    /// The x, y, z location of the vertex.
    fn point3(self) -> Point3<Self::Scalar>;
}

/// If a type is not specified for a scalar along an axis, this is the default type used.
pub type DefaultScalar = f64;
/// If a type is not specified for a piece of geometry, this is the default type used.
pub type Default = Point3<DefaultScalar>;

/// An iterator yielding a vertex for each index yielded by the given indices iterator.
#[derive(Clone, Debug)]
pub struct IterFromIndices<'a, I, V: 'a = Default> {
    indices: I,
    vertices: &'a [V],
}

/// A vertex that is colored with the given linear `RGBA` color.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Rgba<V = Default>(pub V, pub color::Rgba);

/// Produce an iterator yielding a vertex for each index yielded by the given indices iterator.
pub fn iter_from_indices<I, V>(indices: I, vertices: &[V]) -> IterFromIndices<I::IntoIter, V>
where
    I: IntoIterator<Item = usize>,
{
    let indices = indices.into_iter();
    IterFromIndices { indices, vertices }
}

// Iterators

impl<'a, I, V> Iterator for IterFromIndices<'a, I, V>
where
    I: Iterator<Item = usize>,
{
    type Item = &'a V;
    fn next(&mut self) -> Option<Self::Item> {
        let IterFromIndices { ref mut indices, ref vertices } = *self;
        indices.next().map(|i| &vertices[i])
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.indices.size_hint()
    }
}

impl<'a, I, V> DoubleEndedIterator for IterFromIndices<'a, I, V>
where
    I: Iterator<Item = usize> + DoubleEndedIterator,
{
    fn next_back(&mut self) -> Option<Self::Item> {
        let IterFromIndices { ref mut indices, ref vertices } = *self;
        indices.next_back().map(|i| &vertices[i])
    }
}

impl<'a, I, V> ExactSizeIterator for IterFromIndices<'a, I, V>
where
    I: Iterator<Item = usize> + ExactSizeIterator,
{
    fn len(&self) -> usize {
        self.indices.len()
    }
}

// Rgba impls.

impl<V> Rgba<V> {
    /// A reference to the inner vertex.
    pub fn vertex(&self) -> &V {
        &self.0
    }
    /// A reference to the inner rgba.
    pub fn rgba(&self) -> &color::Rgba {
        &self.1
    }
}

impl<V> Deref for Rgba<V> {
    type Target = V;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<V> DerefMut for Rgba<V> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl<V> From<(V, color::Rgba)> for Rgba<V> {
    fn from((v, rgba): (V, color::Rgba)) -> Self {
        Rgba(v, rgba)
    }
}

impl<V> Into<(V, color::Rgba)> for Rgba<V> {
    fn into(self) -> (V, color::Rgba) {
        let Rgba(v, rgba) = self;
        (v, rgba)
    }
}

// Vertex impls

impl<S> Vertex for Point2<S>
where
    S: BaseNum,
{
    type Scalar = S;
}

impl<S> Vertex for Point3<S>
where
    S: BaseNum,
{
    type Scalar = S;
}

impl<S> Vertex for [S; 2]
where
    S: BaseNum,
{
    type Scalar = S;
}

impl<S> Vertex for [S; 3]
where
    S: BaseNum,
{
    type Scalar = S;
}

impl<S> Vertex for (S, S)
where
    S: BaseNum,
{
    type Scalar = S;
}

impl<S> Vertex for (S, S, S)
where
    S: BaseNum,
{
    type Scalar = S;
}

// impl<S> Vertex for Vector2<S>
// where
//     S: BaseNum,
// {
//     type Scalar = S;
// }
//
// impl<S> Vertex for Vector3<S>
// where
//     S: BaseNum,
// {
//     type Scalar = S;
// }

impl<V> Vertex for Rgba<V>
where
    V: Vertex,
{
    type Scalar = V::Scalar;
}

// Vertex2d impls

impl<S> Vertex2d for Point2<S>
where
    S: BaseNum,
{
    fn point2(self) -> Point2<S> {
        Point2 { x: self.x, y: self.y }
    }
}

impl<S> Vertex2d for Point3<S>
where
    S: BaseNum,
{
    fn point2(self) -> Point2<S> {
        Point2 { x: self.x, y: self.y }
    }
}

impl<S> Vertex2d for [S; 2]
where
    S: BaseNum,
{
    fn point2(self) -> Point2<S> {
        Point2 { x: self[0], y: self[1] }
    }
}

impl<S> Vertex2d for [S; 3]
where
    S: BaseNum,
{
    fn point2(self) -> Point2<S> {
        Point2 { x: self[0], y: self[1] }
    }
}

impl<S> Vertex2d for (S, S)
where
    S: BaseNum,
{
    fn point2(self) -> Point2<S> {
        let (x, y) = self;
        Point2 { x, y }
    }
}

impl<S> Vertex2d for (S, S, S)
where
    S: BaseNum,
{
    fn point2(self) -> Point2<S> {
        let (x, y, _) = self;
        Point2 { x, y }
    }
}

// impl<S> Vertex2d for Vector2<S>
// where
//     S: BaseNum,
// {
//     fn point2(self) -> Point2<S> {
//         self
//     }
// }
//
// impl<S> Vertex2d for Vector3<S>
// where
//     S: BaseNum,
// {
//     fn point2(self) -> Point2<S> {
//         Point2 { x: self.x, y: self.y }
//     }
// }

impl<V> Vertex2d for Rgba<V>
where
    V: Vertex2d,
{
    fn point2(self) -> Point2<V::Scalar> {
        self.0.point2()
    }
}

// Vertex3d impls

impl<S> Vertex3d for Point3<S>
where
    S: BaseNum,
{
    fn point3(self) -> Point3<S> {
        Point3 { x: self.x, y: self.y, z: self.z }
    }
}

impl<S> Vertex3d for [S; 3]
where
    S: BaseNum,
{
    fn point3(self) -> Point3<S> {
        Point3 { x: self[0], y: self[1], z: self[2] }
    }
}

impl<S> Vertex3d for (S, S, S)
where
    S: BaseNum,
{
    fn point3(self) -> Point3<S> {
        let (x, y, z) = self;
        Point3 { x, y, z }
    }
}

// impl<S> Vertex3d for Vector3<S>
// where
//     S: BaseNum,
// {
//     fn point3(self) -> Point3<S> {
//         self
//     }
// }

impl<V> Vertex3d for Rgba<V>
where
    V: Vertex3d,
{
    fn point3(self) -> Point3<V::Scalar> {
        self.0.point3()
    }
}
<|endoftext|>


<commit_before>
use std::io::SeekFrom;

use hyper::Error;
use hyper::client::Response;
use hyper::{Request, Method};
use hyper::header::ByteRangeSpec;
use hyper::header::ByteRangeSpec::FromTo;
use hyper::header::Range::Bytes;
use hyper::header::{ContentLength, ContentRange, ContentRangeSpec};

use futures::{Future, Stream};
use hyper::Client;
use tokio_core::reactor::Core;
use reader::Reader;
use buffer::Buffer;

fn get_head(filename: &String) -> Result<Response, Error> {
  let mut core = Core::new()?;
  let client = Client::new(&core.handle());

  let uri = filename.parse()?;
  let req = Request::new(Method::Head, uri);

  let work = client.request(req).and_then(|r| {
    Ok(r)
  });
  core.run(work)
}

fn get_data(filename: &String, range: Vec<ByteRangeSpec>) -> Result<Response, Error> {
  let mut core = Core::new()?;
  let client = Client::new(&core.handle());

  let uri = filename.parse()?;
  let mut req = Request::new(Method::Get, uri);
  req.headers_mut().set(Bytes(range));

  let work = client.request(req).and_then(|r| {
    Ok(r)
  });
  core.run(work)
}

fn get_content_length(response: &Response) -> Option<u64> {
  match response.headers().get::<ContentLength>() {
    Some(length) => Some(**length as u64),
    None => None
  }
}

fn get_content_range(response: &Response) -> Result<Option<u64>, String> {
  match response.headers().get::<ContentRange>() {
    Some(content_range) => {
      match content_range.clone() {
        ContentRange(ContentRangeSpec::Bytes{
            range: _range,
            instance_length: length
          }) => {
          Ok(length)
        },
        ContentRange(ContentRangeSpec::Unregistered{unit: _unit, resp: _resp}) => {
          Err("Unregistered, actually unsupported".to_string())
        }
      }
    },
    None =>
      Err("Missing content_range".to_string()),
  }
}

#[derive(Debug)]
pub struct HttpReader {
  pub filename: String,
  pub file_size: Option<u64>,
  pub position: u64,
  pub buffer: Buffer
}

pub fn exists(filename: &String) -> bool {
  match get_head(filename) {
    Ok(resp) => {
      println!("RESP {:?}", resp.status());
      resp.status().is_success()
    },
    Err(msg) => {
      println!("{:?}", msg);
      false
    }
  }
}

fn get_data_range(position: u64, size: usize) -> Vec<ByteRangeSpec> {
  let start = position;
  let end = position + (size - 1) as u64;

  vec![FromTo(start, end)]
}

fn load_data(reader: &mut HttpReader, size: usize) -> Result<Option<Vec<u8>>, String> {

  info!("make HTTP request with request {:?} bytes", size);

  match reader.file_size {
      Some(size) => {
        if reader.position >= size {
          return Ok(None)
        }
      },
      None => (),
  };

  let range = get_data_range(reader.position, size);

  let response = get_data(&reader.filename, range).unwrap();

  // let core = Core::new().unwrap();
  // let client = Client::new(&core.handle());
  // let uri = reader.filename.parse().unwrap();

  // let mut req = Request::new(Method::Get, uri);
  // req.headers_mut().set(Bytes(range));

  // let response =
  //   client
  //   .request(req).wait().unwrap();

  // let work = client.request(req).and_then(|r| {
  //   // Ok(r)
  // });
  // let response = core.run(work);

    let loaded_size =
      match get_content_length(&response) {
          Some(content_length) => content_length,
          None => return Err("Missing content_length".to_string()),
      };

    match get_content_range(&response) {
      Ok(length) => reader.file_size = length,
      Err(msg) => return Err(msg),
    };

    match loaded_size {
      0 => Err("Bad request range".to_string()),
      _ => {
        let body_data =
          match response.body().concat2().wait() {
            Ok(body) => body.to_vec(),
            Err(_msg) => vec![],
          };
        reader.position = reader.position + loaded_size as u64;
        Ok(Some(body_data))
      }
    }
}

impl Reader for HttpReader {
  fn open(filename: &String) -> HttpReader {
    match get_head(filename) {
      Err(msg) => panic!(msg.to_string()),
      Ok(response) => {
        let content_length = get_content_length(&response);

        HttpReader {
          filename: filename.to_string(),
          file_size: content_length,
          position: 0,
          buffer: Buffer {
            size: None,
            position: 0,
            buffer: vec![]
          }
        }
      }
    }
  }

  fn get_position(&mut self) -> Result<u64, String> {
    Ok(self.position)
  }

  fn get_cache_size(&self) -> Option<usize> {
    self.buffer.size
  }

  fn set_cache_size(&mut self, cache_size: Option<usize>) {
    self.buffer.size = cache_size;
  }

  fn get_size(&mut self) -> Result<u64, String> {
    match self.file_size {
        Some(length) => Ok(length),
        None => Err("No length detected".to_string()),
    }
  }

  fn read(&mut self, size: usize) -> Result<Vec<u8>, String> {
    match load_data(self, size) {
      Err(msg) => Err(msg),
      Ok(some_data) => {
        match some_data {
            Some(data) => {
              println!("{:?}", data);
              match data.len() == size {
                true => Ok(data),
                false => Ok(Vec::new()),
              }
            },
            None => Ok(Vec::new()),
        }
      }
    }
  }

  fn seek(&mut self, seek: SeekFrom) -> Result<u64, String> {
    match seek {
      SeekFrom::Current(offset) => {
        self.position = self.position + offset as u64;
      },
      SeekFrom::Start(offset) => {
        self.position = offset;
      },
      SeekFrom::End(offset) => {
        match self.file_size {
          Some(size) => {
            self.position = size - offset as u64;
          },
          None => return Err("Missing file size".to_string())
        }
      }
    }
    Ok(self.position)
  }
}
<commit_msg>remove print and commented code<commit_after>
use std::io::SeekFrom;

use hyper::Error;
use hyper::client::Response;
use hyper::{Request, Method};
use hyper::header::ByteRangeSpec;
use hyper::header::ByteRangeSpec::FromTo;
use hyper::header::Range::Bytes;
use hyper::header::{ContentLength, ContentRange, ContentRangeSpec};

use futures::{Future, Stream};
use hyper::Client;
use tokio_core::reactor::Core;
use reader::Reader;
use buffer::Buffer;

fn get_head(filename: &String) -> Result<Response, Error> {
  let mut core = Core::new()?;
  let client = Client::new(&core.handle());

  let uri = filename.parse()?;
  let req = Request::new(Method::Head, uri);

  let work = client.request(req).and_then(|r| {
    Ok(r)
  });
  core.run(work)
}

fn get_data(filename: &String, range: Vec<ByteRangeSpec>) -> Result<Response, Error> {
  let mut core = Core::new()?;
  let client = Client::new(&core.handle());

  let uri = filename.parse()?;
  let mut req = Request::new(Method::Get, uri);
  req.headers_mut().set(Bytes(range));

  let work = client.request(req).and_then(|r| {
    Ok(r)
  });
  core.run(work)
}

fn get_content_length(response: &Response) -> Option<u64> {
  match response.headers().get::<ContentLength>() {
    Some(length) => Some(**length as u64),
    None => None
  }
}

fn get_content_range(response: &Response) -> Result<Option<u64>, String> {
  match response.headers().get::<ContentRange>() {
    Some(content_range) => {
      match content_range.clone() {
        ContentRange(ContentRangeSpec::Bytes{
            range: _range,
            instance_length: length
          }) => {
          Ok(length)
        },
        ContentRange(ContentRangeSpec::Unregistered{unit: _unit, resp: _resp}) => {
          Err("Unregistered, actually unsupported".to_string())
        }
      }
    },
    None =>
      Err("Missing content_range".to_string()),
  }
}

#[derive(Debug)]
pub struct HttpReader {
  pub filename: String,
  pub file_size: Option<u64>,
  pub position: u64,
  pub buffer: Buffer
}

pub fn exists(filename: &String) -> bool {
  match get_head(filename) {
    Ok(resp) => {
      println!("RESP {:?}", resp.status());
      resp.status().is_success()
    },
    Err(msg) => {
      println!("{:?}", msg);
      false
    }
  }
}

fn get_data_range(position: u64, size: usize) -> Vec<ByteRangeSpec> {
  let start = position;
  let end = position + (size - 1) as u64;

  vec![FromTo(start, end)]
}

fn load_data(reader: &mut HttpReader, size: usize) -> Result<Option<Vec<u8>>, String> {

  info!("make HTTP request with request {:?} bytes", size);

  match reader.file_size {
      Some(size) => {
        if reader.position >= size {
          return Ok(None)
        }
      },
      None => (),
  };

  let range = get_data_range(reader.position, size);

  let response = get_data(&reader.filename, range).unwrap();

  let loaded_size =
    match get_content_length(&response) {
        Some(content_length) => content_length,
        None => return Err("Missing content_length".to_string()),
    };

  match get_content_range(&response) {
    Ok(length) => reader.file_size = length,
    Err(msg) => return Err(msg),
  };

  match loaded_size {
    0 => Err("Bad request range".to_string()),
    _ => {
      let body_data =
        match response.body().concat2().wait() {
          Ok(body) => body.to_vec(),
          Err(_msg) => vec![],
        };
      reader.position = reader.position + loaded_size as u64;
      Ok(Some(body_data))
    }
  }
}

impl Reader for HttpReader {
  fn open(filename: &String) -> HttpReader {
    match get_head(filename) {
      Err(msg) => panic!(msg.to_string()),
      Ok(response) => {
        let content_length = get_content_length(&response);

        HttpReader {
          filename: filename.to_string(),
          file_size: content_length,
          position: 0,
          buffer: Buffer {
            size: None,
            position: 0,
            buffer: vec![]
          }
        }
      }
    }
  }

  fn get_position(&mut self) -> Result<u64, String> {
    Ok(self.position)
  }

  fn get_cache_size(&self) -> Option<usize> {
    self.buffer.size
  }

  fn set_cache_size(&mut self, cache_size: Option<usize>) {
    self.buffer.size = cache_size;
  }

  fn get_size(&mut self) -> Result<u64, String> {
    match self.file_size {
        Some(length) => Ok(length),
        None => Err("No length detected".to_string()),
    }
  }

  fn read(&mut self, size: usize) -> Result<Vec<u8>, String> {
    match load_data(self, size) {
      Err(msg) => Err(msg),
      Ok(some_data) => {
        match some_data {
            Some(data) => {
              // println!("{:?}", data);
              match data.len() == size {
                true => Ok(data),
                false => Ok(Vec::new()),
              }
            },
            None => Ok(Vec::new()),
        }
      }
    }
  }

  fn seek(&mut self, seek: SeekFrom) -> Result<u64, String> {
    match seek {
      SeekFrom::Current(offset) => {
        self.position = self.position + offset as u64;
      },
      SeekFrom::Start(offset) => {
        self.position = offset;
      },
      SeekFrom::End(offset) => {
        match self.file_size {
          Some(size) => {
            self.position = size - offset as u64;
          },
          None => return Err("Missing file size".to_string())
        }
      }
    }
    Ok(self.position)
  }
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::process::exit;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{Sender, Receiver, channel};

use auth_plus::authenticate;
use datatype::{AccessToken, Command, Config, Error, Event, UpdateState};
use datatype::Command::*;
use http_client::HttpClient;
use interaction_library::gateway::Interpret;
use ota_plus::{get_package_updates, install_package_update, update_installed_packages,
               send_install_report};

#[derive(Clone)]
pub struct Env<'a> {
    pub config: Config,
    pub access_token: Option<Cow<'a, AccessToken>>,
    pub http_client: Arc<Mutex<HttpClient>>,
}

pub trait Interpreter<Env, I, O> {
    fn interpret(env: &mut Env, msg: I, otx: Sender<O>);

    fn run(env: &mut Env, irx: Receiver<I>, otx: Sender<O>) {
        loop {
            match irx.recv() {
                Ok(msg) => Self::interpret(env, msg, otx.clone()),
                Err(err) => error!("Error receiving command: {:?}", err),
            }
        }
    }
}

pub struct AutoAcceptor;

impl Interpreter<(), Event, Command> for AutoAcceptor {
    fn interpret(_: &mut (), event: Event, ctx: Sender<Command>) {
        info!("Automatic interpreter: {:?}", event);
        match event {
            Event::Batch(ref evs) => {
                for ev in evs {
                    accept(&ev, ctx.clone())
                }
            }
            ev => accept(&ev, ctx),
        }

        fn accept(event: &Event, ctx: Sender<Command>) {
            if let &Event::NewUpdateAvailable(ref id) = event {
                let _ = ctx.send(Command::AcceptUpdate(id.clone()));
            }
        }
    }
}

pub struct GlobalInterpreter;

impl<'a> Interpreter<Env<'a>, Interpret<Command, Event>, Event> for GlobalInterpreter {
    fn interpret(env: &mut Env, i: Interpret<Command, Event>, etx: Sender<Event>) {
        info!("Interpreting: {:?}", i.cmd);
        let (multi_tx, multi_rx): (Sender<Event>, Receiver<Event>) = channel();
        let local_tx = i.etx.clone();

        let _ = command_interpreter(env, i.cmd, multi_tx)
            .map_err(|err| send(Event::Error(format!("{}", err)), &etx, &local_tx))
            .map(|_| {
                for ev in multi_rx {
                    send(ev, &etx, &local_tx);
                }
            });

        fn send(ev: Event, global_tx: &Sender<Event>, local_tx: &Option<Arc<Mutex<Sender<Event>>>>) {
            // unwrap failed sends to avoid thread deadlocking
            let _ = global_tx.send(ev.clone()).unwrap();
            if let Some(ref local) = *local_tx {
                let _ = local.lock().unwrap().send(ev).unwrap();
            }
        }
    }
}

fn command_interpreter(env: &mut Env, cmd: Command, etx: Sender<Event>) -> Result<(), Error> {
    match env.access_token.to_owned() {
        Some(ref token) => authenticated(env, cmd, etx, token),
        None            => unauthenticated(env, cmd, etx),
    }
}

// This macro partially applies the config, http client and token to the
// passed in functions.
macro_rules! partial_apply {
    ([ $( $fun0: ident ),* ], // Functions of arity 0,
     [ $( $fun1: ident ),* ], // arity 1,
     [ $( $fun2: ident ),* ], // and arity 2.
     $config: expr, $client: expr, $token: expr) => {
        $(let $fun0 = ||           $fun0(&$config, &mut *$client.lock().unwrap(), $token);)*
        $(let $fun1 = |arg|        $fun1(&$config, &mut *$client.lock().unwrap(), $token, &arg);)*
        $(let $fun2 = |arg1, arg2| $fun2(&$config, &mut *$client.lock().unwrap(), $token, &arg1, &arg2);)*
    }
}

fn authenticated<'a>(env: &mut Env, cmd: Command, etx: Sender<Event>, token: &Cow<'a, AccessToken>)
                     -> Result<(), Error> {

    let client = env.http_client.clone();
    partial_apply!([get_package_updates, update_installed_packages],
                   [send_install_report],
                   [install_package_update],
                   &env.config, client, &token);

    match cmd {
        Authenticate(_) => (),

        AcceptUpdate(ref id) => {
            try!(etx.send(Event::UpdateStateChanged(id.clone(), UpdateState::Downloading)));
            let report = try!(install_package_update(id.to_owned(), etx.to_owned()));
            try!(send_install_report(report.clone()));
            info!("Update finished. Report sent: {:?}", report)
        }

        GetPendingUpdates => {
            let mut updates = try!(get_package_updates());
            updates.sort_by_key(|e| e.installPos);
            let evs: Vec<Event> = updates.iter()
                                         .map(|up| Event::NewUpdateAvailable(up.requestId.clone()))
                                         .collect();
            info!("New package updates available: {:?}", evs);
            try!(etx.send(Event::Batch(evs)))
        }

        ListInstalledPackages => {
            let pkgs = try!(env.config.ota.package_manager.installed_packages());
            try!(etx.send(Event::FoundInstalledPackages(pkgs.clone())))
        }

        UpdateInstalledPackages => {
            try!(update_installed_packages());
            try!(etx.send(Event::Ok));
            info!("Posted installed packages to the server.")
        }

        Shutdown => exit(0),
    }

    Ok(())
}

fn unauthenticated(env: &mut Env, cmd: Command, etx: Sender<Event>) -> Result<(), Error> {
    match cmd {
        Authenticate(_) => {
            let client_clone = env.http_client.clone();
            let mut client = client_clone.lock().unwrap();
            let token = try!(authenticate(&env.config.auth, &mut *client));
            env.access_token = Some(token.into());
            try!(etx.send(Event::Ok));
        }

        AcceptUpdate(_)       |
        GetPendingUpdates     |
        ListInstalledPackages |
        UpdateInstalledPackages => try!(etx.send(Event::NotAuthenticated)),

        Shutdown => exit(0),
    }

    Ok(())
}
<commit_msg>Only send last Event to local transmitter<commit_after>use std::borrow::Cow;
use std::process::exit;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{Sender, Receiver, channel};

use auth_plus::authenticate;
use datatype::{AccessToken, Command, Config, Error, Event, UpdateState};
use datatype::Command::*;
use http_client::HttpClient;
use interaction_library::gateway::Interpret;
use ota_plus::{get_package_updates, install_package_update, update_installed_packages,
               send_install_report};

#[derive(Clone)]
pub struct Env<'a> {
    pub config: Config,
    pub access_token: Option<Cow<'a, AccessToken>>,
    pub http_client: Arc<Mutex<HttpClient>>,
}

pub trait Interpreter<Env, I, O> {
    fn interpret(env: &mut Env, msg: I, otx: Sender<O>);

    fn run(env: &mut Env, irx: Receiver<I>, otx: Sender<O>) {
        loop {
            match irx.recv() {
                Ok(msg) => Self::interpret(env, msg, otx.clone()),
                Err(err) => error!("Error receiving command: {:?}", err),
            }
        }
    }
}

pub struct AutoAcceptor;

impl Interpreter<(), Event, Command> for AutoAcceptor {
    fn interpret(_: &mut (), event: Event, ctx: Sender<Command>) {
        info!("Automatic interpreter: {:?}", event);
        match event {
            Event::Batch(ref evs) => {
                for ev in evs {
                    accept(&ev, ctx.clone())
                }
            }
            ev => accept(&ev, ctx),
        }

        fn accept(event: &Event, ctx: Sender<Command>) {
            if let &Event::NewUpdateAvailable(ref id) = event {
                let _ = ctx.send(Command::AcceptUpdate(id.clone()));
            }
        }
    }
}

pub struct GlobalInterpreter;

impl<'a> Interpreter<Env<'a>, Interpret<Command, Event>, Event> for GlobalInterpreter {
    fn interpret(env: &mut Env, i: Interpret<Command, Event>, etx: Sender<Event>) {
        info!("Interpreting: {:?}", i.cmd);
        let (multi_tx, multi_rx): (Sender<Event>, Receiver<Event>) = channel();
        let local_tx = i.etx.clone();

        let _ = command_interpreter(env, i.cmd, multi_tx)
            .map_err(|err| {
                let ev = Event::Error(format!("{}", err));
                let _  = etx.send(ev.clone()).unwrap();
                send(ev, &local_tx);
            })
            .map(|_| {
                let mut last_ev: Event;
                for ev in multi_rx {
                    let _ = etx.send(ev.clone()).unwrap();
                    last_ev = ev;
                }
                send(last_ev, &local_tx);
            });

        fn send(ev: Event, local_tx: &Option<Arc<Mutex<Sender<Event>>>>) {
            // unwrap failed sends to avoid receiver thread deadlocking
            if let Some(ref local) = *local_tx {
                let _ = local.lock().unwrap().send(ev).unwrap();
            }
        }
    }
}

fn command_interpreter(env: &mut Env, cmd: Command, etx: Sender<Event>) -> Result<(), Error> {
    match env.access_token.to_owned() {
        Some(ref token) => authenticated(env, cmd, etx, token),
        None            => unauthenticated(env, cmd, etx),
    }
}

// This macro partially applies the config, http client and token to the
// passed in functions.
macro_rules! partial_apply {
    ([ $( $fun0: ident ),* ], // Functions of arity 0,
     [ $( $fun1: ident ),* ], // arity 1,
     [ $( $fun2: ident ),* ], // and arity 2.
     $config: expr, $client: expr, $token: expr) => {
        $(let $fun0 = ||           $fun0(&$config, &mut *$client.lock().unwrap(), $token);)*
        $(let $fun1 = |arg|        $fun1(&$config, &mut *$client.lock().unwrap(), $token, &arg);)*
        $(let $fun2 = |arg1, arg2| $fun2(&$config, &mut *$client.lock().unwrap(), $token, &arg1, &arg2);)*
    }
}

fn authenticated<'a>(env: &mut Env, cmd: Command, etx: Sender<Event>, token: &Cow<'a, AccessToken>)
                     -> Result<(), Error> {

    let client = env.http_client.clone();
    partial_apply!([get_package_updates, update_installed_packages],
                   [send_install_report],
                   [install_package_update],
                   &env.config, client, &token);

    match cmd {
        Authenticate(_) => (),

        AcceptUpdate(ref id) => {
            try!(etx.send(Event::UpdateStateChanged(id.clone(), UpdateState::Downloading)));
            let report = try!(install_package_update(id.to_owned(), etx.to_owned()));
            try!(send_install_report(report.clone()));
            info!("Update finished. Report sent: {:?}", report)
        }

        GetPendingUpdates => {
            let mut updates = try!(get_package_updates());
            updates.sort_by_key(|e| e.installPos);
            let evs: Vec<Event> = updates.iter()
                                         .map(|up| Event::NewUpdateAvailable(up.requestId.clone()))
                                         .collect();
            info!("New package updates available: {:?}", evs);
            try!(etx.send(Event::Batch(evs)))
        }

        ListInstalledPackages => {
            let pkgs = try!(env.config.ota.package_manager.installed_packages());
            try!(etx.send(Event::FoundInstalledPackages(pkgs.clone())))
        }

        UpdateInstalledPackages => {
            try!(update_installed_packages());
            try!(etx.send(Event::Ok));
            info!("Posted installed packages to the server.")
        }

        Shutdown => exit(0),
    }

    Ok(())
}

fn unauthenticated(env: &mut Env, cmd: Command, etx: Sender<Event>) -> Result<(), Error> {
    match cmd {
        Authenticate(_) => {
            let client_clone = env.http_client.clone();
            let mut client = client_clone.lock().unwrap();
            let token = try!(authenticate(&env.config.auth, &mut *client));
            env.access_token = Some(token.into());
            try!(etx.send(Event::Ok));
        }

        AcceptUpdate(_)       |
        GetPendingUpdates     |
        ListInstalledPackages |
        UpdateInstalledPackages => try!(etx.send(Event::NotAuthenticated)),

        Shutdown => exit(0),
    }

    Ok(())
}
<|endoftext|>


<commit_before>/// Owner information for the object
#[derive(Deserialize, Debug)]
pub struct Owner {
    #[serde(rename = "DisplayName")]
    /// Object owner's name.
    pub display_name: String,
    #[serde(rename = "ID")]
    /// Object owner's ID.
    pub id: String,
}

/// An individual object in a ListBucketResult
#[derive(Deserialize, Debug)]
pub struct Object {
    #[serde(rename = "LastModified")]
    /// Date and time the object was last modified.
    pub last_modified: String,
    #[serde(rename = "ETag")]
    /// The entity tag is an MD5 hash of the object. The ETag only reflects changes to the
    /// contents of an object, not its metadata.
    pub e_tag: String,
    #[serde(rename = "StorageClass")]
    /// STANDARD | STANDARD_IA | REDUCED_REDUNDANCY | GLACIER
    pub storage_class: String,
    #[serde(rename = "Key")]
    /// The object's key
    pub key: String,
    #[serde(rename = "Owner")]
    /// Bucket owner
    pub owner: Owner,
    #[serde(rename = "Size")]
    /// Size in bytes of the object.
    pub size: i32,
}

/// The parsed result of a s3 bucket listing
#[derive(Deserialize, Debug)]
pub struct ListBucketResult {
    #[serde(rename = "Name")]
    /// Name of the bucket.
    pub name: String,
    #[serde(rename = "NextMarker")]
    /// When the response is truncated (that is, the IsTruncated element value in the response
    /// is true), you can use the key name in this field as a marker in the subsequent request
    /// to get next set of objects. Amazon S3 lists objects in UTF-8 character encoding in
    /// lexicographical order.
    pub next_marker: String,
    #[serde(rename = "Delimiter")]
    /// A delimiter is a character you use to group keys.
    pub delimiter: String,
    #[serde(rename = "MaxKeys")]
    /// Sets the maximum number of keys returned in the response body.
    pub max_keys: i32,
    #[serde(rename = "Prefix")]
    /// Limits the response to keys that begin with the specified prefix.
    pub prefix: String,
    #[serde(rename = "Marker")]
    /// Indicates where in the bucket listing begins. Marker is included in the response if
    /// it was sent with the request.
    pub marker: String,
    #[serde(rename = "EncodingType")]
    /// Specifies the encoding method to used
    pub encoding_type: String,
    #[serde(rename = "IsTruncated")]
    ///  Specifies whether (true) or not (false) all of the results were returned.
    ///  If the number of results exceeds that specified by MaxKeys, all of the results
    ///  might not be returned.
    pub is_truncated: bool,
    #[serde(rename = "Contents")]
    /// Metadata about each object returned.
    pub contents: Vec<Object>,
    #[serde(rename = "CommonPrefixs")]
    /// All of the keys rolled up into a common prefix count as a single return when
    /// calculating the number of returns.
    pub common_prefixes: Vec<CommonPrefix>,
}

/// CommonPrefix is used to group keys
#[derive(Deserialize, Debug)]
pub struct CommonPrefix {
    #[serde(rename = "Prefix")]
    /// Keys that begin with the indicated prefix.
    pub prefix: String,
}
<commit_msg>Make some fields optional as they may be missing in the response<commit_after>/// Owner information for the object
#[derive(Deserialize, Debug)]
pub struct Owner {
    #[serde(rename = "DisplayName")]
    /// Object owner's name.
    pub display_name: String,
    #[serde(rename = "ID")]
    /// Object owner's ID.
    pub id: String,
}

/// An individual object in a ListBucketResult
#[derive(Deserialize, Debug)]
pub struct Object {
    #[serde(rename = "LastModified")]
    /// Date and time the object was last modified.
    pub last_modified: String,
    #[serde(rename = "ETag")]
    /// The entity tag is an MD5 hash of the object. The ETag only reflects changes to the
    /// contents of an object, not its metadata.
    pub e_tag: String,
    #[serde(rename = "StorageClass")]
    /// STANDARD | STANDARD_IA | REDUCED_REDUNDANCY | GLACIER
    pub storage_class: String,
    #[serde(rename = "Key")]
    /// The object's key
    pub key: String,
    #[serde(rename = "Owner")]
    /// Bucket owner
    pub owner: Option<Owner>,
    #[serde(rename = "Size")]
    /// Size in bytes of the object.
    pub size: i32,
}

/// The parsed result of a s3 bucket listing
#[derive(Deserialize, Debug)]
pub struct ListBucketResult {
    #[serde(rename = "Name")]
    /// Name of the bucket.
    pub name: String,
    #[serde(rename = "NextMarker")]
    /// When the response is truncated (that is, the IsTruncated element value in the response
    /// is true), you can use the key name in this field as a marker in the subsequent request
    /// to get next set of objects. Amazon S3 lists objects in UTF-8 character encoding in
    /// lexicographical order.
    pub next_marker: Option<String>,
    #[serde(rename = "Delimiter")]
    /// A delimiter is a character you use to group keys.
    pub delimiter: Option<String>,
    #[serde(rename = "MaxKeys")]
    /// Sets the maximum number of keys returned in the response body.
    pub max_keys: i32,
    #[serde(rename = "Prefix")]
    /// Limits the response to keys that begin with the specified prefix.
    pub prefix: String,
    #[serde(rename = "Marker")]
    /// Indicates where in the bucket listing begins. Marker is included in the response if
    /// it was sent with the request.
    pub marker: Option<String>,
    #[serde(rename = "EncodingType")]
    /// Specifies the encoding method to used
    pub encoding_type: Option<String>,
    #[serde(rename = "IsTruncated")]
    ///  Specifies whether (true) or not (false) all of the results were returned.
    ///  If the number of results exceeds that specified by MaxKeys, all of the results
    ///  might not be returned.
    pub is_truncated: bool,
    #[serde(rename = "Contents")]
    /// Metadata about each object returned.
    pub contents: Vec<Object>,
    #[serde(rename = "CommonPrefixs")]
    /// All of the keys rolled up into a common prefix count as a single return when
    /// calculating the number of returns.
    pub common_prefixes: Option<Vec<CommonPrefix>>,
}

/// CommonPrefix is used to group keys
#[derive(Deserialize, Debug)]
pub struct CommonPrefix {
    #[serde(rename = "Prefix")]
    /// Keys that begin with the indicated prefix.
    pub prefix: String,
}
<|endoftext|>


<commit_before>use std::string::String;
use std::vec::Vec;

// use anymap::AnyMap;
// use std::any::Any;

use types::{BERT_LABEL, BertTag};

pub struct Serialiazer {
//    data: Any
}

pub struct Deserializer {
//    data: Vec<u8>
}

pub trait Serialize<T> {
    fn to_bert(&self, data: T) -> Vec<u8>;
}

pub trait Deserialize<T> {
    fn to_bert(&self, data: T) -> Vec<u8>;
}

impl Serialiazer {
    fn generate_term(&self, tag: BertTag, data: Vec<u8>) -> Vec<u8> {
        let mut binary = vec![tag as u8];
        binary.extend(data.iter().clone());
        binary
    }

    fn convert_string_to_binary(&self, data: String) -> Vec<u8> {
        let binary_string = data.into_bytes();
        let binary_length = binary_string.len() as u8;
        let mut binary = vec![0u8, binary_length];
        binary.extend(binary_string.iter().clone());
        binary
    }

    fn merge_atoms(&self, atom_1: Vec<u8>, atom_2: Vec<u8>) -> Vec<u8> {
        let mut binary: Vec<u8> = atom_1.clone();
        binary.extend(atom_2.iter().clone());
        binary
    }

    fn get_bert_atom(&self) -> Vec<u8> {
        let bert_string = BERT_LABEL.to_string();
        let binary_string = self.convert_string_to_binary(bert_string);
        self.generate_term(BertTag::Atom, binary_string)
    }
}

impl Serialize<u8> for Serialiazer {
    fn to_bert(&self, data: u8) -> Vec<u8> {
        self.generate_term(BertTag::SmallInteger, vec![data])
    }
}

impl Serialize<String> for Serialiazer {
    fn to_bert(&self, data: String) -> Vec<u8> {
        let binary_string = self.convert_string_to_binary(data);
        self.generate_term(BertTag::String, binary_string)
    }
}

impl Serialize<bool> for Serialiazer {
    fn to_bert(&self, data: bool) -> Vec<u8> {
        let boolean_string = data.to_string();
        let binary_boolean = self.convert_string_to_binary(boolean_string);

        let bert_atom = self.get_bert_atom();
        let boolean_atom = self.generate_term(BertTag::Atom, binary_boolean);

        self.merge_atoms(bert_term, boolean_term)
    }
}
<commit_msg>Changed String to &str type of a parameter of the convert function<commit_after>use std::string::String;
use std::vec::Vec;

// use anymap::AnyMap;
// use std::any::Any;

use types::{BERT_LABEL, BertTag};

pub struct Serialiazer {
//    data: Any
}

pub struct Deserializer {
//    data: Vec<u8>
}

pub trait Serialize<T> {
    fn to_bert(&self, data: T) -> Vec<u8>;
}

pub trait Deserialize<T> {
    fn to_bert(&self, data: T) -> Vec<u8>;
}

impl Serialiazer {
    fn generate_term(&self, tag: BertTag, data: Vec<u8>) -> Vec<u8> {
        let mut binary = vec![tag as u8];
        binary.extend(data.iter().clone());
        binary
    }

    fn convert_string_to_binary(&self, data: &str) -> Vec<u8> {
        let binary_string = data.as_bytes();
        let binary_length = binary_string.len() as u8;
        let mut binary = vec![0u8, binary_length];
        binary.extend(binary_string.iter().clone());
        binary
    }

    fn merge_atoms(&self, atom_1: Vec<u8>, atom_2: Vec<u8>) -> Vec<u8> {
        let mut binary: Vec<u8> = atom_1.clone();
        binary.extend(atom_2.iter().clone());
        binary
    }

    fn get_bert_atom(&self) -> Vec<u8> {
        let binary_string = self.convert_string_to_binary(BERT_LABEL);
        self.generate_term(BertTag::Atom, binary_string)
    }
}

impl Serialize<u8> for Serialiazer {
    fn to_bert(&self, data: u8) -> Vec<u8> {
        self.generate_term(BertTag::SmallInteger, vec![data])
    }
}

impl Serialize<String> for Serialiazer {
    fn to_bert(&self, data: String) -> Vec<u8> {
        let binary_string = self.convert_string_to_binary(&data);
        self.generate_term(BertTag::String, binary_string)
    }
}

impl Serialize<bool> for Serialiazer {
    fn to_bert(&self, data: bool) -> Vec<u8> {
        let boolean_string = data.to_string();
        let binary_boolean = self.convert_string_to_binary(&boolean_string);

        let bert_atom = self.get_bert_atom();
        let boolean_atom = self.generate_term(BertTag::Atom, binary_boolean);

        self.merge_atoms(bert_atom, boolean_atom)
    }
}
<|endoftext|>


<commit_before>//! Storage Engine trait and several implementations
//!
//!

pub mod flatfile;

extern crate log;

use self::flatfile::FlatFile;

use std::mem;

use std::io;
use std::io::prelude::*;

use std::fs;
use std::fs::{OpenOptions,create_dir};

use std::convert::From;

use byteorder::Error;
use byteorder::{WriteBytesExt, ReadBytesExt, BigEndian};

use bincode::SizeLimit;
use bincode::rustc_serialize::{EncodingError,DecodingError,encode_into,decode_from};

/// constants
 const MAGIC_NUMBER: u64 = 0x6561742073686974; // secret
 const VERSION_NO: u8 = 1;

/// Storage Engine Interface.
///
/// A storage engine, like MyISAM and InnoDB, is responsible for reading and
/// writing data to disk, maintain and use indices, check for data corruption
/// and repair corrupt files.
///
/// Each table in a database may use a different storage engine.
pub trait Engine {
    fn create_table(&mut self, cols: &[Column]) -> Result<(), DatabaseError>;
}

/// A database table
///
/// Through this type, you can retreive certain meta information about the
/// table (like column names, column types, storage engine, ...). It's `access`
/// method locks the table globally and returns a storage engine to access
/// the table data.
#[derive(Debug)]
pub enum DatabaseError {
    Io(io::Error),
    BinEn(EncodingError),
    BinDe(DecodingError),
    Byteorder(::byteorder::Error),
    WrongMagicNmbr,
    Engine, //cur not used
    LoadDataBase,
    RemoveColumn,
    AddColumn,
}

impl From<io::Error> for DatabaseError {
    fn from(err: io::Error) -> DatabaseError {
        DatabaseError::Io(err)
    }
}

impl  From<EncodingError> for DatabaseError {
    fn from(err: EncodingError) -> DatabaseError {
        DatabaseError::BinEn(err)
    }
}

impl From<DecodingError> for DatabaseError {
    fn from(err: DecodingError) -> DatabaseError {
        DatabaseError::BinDe(err)
    }
}

impl From< ::byteorder::Error> for DatabaseError {
    fn from(err: ::byteorder::Error) -> DatabaseError {
        DatabaseError::Byteorder(err)
    }
}

/// A Enum for File Modes
///
/// Can be used to define the save and load configuration of open_file
#[derive(Debug)]
enum _FileMode{ LoadDefault, SaveDefault, }

/// A Enum for Datatypes (will be removed later)
#[repr(u8)]
#[derive(Clone,Copy,Debug,RustcDecodable, RustcEncodable)]
pub enum DataType{ Integer = 1, Float = 2, }

impl DataType {
    pub fn value(&self) -> u8 {
       *self as u8
    }
}

pub struct Database {
    name: String,
}

impl Database {
    /// Starts the process of creating a new Database
    /// Returns database or on fail DatabaseError
    pub fn new_database(database_name: &str) -> Result<Database, DatabaseError> {
        let d = Database{ name: database_name.to_string() };
        try!(d.create_database());
        Ok(d)
    }

    /// Loads already existing Database
    /// returns DataBase Error when database does not exist else the loaded DB
    pub fn load_database(database_name: &str) -> Result<Database, DatabaseError> {
        if try!(fs::metadata(database_name)).is_dir() {
            Ok(Database{ name: database_name.to_string() })
        } else {
            return Err(DatabaseError::LoadDataBase)
        }
    }

    /// Creates a folder for the database
    fn create_database(&self) -> Result<(), DatabaseError> {
        println!("trying to create dir!");
        try!(create_dir(&self.name));
        println!("created dir");
        Ok(())
    }

    /// Creates a new table in the DB folder
    /// Returns with DatabaseError on fail else Table
    pub fn create_table(&self, engine_id: u8, cols: Vec<Column>, table_name: &str)
        -> Result<Table, DatabaseError> {

        let t = Table::new(engine_id, &self.name, table_name, cols);
        try!(t.save());
        Ok(t)
    }

    /// calls load for table with the database path
    /// Returns with DatabaseError on fail else Table
    pub fn load_table(&self, table_name: &str) -> Result<Table, DatabaseError> {
        Self::load(&self.name, table_name)
    }

    /// Loads the table from the DB
    /// Returns with DatabaseError on fail else Table
    fn load(database: &str, table: &str) -> Result<Table, DatabaseError> {
        // TODO: Read the .tbl file from disk and parse it
        let path_to_table = Table::get_path(database, table, "tbl");
        let mut file = try!(OpenOptions::new()
            .read(true)
            .open(path_to_table));

        let ma_nmbr = try!(file.read_uint::<BigEndian>( mem::size_of_val(&MAGIC_NUMBER)));

        if ma_nmbr != MAGIC_NUMBER {
            println!("Magic Number not correct");
            return Err(DatabaseError::WrongMagicNmbr)
        }
        let table: Table = try!(decode_from(&mut file, SizeLimit::Infinite));
        println!("{:?}", table);

        Ok(table)
    }
}

/// Table struct that contains the table information
#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct Table {
    version_nmbr: u8,
    engine_id: u8,
    columns: Vec<Column>,
    name: String,
    name_of_database: String,
}

impl Table {
    /// Creates new table object
    /// Returns Table
    pub fn new(engine: u8, database: &str, table_name: &str, cols: Vec<Column>) -> Table {
        Table {
            version_nmbr: VERSION_NO,
            engine_id: engine,
            columns: cols,
            name: table_name.to_string(),
            name_of_database: database.to_string(),
        }
    }

    /// Saves the table with a identification number in table file
    /// Returns DatabaseError on fail else Nothing
    pub fn save(&self) -> Result<(), DatabaseError> {
        // call for open file
        let mut file = try!(OpenOptions::new()
            .write(true)
            .create(true)
            .open(self.get_table_metadata_path()));

        try!(file.write_u64::<BigEndian>(MAGIC_NUMBER));//MAGIC_NUMBER
        try!(encode_into(&self, &mut file,SizeLimit::Infinite));

        // debug message all okay
        println!("I Wrote my File");
        Ok(())
    }

    /// Returns columns of table as array
    pub fn columns(&self) -> &[Column] {
        // TODO: Return real columns
        &self.columns
    }

    /// Adds a column to the tabel
    /// Returns name of Column or on fail DatabaseError
    pub fn add_column(&mut self, name: &str, dtype: DataType) -> Result<String, DatabaseError> {
        match self.columns.iter().find(|x| x.name == name) {
            Some(_x) => {
                info!(target: "Column add event", "Column already exists");
                return Err(DatabaseError::AddColumn)
            },
            None => {
                info!(target: "Column add event", "Column was added");
            },
        }
        self.columns.push(Column::create_new(name, dtype));
        Ok(name.into())
    }

    /// Removes a column from the table
    /// Returns name of Column or on fail DatabaseError
    pub fn remove_column(&mut self, name: &str) -> Result<String, DatabaseError> {
        let index = match self.columns.iter().position(|x| x.name == name) {
            Some(_x) => {
                info!("Column {:?} was removed" , self.name);
                _x
            },
            None => {
                info!("Column {:?} could not be found", self.name);
                return Err(DatabaseError::RemoveColumn)
            },
        };
        self.columns.remove(index);
        Ok(name.into())
    }

    /// Creates an engine for Table
    /// Returns Box<Engine>
    pub fn create_engine(&self) -> Box<Engine> {
        Box::new(FlatFile::new(self.get_table_data_path()))
    }

    /// Returns the path for the metadata files
    fn get_table_metadata_path(&self) -> String {
        Self::get_path(&self.name_of_database, &self.name, "tbl")
    }

    /// Returns the path for the data files
    fn get_table_data_path(&self) -> String {
        Self::get_path(&self.name_of_database, &self.name, "dat")
    }

    /// Returns the path of the table
    fn get_path(database: &str, name: &str, ext: &str) -> String {
         format!("{}/{}.{}", database, name, ext)
    }
}

/// A table column. Has a name, a type, ...
#[derive(Debug,RustcDecodable, RustcEncodable,Clone)]
pub struct Column {
    pub name: String, //name of column
    pub data_type: DataType, //name of the data type that is contained in this column
}

impl Default for Column {
    /// Returns a default Column construct
    fn default() -> Column {
        Column {
            name: "default".to_string(),
            data_type: DataType::Integer
        }
    }
}

impl Column {
    /// Creates a new column object
    /// Returns with Column
    pub fn create_new(name: &str, dtype: DataType) -> Column {
        Column {
            name: name.to_string(),
            data_type: dtype.clone()
        }
    }
}

// # Some information for the `storage` working group:
//
// You work at the very bottom of the database: The thing that actually
// writes the data disk. Everything in this module is used only by the
// query execution module.
//
// The file layout may look like this:
// We have some `db_dir` where everything lives. In that directory, there are
// subdirectories for every database. In each of those subdirs is optionally
// a file `db.meta` that contains information about the database (such as
// permissions). The tables of each database are saved in *.tbl files that
// live inside the database directory.
//
// Your task is to provide types and method to:
// - read a specific table from a specific
//   database from file
// - create a new table in a database
// - query meta information about a table (columns for example)
// - lock a table for reading/writing it's data through a storage engine
//
// The other main task is to:
// - specify the storage engine interface
// - implement a simple storage engine (heap/flatfiles)
//
<commit_msg>Solve last issues of pull request<commit_after>//! Storage Engine trait and several implementations
//!
//!
pub mod flatfile;

use self::flatfile::FlatFile;

use std::mem;

use std::io;
use std::io::prelude::*;

use std::fs;
use std::fs::{OpenOptions, create_dir};

use std::convert::From;

use byteorder::Error;
use byteorder::{WriteBytesExt, ReadBytesExt, BigEndian};

use bincode::SizeLimit;
use bincode::rustc_serialize::{EncodingError, DecodingError, encode_into, decode_from};

/// constants
 const MAGIC_NUMBER: u64 = 0x6561742073686974; // secret
 const VERSION_NO: u8 = 1;

/// Storage Engine Interface.
///
/// A storage engine, like MyISAM and InnoDB, is responsible for reading and
/// writing data to disk, maintain and use indices, check for data corruption
/// and repair corrupt files.
///
/// Each table in a database may use a different storage engine.
pub trait Engine {
    fn create_table(&mut self, cols: &[Column]) -> Result<(), DatabaseError>;
}

/// A database table
///
/// Through this type, you can retreive certain meta information about the
/// table (like column names, column types, storage engine, ...). It's `access`
/// method locks the table globally and returns a storage engine to access
/// the table data.
#[derive(Debug)]
pub enum DatabaseError {
    Io(io::Error),
    BinEn(EncodingError),
    BinDe(DecodingError),
    Byteorder(::byteorder::Error),
    WrongMagicNmbr,
    Engine, //cur not used
    LoadDataBase,
    RemoveColumn,
    AddColumn,
}

impl From<io::Error> for DatabaseError {
    fn from(err: io::Error) -> DatabaseError {
        DatabaseError::Io(err)
    }
}

impl  From<EncodingError> for DatabaseError {
    fn from(err: EncodingError) -> DatabaseError {
        DatabaseError::BinEn(err)
    }
}

impl From<DecodingError> for DatabaseError {
    fn from(err: DecodingError) -> DatabaseError {
        DatabaseError::BinDe(err)
    }
}

impl From< ::byteorder::Error> for DatabaseError {
    fn from(err: ::byteorder::Error) -> DatabaseError {
        DatabaseError::Byteorder(err)
    }
}

/// A Enum for Datatypes (will be removed later)
#[repr(u8)]
#[derive(Clone,Copy,Debug,RustcDecodable, RustcEncodable)]
pub enum DataType{ Integer = 1, Float = 2, }

impl DataType {
    pub fn value(&self) -> u8 {
       *self as u8
    }
}

pub struct Database {
    name: String,
}

impl Database {
    /// Starts the process of creating a new Database
    /// Returns database or on fail DatabaseError
    pub fn new_database(database_name: &str) -> Result<Database, DatabaseError> {
        let d = Database{ name: database_name.to_string() };
        try!(d.create_database());
        Ok(d)
    }

    /// Loads already existing Database
    /// returns DataBase Error when database does not exist else the loaded DB
    pub fn load_database(database_name: &str) -> Result<Database, DatabaseError> {
        if try!(fs::metadata(database_name)).is_dir() {
            Ok(Database{ name: database_name.to_string() })
        } else {
            return Err(DatabaseError::LoadDataBase)
        }
    }

    /// Creates a folder for the database
    fn create_database(&self) -> Result<(), DatabaseError> {
        println!("trying to create dir!");
        try!(create_dir(&self.name));
        println!("created dir");
        Ok(())
    }

    /// Creates a new table in the DB folder
    /// Returns with DatabaseError on fail else Table
    pub fn create_table(&self, engine_id: u8, cols: Vec<Column>, table_name: &str)
        -> Result<Table, DatabaseError> {

        let t = Table::new(engine_id, &self.name, table_name, cols);
        try!(t.save());
        Ok(t)
    }

    /// calls load for table with the database path
    /// Returns with DatabaseError on fail else Table
    pub fn load_table(&self, table_name: &str) -> Result<Table, DatabaseError> {
        Self::load(&self.name, table_name)
    }

    /// Loads the table from the DB
    /// Returns with DatabaseError on fail else Table
    fn load(database: &str, table: &str) -> Result<Table, DatabaseError> {
        // TODO: Read the .tbl file from disk and parse it
        let path_to_table = Table::get_path(database, table, "tbl");
        let mut file = try!(OpenOptions::new()
            .read(true)
            .open(path_to_table));

        let ma_nmbr = try!(file.read_uint::<BigEndian>( mem::size_of_val(&MAGIC_NUMBER)));

        if ma_nmbr != MAGIC_NUMBER {
            println!("Magic Number not correct");
            return Err(DatabaseError::WrongMagicNmbr)
        }
        let table: Table = try!(decode_from(&mut file, SizeLimit::Infinite));
        println!("{:?}", table);

        Ok(table)
    }
}

/// Table struct that contains the table information
#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct Table {
    version_nmbr: u8,
    engine_id: u8,
    columns: Vec<Column>,
    name: String,
    name_of_database: String,
}

impl Table {
    /// Creates new table object
    /// Returns Table
    pub fn new(engine: u8, database: &str, table_name: &str, cols: Vec<Column>) -> Table {
        Table {
            version_nmbr: VERSION_NO,
            engine_id: engine,
            columns: cols,
            name: table_name.to_string(),
            name_of_database: database.to_string(),
        }
    }

    /// Saves the table with a identification number in table file
    /// Returns DatabaseError on fail else Nothing
    pub fn save(&self) -> Result<(), DatabaseError> {
        // call for open file
        let mut file = try!(OpenOptions::new()
            .write(true)
            .create(true)
            .open(self.get_table_metadata_path()));

        try!(file.write_u64::<BigEndian>(MAGIC_NUMBER));//MAGIC_NUMBER
        try!(encode_into(&self, &mut file,SizeLimit::Infinite));

        // debug message all okay
        println!("I Wrote my File");
        Ok(())
    }

    /// Returns columns of table as array
    pub fn columns(&self) -> &[Column] {
        // TODO: Return real columns
        &self.columns
    }

    /// Adds a column to the tabel
    /// Returns name of Column or on fail DatabaseError
    pub fn add_column(&mut self, name: &str, dtype: DataType) -> Result<(), DatabaseError> {
        match self.columns.iter().find(|x| x.name == name) {
            Some(_) => {
                warn!("Column {:?} already exists", name);
                return Err(DatabaseError::AddColumn)
            },
            None => {
                info!("Column {:?} was added", name);
            },
        }
        self.columns.push(Column::create_new(name, dtype));
        Ok(())
    }

    /// Removes a column from the table
    /// Returns name of Column or on fail DatabaseError
    pub fn remove_column(&mut self, name: &str) -> Result<(), DatabaseError> {
        let index = match self.columns.iter().position(|x| x.name == name) {
            Some(x) => {
                info!("Column {:?} was removed" , self.name);
                x
            },
            None => {
                warn!("Column {:?} could not be found", self.name);
                return Err(DatabaseError::RemoveColumn)
            },
        };
        self.columns.swap_remove(index);
        Ok(())
    }

    /// Creates an engine for Table
    /// Returns Box<Engine>
    pub fn create_engine(&self) -> Box<Engine> {
        Box::new(FlatFile::new(self.get_table_data_path()))
    }

    /// Returns the path for the metadata files
    fn get_table_metadata_path(&self) -> String {
        Self::get_path(&self.name_of_database, &self.name, "tbl")
    }

    /// Returns the path for the data files
    fn get_table_data_path(&self) -> String {
        Self::get_path(&self.name_of_database, &self.name, "dat")
    }

    /// Returns the path of the table
    fn get_path(database: &str, name: &str, ext: &str) -> String {
         format!("{}/{}.{}", database, name, ext)
    }
}

/// A table column. Has a name, a type, ...
#[derive(Debug,RustcDecodable, RustcEncodable,Clone)]
pub struct Column {
    pub name: String, //name of column
    pub data_type: DataType, //name of the data type that is contained in this column
}

impl Default for Column {
    /// Returns a default Column construct
    fn default() -> Column {
        Column {
            name: "default".to_string(),
            data_type: DataType::Integer
        }
    }
}

impl Column {
    /// Creates a new column object
    /// Returns with Column
    pub fn create_new(name: &str, dtype: DataType) -> Column {
        Column {
            name: name.to_string(),
            data_type: dtype.clone()
        }
    }
}

// # Some information for the `storage` working group:
//
// You work at the very bottom of the database: The thing that actually
// writes the data disk. Everything in this module is used only by the
// query execution module.
//
// The file layout may look like this:
// We have some `db_dir` where everything lives. In that directory, there are
// subdirectories for every database. In each of those subdirs is optionally
// a file `db.meta` that contains information about the database (such as
// permissions). The tables of each database are saved in *.tbl files that
// live inside the database directory.
//
// Your task is to provide types and method to:
// - read a specific table from a specific
//   database from file
// - create a new table in a database
// - query meta information about a table (columns for example)
// - lock a table for reading/writing it's data through a storage engine
//
// The other main task is to:
// - specify the storage engine interface
// - implement a simple storage engine (heap/flatfiles)
//
<|endoftext|>


<commit_before>#![allow(unused_variables, unused_imports)]
use tdo_core::*;
use tdo_export;
use std::fs::File;
use std::io::{Write, Read, stdin, stdout};
use std::io::prelude::*;
use super::exit;
use super::colored::*;

use filesystem;

pub fn print_out(tdo: &super::tdo_core::tdo::Tdo, all: bool) {
    if tdo.get_highest_id() > 0 {
        tdo_export::render_terminal_output(tdo, all);
    } else {
        println!("No todos yet");
    }
}

pub fn add(tdo: &mut tdo::Tdo, new_todo: &str, in_list: Option<&str>) {
    let todo = todo::Todo::new(tdo.get_highest_id() + 1, new_todo);
    match tdo.add_todo(in_list, todo) {
        Err(e) => errorprint!(e.description()),
        _ => {}
    }
}

pub fn edit(tdo: &mut tdo::Tdo, id: u32) {
    let list = match tdo.find_id(id) {
        Ok(list_id) => list_id,
        Err(e) => {
            errorprint!(e.description());
            exit(1);
        }
    };
    let position = match tdo.lists[list].contains_id(id) {
        Ok(position) => position,
        Err(e) => {
            errorprint!(e.description());
            exit(1);
        }
    };
    println!("Task #{}: {}", id, tdo.lists[list].list[position].name);
    println!("Enter your new task description (leave blank for abort)");
    let mut new_task = String::new();
    stdin().read_line(&mut new_task).unwrap();
    match new_task.trim() {
        "" => {}
        _ => tdo.lists[list].list[position].edit(&new_task.trim()),
    };
}

pub fn done(tdo: &mut tdo::Tdo, id: u32) {
    match tdo.done_id(id) {
        Ok(()) => {}
        Err(e) => errorprint!(e.description()),
    }
}

pub fn newlist(tdo: &mut tdo::Tdo, new_list: &str) {
    match tdo.add_list(list::TodoList::new(new_list)) {
        Ok(()) => { println!("Created a new list named '{}'", new_list); }
        Err(e) => errorprint!(e.description()),
    }
}

pub fn move_todo(tdo: &mut tdo::Tdo, id: u32, listname: &str){
    match tdo.move_todo(id,listname) {
        Ok(()) => {},
        Err(e) => errorprint!(e.description()),
    }
}

pub fn remove(tdo: &mut tdo::Tdo, list_name: &str) {
    print!("{}",
           format!("[WARNING] Are you sure you want to delete \"{}\" ans all todos in it? [y/N] ",
                   &list_name)
               .red());
    stdout().flush().ok().expect("Could not flush stdout!");
    let mut answer = String::new();
    stdin().read_line(&mut answer).unwrap();
    let should_delete = match answer.to_lowercase().trim() {
        "y" | "yes" => true,
        "n" | "no" | "" => false,
        _ => {
            errorprint!("No valid answer given. Defaulting to \"no\"");
            false
        }
    };
    if should_delete {
        match tdo.remove_list(list_name) {
            Ok(()) => println!("Removed the list '{}'", list_name),
            Err(e) => errorprint!(e),
        }
    }

}

pub fn github_set(tdo: &mut tdo::Tdo, token: Option<&str>) {
    tdo.set_gh_token(token);
}

pub fn github(tdo: &mut tdo::Tdo, repo: &str, title: &str, body: Option<&str>) {
    tdo_export::github_issue(tdo, repo, title, body);
}

pub fn clean(tdo: &mut tdo::Tdo, list_name: Option<&str>) {
    match list_name {
        Some(name) => {
            match tdo.clean_list(name) {
                Err(e) => errorprint!(e.description()),
                _ => {}
            }
        }
        None => tdo.clean_lists(),
    }
}

pub fn lists(tdo: &tdo::Tdo) {
    println!("Your todo collection currently encompasses the following lists:\n");

    for list in tdo.lists.iter() {
        let done = list.list
            .iter()
            .fold(0, |acc, &ref item| if item.done { acc + 1 } else { acc });
        let undone: u64 = (list.list.len() - done) as u64;
        println!("    [{undone}|{done}] {name}",
                 undone = undone.to_string().red(),
                 done = (done as u64).to_string().green(),
                 name = &list.name);
    }
}

pub fn export(tdo: &tdo::Tdo, destination: &str, undone: bool) {
    let target = match filesystem::validate_target_file(destination) {
        Ok(path) => path,
        Err(e) => {
            errorprint!(e);
            return;
        }
    };
    match File::create(target) {
        Ok(mut file) => {
            file.write(&tdo_export::gen_tasks_md(tdo, true).unwrap().into_bytes())
                .unwrap();
        }
        Err(e) => errorprint!(e),
    }
}

pub fn reset(tdo: &mut tdo::Tdo) -> Option<tdo::Tdo> {
    print!("{}",
           "[WARNING] Are you sure you want to delete all todos and lists? [y/N] ".red());
    stdout().flush().ok().expect("Could not flush stdout!");
    let mut answer = String::new();
    stdin().read_line(&mut answer).unwrap();
    let should_delete = match answer.to_lowercase().trim() {
        "y" | "yes" => true,
        "n" | "no" | "" => false,
        _ => {
            errorprint!("No valid answer given. Defaulting to \"no\"");
            false
        }
    };
    if should_delete {
        Some(tdo::Tdo::new())
    } else {
        None
    }
}
<commit_msg>fix adding gh issue to todos<commit_after>#![allow(unused_variables, unused_imports)]
use tdo_core::*;
use tdo_export;
use std::fs::File;
use std::io::{Write, Read, stdin, stdout};
use std::io::prelude::*;
use super::exit;
use super::colored::*;

use filesystem;

pub fn print_out(tdo: &super::tdo_core::tdo::Tdo, all: bool) {
    if tdo.get_highest_id() > 0 {
        tdo_export::render_terminal_output(tdo, all);
    } else {
        println!("No todos yet");
    }
}

pub fn add(tdo: &mut tdo::Tdo, new_todo: &str, in_list: Option<&str>) {
    let todo = todo::Todo::new(tdo.get_highest_id() + 1, new_todo);
    match tdo.add_todo(in_list, todo) {
        Err(e) => errorprint!(e.description()),
        _ => {}
    }
}

pub fn edit(tdo: &mut tdo::Tdo, id: u32) {
    let list = match tdo.find_id(id) {
        Ok(list_id) => list_id,
        Err(e) => {
            errorprint!(e.description());
            exit(1);
        }
    };
    let position = match tdo.lists[list].contains_id(id) {
        Ok(position) => position,
        Err(e) => {
            errorprint!(e.description());
            exit(1);
        }
    };
    println!("Task #{}: {}", id, tdo.lists[list].list[position].name);
    println!("Enter your new task description (leave blank for abort)");
    let mut new_task = String::new();
    stdin().read_line(&mut new_task).unwrap();
    match new_task.trim() {
        "" => {}
        _ => tdo.lists[list].list[position].edit(&new_task.trim()),
    };
}

pub fn done(tdo: &mut tdo::Tdo, id: u32) {
    match tdo.done_id(id) {
        Ok(()) => {}
        Err(e) => errorprint!(e.description()),
    }
}

pub fn newlist(tdo: &mut tdo::Tdo, new_list: &str) {
    match tdo.add_list(list::TodoList::new(new_list)) {
        Ok(()) => { println!("Created a new list named '{}'", new_list); }
        Err(e) => errorprint!(e.description()),
    }
}

pub fn move_todo(tdo: &mut tdo::Tdo, id: u32, listname: &str) {
    match tdo.move_todo(id, listname) {
        Ok(()) => {}
        Err(e) => errorprint!(e.description()),
    }
}

pub fn remove(tdo: &mut tdo::Tdo, list_name: &str) {
    print!("{}",
           format!("[WARNING] Are you sure you want to delete \"{}\" ans all todos in it? [y/N] ",
                   &list_name)
               .red());
    stdout().flush().ok().expect("Could not flush stdout!");
    let mut answer = String::new();
    stdin().read_line(&mut answer).unwrap();
    let should_delete = match answer.to_lowercase().trim() {
        "y" | "yes" => true,
        "n" | "no" | "" => false,
        _ => {
            errorprint!("No valid answer given. Defaulting to \"no\"");
            false
        }
    };
    if should_delete {
        match tdo.remove_list(list_name) {
            Ok(()) => println!("Removed the list '{}'", list_name),
            Err(e) => errorprint!(e),
        }
    }

}

pub fn github_set(tdo: &mut tdo::Tdo, token: Option<&str>) {
    tdo.set_gh_token(token);
}

pub fn github(tdo: &mut tdo::Tdo, repo: &str, title: &str, body: Option<&str>) {
    match tdo_export::github_issue(tdo, repo, title, body) {
        true => {
            let todo = todo::Todo::new(tdo.get_highest_id() + 1, format!("{}: {}", repo, title).as_str());
            match tdo.add_todo(None, todo) {
                Err(e) => errorprint!(e.description()),
                _ => {}
            }
        }
        false => errorprint!("Could not create issue.")
    }
}

pub fn clean(tdo: &mut tdo::Tdo, list_name: Option<&str>) {
    match list_name {
        Some(name) => {
            match tdo.clean_list(name) {
                Err(e) => errorprint!(e.description()),
                _ => {}
            }
        }
        None => tdo.clean_lists(),
    }
}

pub fn lists(tdo: &tdo::Tdo) {
    println!("Your todo collection currently encompasses the following lists:\n");

    for list in tdo.lists.iter() {
        let done = list.list
            .iter()
            .fold(0, |acc, &ref item| if item.done { acc + 1 } else { acc });
        let undone: u64 = (list.list.len() - done) as u64;
        println!("    [{undone}|{done}] {name}",
                 undone = undone.to_string().red(),
                 done = (done as u64).to_string().green(),
                 name = &list.name);
    }
}

pub fn export(tdo: &tdo::Tdo, destination: &str, undone: bool) {
    let target = match filesystem::validate_target_file(destination) {
        Ok(path) => path,
        Err(e) => {
            errorprint!(e);
            return;
        }
    };
    match File::create(target) {
        Ok(mut file) => {
            file.write(&tdo_export::gen_tasks_md(tdo, true).unwrap().into_bytes())
                .unwrap();
        }
        Err(e) => errorprint!(e),
    }
}

pub fn reset(tdo: &mut tdo::Tdo) -> Option<tdo::Tdo> {
    print!("{}",
           "[WARNING] Are you sure you want to delete all todos and lists? [y/N] ".red());
    stdout().flush().ok().expect("Could not flush stdout!");
    let mut answer = String::new();
    stdin().read_line(&mut answer).unwrap();
    let should_delete = match answer.to_lowercase().trim() {
        "y" | "yes" => true,
        "n" | "no" | "" => false,
        _ => {
            errorprint!("No valid answer given. Defaulting to \"no\"");
            false
        }
    };
    if should_delete {
        Some(tdo::Tdo::new())
    } else {
        None
    }
}
<|endoftext|>


<commit_before>use std::io::prelude::*;

use pg::Pg;
use types::{self, FromSql, IsNull, ToSql, ToSqlOutput};
use {deserialize, serialize};

impl FromSql<types::Bool, Pg> for bool {
    fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
        match bytes {
            Some(bytes) => Ok(bytes[0] != 0),
            None => Ok(false),
        }
    }
}

impl ToSql<types::Bool, Pg> for bool {
    fn to_sql<W: Write>(&self, out: &mut ToSqlOutput<W, Pg>) -> serialize::Result {
        out.write_all(&[*self as u8]).map(|_| IsNull::No).map_err(Into::into)
    }
}

#[test]
fn bool_to_sql() {
    let mut bytes = ToSqlOutput::test();
    ToSql::<types::Bool, Pg>::to_sql(&true, &mut bytes).unwrap();
    ToSql::<types::Bool, Pg>::to_sql(&false, &mut bytes).unwrap();
    assert_eq!(bytes, vec![1u8, 0u8]);
}

#[test]
fn bool_from_sql_treats_null_as_false() {
    let result = <bool as FromSql<types::Bool, Pg>>::from_sql(None).unwrap();
    assert!(!result);
}
<commit_msg>Rustfmt (I always forget to do this when I rebase :\ )<commit_after>use std::io::prelude::*;

use pg::Pg;
use types::{self, FromSql, IsNull, ToSql, ToSqlOutput};
use {deserialize, serialize};

impl FromSql<types::Bool, Pg> for bool {
    fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
        match bytes {
            Some(bytes) => Ok(bytes[0] != 0),
            None => Ok(false),
        }
    }
}

impl ToSql<types::Bool, Pg> for bool {
    fn to_sql<W: Write>(&self, out: &mut ToSqlOutput<W, Pg>) -> serialize::Result {
        out.write_all(&[*self as u8])
            .map(|_| IsNull::No)
            .map_err(Into::into)
    }
}

#[test]
fn bool_to_sql() {
    let mut bytes = ToSqlOutput::test();
    ToSql::<types::Bool, Pg>::to_sql(&true, &mut bytes).unwrap();
    ToSql::<types::Bool, Pg>::to_sql(&false, &mut bytes).unwrap();
    assert_eq!(bytes, vec![1u8, 0u8]);
}

#[test]
fn bool_from_sql_treats_null_as_false() {
    let result = <bool as FromSql<types::Bool, Pg>>::from_sql(None).unwrap();
    assert!(!result);
}
<|endoftext|>


<commit_before>use std::env;
use std::fmt;
use std::fs::{self, PathExt};
use std::io::Read;
use std::path::{Path, PathBuf};
use std::process;
use std::str::FromStr;
use std::sync::atomic;

use csv;

use Csv;

static XSV_INTEGRATION_TEST_DIR: &'static str = "xit";

static NEXT_ID: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;

pub struct Workdir {
    root: PathBuf,
    dir: PathBuf,
    flexible: bool,
}

impl Workdir {
    pub fn new(name: &str) -> Workdir {
        let id = NEXT_ID.fetch_add(1, atomic::Ordering::SeqCst);
        let root = env::current_exe().unwrap()
                       .parent()
                       .expect("executable's directory")
                       .to_path_buf();
        let dir = root.join(XSV_INTEGRATION_TEST_DIR)
                      .join(name)
                      .join(&format!("test-{}", id));

        // I don't get why this is necessary, but Travis seems to need it?
        // let md = fs::metadata(&dir);
        // if fs::metadata(&dir).map(|md| md.is_dir()).unwrap_or(false) {
            // if let Err(err) = fs::remove_dir_all(&dir) {
                // panic!("Could not remove directory '{:?}': {}", dir, err);
            // }
        // }
        // if fs::metadata(&dir).map(|md| md.is_file()).unwrap_or(false) {
            // if let Err(err) = fs::remove_file(&dir) {
                // panic!("Could not remove file '{:?}': {}", dir, err);
            // }
        // }
        if let Err(err) = fs::create_dir_all(&dir) {
            let md = match fs::metadata(&dir) {
                Ok(md) => md,
                Err(err) => panic!("Could not get metadata '{:?}': {}",
                                   dir, err),
            };
            panic!("Could not create '{:?}': {} -- {}, {}, {}",
                   dir, err, md.is_dir(), md.is_file(), md.len());
        }
        Workdir { root: root, dir: dir, flexible: false }
    }

    pub fn flexible(mut self, yes: bool) -> Workdir {
        self.flexible = yes;
        self
    }

    pub fn create<T: Csv>(&self, name: &str, rows: T) {
        let mut wtr = match csv::Writer::from_file(&self.path(name)) {
            Ok(wtr) => wtr.flexible(self.flexible),
            Err(err) => panic!("Could not open '{:?}': {}",
                                self.path(name), err),
        };
        for row in rows.to_vecs().into_iter() {
            wtr.write(row.iter()).unwrap();
        }
        wtr.flush().unwrap();
    }

    pub fn create_indexed<T: Csv>(&self, name: &str, rows: T) {
        self.create(name, rows);

        let mut cmd = self.command("index");
        cmd.arg(name);
        self.run(&mut cmd);
    }

    pub fn read_stdout<T: Csv>(&self, cmd: &mut process::Command) -> T {
        let mut rdr = csv::Reader::from_string(self.stdout::<String>(cmd))
                                  .has_headers(false);
        Csv::from_vecs(rdr.records().collect::<Result<_, _>>().unwrap())
    }

    pub fn command(&self, sub_command: &str) -> process::Command {
        let mut cmd = process::Command::new(&self.xsv_bin());
        cmd.current_dir(&self.dir).arg(sub_command);
        cmd
    }

    pub fn output(&self, cmd: &mut process::Command) -> process::Output {
        debug!("[{}]: {:?}", self.dir.display(), cmd);
        let o = cmd.output().unwrap();
        if !o.status.success() {
            panic!("\n\n===== {:?} =====\n\
                    command failed but expected success!\
                    \n\ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\n\nstderr: {}\
                    \n\n=====\n",
                   cmd, self.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr))
        }
        o
    }

    pub fn run(&self, cmd: &mut process::Command) {
        self.output(cmd);
    }

    pub fn stdout<T: FromStr>(&self, cmd: &mut process::Command) -> T {
        let o = self.output(cmd);
        let stdout = String::from_utf8_lossy(&o.stdout);
        stdout.trim().parse().ok().expect(
            &format!("Could not convert from string: '{}'", stdout))
    }

    pub fn assert_err(&self, cmd: &mut process::Command) {
        let o = cmd.output().unwrap();
        if o.status.success() {
            panic!("\n\n===== {:?} =====\n\
                    command succeeded but expected failure!\
                    \n\ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\n\nstderr: {}\
                    \n\n=====\n",
                   cmd, self.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr));
        }
    }

    pub fn from_str<T: FromStr>(&self, name: &Path) -> T {
        let mut o = String::new();
        fs::File::open(name).unwrap().read_to_string(&mut o).unwrap();
        o.parse().ok().expect("fromstr")
    }

    pub fn path(&self, name: &str) -> PathBuf {
        self.dir.join(name)
    }

    pub fn xsv_bin(&self) -> PathBuf {
        self.root.join("xsv")
    }
}

impl fmt::Debug for Workdir {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "path={}", self.dir.display())
    }
}
<commit_msg>travis<commit_after>use std::env;
use std::fmt;
use std::fs::{self, PathExt};
use std::io::Read;
use std::path::{Path, PathBuf};
use std::process;
use std::str::FromStr;
use std::sync::atomic;

use csv;

use Csv;

static XSV_INTEGRATION_TEST_DIR: &'static str = "xit";

static NEXT_ID: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;

pub struct Workdir {
    root: PathBuf,
    dir: PathBuf,
    flexible: bool,
}

impl Workdir {
    pub fn new(name: &str) -> Workdir {
        let id = NEXT_ID.fetch_add(1, atomic::Ordering::SeqCst);
        let root = env::current_exe().unwrap()
                       .parent()
                       .expect("executable's directory")
                       .to_path_buf();
        let dir = root.join(XSV_INTEGRATION_TEST_DIR)
                      .join(name)
                      .join(&format!("test-{}", id));

        // I don't get why this is necessary, but Travis seems to need it?
        // let md = fs::metadata(&dir);
        // if fs::metadata(&dir).map(|md| md.is_dir()).unwrap_or(false) {
            // if let Err(err) = fs::remove_dir_all(&dir) {
                // panic!("Could not remove directory '{:?}': {}", dir, err);
            // }
        // }
        // if fs::metadata(&dir).map(|md| md.is_file()).unwrap_or(false) {
            // if let Err(err) = fs::remove_file(&dir) {
                // panic!("Could not remove file '{:?}': {}", dir, err);
            // }
        // }
        if let Err(err) = fs::create_dir_all(&dir) {
            let md = match fs::metadata(&dir) {
                Ok(md) => md,
                Err(err2) => panic!("Could not get metadata '{:?}': {} \
                                     (other error: {})",
                                    dir, err2, err),
            };
            panic!("Could not create '{:?}': {} -- {}, {}, {}",
                   dir, err, md.is_dir(), md.is_file(), md.len());
        }
        Workdir { root: root, dir: dir, flexible: false }
    }

    pub fn flexible(mut self, yes: bool) -> Workdir {
        self.flexible = yes;
        self
    }

    pub fn create<T: Csv>(&self, name: &str, rows: T) {
        let mut wtr = match csv::Writer::from_file(&self.path(name)) {
            Ok(wtr) => wtr.flexible(self.flexible),
            Err(err) => panic!("Could not open '{:?}': {}",
                                self.path(name), err),
        };
        for row in rows.to_vecs().into_iter() {
            wtr.write(row.iter()).unwrap();
        }
        wtr.flush().unwrap();
    }

    pub fn create_indexed<T: Csv>(&self, name: &str, rows: T) {
        self.create(name, rows);

        let mut cmd = self.command("index");
        cmd.arg(name);
        self.run(&mut cmd);
    }

    pub fn read_stdout<T: Csv>(&self, cmd: &mut process::Command) -> T {
        let mut rdr = csv::Reader::from_string(self.stdout::<String>(cmd))
                                  .has_headers(false);
        Csv::from_vecs(rdr.records().collect::<Result<_, _>>().unwrap())
    }

    pub fn command(&self, sub_command: &str) -> process::Command {
        let mut cmd = process::Command::new(&self.xsv_bin());
        cmd.current_dir(&self.dir).arg(sub_command);
        cmd
    }

    pub fn output(&self, cmd: &mut process::Command) -> process::Output {
        debug!("[{}]: {:?}", self.dir.display(), cmd);
        let o = cmd.output().unwrap();
        if !o.status.success() {
            panic!("\n\n===== {:?} =====\n\
                    command failed but expected success!\
                    \n\ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\n\nstderr: {}\
                    \n\n=====\n",
                   cmd, self.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr))
        }
        o
    }

    pub fn run(&self, cmd: &mut process::Command) {
        self.output(cmd);
    }

    pub fn stdout<T: FromStr>(&self, cmd: &mut process::Command) -> T {
        let o = self.output(cmd);
        let stdout = String::from_utf8_lossy(&o.stdout);
        stdout.trim().parse().ok().expect(
            &format!("Could not convert from string: '{}'", stdout))
    }

    pub fn assert_err(&self, cmd: &mut process::Command) {
        let o = cmd.output().unwrap();
        if o.status.success() {
            panic!("\n\n===== {:?} =====\n\
                    command succeeded but expected failure!\
                    \n\ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\n\nstderr: {}\
                    \n\n=====\n",
                   cmd, self.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr));
        }
    }

    pub fn from_str<T: FromStr>(&self, name: &Path) -> T {
        let mut o = String::new();
        fs::File::open(name).unwrap().read_to_string(&mut o).unwrap();
        o.parse().ok().expect("fromstr")
    }

    pub fn path(&self, name: &str) -> PathBuf {
        self.dir.join(name)
    }

    pub fn xsv_bin(&self) -> PathBuf {
        self.root.join("xsv")
    }
}

impl fmt::Debug for Workdir {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "path={}", self.dir.display())
    }
}
<|endoftext|>


<commit_before>
///
/// Systems are a set of event handlers and optionally some associated state.
///
/// The event handlers are invoked with a list of event data and have access to component
/// lists. This access can be immutable or mutable which is made explicit so that
/// the event handler scheduler might parallelize handler invocations.
///
/// To properly enforce this I guess the scheduler would acquire the locks on the component
/// lists.
///
/// So the context of the handler function would consist of:
///
///   The handler state
///   The event data list
///   Immutable components lists
///   Mutable components lists
///
/// For example the following invocation:
///
/// system! my_system {
///	  on!(event_name, { positions: Position}, { descriptions: Description }) {
///     let position = positions[0];
///     descriptions[0].set(format!("Position = {},{}", position.x, position.y));
///   }
/// }
///
/// Expands to:
///
/// pub mod my_system {
///   struct State {}
///
///   pub fn event_name(state: &mut State, data: &Vec<event_name::Data>, positions: &Vec<Position>, descriptions: &mut Vec<Description> ) {
///     let position = positions[0];
///     descriptions[0].set(format!("Position = {},{}", position.x, position.y));
///   }
///
/// }<commit_msg>woops tab<commit_after>
///
/// Systems are a set of event handlers and optionally some associated state.
///
/// The event handlers are invoked with a list of event data and have access to component
/// lists. This access can be immutable or mutable which is made explicit so that
/// the event handler scheduler might parallelize handler invocations.
///
/// To properly enforce this I guess the scheduler would acquire the locks on the component
/// lists.
///
/// So the context of the handler function would consist of:
///
///   The handler state
///   The event data list
///   Immutable components lists
///   Mutable components lists
///
/// For example the following invocation:
///
/// system! my_system {
///   on!(event_name, { positions: Position}, { descriptions: Description }) {
///     let position = positions[0];
///     descriptions[0].set(format!("Position = {},{}", position.x, position.y));
///   }
/// }
///
/// Expands to:
///
/// pub mod my_system {
///   struct State {}
///
///   pub fn event_name(state: &mut State, data: &Vec<event_name::Data>, positions: &Vec<Position>, descriptions: &mut Vec<Description> ) {
///     let position = positions[0];
///     descriptions[0].set(format!("Position = {},{}", position.x, position.y));
///   }
///
/// }<|endoftext|>