<commit_before>#![deny(missing_docs)]

//! A Gfx texture representation that works nicely with Piston libraries.

extern crate gfx;
extern crate gfx_core;
extern crate texture;
extern crate image;

pub use texture::*;

use std::path::Path;
use image::{
    DynamicImage,
    RgbaImage,
};
use gfx::CombinedError;
use gfx::format::{Srgba8, R8_G8_B8_A8};

/// Flip settings.
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Flip {
    /// Does not flip.
    None,
    /// Flips image vertically.
    Vertical,
}

/// Represents a texture.
pub struct Texture<R> where R: gfx::Resources {
    /// Pixel storage for texture.
    pub surface: gfx::handle::Texture<R, R8_G8_B8_A8>,
    /// Sampler for texture.
    pub sampler: gfx::handle::Sampler<R>,
    /// View used by shader.
    pub view: gfx::handle::ShaderResourceView<R, [f32; 4]>
}

impl<R: gfx::Resources> Texture<R> {
    /// Returns empty texture.
    pub fn empty<F>(factory: &mut F) -> Result<Self, CombinedError>
        where F: gfx::Factory<R>
    {
        CreateTexture::create(factory, Format::Rgba8, &[0u8; 4], [1, 1],
                              &TextureSettings::new())
    }

    /// Creates a texture from path.
    pub fn from_path<F, P>(
        factory: &mut F,
        path: P,
        flip: Flip,
        settings: &TextureSettings,
    ) -> Result<Self, String>
        where F: gfx::Factory<R>,
              P: AsRef<Path>
    {
        let img = try!(image::open(path).map_err(|e| e.to_string()));

        let img = match img {
            DynamicImage::ImageRgba8(img) => img,
            img => img.to_rgba()
        };

        let img = if flip == Flip::Vertical {
            image::imageops::flip_vertical(&img)
        } else {
            img
        };

        Texture::from_image(factory, &img, settings).map_err(
            |e| format!("{:?}", e))
    }

    /// Creates a texture from image.
    pub fn from_image<F>(
        factory: &mut F,
        img: &RgbaImage,
        settings: &TextureSettings
    ) -> Result<Self, CombinedError>
        where F: gfx::Factory<R>
    {
        let (width, height) = img.dimensions();
        CreateTexture::create(factory, Format::Rgba8,
                              img, [width, height], settings)
    }

    /// Creates texture from memory alpha.
    pub fn from_memory_alpha<F>(
        factory: &mut F,
        buffer: &[u8],
        width: u32,
        height: u32,
        settings: &TextureSettings
    ) -> Result<Self, CombinedError>
        where F: gfx::Factory<R>
    {
        if width == 0 || height == 0 {
            return Texture::empty(factory);
        }

        let size = [width, height];
        let buffer = texture::ops::alpha_to_rgba8(buffer, size);
        CreateTexture::create(factory, Format::Rgba8, &buffer, size, settings)
    }

    /// Updates the texture with an image.
    pub fn update<C>(
        &mut self,
        encoder: &mut gfx::Encoder<R, C>,
        img: &RgbaImage
    ) -> Result<(), gfx::UpdateError<[u16; 3]>>
        where C: gfx::CommandBuffer<R>
    {
        let (width, height) = img.dimensions();
        let offset = [0, 0];
        let size = [width, height];
        UpdateTexture::update(self, encoder, Format::Rgba8, img, offset, size)
    }
}

impl<F, R> CreateTexture<F> for Texture<R>
    where F: gfx::Factory<R>,
          R: gfx::Resources
{
    type Error = CombinedError;

    fn create<S: Into<[u32; 2]>>(
        factory: &mut F,
        _format: Format,
        memory: &[u8],
        size: S,
        settings: &TextureSettings
    ) -> Result<Self, Self::Error> {
        // Modified `Factory::create_texture_immutable_u8` for dynamic texture.
        fn create_texture<T, F, R>(
            factory: &mut F,
            kind: gfx::texture::Kind,
            data: &[&[u8]]
        ) -> Result<(
            gfx::handle::Texture<R, T::Surface>,
            gfx::handle::ShaderResourceView<R, T::View>
        ), CombinedError>
            where F: gfx::Factory<R>,
                  R: gfx::Resources,
                  T: gfx::format::TextureFormat
        {
            use gfx::{format, texture};
            use gfx::memory::{Usage, SHADER_RESOURCE};
            use gfx_core::memory::Typed;

            let surface = <T::Surface as format::SurfaceTyped>::get_surface_type();
            let num_slices = kind.get_num_slices().unwrap_or(1) as usize;
            let num_faces = if kind.is_cube() {6} else {1};
            let desc = texture::Info {
                kind: kind,
                levels: (data.len() / (num_slices * num_faces)) as texture::Level,
                format: surface,
                bind: SHADER_RESOURCE,
                usage: Usage::Dynamic,
            };
            let cty = <T::Channel as format::ChannelTyped>::get_channel_type();
            let raw = try!(factory.create_texture_raw(desc, Some(cty), Some(data)));
            let levels = (0, raw.get_info().levels - 1);
            let tex = Typed::new(raw);
            let view = try!(factory.view_texture_as_shader_resource::<T>(
                &tex, levels, format::Swizzle::new()
            ));
            Ok((tex, view))
        }

        let size = size.into();
        let (width, height) = (size[0] as u16, size[1] as u16);
        let tex_kind = gfx::texture::Kind::D2(width, height,
            gfx::texture::AaMode::Single);

        // FIXME Use get_min too. gfx has only one filter setting for both.
        let filter_method = match settings.get_mag() {
            texture::Filter::Nearest => gfx::texture::FilterMethod::Scale,
            texture::Filter::Linear => gfx::texture::FilterMethod::Bilinear,
        };
        let sampler_info = gfx::texture::SamplerInfo::new(
            filter_method,
            gfx::texture::WrapMode::Clamp
        );

        let (surface, view) = try!(create_texture::<Srgba8, F, R>(
            factory, tex_kind, &[memory])
        );
        let sampler = factory.create_sampler(sampler_info);
        Ok(Texture { surface: surface, sampler: sampler, view: view })
    }
}

impl<R, C> UpdateTexture<gfx::Encoder<R, C>> for Texture<R>
    where R: gfx::Resources,
          C: gfx::CommandBuffer<R>
{
    type Error = gfx::UpdateError<[u16; 3]>;

    fn update<O, S>(
        &mut self,
        encoder: &mut gfx::Encoder<R, C>,
        format: Format,
        memory: &[u8],
        offset: O,
        size: S,
    ) -> Result<(), Self::Error>
        where O: Into<[u32; 2]>,
              S: Into<[u32; 2]>,
    {
        let offset = offset.into();
        let size = size.into();
        let tex = &self.surface;
        let face = None;
        let img_info = gfx::texture::ImageInfoCommon {
            xoffset: offset[0] as u16,
            yoffset: offset[1] as u16,
            zoffset: 0,
            width: size[0] as u16,
            height: size[1] as u16,
            depth: 0,
            format: (),
            mipmap: 0,
        };
        let data = gfx::memory::cast_slice(memory);

        match format {
            Format::Rgba8 => {
                use gfx::format::Rgba8;
                encoder.update_texture::<_, Rgba8>(tex, face, img_info, data).map_err(Into::into)
            },
        }
    }
}

impl<R> ImageSize for Texture<R> where R: gfx::Resources {
    #[inline(always)]
    fn get_size(&self) -> (u32, u32) {
        let (w, h, _, _) = self.surface.get_info().kind.get_dimensions();
        (w as u32, h as u32)
    }
}
<commit_msg>Flip horizontal<commit_after>#![deny(missing_docs)]

//! A Gfx texture representation that works nicely with Piston libraries.

extern crate gfx;
extern crate gfx_core;
extern crate texture;
extern crate image;

pub use texture::*;

use std::path::Path;
use image::{
    DynamicImage,
    RgbaImage,
};
use gfx::CombinedError;
use gfx::format::{Srgba8, R8_G8_B8_A8};

/// Flip settings.
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Flip {
    /// Does not flip.
    None,
    /// Flips image vertically.
    Vertical,
    /// Flips image horizontally.
    Horizonal,
}

/// Represents a texture.
pub struct Texture<R> where R: gfx::Resources {
    /// Pixel storage for texture.
    pub surface: gfx::handle::Texture<R, R8_G8_B8_A8>,
    /// Sampler for texture.
    pub sampler: gfx::handle::Sampler<R>,
    /// View used by shader.
    pub view: gfx::handle::ShaderResourceView<R, [f32; 4]>
}

impl<R: gfx::Resources> Texture<R> {
    /// Returns empty texture.
    pub fn empty<F>(factory: &mut F) -> Result<Self, CombinedError>
        where F: gfx::Factory<R>
    {
        CreateTexture::create(factory, Format::Rgba8, &[0u8; 4], [1, 1],
                              &TextureSettings::new())
    }

    /// Creates a texture from path.
    pub fn from_path<F, P>(
        factory: &mut F,
        path: P,
        flip: Flip,
        settings: &TextureSettings,
    ) -> Result<Self, String>
        where F: gfx::Factory<R>,
              P: AsRef<Path>
    {
        let img = try!(image::open(path).map_err(|e| e.to_string()));

        let img = match img {
            DynamicImage::ImageRgba8(img) => img,
            img => img.to_rgba()
        };

        let img = if flip == Flip::Vertical {
            image::imageops::flip_vertical(&img)
        } else if flip == Flip::Horizontal {
            image::imageops::flip_horizontal(&img)
        } else {
            img
        };

        Texture::from_image(factory, &img, settings).map_err(
            |e| format!("{:?}", e))
    }

    /// Creates a texture from image.
    pub fn from_image<F>(
        factory: &mut F,
        img: &RgbaImage,
        settings: &TextureSettings
    ) -> Result<Self, CombinedError>
        where F: gfx::Factory<R>
    {
        let (width, height) = img.dimensions();
        CreateTexture::create(factory, Format::Rgba8,
                              img, [width, height], settings)
    }

    /// Creates texture from memory alpha.
    pub fn from_memory_alpha<F>(
        factory: &mut F,
        buffer: &[u8],
        width: u32,
        height: u32,
        settings: &TextureSettings
    ) -> Result<Self, CombinedError>
        where F: gfx::Factory<R>
    {
        if width == 0 || height == 0 {
            return Texture::empty(factory);
        }

        let size = [width, height];
        let buffer = texture::ops::alpha_to_rgba8(buffer, size);
        CreateTexture::create(factory, Format::Rgba8, &buffer, size, settings)
    }

    /// Updates the texture with an image.
    pub fn update<C>(
        &mut self,
        encoder: &mut gfx::Encoder<R, C>,
        img: &RgbaImage
    ) -> Result<(), gfx::UpdateError<[u16; 3]>>
        where C: gfx::CommandBuffer<R>
    {
        let (width, height) = img.dimensions();
        let offset = [0, 0];
        let size = [width, height];
        UpdateTexture::update(self, encoder, Format::Rgba8, img, offset, size)
    }
}

impl<F, R> CreateTexture<F> for Texture<R>
    where F: gfx::Factory<R>,
          R: gfx::Resources
{
    type Error = CombinedError;

    fn create<S: Into<[u32; 2]>>(
        factory: &mut F,
        _format: Format,
        memory: &[u8],
        size: S,
        settings: &TextureSettings
    ) -> Result<Self, Self::Error> {
        // Modified `Factory::create_texture_immutable_u8` for dynamic texture.
        fn create_texture<T, F, R>(
            factory: &mut F,
            kind: gfx::texture::Kind,
            data: &[&[u8]]
        ) -> Result<(
            gfx::handle::Texture<R, T::Surface>,
            gfx::handle::ShaderResourceView<R, T::View>
        ), CombinedError>
            where F: gfx::Factory<R>,
                  R: gfx::Resources,
                  T: gfx::format::TextureFormat
        {
            use gfx::{format, texture};
            use gfx::memory::{Usage, SHADER_RESOURCE};
            use gfx_core::memory::Typed;

            let surface = <T::Surface as format::SurfaceTyped>::get_surface_type();
            let num_slices = kind.get_num_slices().unwrap_or(1) as usize;
            let num_faces = if kind.is_cube() {6} else {1};
            let desc = texture::Info {
                kind: kind,
                levels: (data.len() / (num_slices * num_faces)) as texture::Level,
                format: surface,
                bind: SHADER_RESOURCE,
                usage: Usage::Dynamic,
            };
            let cty = <T::Channel as format::ChannelTyped>::get_channel_type();
            let raw = try!(factory.create_texture_raw(desc, Some(cty), Some(data)));
            let levels = (0, raw.get_info().levels - 1);
            let tex = Typed::new(raw);
            let view = try!(factory.view_texture_as_shader_resource::<T>(
                &tex, levels, format::Swizzle::new()
            ));
            Ok((tex, view))
        }

        let size = size.into();
        let (width, height) = (size[0] as u16, size[1] as u16);
        let tex_kind = gfx::texture::Kind::D2(width, height,
            gfx::texture::AaMode::Single);

        // FIXME Use get_min too. gfx has only one filter setting for both.
        let filter_method = match settings.get_mag() {
            texture::Filter::Nearest => gfx::texture::FilterMethod::Scale,
            texture::Filter::Linear => gfx::texture::FilterMethod::Bilinear,
        };
        let sampler_info = gfx::texture::SamplerInfo::new(
            filter_method,
            gfx::texture::WrapMode::Clamp
        );

        let (surface, view) = try!(create_texture::<Srgba8, F, R>(
            factory, tex_kind, &[memory])
        );
        let sampler = factory.create_sampler(sampler_info);
        Ok(Texture { surface: surface, sampler: sampler, view: view })
    }
}

impl<R, C> UpdateTexture<gfx::Encoder<R, C>> for Texture<R>
    where R: gfx::Resources,
          C: gfx::CommandBuffer<R>
{
    type Error = gfx::UpdateError<[u16; 3]>;

    fn update<O, S>(
        &mut self,
        encoder: &mut gfx::Encoder<R, C>,
        format: Format,
        memory: &[u8],
        offset: O,
        size: S,
    ) -> Result<(), Self::Error>
        where O: Into<[u32; 2]>,
              S: Into<[u32; 2]>,
    {
        let offset = offset.into();
        let size = size.into();
        let tex = &self.surface;
        let face = None;
        let img_info = gfx::texture::ImageInfoCommon {
            xoffset: offset[0] as u16,
            yoffset: offset[1] as u16,
            zoffset: 0,
            width: size[0] as u16,
            height: size[1] as u16,
            depth: 0,
            format: (),
            mipmap: 0,
        };
        let data = gfx::memory::cast_slice(memory);

        match format {
            Format::Rgba8 => {
                use gfx::format::Rgba8;
                encoder.update_texture::<_, Rgba8>(tex, face, img_info, data).map_err(Into::into)
            },
        }
    }
}

impl<R> ImageSize for Texture<R> where R: gfx::Resources {
    #[inline(always)]
    fn get_size(&self) -> (u32, u32) {
        let (w, h, _, _) = self.surface.get_info().kind.get_dimensions();
        (w as u32, h as u32)
    }
}
<|endoftext|>


<commit_before>use super::response::Response;
use super::request::Request;
use super::alloy::Alloy;

/// The Status returned by `Ingot's` `enter` and `exit` methods. This indicates
/// to the `Furnace` whether this is a terminal `Ingot` or whether to continue
/// passing the `Request` and `Response` down the `Furnace's` stack.
///
/// Most `Furnaces` will ignore the returned `Status` from the `exit` method of
/// `Ingots`.
pub enum Status {
    /// `Continue` indicates that this is an intermediate `Ingot` in the stack
    /// and the `Furnace` should continue passing requests down the `Furnace's`
    /// stack.
    ///
    /// Most `Ingots` will return `Continue` from both `enter` and `exit`.
    Continue,

    /// `Unwind` indicates that this is a terminal `Ingot` or something went
    /// wrong. It can be used to immediately stop passing requests down the
    /// `Furnace's` stack and start calling `exit` of all previous `Ingots`.
    ///
    /// For instance, an authorization `Ingot` might return `Unwind` if the
    /// request fails an authentication check, and `Continue` otherwise.
    Unwind
}

pub trait Ingot<Rq: Request, Rs: Response>: Send + Clone {
    fn enter(&mut self, _request: &mut Rq, _response: &mut Rs, _alloy: &mut Alloy) -> Status {
        Continue
    }
    fn exit(&mut self, _request: &mut Rq, _response: &mut Rs, _alloy: &mut Alloy) -> Status {
        Continue
    }
    fn clone_box(&self) -> Box<Ingot<Rq, Rs>> { box self.clone() as Box<Ingot<Rq, Rs>> }
}

impl<Rq: Request, Rs: Response> Clone for Box<Ingot<Rq, Rs>> {
    fn clone(&self) -> Box<Ingot<Rq, Rs>> { self.clone_box() }
}
<commit_msg>(doc) Documented Ingot trait.<commit_after>use super::response::Response;
use super::request::Request;
use super::alloy::Alloy;

/// The Status returned by `Ingot's` `enter` and `exit` methods. This indicates
/// to the `Furnace` whether this is a terminal `Ingot` or whether to continue
/// passing the `Request` and `Response` down the `Furnace's` stack.
///
/// Most `Furnaces` will ignore the returned `Status` from the `exit` method of
/// `Ingots`.
pub enum Status {
    /// `Continue` indicates that this is an intermediate `Ingot` in the stack
    /// and the `Furnace` should continue passing requests down the `Furnace's`
    /// stack.
    ///
    /// Most `Ingots` will return `Continue` from both `enter` and `exit`.
    Continue,

    /// `Unwind` indicates that this is a terminal `Ingot` or something went
    /// wrong. It can be used to immediately stop passing requests down the
    /// `Furnace's` stack and start calling `exit` of all previous `Ingots`.
    ///
    /// For instance, an authorization `Ingot` might return `Unwind` if the
    /// request fails an authentication check, and `Continue` otherwise.
    Unwind
}

/// All middleware should implement `Ingot`, which allows it to be `smelted`
/// to a `Furnace` so that it will be called for each incoming request.
///
/// There are two sorts of data associated with `Ingots`, data internal
/// to the `Ingot` and APIs that the `Ingot` would like to expose to `Ingots`
/// further down the stack or terminal controllers.
///
/// Internal data should be stored on the `struct` that implements `Ingot`
/// itself. All `Ingots` are cloned for each client request, so the object
/// initially smelted on to the `Iron` instance will be provided as `&self` to
/// enter for every request. Data stored on `Ingot` instances does _not_ persist
/// between requests and is _not_ shared between different, concurrent, requests.
/// The same is true for data stored on `Alloys`.
///
/// External data should be stored in the `Alloy` passed to both `enter` and
/// `exit`. `Alloy` is a thin wrapper around `AnyMap` and is effectively a
/// a key value store from a type to an instance of that type. This means
/// that each `Ingot` can have a unique type that it stores in the `Alloy`.
/// This can either be an instance of that `Ingot` or some other type. Since
/// the same `Alloy` is passed to all further `Ingots` in the `Furnace`, this
/// scheme allows you to expose data or functionality to future `Ingots`.
pub trait Ingot<Rq: Request, Rs: Response>: Send + Clone {
    fn enter(&mut self, _request: &mut Rq, _response: &mut Rs, _alloy: &mut Alloy) -> Status {
        Continue
    }
    fn exit(&mut self, _request: &mut Rq, _response: &mut Rs, _alloy: &mut Alloy) -> Status {
        Continue
    }
    fn clone_box(&self) -> Box<Ingot<Rq, Rs>> { box self.clone() as Box<Ingot<Rq, Rs>> }
}

impl<Rq: Request, Rs: Response> Clone for Box<Ingot<Rq, Rs>> {
    fn clone(&self) -> Box<Ingot<Rq, Rs>> { self.clone_box() }
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate url;
extern crate json_flex;

use std::io::Read;

use hyper::Client;
use hyper::client::response::Response;
use hyper::error::Error as HyperError;
use hyper::header::{Connection, ContentType};
use url::form_urlencoded;
use json_flex::{JFObject, Unwrap};

pub struct HTTPRequest {
    client: Client,
}

impl HTTPRequest {
    pub fn new() -> HTTPRequest {
        // Create a client.
        let client = Client::new();
        HTTPRequest{client: client}
    }

    pub fn get(&mut self, url: String)
                   -> Result<Response, HyperError> {
        // Creating an outgoing request.
        let res = self.client.get(&*url)
            .header(Connection::close())
            .send();
        res
    }

    pub fn load(&mut self, url: String, body: &str)
                   -> Result<Response, HyperError> {
        // Creating an loading data request via POST.
        let res = self.client.post(&*url)
            .header(ContentType::json())
            .body(body)
            .send();
        res
    }

    pub fn receive(&mut self, res: &mut Response) -> String {
        // Read the Response.
        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        body
    }
}

pub type Query<'a> = Vec<(&'a str, &'a str)>;

#[derive(Clone, Debug)]
pub struct CommandQuery<'a> {
    command: String,
    arguments: Query<'a>
}

impl<'a> CommandQuery<'a> {
    pub fn new(command: &str) -> CommandQuery {
        let arguments: Query = vec![];
        CommandQuery{command: command.to_string(), arguments: arguments}
    }

    pub fn get_command(&mut self) -> String {
        self.command.clone()
    }

    pub fn set_argument(&mut self, arguments: Query<'a>) {
        self.arguments = arguments
    }

    pub fn make_query(&mut self) -> String {
        form_urlencoded::serialize(self.arguments.clone().into_iter())
    }

    pub fn encode(&mut self) -> String {
        format!("/d/{}?{}", self.get_command(), self.make_query())
    }
}

#[cfg(test)]
mod command_query_test {
    use super::*;

    #[test]
    fn construct_query() {
        let mut command = CommandQuery::new("select");
        command.set_argument(vec![("table", "Site")]);
        let url_encoded = "/d/select?table=Site";
        assert_eq!(url_encoded, command.encode());
    }

    #[test]
    fn construct_complex_query() {
        let mut command = CommandQuery::new("select");
        command.set_argument(vec![("table", "Site"),
                                  ("--query","\'_key:\"http://example.org/\"\'")]);
        let url_encoded = "/d/select?table=Site&--query=%27_key%3A%22http%3A%2F%2Fexample.org%2F%22%27";
        assert_eq!(url_encoded, command.encode());
    }
}

#[derive(Clone, Debug)]
pub struct ResultParser {
    result: Box<JFObject>
}

impl ResultParser {
    pub fn new(json: String) -> ResultParser {
        ResultParser{result: json_flex::decode(json)}
    }

    pub fn get_raw_object(&mut self) -> Box<JFObject> {
        self.result.clone()
    }

    pub fn get_header(&mut self) -> JFObject {
        self.result[0].clone()
    }

    pub fn status(&mut self) -> Option<&i64> {
        self.result[0][0].into_i64()
    }

    pub fn start_time(&mut self) -> Option<&f64> {
        self.result[0][1].into_f64()
    }

    pub fn elapsed_time(&mut self) -> Option<&f64> {
        self.result[0][2].into_f64()
    }

    #[inline]
    fn matched_columns_num(&mut self) -> i64 {
        self.result[1][0][0]
            .unwrap_vec().clone()
            .pop().unwrap()
            .unwrap_i64().clone()
    }

    pub fn matched_columns(&mut self) -> Option<i64> {
        match self.status() {
            Some(&0) => Some(self.matched_columns_num()),
            Some(_) => Some(-1),
            None    => None
        }
    }

    pub fn result(&mut self) -> Option<Vec<JFObject>> {
        match self.status() {
            Some(&0) => Some(vec![self.result[1][0].clone()]),
            Some(_) => Some(vec![self.result[0][3].clone()]),
            None    => None
        }
    }
}

#[cfg(test)]
mod result_parser_test {
    use super::*;

    #[test]
    fn parse_result() {
        let response = "
    [[0,1452348610.39281,0.000101566314697266],
    [[[9],[[\"_id\",\"UInt32\"],[\"_key\",\"ShortText\"],[\"title\",\"ShortText\"]],
    [1,\"http://example.org/\",\"This is test record 1!\"],
    [2,\"http://example.net/\",\"test record 2.\"],
    [3,\"http://example.com/\",\"test test record three.\"],
    [4,\"http://example.net/afr\",\"test record four.\"],
    [5,\"http://example.org/aba\",\"test test test record five.\"],
    [6,\"http://example.com/rab\",\"test test test test record six.\"],
    [7,\"http://example.net/atv\",\"test test test record seven.\"],
    [8,\"http://example.org/gat\",\"test test record eight.\"],
    [9,\"http://example.com/vdw\",\"test test record nine.\"]]]]";
        let mut decode = ResultParser::new(response.to_string());
        assert_eq!(&0, decode.status().unwrap());
        assert_eq!(&1452348610.39281, decode.start_time().unwrap());
        assert_eq!(&0.000101566314697266, decode.elapsed_time().unwrap());
        assert_eq!(9, decode.matched_columns().unwrap());
        let vec = decode.result().unwrap().pop().unwrap().unwrap_vec().clone();
        let expected = r#"Array([Integer(1), String("http://example.org/"), String("This is test record 1!")])"#.to_owned();
        assert_eq!(expected, format!("{:?}", vec[2]))
    }
}
<commit_msg>Treat as None if not success<commit_after>extern crate hyper;
extern crate url;
extern crate json_flex;

use std::io::Read;

use hyper::Client;
use hyper::client::response::Response;
use hyper::error::Error as HyperError;
use hyper::header::{Connection, ContentType};
use url::form_urlencoded;
use json_flex::{JFObject, Unwrap};

pub struct HTTPRequest {
    client: Client,
}

impl HTTPRequest {
    pub fn new() -> HTTPRequest {
        // Create a client.
        let client = Client::new();
        HTTPRequest{client: client}
    }

    pub fn get(&mut self, url: String)
                   -> Result<Response, HyperError> {
        // Creating an outgoing request.
        let res = self.client.get(&*url)
            .header(Connection::close())
            .send();
        res
    }

    pub fn load(&mut self, url: String, body: &str)
                   -> Result<Response, HyperError> {
        // Creating an loading data request via POST.
        let res = self.client.post(&*url)
            .header(ContentType::json())
            .body(body)
            .send();
        res
    }

    pub fn receive(&mut self, res: &mut Response) -> String {
        // Read the Response.
        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        body
    }
}

pub type Query<'a> = Vec<(&'a str, &'a str)>;

#[derive(Clone, Debug)]
pub struct CommandQuery<'a> {
    command: String,
    arguments: Query<'a>
}

impl<'a> CommandQuery<'a> {
    pub fn new(command: &str) -> CommandQuery {
        let arguments: Query = vec![];
        CommandQuery{command: command.to_string(), arguments: arguments}
    }

    pub fn get_command(&mut self) -> String {
        self.command.clone()
    }

    pub fn set_argument(&mut self, arguments: Query<'a>) {
        self.arguments = arguments
    }

    pub fn make_query(&mut self) -> String {
        form_urlencoded::serialize(self.arguments.clone().into_iter())
    }

    pub fn encode(&mut self) -> String {
        format!("/d/{}?{}", self.get_command(), self.make_query())
    }
}

#[cfg(test)]
mod command_query_test {
    use super::*;

    #[test]
    fn construct_query() {
        let mut command = CommandQuery::new("select");
        command.set_argument(vec![("table", "Site")]);
        let url_encoded = "/d/select?table=Site";
        assert_eq!(url_encoded, command.encode());
    }

    #[test]
    fn construct_complex_query() {
        let mut command = CommandQuery::new("select");
        command.set_argument(vec![("table", "Site"),
                                  ("--query","\'_key:\"http://example.org/\"\'")]);
        let url_encoded = "/d/select?table=Site&--query=%27_key%3A%22http%3A%2F%2Fexample.org%2F%22%27";
        assert_eq!(url_encoded, command.encode());
    }
}

#[derive(Clone, Debug)]
pub struct ResultParser {
    result: Box<JFObject>
}

impl ResultParser {
    pub fn new(json: String) -> ResultParser {
        ResultParser{result: json_flex::decode(json)}
    }

    pub fn get_raw_object(&mut self) -> Box<JFObject> {
        self.result.clone()
    }

    pub fn get_header(&mut self) -> JFObject {
        self.result[0].clone()
    }

    pub fn status(&mut self) -> Option<&i64> {
        self.result[0][0].into_i64()
    }

    pub fn start_time(&mut self) -> Option<&f64> {
        self.result[0][1].into_f64()
    }

    pub fn elapsed_time(&mut self) -> Option<&f64> {
        self.result[0][2].into_f64()
    }

    #[inline]
    fn matched_columns_num(&mut self) -> i64 {
        self.result[1][0][0]
            .unwrap_vec().clone()
            .pop().unwrap()
            .unwrap_i64().clone()
    }

    pub fn matched_columns(&mut self) -> Option<i64> {
        match self.status() {
            Some(&0) => Some(self.matched_columns_num()),
            Some(_) => None,
            None    => None
        }
    }

    pub fn result(&mut self) -> Option<Vec<JFObject>> {
        match self.status() {
            Some(&0) => Some(vec![self.result[1][0].clone()]),
            Some(_) => Some(vec![self.result[0][3].clone()]),
            None    => None
        }
    }
}

#[cfg(test)]
mod result_parser_test {
    use super::*;

    #[test]
    fn parse_result() {
        let response = "
    [[0,1452348610.39281,0.000101566314697266],
    [[[9],[[\"_id\",\"UInt32\"],[\"_key\",\"ShortText\"],[\"title\",\"ShortText\"]],
    [1,\"http://example.org/\",\"This is test record 1!\"],
    [2,\"http://example.net/\",\"test record 2.\"],
    [3,\"http://example.com/\",\"test test record three.\"],
    [4,\"http://example.net/afr\",\"test record four.\"],
    [5,\"http://example.org/aba\",\"test test test record five.\"],
    [6,\"http://example.com/rab\",\"test test test test record six.\"],
    [7,\"http://example.net/atv\",\"test test test record seven.\"],
    [8,\"http://example.org/gat\",\"test test record eight.\"],
    [9,\"http://example.com/vdw\",\"test test record nine.\"]]]]";
        let mut decode = ResultParser::new(response.to_string());
        assert_eq!(&0, decode.status().unwrap());
        assert_eq!(&1452348610.39281, decode.start_time().unwrap());
        assert_eq!(&0.000101566314697266, decode.elapsed_time().unwrap());
        assert_eq!(9, decode.matched_columns().unwrap());
        let vec = decode.result().unwrap().pop().unwrap().unwrap_vec().clone();
        let expected = r#"Array([Integer(1), String("http://example.org/"), String("This is test record 1!")])"#.to_owned();
        assert_eq!(expected, format!("{:?}", vec[2]))
    }
}
<|endoftext|>


<commit_before>// Module for parsing ISO Base Media Format aka video/mp4 streams.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

/// Basic ISO box structure.
pub struct BoxHeader {
    /// Four character box type
pub name: u32,
    /// Size of the box in bytes
pub size: u64,
    /// Offset to the start of the contained data (or header size).
pub offset: u64,
}

/// File type box 'ftyp'.
pub struct FileTypeBox {
    name: u32,
    size: u64,
    major_brand: u32,
    minor_version: u32,
    compatible_brands: Vec<u32>,
}

/// Movie header box 'mvhd'.
pub struct MovieHeaderBox {
    pub name: u32,
    pub size: u64,
    pub timescale: u32,
    pub duration: u64,
    // Ignore other fields.
}

pub struct TrackHeaderBox {
    pub name: u32,
    pub size: u64,
    pub track_id: u32,
    pub duration: u64,
    pub width: u32,
    pub height: u32,
}

extern crate byteorder;
use byteorder::{BigEndian, ReadBytesExt};
use std::io::{Error, ErrorKind, Read, Result, Seek, SeekFrom, Take};
use std::io::Cursor;

/// Parse a box out of a data buffer.
pub fn read_box_header<T: ReadBytesExt>(src: &mut T) -> Result<BoxHeader> {
    let tmp_size = try!(src.read_u32::<BigEndian>());
    let name = try!(src.read_u32::<BigEndian>());
    let size = match tmp_size {
        1 => try!(src.read_u64::<BigEndian>()),
        _ => tmp_size as u64,
    };
    assert!(size >= 8);
    if tmp_size == 1 {
        assert!(size >= 16);
    }
    let offset = match tmp_size {
        1 => 4 + 4 + 8,
        _ => 4 + 4,
    };
    assert!(offset <= size);
    Ok(BoxHeader{
      name: name,
      size: size,
      offset: offset,
    })
}

/// Parse the extra header fields for a full box.
fn read_fullbox_extra<T: ReadBytesExt>(src: &mut T) -> (u8, u32) {
    let version = src.read_u8().unwrap();
    let flags_a = src.read_u8().unwrap();
    let flags_b = src.read_u8().unwrap();
    let flags_c = src.read_u8().unwrap();
    (version, (flags_a as u32) << 16 |
              (flags_b as u32) <<  8 |
              (flags_c as u32))
}

/// Skip over the contents of a box.
pub fn skip_box_content<T: ReadBytesExt + Seek>
  (src: &mut T, header: &BoxHeader)
  -> std::io::Result<u64>
{
    src.seek(SeekFrom::Current((header.size - header.offset) as i64))
}

/// Helper to construct a Take over the contents of a box.
fn limit<'a, T: Read>(f: &'a mut T, h: &BoxHeader) -> Take<&'a mut T> {
    f.take(h.size - h.offset)
}

/// Helper to construct a Cursor over the contents of a box.
fn recurse<T: Read>(f: &mut T, h: &BoxHeader) -> Result<()> {
    println!("{} -- recursing", h);
    // FIXME: I couldn't figure out how to do this without copying.
    // We use Seek on the Read we return in skip_box_content, but
    // that trait isn't implemented for a Take like our limit()
    // returns. Slurping the buffer and wrapping it in a Cursor
    // functions as a work around.
    let buf: Vec<u8> = limit(f, &h)
        .bytes()
        .map(|u| u.unwrap())
        .collect();
    let mut content = Cursor::new(buf);
    loop {
        match read_box(&mut content) {
            Ok(_) => {},
            Err(e) => {
                println!("Error '{:?}' reading box", e.kind());
                return Err(e);
            },
        }
    }
    println!("{} -- end", h);
    Ok(())
}

/// Read the contents of a box, including sub boxes.
/// Right now it just prints the box value rather than
/// returning anything.
pub fn read_box<T: Read + Seek>(f: &mut T) -> Result<()> {
    read_box_header(f).and_then(|h| {
        match &(fourcc_to_string(h.name))[..] {
            "ftyp" => {
                let mut content = limit(f, &h);
                let ftyp = try!(read_ftyp(&mut content, &h));
                println!("{}", ftyp);
            },
            "moov" => try!(recurse(f, &h)),
            "mvhd" => {
                let mut content = limit(f, &h);
                let mvhd = try!(read_mvhd(&mut content, &h));
                println!("  {}", mvhd);
            },
            "trak" => try!(recurse(f, &h)),
            "tkhd" => {
                let mut content = limit(f, &h);
                let tkhd = try!(read_tkhd(&mut content, &h));
                println!("  {}", tkhd);
            },
            _ => {
                // Skip the contents of unknown chunks.
                println!("{} (skipped)", h);
                try!(skip_box_content(f, &h).and(Ok(())));
            },
        };
        Ok(()) // and_then needs a Result to return.
    })
}

/// Entry point for C language callers.
/// Take a buffer and call read_box() on it.
#[no_mangle]
pub unsafe extern fn read_box_from_buffer(buffer: *const u8, size: usize)
  -> bool {
    use std::slice;
    use std::thread;

    // Validate arguments from C.
    if buffer.is_null() || size < 8 {
        return false;
    }

    // Wrap the buffer we've been give in a slice.
    let b = slice::from_raw_parts(buffer, size);
    let mut c = Cursor::new(b);

    // Parse in a subthread.
    let task = thread::spawn(move || {
        read_box(&mut c).unwrap();
    });
    // Catch any panics.
    task.join().is_ok()
}

/// Parse an ftype box.
pub fn read_ftyp<T: ReadBytesExt>(src: &mut T, head: &BoxHeader)
  -> Result<FileTypeBox> {
    let major = try!(src.read_u32::<BigEndian>());
    let minor = try!(src.read_u32::<BigEndian>());
    let brand_count = (head.size - 8 - 8) /4;
    let mut brands = Vec::new();
    for _ in 0..brand_count {
        brands.push( try!(src.read_u32::<BigEndian>()) );
    }
    Ok(FileTypeBox{
        name: head.name,
        size: head.size,
        major_brand: major,
        minor_version: minor,
        compatible_brands: brands,
    })
}

/// Parse an mvhd box.
pub fn read_mvhd<T: ReadBytesExt>(src: &mut T, head: &BoxHeader)
  -> Result<MovieHeaderBox> {
    let (version, _) = read_fullbox_extra(src);
    match version {
        1 => {
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 16];
            let r = try!(src.read(&mut skip));
            assert!(r == skip.len());
        },
        0 => {
            // 32 bit creation and modification times.
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 8];
            let r = try!(src.read(&mut skip));
            assert!(r == skip.len());
        },
        _ => panic!("invalid mhdr version"),
    }
    let timescale = src.read_u32::<BigEndian>().unwrap();
    let duration = match version {
        1 => try!(src.read_u64::<BigEndian>()),
        0 => try!(src.read_u32::<BigEndian>()) as u64,
        _ => panic!("invalid mhdr version"),
    };
    // Skip remaining fields.
    let mut skip: Vec<u8> = vec![0; 80];
    let r = try!(src.read(&mut skip));
    assert!(r == skip.len());
    Ok(MovieHeaderBox {
        name: head.name,
        size: head.size,
        timescale: timescale,
        duration: duration,
    })
}

/// Parse a tkhd box.
pub fn read_tkhd<T: ReadBytesExt>(src: &mut T, head: &BoxHeader)
  -> Result<TrackHeaderBox> {
    let (version, flags) = read_fullbox_extra(src);
    if flags & 0x1u32 == 0 || flags & 0x2u32 == 0 {
        return Err(Error::new(ErrorKind::Other, "Track is disabled"));
    }
    match version {
        1 => {
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 16];
            let r = try!(src.read(&mut skip));
            assert!(r == skip.len());
        },
        0 => {
            // 32 bit creation and modification times.
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 8];
            let r = try!(src.read(&mut skip));
            assert!(r == skip.len());
        },
        _ => panic!("invalid tkhd version"),
    }
    let track_id = try!(src.read_u32::<BigEndian>());
    let _reserved = try!(src.read_u32::<BigEndian>());
    assert!(_reserved == 0);
    let duration = match version {
        1 => {
            try!(src.read_u64::<BigEndian>())
        },
        0 => try!(src.read_u32::<BigEndian>()) as u64,
        _ => panic!("invalid tkhd version"),
    };
    let _reserved = try!(src.read_u32::<BigEndian>());
    let _reserved = try!(src.read_u32::<BigEndian>());
    // Skip uninterested fields.
    let mut skip: Vec<u8> = vec![0; 44];
    let r = try!(src.read(&mut skip));
    assert!(r == skip.len());
    let width = try!(src.read_u32::<BigEndian>());
    let height = try!(src.read_u32::<BigEndian>());
    Ok(TrackHeaderBox {
        name: head.name,
        size: head.size,
        track_id: track_id,
        duration: duration,
        width: width,
        height: height,
    })
}

/// Convert the iso box type or other 4-character value to a string.
fn fourcc_to_string(name: u32) -> String {
    let u32_to_vec = |u| {
        vec!((u >> 24 & 0xffu32) as u8,
             (u >> 16 & 0xffu32) as u8,
             (u >>  8 & 0xffu32) as u8,
             (u & 0xffu32) as u8)
    };
    let name_bytes = u32_to_vec(name);
    String::from_utf8_lossy(&name_bytes).into_owned()
}

use std::fmt;
impl fmt::Display for BoxHeader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "'{}' {} bytes", fourcc_to_string(self.name), self.size)
    }
}

impl fmt::Display for FileTypeBox {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = fourcc_to_string(self.name);
        let brand = fourcc_to_string(self.major_brand);
        write!(f, "'{}' {} bytes '{}' v{}", name, self.size,
            brand, self.minor_version)
    }
}

impl fmt::Display for MovieHeaderBox {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = fourcc_to_string(self.name);
        write!(f, "'{}' {} bytes duration {}s", name, self.size,
            (self.duration as f64)/(self.timescale as f64))
    }
}

use std::u16;
impl fmt::Display for TrackHeaderBox {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = fourcc_to_string(self.name);
        // Dimensions are 16.16 fixed-point.
        let base = u16::MAX as f64 + 1.0;
        let width = (self.width as f64) / base;
        let height = (self.height as f64) / base;
        write!(f, "'{}' {} bytes duration {} id {} {}x{}",
            name, self.size, self.duration, self.track_id,
            width, height)
    }
}

#[test]
fn test_read_box_header() {
    use std::io::Cursor;
    use std::io::Write;
    let mut test: Vec<u8> = vec![0, 0, 0, 8];  // minimal box length
    write!(&mut test, "test").unwrap(); // box type
    let mut stream = Cursor::new(test);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, 1952805748);
    assert_eq!(parsed.size, 8);
    println!("box {}", parsed);
}

#[test]
fn test_read_box_header_long() {
    use std::io::Cursor;
    let mut test: Vec<u8> = vec![0, 0, 0, 1]; // long box extension code
    test.extend("long".to_string().into_bytes()); // box type
    test.extend(vec![0, 0, 0, 0, 0, 0, 16, 0]); // 64 bit size
    // Skip generating box content.
    let mut stream = Cursor::new(test);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, 1819242087);
    assert_eq!(parsed.size, 4096);
    println!("box {}", parsed);
}

#[test]
fn test_read_ftyp() {
    use std::io::Cursor;
    use std::io::Write;
    let mut test: Vec<u8> = vec![0, 0, 0, 24]; // size
    write!(&mut test, "ftyp").unwrap(); // type
    write!(&mut test, "mp42").unwrap(); // major brand
    test.extend(vec![0, 0, 0, 0]);      // minor version
    write!(&mut test, "isom").unwrap(); // compatible brands...
    write!(&mut test, "mp42").unwrap();
    assert_eq!(test.len(), 24);

    let mut stream = Cursor::new(test);
    let header = read_box_header(&mut stream).unwrap();
    let parsed = read_ftyp(&mut stream, &header).unwrap();
    assert_eq!(parsed.name, 1718909296);
    assert_eq!(parsed.size, 24);
    assert_eq!(parsed.major_brand, 1836069938);
    assert_eq!(parsed.minor_version, 0);
    assert_eq!(parsed.compatible_brands.len(), 2);
    println!("box {}", parsed);
}
<commit_msg>Return byteorder::Result instead of io::Result.<commit_after>// Module for parsing ISO Base Media Format aka video/mp4 streams.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

/// Basic ISO box structure.
pub struct BoxHeader {
    /// Four character box type
pub name: u32,
    /// Size of the box in bytes
pub size: u64,
    /// Offset to the start of the contained data (or header size).
pub offset: u64,
}

/// File type box 'ftyp'.
pub struct FileTypeBox {
    name: u32,
    size: u64,
    major_brand: u32,
    minor_version: u32,
    compatible_brands: Vec<u32>,
}

/// Movie header box 'mvhd'.
pub struct MovieHeaderBox {
    pub name: u32,
    pub size: u64,
    pub timescale: u32,
    pub duration: u64,
    // Ignore other fields.
}

pub struct TrackHeaderBox {
    pub name: u32,
    pub size: u64,
    pub track_id: u32,
    pub duration: u64,
    pub width: u32,
    pub height: u32,
}

extern crate byteorder;
use byteorder::{BigEndian, ReadBytesExt};
use std::io::{Error, ErrorKind, Read, Seek, SeekFrom, Take};
use std::io::Cursor;

/// Parse a box out of a data buffer.
pub fn read_box_header<T: ReadBytesExt>(src: &mut T) -> byteorder::Result<BoxHeader> {
    let tmp_size = try!(src.read_u32::<BigEndian>());
    let name = try!(src.read_u32::<BigEndian>());
    let size = match tmp_size {
        1 => try!(src.read_u64::<BigEndian>()),
        _ => tmp_size as u64,
    };
    assert!(size >= 8);
    if tmp_size == 1 {
        assert!(size >= 16);
    }
    let offset = match tmp_size {
        1 => 4 + 4 + 8,
        _ => 4 + 4,
    };
    assert!(offset <= size);
    Ok(BoxHeader{
      name: name,
      size: size,
      offset: offset,
    })
}

/// Parse the extra header fields for a full box.
fn read_fullbox_extra<T: ReadBytesExt>(src: &mut T) -> (u8, u32) {
    let version = src.read_u8().unwrap();
    let flags_a = src.read_u8().unwrap();
    let flags_b = src.read_u8().unwrap();
    let flags_c = src.read_u8().unwrap();
    (version, (flags_a as u32) << 16 |
              (flags_b as u32) <<  8 |
              (flags_c as u32))
}

/// Skip over the contents of a box.
pub fn skip_box_content<T: ReadBytesExt + Seek>
  (src: &mut T, header: &BoxHeader)
  -> std::io::Result<u64>
{
    src.seek(SeekFrom::Current((header.size - header.offset) as i64))
}

/// Helper to construct a Take over the contents of a box.
fn limit<'a, T: Read>(f: &'a mut T, h: &BoxHeader) -> Take<&'a mut T> {
    f.take(h.size - h.offset)
}

/// Helper to construct a Cursor over the contents of a box.
fn recurse<T: Read>(f: &mut T, h: &BoxHeader) -> byteorder::Result<()> {
    println!("{} -- recursing", h);
    // FIXME: I couldn't figure out how to do this without copying.
    // We use Seek on the Read we return in skip_box_content, but
    // that trait isn't implemented for a Take like our limit()
    // returns. Slurping the buffer and wrapping it in a Cursor
    // functions as a work around.
    let buf: Vec<u8> = limit(f, &h)
        .bytes()
        .map(|u| u.unwrap())
        .collect();
    let mut content = Cursor::new(buf);
    loop {
        match read_box(&mut content) {
            Ok(_) => {},
            Err(byteorder::Error::UnexpectedEOF) => {
                // byteorder returns EOF at the end of the buffer.
                // This isn't an error for us, just an signal to
                // stop recursion.
                break;
            },
            Err(byteorder::Error::Io(e)) => {
                println!("Error '{:?}' reading box", e.kind());
                return Err(byteorder::Error::Io(e));
            },
        }
    }
    println!("{} -- end", h);
    Ok(())
}

/// Read the contents of a box, including sub boxes.
/// Right now it just prints the box value rather than
/// returning anything.
pub fn read_box<T: Read + Seek>(f: &mut T) -> byteorder::Result<()> {
    read_box_header(f).and_then(|h| {
        match &(fourcc_to_string(h.name))[..] {
            "ftyp" => {
                let mut content = limit(f, &h);
                let ftyp = try!(read_ftyp(&mut content, &h));
                println!("{}", ftyp);
            },
            "moov" => try!(recurse(f, &h)),
            "mvhd" => {
                let mut content = limit(f, &h);
                let mvhd = try!(read_mvhd(&mut content, &h));
                println!("  {}", mvhd);
            },
            "trak" => try!(recurse(f, &h)),
            "tkhd" => {
                let mut content = limit(f, &h);
                let tkhd = try!(read_tkhd(&mut content, &h));
                println!("  {}", tkhd);
            },
            _ => {
                // Skip the contents of unknown chunks.
                println!("{} (skipped)", h);
                try!(skip_box_content(f, &h).and(Ok(())));
            },
        };
        Ok(()) // and_then needs a Result to return.
    })
}

/// Entry point for C language callers.
/// Take a buffer and call read_box() on it.
#[no_mangle]
pub unsafe extern fn read_box_from_buffer(buffer: *const u8, size: usize)
  -> bool {
    use std::slice;
    use std::thread;

    // Validate arguments from C.
    if buffer.is_null() || size < 8 {
        return false;
    }

    // Wrap the buffer we've been give in a slice.
    let b = slice::from_raw_parts(buffer, size);
    let mut c = Cursor::new(b);

    // Parse in a subthread.
    let task = thread::spawn(move || {
        read_box(&mut c).unwrap();
    });
    // Catch any panics.
    task.join().is_ok()
}

/// Parse an ftype box.
pub fn read_ftyp<T: ReadBytesExt>(src: &mut T, head: &BoxHeader)
  -> byteorder::Result<FileTypeBox> {
    let major = try!(src.read_u32::<BigEndian>());
    let minor = try!(src.read_u32::<BigEndian>());
    let brand_count = (head.size - 8 - 8) /4;
    let mut brands = Vec::new();
    for _ in 0..brand_count {
        brands.push( try!(src.read_u32::<BigEndian>()) );
    }
    Ok(FileTypeBox{
        name: head.name,
        size: head.size,
        major_brand: major,
        minor_version: minor,
        compatible_brands: brands,
    })
}

/// Parse an mvhd box.
pub fn read_mvhd<T: ReadBytesExt>(src: &mut T, head: &BoxHeader)
  -> byteorder::Result<MovieHeaderBox> {
    let (version, _) = read_fullbox_extra(src);
    match version {
        1 => {
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 16];
            let r = try!(src.read(&mut skip));
            assert!(r == skip.len());
        },
        0 => {
            // 32 bit creation and modification times.
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 8];
            let r = try!(src.read(&mut skip));
            assert!(r == skip.len());
        },
        _ => panic!("invalid mhdr version"),
    }
    let timescale = src.read_u32::<BigEndian>().unwrap();
    let duration = match version {
        1 => try!(src.read_u64::<BigEndian>()),
        0 => try!(src.read_u32::<BigEndian>()) as u64,
        _ => panic!("invalid mhdr version"),
    };
    // Skip remaining fields.
    let mut skip: Vec<u8> = vec![0; 80];
    let r = try!(src.read(&mut skip));
    assert!(r == skip.len());
    Ok(MovieHeaderBox {
        name: head.name,
        size: head.size,
        timescale: timescale,
        duration: duration,
    })
}

/// Parse a tkhd box.
pub fn read_tkhd<T: ReadBytesExt>(src: &mut T, head: &BoxHeader)
  -> byteorder::Result<TrackHeaderBox> {
    let (version, flags) = read_fullbox_extra(src);
    if flags & 0x1u32 == 0 || flags & 0x2u32 == 0 {
        return Err(byteorder::Error::Io(
            Error::new(ErrorKind::Other, "Track is disabled")
        ));
    }
    match version {
        1 => {
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 16];
            let r = try!(src.read(&mut skip));
            assert!(r == skip.len());
        },
        0 => {
            // 32 bit creation and modification times.
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 8];
            let r = try!(src.read(&mut skip));
            assert!(r == skip.len());
        },
        _ => panic!("invalid tkhd version"),
    }
    let track_id = try!(src.read_u32::<BigEndian>());
    let _reserved = try!(src.read_u32::<BigEndian>());
    assert!(_reserved == 0);
    let duration = match version {
        1 => {
            try!(src.read_u64::<BigEndian>())
        },
        0 => try!(src.read_u32::<BigEndian>()) as u64,
        _ => panic!("invalid tkhd version"),
    };
    let _reserved = try!(src.read_u32::<BigEndian>());
    let _reserved = try!(src.read_u32::<BigEndian>());
    // Skip uninterested fields.
    let mut skip: Vec<u8> = vec![0; 44];
    let r = try!(src.read(&mut skip));
    assert!(r == skip.len());
    let width = try!(src.read_u32::<BigEndian>());
    let height = try!(src.read_u32::<BigEndian>());
    Ok(TrackHeaderBox {
        name: head.name,
        size: head.size,
        track_id: track_id,
        duration: duration,
        width: width,
        height: height,
    })
}

/// Convert the iso box type or other 4-character value to a string.
fn fourcc_to_string(name: u32) -> String {
    let u32_to_vec = |u| {
        vec!((u >> 24 & 0xffu32) as u8,
             (u >> 16 & 0xffu32) as u8,
             (u >>  8 & 0xffu32) as u8,
             (u & 0xffu32) as u8)
    };
    let name_bytes = u32_to_vec(name);
    String::from_utf8_lossy(&name_bytes).into_owned()
}

use std::fmt;
impl fmt::Display for BoxHeader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "'{}' {} bytes", fourcc_to_string(self.name), self.size)
    }
}

impl fmt::Display for FileTypeBox {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = fourcc_to_string(self.name);
        let brand = fourcc_to_string(self.major_brand);
        write!(f, "'{}' {} bytes '{}' v{}", name, self.size,
            brand, self.minor_version)
    }
}

impl fmt::Display for MovieHeaderBox {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = fourcc_to_string(self.name);
        write!(f, "'{}' {} bytes duration {}s", name, self.size,
            (self.duration as f64)/(self.timescale as f64))
    }
}

use std::u16;
impl fmt::Display for TrackHeaderBox {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = fourcc_to_string(self.name);
        // Dimensions are 16.16 fixed-point.
        let base = u16::MAX as f64 + 1.0;
        let width = (self.width as f64) / base;
        let height = (self.height as f64) / base;
        write!(f, "'{}' {} bytes duration {} id {} {}x{}",
            name, self.size, self.duration, self.track_id,
            width, height)
    }
}

#[test]
fn test_read_box_header() {
    use std::io::Cursor;
    use std::io::Write;
    let mut test: Vec<u8> = vec![0, 0, 0, 8];  // minimal box length
    write!(&mut test, "test").unwrap(); // box type
    let mut stream = Cursor::new(test);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, 1952805748);
    assert_eq!(parsed.size, 8);
    println!("box {}", parsed);
}

#[test]
fn test_read_box_header_long() {
    use std::io::Cursor;
    let mut test: Vec<u8> = vec![0, 0, 0, 1]; // long box extension code
    test.extend("long".to_string().into_bytes()); // box type
    test.extend(vec![0, 0, 0, 0, 0, 0, 16, 0]); // 64 bit size
    // Skip generating box content.
    let mut stream = Cursor::new(test);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, 1819242087);
    assert_eq!(parsed.size, 4096);
    println!("box {}", parsed);
}

#[test]
fn test_read_ftyp() {
    use std::io::Cursor;
    use std::io::Write;
    let mut test: Vec<u8> = vec![0, 0, 0, 24]; // size
    write!(&mut test, "ftyp").unwrap(); // type
    write!(&mut test, "mp42").unwrap(); // major brand
    test.extend(vec![0, 0, 0, 0]);      // minor version
    write!(&mut test, "isom").unwrap(); // compatible brands...
    write!(&mut test, "mp42").unwrap();
    assert_eq!(test.len(), 24);

    let mut stream = Cursor::new(test);
    let header = read_box_header(&mut stream).unwrap();
    let parsed = read_ftyp(&mut stream, &header).unwrap();
    assert_eq!(parsed.name, 1718909296);
    assert_eq!(parsed.size, 24);
    assert_eq!(parsed.major_brand, 1836069938);
    assert_eq!(parsed.minor_version, 0);
    assert_eq!(parsed.compatible_brands.len(), 2);
    println!("box {}", parsed);
}
<|endoftext|>


<commit_before>/*!
Simple persistent generic HashMap/Key-value store.

Basic usage:

```
extern crate kv_cab;

use kv_cab::{ KV, Value };

fn main() {
    let mut test_store = KV::<String, Value>::new("./db.cab").unwrap();

    let _ = test_store.insert("key".to_string(), Value::String("value".to_string()));
    println!("{:?}", test_store.get("key".to_string()));
    let _ = test_store.remove("key".to_string());
}
```

Usage with user defined Key and Value types:

```
extern crate kv_cab;
extern crate rustc_serialize;

use kv_cab::KV;

#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash)]
enum MyKey {
    String(String),
    Int(i32),
}

#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
enum MyValue {
    String(String),
    Int(i32),
}

fn main() {
    let mut test_store = KV::<MyKey, MyValue>::new("./db.cab").unwrap();

    let _ = test_store.insert(MyKey::Int(1i32), MyValue::String("value".to_string()));
    println!("{:?}", test_store.get(MyKey::Int(1i32)));
    let _ = test_store.remove(MyKey::Int(1i32));
}
```

*/

extern crate bincode;
extern crate rustc_serialize;
#[macro_use]
extern crate log;

use std::collections::HashMap;
use std::fs;
use std::fs::{ File, OpenOptions };
use std::io::prelude::*;
use std::hash::Hash;

use bincode::SizeLimit;
use bincode::rustc_serialize::{ encode, decode };

use rustc_serialize::{ Encodable, Decodable };

/// The maximum number of retries the cab will make
const MAX_RETRIES:i32 = 10;

/// Definition of a macro for retrying an operation
macro_rules! retry {
    ($i:ident, $b:block) => (
        for $i in 0..MAX_RETRIES {
            if $i != 0 {
                std::thread::park_timeout(std::time::Duration::new(0u64, 1000u32));
            }

            $b
        }
    )
}

/// A default value type to use with KV
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
pub enum Value {
    String(String),
    Int(i32),
    Float(f32),
    Map(HashMap<String, Value>),
}

/// Type alias for results from KV
type KVResult = Result<bool, KVError>;

/// Errors that KV might have
#[derive(Debug, PartialEq)]
pub enum KVError {
    CabEmpty,
    CouldntDecode,
    DoesntExistOrNotReadable,
    CouldntEncode,
    CouldntWrite,
    CouldntSetPermissions,
    CoudlntGetPermissions,
    FailedToRead,
}

/// The type that represents the key-value store
pub struct KV<K,V> {
    cab: HashMap<K, V>,
    file: File,
}

impl<K: Clone + Encodable + Decodable + Eq + Hash, V: Clone + Encodable + Decodable> KV<K,V> {
    /// Creates a new instance of the KV store
    pub fn new(p:&'static str) -> Result<KV<K,V>, KVError> {
        // create the KV instance
        let mut store = KV {
            cab: HashMap::new(),
            file: KV::<K, V>::retry_get_file(p),
        };

        // lock the cab for writes
        if let Err(e) = store.lock_cab(true) {
            return Err(e);
        }

        match store.load_from_persist() {
            Ok(f) => trace!("{}", f),
            Err(e) => {
                if e == KVError::CouldntDecode {
                    return Err(e);
                }
                warn!("{:?}", e);
            },
        };

        Ok(store)
    }

    /// Sets file permission for a path to not be readonly
    fn set_path_permission(p: &'static str) {
        match fs::metadata(p) {
            Ok(f) => {
                let mut perms = f.permissions();
                perms.set_readonly(false);

                match fs::set_permissions(p, perms) {
                    Ok(_) => (),
                    Err(e) => {
                        error!("{}", e);
                    }
                }
            },
            Err(e) => {
                if e.kind() != std::io::ErrorKind::NotFound {
                    error!("{}", e);
                }
            },
        }
    }

    /// Retry to get a reference to the cab file at path p and create if doesn't exist
    fn retry_get_file(p:&'static str) -> File {
        retry!(i, {
            match OpenOptions::new().read(true).write(true).create(true).open(p) {
                Ok(f) => { return f; },
                Err(e) => {
                    error!("{}", e);
                    if i >= MAX_RETRIES - 1 {
                        panic!("Could not open file after retries");
                    }

                    KV::<K, V>::set_path_permission(p);
                    continue;
                }
            };

        });
        panic!("retry_get_file: Failed to get file");
    }

    /// Inserta a key, value pair into the key-value store
    pub fn insert(&mut self, key: K, value: V) -> KVResult {
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist() {
            return Err(e);
        }
        // insert into the HashMap
        self.cab.insert(key, value);
        // persist
        self.write_to_persist()
    }

    /// Get the value from a key
    pub fn get(&mut self, key: K) -> Result<Option<V>, KVError> {
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist() {
            return Err(e);
        }
        // get the value from the cab
        match self.cab.get(&key) {
            Some(v) => Ok(Some((*v).clone())),
            None => Ok(None),
        }
    }

    /// Removes a key and associated value from the key-value Store
    pub fn remove(&mut self, key: K) -> KVResult {
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist() {
            return Err(e);
        }
        // remove from the HashMap
        self.cab.remove(&key);
        // persist
        self.write_to_persist()
    }

    /// get all the keys contained in the KV Store
    pub fn keys(&mut self) -> Result<Vec<K>, KVError> {
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist() {
            return Err(e);
        }
        // create a vec from the cabs keys
        Ok(self.cab.keys().map(|k| k.clone()).collect())
    }

    /// Locks/unlocks cab for writing purposes
    fn lock_cab(&mut self, readonly:bool) -> KVResult {
        retry!(i, {
            // set not readonly while writing
            let mut perms = match self.file.metadata() {
                Ok(f) => f.permissions(),
                Err(e) => {
                    error!("{}", e);
                    if i >= MAX_RETRIES - 1 {
                        return Err(KVError::CoudlntGetPermissions);
                    }
                    continue;
                },
            };
            perms.set_readonly(readonly);

            match self.file.set_permissions(perms) {
                Ok(_) => {
                    let _ = self.file.sync_all();
                    break;
                },
                Err(e) => {
                    error!("{}", e);
                    if i >= MAX_RETRIES - 1 {
                        return Err(KVError::CouldntSetPermissions);
                    }
                    continue;
                },
            }
        });

        Ok(true)
    }

    /// Waits for the cab to become free
    fn wait_for_free(&mut self, lock:bool) -> KVResult {
        loop {
            // check if the cab is being written to
            let _ = self.file.sync_all();
            let metadata = match self.file.metadata() {
                Ok(m) => m,
                Err(_) => return Err(KVError::DoesntExistOrNotReadable),
            };

            if metadata.permissions().readonly() {
                if lock {
                    if let Err(e) = self.lock_cab(false) {
                        return Err(e);
                    }
                }
                break;
            }
        }

        Ok(true)
    }

    /// Writes the key-value Store to file
    fn write_to_persist(&mut self) -> KVResult {
        // encode the cab as a u8 vec
        let byte_vec: Vec<u8> = match encode(&mut self.cab, SizeLimit::Infinite) {
            Ok(bv) => bv,
            Err(e) => {
                error!("encode: {}", e);
                return Err(KVError::CouldntEncode);
            },
        };

        if !self.wait_for_free(true).is_ok() {
            return Err(KVError::DoesntExistOrNotReadable);
        }
        // attempt to write to the cab
        retry!(i, {
            // write the bytes to it
            match self.file.write_all(byte_vec.as_slice()) {
                Ok(_) => (),
                Err(e) => {
                    error!("file.write_all/retry: {}", e);
                    if i >= MAX_RETRIES - 1 {
                        panic!(KVError::CouldntWrite);
                    }
                    continue;
                },
            }

            // flush to disk
            let _ = self.file.flush();
            if let Err(e) = self.lock_cab(true) {
                if i >= MAX_RETRIES - 1 {
                    return Err(e);
                }
                error!("{:?}", e);
            }

            // leave the retry loop as successful
            break;
        });

        Ok(true)
    }

    /// Loads key-value store from file
    fn load_from_persist(&mut self) -> KVResult {
        // byte vec to read into
        let mut byte_vec = Vec::new();

        // wait/lock the cab and read the bytes
        if !self.wait_for_free(false).is_ok() {
            return Err(KVError::DoesntExistOrNotReadable);
        }
        match self.file.read_to_end(&mut byte_vec) {
            Ok(count) => {
                if count == 0 {
                    return Err(KVError::CabEmpty);
                }
            },
            Err(e) => {
                error!("{}", e);
                return Err(KVError::FailedToRead);
            },
        }

        // decode u8 vec back into HashMap
        let decoded: HashMap<K, V> = match decode(byte_vec.as_slice()) {
            Ok(f) => f,
            Err(e) => {
                error!("{}", e);
                return Err(KVError::CouldntDecode);
            },
        };
        // assign read HashMap back to self
        self.cab = decoded;

        Ok(true)
    }
}
<commit_msg>Errors around syncing file metadata and flushing to file<commit_after>/*!
Simple persistent generic HashMap/Key-value store.

Basic usage:

```
extern crate kv_cab;

use kv_cab::{ KV, Value };

fn main() {
    let mut test_store = KV::<String, Value>::new("./db.cab").unwrap();

    let _ = test_store.insert("key".to_string(), Value::String("value".to_string()));
    println!("{:?}", test_store.get("key".to_string()));
    let _ = test_store.remove("key".to_string());
}
```

Usage with user defined Key and Value types:

```
extern crate kv_cab;
extern crate rustc_serialize;

use kv_cab::KV;

#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash)]
enum MyKey {
    String(String),
    Int(i32),
}

#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
enum MyValue {
    String(String),
    Int(i32),
}

fn main() {
    let mut test_store = KV::<MyKey, MyValue>::new("./db.cab").unwrap();

    let _ = test_store.insert(MyKey::Int(1i32), MyValue::String("value".to_string()));
    println!("{:?}", test_store.get(MyKey::Int(1i32)));
    let _ = test_store.remove(MyKey::Int(1i32));
}
```

*/

extern crate bincode;
extern crate rustc_serialize;
#[macro_use]
extern crate log;

use std::collections::HashMap;
use std::fs;
use std::fs::{ File, OpenOptions };
use std::io::prelude::*;
use std::hash::Hash;

use bincode::SizeLimit;
use bincode::rustc_serialize::{ encode, decode };

use rustc_serialize::{ Encodable, Decodable };

/// The maximum number of retries the cab will make
const MAX_RETRIES:i32 = 10;

/// Definition of a macro for retrying an operation
macro_rules! retry {
    ($i:ident, $b:block) => (
        for $i in 0..MAX_RETRIES {
            if $i != 0 {
                std::thread::park_timeout(std::time::Duration::new(0u64, 1000u32));
            }

            $b
        }
    )
}

/// A default value type to use with KV
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
pub enum Value {
    String(String),
    Int(i32),
    Float(f32),
    Map(HashMap<String, Value>),
}

/// Type alias for results from KV
type KVResult = Result<bool, KVError>;

/// Errors that KV might have
#[derive(Debug, PartialEq)]
pub enum KVError {
    CabEmpty,
    CouldntDecode,
    DoesntExistOrNotReadable,
    CouldntEncode,
    CouldntWrite,
    CouldntSetPermissions,
    CoudlntGetPermissions,
    FailedToRead,
    CouldntSyncMetadata,
    CouldntFlush,
}

/// The type that represents the key-value store
pub struct KV<K,V> {
    cab: HashMap<K, V>,
    file: File,
}

impl<K: Clone + Encodable + Decodable + Eq + Hash, V: Clone + Encodable + Decodable> KV<K,V> {
    /// Creates a new instance of the KV store
    pub fn new(p:&'static str) -> Result<KV<K,V>, KVError> {
        // create the KV instance
        let mut store = KV {
            cab: HashMap::new(),
            file: KV::<K, V>::retry_get_file(p),
        };

        // lock the cab for writes
        if let Err(e) = store.lock_cab(true) {
            return Err(e);
        }

        match store.load_from_persist() {
            Ok(f) => trace!("{}", f),
            Err(e) => {
                if e == KVError::CouldntDecode {
                    return Err(e);
                }
                warn!("{:?}", e);
            },
        };

        Ok(store)
    }

    /// Sets file permission for a path to not be readonly
    fn set_path_permission(p: &'static str) {
        match fs::metadata(p) {
            Ok(f) => {
                let mut perms = f.permissions();
                perms.set_readonly(false);

                match fs::set_permissions(p, perms) {
                    Ok(_) => (),
                    Err(e) => {
                        error!("{}", e);
                    }
                }
            },
            Err(e) => {
                if e.kind() != std::io::ErrorKind::NotFound {
                    error!("{}", e);
                }
            },
        }
    }

    /// Retry to get a reference to the cab file at path p and create if doesn't exist
    fn retry_get_file(p:&'static str) -> File {
        retry!(i, {
            match OpenOptions::new().read(true).write(true).create(true).open(p) {
                Ok(f) => { return f; },
                Err(e) => {
                    error!("{}", e);
                    if i >= MAX_RETRIES - 1 {
                        panic!("Could not open file after retries");
                    }

                    KV::<K, V>::set_path_permission(p);
                    continue;
                }
            };

        });
        panic!("retry_get_file: Failed to get file");
    }

    /// Inserta a key, value pair into the key-value store
    pub fn insert(&mut self, key: K, value: V) -> KVResult {
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist() {
            return Err(e);
        }
        // insert into the HashMap
        self.cab.insert(key, value);
        // persist
        self.write_to_persist()
    }

    /// Get the value from a key
    pub fn get(&mut self, key: K) -> Result<Option<V>, KVError> {
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist() {
            return Err(e);
        }
        // get the value from the cab
        match self.cab.get(&key) {
            Some(v) => Ok(Some((*v).clone())),
            None => Ok(None),
        }
    }

    /// Removes a key and associated value from the key-value Store
    pub fn remove(&mut self, key: K) -> KVResult {
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist() {
            return Err(e);
        }
        // remove from the HashMap
        self.cab.remove(&key);
        // persist
        self.write_to_persist()
    }

    /// get all the keys contained in the KV Store
    pub fn keys(&mut self) -> Result<Vec<K>, KVError> {
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist() {
            return Err(e);
        }
        // create a vec from the cabs keys
        Ok(self.cab.keys().map(|k| k.clone()).collect())
    }

    /// Locks/unlocks cab for writing purposes
    fn lock_cab(&mut self, readonly:bool) -> KVResult {
        retry!(i, {
            // set not readonly while writing
            let mut perms = match self.file.metadata() {
                Ok(f) => f.permissions(),
                Err(e) => {
                    error!("{}", e);
                    if i >= MAX_RETRIES - 1 {
                        return Err(KVError::CoudlntGetPermissions);
                    }
                    continue;
                },
            };
            perms.set_readonly(readonly);

            match self.file.set_permissions(perms) {
                Ok(_) => {
                    if let Err(e) = self.file.sync_all() {
                        error!("{}", e);
                        return Err(KVError::CouldntSyncMetadata);
                    }
                    break;
                },
                Err(e) => {
                    error!("{}", e);
                    if i >= MAX_RETRIES - 1 {
                        return Err(KVError::CouldntSetPermissions);
                    }
                    continue;
                },
            }
        });

        Ok(true)
    }

    /// Waits for the cab to become free
    fn wait_for_free(&mut self, lock:bool) -> KVResult {
        loop {
            // check if the cab is being written to
            if let Err(e) = self.file.sync_all() {
                error!("{}", e);
                return Err(KVError::CouldntSyncMetadata);
            }
            let metadata = match self.file.metadata() {
                Ok(m) => m,
                Err(_) => return Err(KVError::DoesntExistOrNotReadable),
            };

            if metadata.permissions().readonly() {
                if lock {
                    if let Err(e) = self.lock_cab(false) {
                        return Err(e);
                    }
                }
                break;
            }
        }

        Ok(true)
    }

    /// Writes the key-value Store to file
    fn write_to_persist(&mut self) -> KVResult {
        // encode the cab as a u8 vec
        let byte_vec: Vec<u8> = match encode(&mut self.cab, SizeLimit::Infinite) {
            Ok(bv) => bv,
            Err(e) => {
                error!("encode: {}", e);
                return Err(KVError::CouldntEncode);
            },
        };

        if !self.wait_for_free(true).is_ok() {
            return Err(KVError::DoesntExistOrNotReadable);
        }
        // attempt to write to the cab
        retry!(i, {
            // write the bytes to it
            match self.file.write_all(byte_vec.as_slice()) {
                Ok(_) => (),
                Err(e) => {
                    error!("file.write_all/retry: {}", e);
                    if i >= MAX_RETRIES - 1 {
                        panic!(KVError::CouldntWrite);
                    }
                    continue;
                },
            }

            // flush to disk
            if let Err(e) = self.file.flush() {
                error!("{}", e);
                return Err(KVError::CouldntFlush);
            }
            if let Err(e) = self.lock_cab(true) {
                if i >= MAX_RETRIES - 1 {
                    return Err(e);
                }
                error!("{:?}", e);
            }

            // leave the retry loop as successful
            break;
        });

        Ok(true)
    }

    /// Loads key-value store from file
    fn load_from_persist(&mut self) -> KVResult {
        // byte vec to read into
        let mut byte_vec = Vec::new();

        // wait/lock the cab and read the bytes
        if !self.wait_for_free(false).is_ok() {
            return Err(KVError::DoesntExistOrNotReadable);
        }
        match self.file.read_to_end(&mut byte_vec) {
            Ok(count) => {
                if count == 0 {
                    return Err(KVError::CabEmpty);
                }
            },
            Err(e) => {
                error!("{}", e);
                return Err(KVError::FailedToRead);
            },
        }

        // decode u8 vec back into HashMap
        let decoded: HashMap<K, V> = match decode(byte_vec.as_slice()) {
            Ok(f) => f,
            Err(e) => {
                error!("{}", e);
                return Err(KVError::CouldntDecode);
            },
        };
        // assign read HashMap back to self
        self.cab = decoded;

        Ok(true)
    }
}
<|endoftext|>


<commit_before>// Copyright [yyyy] [name of copyright owner]

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//    http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(convert)]

extern crate openssl;

use openssl::crypto::hash::{hash, Type};

/// List of types currently supported in Multihash.
/// SHA3, Blake2b, and Blake2s are not yet supported in OpenSSL, so are not available in rust-multihash.
pub enum HashTypes {
    SHA1,
    SHA2256,
    SHA2512,
    SHA3,
    Blake2b,
    Blake2s
}

impl HashTypes {
    pub fn to_u8(&self) -> u8 {
        match *self {
            HashTypes::SHA1 => 0x11,
            HashTypes::SHA2256 => 0x12,
            HashTypes::SHA2512 => 0x13,
            HashTypes::SHA3 => 0x14,
            HashTypes::Blake2b => 0x40,
            HashTypes::Blake2s => 0x41,
        }
    }
}

/// Hashes the input using the given hash algorithm. Also adds the leading bytes for type of algo
/// and length of digest.
///
/// # Example
/// ```
/// use rust-multihash:::{HashTypes, multihash};
///
/// let testphrase = b"Hello World"
/// let digest = multihash(HashTypes::SHA2512, testphrase.to_vec());
/// ```
pub fn multihash(wanthash: HashTypes, input: Vec<u8>) -> Result<Vec<u8>, String> {
    let ssl_hash: Option<Type> = match wanthash {
        HashTypes::SHA1 => Some(Type::SHA1),
        HashTypes::SHA2256 => Some(Type::SHA256),
        HashTypes::SHA2512 => Some(Type::SHA512),
        _ => None,
    };
    match ssl_hash {
        Some(openssl_type) => {
            let mut temphash = hash(openssl_type, input.as_slice());
            let length = temphash.len() as u8;
            temphash.insert(0, length);
            temphash.insert(0, wanthash.to_u8()); // Add the hashtype to the hash.
            Ok(temphash)
        }
        None => Err("Sorry, we don't support that hash algorithm yet.".to_string()),
    }
}

#[cfg(test)]
mod test {
    use super::{HashTypes, multihash};
    use openssl::crypto::hash::{hash, Type};

    #[test]
    fn test1() {
        let example = b"Hello World";
        let mut result = hash(Type::SHA256, example);
        let length = result.len() as u8;
        result.insert(0, 0x12);
        result.insert(1, length);

        assert_eq!(multihash(HashTypes::SHA2256, example.to_vec()).unwrap(), result);
    }
}
<commit_msg>Fix copyright line<commit_after>// Copyright 2015 Google, Inc.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//    http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(convert)]

extern crate openssl;

use openssl::crypto::hash::{hash, Type};

/// List of types currently supported in Multihash.
/// SHA3, Blake2b, and Blake2s are not yet supported in OpenSSL, so are not available in rust-multihash.
pub enum HashTypes {
    SHA1,
    SHA2256,
    SHA2512,
    SHA3,
    Blake2b,
    Blake2s
}

impl HashTypes {
    pub fn to_u8(&self) -> u8 {
        match *self {
            HashTypes::SHA1 => 0x11,
            HashTypes::SHA2256 => 0x12,
            HashTypes::SHA2512 => 0x13,
            HashTypes::SHA3 => 0x14,
            HashTypes::Blake2b => 0x40,
            HashTypes::Blake2s => 0x41,
        }
    }
}

/// Hashes the input using the given hash algorithm. Also adds the leading bytes for type of algo
/// and length of digest.
///
/// # Example
/// ```
/// use rust-multihash:::{HashTypes, multihash};
///
/// let testphrase = b"Hello World"
/// let digest = multihash(HashTypes::SHA2512, testphrase.to_vec());
/// ```
pub fn multihash(wanthash: HashTypes, input: Vec<u8>) -> Result<Vec<u8>, String> {
    let ssl_hash: Option<Type> = match wanthash {
        HashTypes::SHA1 => Some(Type::SHA1),
        HashTypes::SHA2256 => Some(Type::SHA256),
        HashTypes::SHA2512 => Some(Type::SHA512),
        _ => None,
    };
    match ssl_hash {
        Some(openssl_type) => {
            let mut temphash = hash(openssl_type, input.as_slice());
            let length = temphash.len() as u8;
            temphash.insert(0, length);
            temphash.insert(0, wanthash.to_u8()); // Add the hashtype to the hash.
            Ok(temphash)
        }
        None => Err("Sorry, we don't support that hash algorithm yet.".to_string()),
    }
}

#[cfg(test)]
mod test {
    use super::{HashTypes, multihash};
    use openssl::crypto::hash::{hash, Type};

    #[test]
    fn test1() {
        let example = b"Hello World";
        let mut result = hash(Type::SHA256, example);
        let length = result.len() as u8;
        result.insert(0, 0x12);
        result.insert(1, length);

        assert_eq!(multihash(HashTypes::SHA2256, example.to_vec()).unwrap(), result);
    }
}
<|endoftext|>


<commit_before>//! ![Coinnect](https://raw.githubusercontent.com/hugues31/coinnect/master/coinnect.png)
//!
//! Coinnect is a Rust library aiming to provide a complete access to REST APIs for various
//! crypto-currencies exchanges (see below for a list of supported exchanges).
//! All methods consume HTTPS api. The purpose of this crate is not
//! to stream data (you should use websocket/FIX in that case).
//!
//! For optional parameters, most methods require an empty str (`""`) or `Option` (`None`) if
//! you don't want to specify them.
//!
//! ### Exchanges support:
//! - [x] Poloniex
//! - [x] Kraken
//! - [x] Bitstamp (partial)
//! - [x] Bittrex
//!
//! # WARNING
//! This library is highly experimental at the moment. Please do not invest what you
//! can't afford to loose. This is a personal project, I can not be held responsible for
//! the library malfunction, which can lead to a loss of money.

// Move all the clippy warning in deny.
#![deny(clippy)]

// error_chain can make a lot of recursions.
#![recursion_limit="128"]
// Allow lint customization.
#![allow(unknown_lints)]
// Avoid warning for the Crypto-currency about quotes.
#![allow(doc_markdown)]

#[macro_use]
extern crate hyper;
extern crate sha2;
extern crate hmac;
extern crate hyper_native_tls;
extern crate serde_json;
extern crate chrono;
#[macro_use]
extern crate lazy_static;
extern crate bidir_map;
extern crate data_encoding;
#[macro_use]
extern crate error_chain;
extern crate bigdecimal;

pub mod coinnect;
pub mod exchange;
pub mod error;
pub mod types;
mod helpers;

pub mod bitstamp;
pub mod poloniex;
pub mod kraken;
pub mod bittrex;
<commit_msg>Fix the clippy lint warning<commit_after>//! ![Coinnect](https://raw.githubusercontent.com/hugues31/coinnect/master/coinnect.png)
//!
//! Coinnect is a Rust library aiming to provide a complete access to REST APIs for various
//! crypto-currencies exchanges (see below for a list of supported exchanges).
//! All methods consume HTTPS api. The purpose of this crate is not
//! to stream data (you should use websocket/FIX in that case).
//!
//! For optional parameters, most methods require an empty str (`""`) or `Option` (`None`) if
//! you don't want to specify them.
//!
//! ### Exchanges support:
//! - [x] Poloniex
//! - [x] Kraken
//! - [x] Bitstamp (partial)
//! - [x] Bittrex
//!
//! # WARNING
//! This library is highly experimental at the moment. Please do not invest what you
//! can't afford to loose. This is a personal project, I can not be held responsible for
//! the library malfunction, which can lead to a loss of money.

// error_chain can make a lot of recursions.
#![recursion_limit="128"]

// Allow lint customization.
#![allow(unknown_lints)]

// Move all the clippy warning in deny.
#![deny(clippy)]

// Avoid warning for the Crypto-currency about quotes.
#![allow(doc_markdown)]

#[macro_use]
extern crate hyper;
extern crate sha2;
extern crate hmac;
extern crate hyper_native_tls;
extern crate serde_json;
extern crate chrono;
#[macro_use]
extern crate lazy_static;
extern crate bidir_map;
extern crate data_encoding;
#[macro_use]
extern crate error_chain;
extern crate bigdecimal;

pub mod coinnect;
pub mod exchange;
pub mod error;
pub mod types;
mod helpers;

pub mod bitstamp;
pub mod poloniex;
pub mod kraken;
pub mod bittrex;
<|endoftext|>


<commit_before>extern crate libc;

use libc::{c_char, c_short, c_int};

pub enum SpcHandle {}

#[link(name = "snes_spc")]
extern {
    // Instantiate a new SPC emulator and return a handle to it.
    fn spc_new() -> *mut SpcHandle;

    // Free an SPC emulator given its handle.
    fn spc_delete(spc: *mut SpcHandle);

    // Load SPC data into emulator.
    fn spc_load_spc(spc: *mut SpcHandle, data: *const u8, len: c_int)
        -> *const c_char;

    // Clear SPC echo buffer.
    fn spc_clear_echo(spc: *mut SpcHandle);

    // Emulate SPC output, recording `count` 16-bit samples to `out`
    fn spc_play(spc: *mut SpcHandle, count: c_int, out: *mut c_short)
        -> *const c_char;
}

/// A simple, safe wrapper around an opaque SNES_SPC handle.
pub struct SnesSpc {
    handle: *mut SpcHandle
}

unsafe impl Send for SnesSpc {}

impl SnesSpc {
    pub fn new() -> SnesSpc {
        unsafe {
            SnesSpc {
                handle: spc_new()
            }
        }
    }

    pub fn load_spc(&mut self, data: &[u8]) {
        unsafe {
            spc_load_spc(self.handle, data.as_ptr(), data.len() as c_int);
        }
    }

    pub fn clear_echo(&mut self) {
        unsafe {
            spc_clear_echo(self.handle);
        }
    }

    pub fn play(&mut self, count: u32, out: &mut [i16]) {
        unsafe {
            // TODO: check that out is big enough :)
            spc_play(self.handle, count as c_int, out.as_mut_ptr());
        }
    }
}

#[test]
fn can_call_unsafe_api_without_exploding() {
    unsafe {
        let mut spc = spc_new();
        spc_delete(spc);
    }
}

#[test]
fn can_use_safe_wrapper_without_being_stabbed() {
    let mut spc = SnesSpc::new();
    spc.clear_echo();
    // Drop it!
}
<commit_msg>Add Results to relevant functions. Add from_data and from_file constructors.<commit_after>extern crate libc;

use std::convert::From;
use std::error;
use std::ffi::CStr;
use std::fmt;
use std::fs::File;
use std::io;
use std::io::Read;
use std::path::Path;
use std::result;

use libc::{c_char, c_short, c_int};

/// The error type for SPC operations; either an io::Error, or an error
/// originating within the underlying snes_spc library. The latter case
/// is just exposed as a string containing the error message.
#[derive(Debug)]
pub enum SpcError {
    Io(io::Error),
    Internal(String)
}

impl fmt::Display for SpcError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SpcError::Io(ref e) => write!(f, "IO error: {}", e),
            SpcError::Internal(ref e) => write!(f, "Internal SPC error: {}", e),
        }
    }
}

impl error::Error for SpcError {
    fn description(&self) -> &str {
        match *self {
            SpcError::Io(ref e) => e.description(),
            SpcError::Internal(ref e) => &e,
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            SpcError::Io(ref e) => Some(e),
            SpcError::Internal(_) => None
        }
    }
}

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

impl From<String> for SpcError {
    fn from(err: String) -> SpcError {
        SpcError::Internal(err)
    }
}

/// Convert an ffi C-string into our error type. Deal with the rigmarole
/// of cloning into an owned string.
impl From<*const c_char> for SpcError {
    fn from(err: *const c_char) -> SpcError {
        unsafe {
            SpcError::Internal(String::from_utf8_lossy(
                CStr::from_ptr(err).to_bytes()).into_owned())
        }
    }
}

/// The result type for SPC operations that may fail.
pub type Result<T> = result::Result<T, SpcError>;

/// Convert a possibly null ffi C-string into our Result<()> type.
/// N.B.: this is not an implementation of `std::convert::From` because
/// Rust's coherency rules prohibit us from defining external traits for
/// `snes_spc::Result`, which is just an alias of `std::result::Result`.
/// This makes tiny kittens sad, but they try their best to understand.
fn result_from(err: *const c_char) -> Result<()> {
    if err.is_null() {
        Ok(())
    } else {
        Err(SpcError::from(err))
    }
}

/// A type for the internal library's opaque struct SNES_SPC
enum SpcHandle {}

#[link(name = "snes_spc")]
extern {
    // Instantiate a new SPC emulator and return a handle to it.
    fn spc_new() -> *mut SpcHandle;

    // Free an SPC emulator given its handle.
    fn spc_delete(spc: *mut SpcHandle);

    // Load SPC data into emulator.
    fn spc_load_spc(spc: *mut SpcHandle, data: *const u8, len: c_int)
        -> *const c_char;

    // Clear SPC echo buffer.
    fn spc_clear_echo(spc: *mut SpcHandle);

    // Emulate SPC output, recording `count` 16-bit samples to `out`
    fn spc_play(spc: *mut SpcHandle, count: c_int, out: *mut c_short)
        -> *const c_char;
}

/// A simple, safe wrapper around an opaque SNES_SPC handle.
pub struct SnesSpc {
    handle: *mut SpcHandle
}

/// SnesSpc's internal handle is never exposed except through its safe
/// implementation, so it should be save to move to another thread.
unsafe impl Send for SnesSpc {}

impl SnesSpc {
    pub fn new() -> SnesSpc {
        unsafe {
            SnesSpc {
                handle: spc_new()
            }
        }
    }

    /// Creates a new `SnesSpc` using a byte slice as its initial SPC data.
    pub fn from_data(data: &[u8]) -> Result<SnesSpc> {
        let mut spc = SnesSpc::new();
        try!(spc.load_spc(data));
        Ok(spc)
    }

    /// Creates a new SPC emulator initially loaded with the contents of a
    /// file at the given path.
    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<SnesSpc> {
        let mut data = Vec::new();
        let mut file = try!(File::open(path));
        try!(file.read_to_end(&mut data));
        SnesSpc::from_data(&data)
    }

    /// Loads data into the SPC emulator.
    pub fn load_spc(&mut self, data: &[u8]) -> Result<()> {
        unsafe {
            result_from(spc_load_spc(
                self.handle, data.as_ptr(), data.len() as c_int))
        }
    }

    /// Clears the SPC emulator's echo buffer. This can be useful if loading
    /// SPC files that have garbage in the initial echo buffer.
    pub fn clear_echo(&mut self) {
        unsafe {
            spc_clear_echo(self.handle);
        }
    }

    /// Emulate a specified number of samples, storing them in a given buffer.
    pub fn play(&mut self, count: u32, out: &mut [i16]) -> Result<()> {
        unsafe {
            // TODO: check that out is big enough :)
            result_from(spc_play(self.handle, count as c_int, out.as_mut_ptr()))
        }
    }
}

#[test]
fn can_call_unsafe_api_without_exploding() {
    unsafe {
        let mut spc = spc_new();
        spc_delete(spc);
    }
}

#[test]
fn can_use_safe_wrapper_without_being_stabbed() {
    let mut spc = SnesSpc::new();
    spc.clear_echo();
    // Drop it!
}
<|endoftext|>