<commit_before>extern crate libc;

use std::error;
use std::fmt;
use std::path;
use std::ffi::CString;
use std::marker::PhantomData;
use libc::types::os::arch::c95::{c_char, time_t};
use libc::types::common::c95::c_void;
use libc::funcs::c95::stdlib::free;

// C function definitions
#[link(name = "raw")]
extern {
    fn libraw_init(flags: u32) -> *mut LibrawData;
    fn libraw_open_file(imgdat: *mut LibrawData, fpath: *const libc::c_char) -> i32;
    fn libraw_open_buffer(imgdat: *mut LibrawData, buffer: &[u8], bufsize: libc::size_t) -> i32;
    fn libraw_unpack(imgdat: *mut LibrawData) -> i32;
    fn libraw_unpack_thumb(imgdat: *mut LibrawData) -> i32;
}

// C struct definitions
#[repr(C)]
pub struct LibrawData {
    image: [*mut u16; 4],
    sizes: LibrawImageSizes,
    idata: LibrawIparams,
    progress_flags: u32,
    process_warnings: u32,
    color: LibrawColorData,
    other: LibrawImgOther,
    thumbnail: LibrawThumb,
    rawdata: LibrawRawData,
    parent_class: *mut libc::c_void,
}

#[repr(C)]
struct LibrawImageSizes {
    raw_height: u16,
    raw_width: u16,
    height: u16,
    width: u16,
    top_margin: u16,
    left_margin: u16,
    iheight: u16,
    iwidth: u16,
    raw_pitch: u32,
    pixel_aspect: f64,
    flip: i32,
    mask: [[u32; 8]; 4],
}

#[repr(C)]
struct LibrawIparams {
    make: [c_char; 64],
    model: [c_char; 64],
    raw_count: u32,
    dng_version: u32,
    is_foveon: u32,
    colors: i32,
    filters: u32,
    xtrans: [[c_char; 6]; 6],
    cdesc: [c_char; 5],
}

#[repr(C)]
struct LibrawColorData {
    make: [c_char; 64],
    model: [c_char; 64],
    raw_count: u32,
    dng_version: u32,
    is_foveon: u32,
    colors: i32,
    filters: u32,
    xtrans: [[c_char; 6]; 6],
    cdesc: [c_char; 5],
    phase_one_data: LibrawPh1,
    flash_used: f32,
    canon_ev: f32,
    model2: [c_char; 64],
    profile: *mut libc::c_void,
    profile_length: u32,
    black_stat: [u32; 8],
}

#[repr(C)]
struct LibrawPh1 {
    format: i32,
    key_off: i32,
    t_black: i32,
    black_off: i32,
    split_col: i32,
    tag_21a: i32,
    tag_210: f32,
}

#[repr(C)]
struct LibrawImgOther {
    iso_speed: f32,
    shutter: f32,
    aperture: f32,
    focal_len: f32,
    timestamp: time_t,
    shot_order: u32,
    gpsdata: [u32; 32],
    desc: [c_char; 512],
    artist: [c_char; 64],
}

#[repr(C)]
struct LibrawThumb {
    tformat: LibrawThumbnailFormat,
    twidth: u16,
    theight: u16,
    tlength: u32,
    tcolors: i32,
    thumb: *mut c_char,
}

#[repr(C)]
struct LibrawRawData {
    raw_alloc: *mut libc::c_void,
    raw_image: *mut u16,
    color4_image: [*mut u16; 4],
    color3_image: [*mut u16; 3],
    ph1_black: [*mut i16; 2],
    iparams: LibrawIparams,
    sizes: LibrawImageSizes,
    ioparams: LibrawInternalOutputParams,
    color: LibrawColorData,
}

#[repr(C)]
struct LibrawInternalOutputParams {
    mix_green: u32,
    raw_color: u32,
    zero_is_bad: u32,
    shrink: u16,
    fuji_width: u16,
}

// C enum definitions
#[repr(C)]
enum LibrawThumbnailFormat {
    Unknown = 0,
    Jpeg = 1,
    Bitmap = 2,
    Layer = 4,
    Rollei = 5,
}

// Errors
pub enum LibrawError {
    NulError(std::ffi::NulError),
    AllocError(LibrawAllocError),
    IOError(std::io::Error),
    LibError(LibrawLibraryError),
}

#[derive(Debug)]
pub struct LibrawAllocError;

impl fmt::Display for LibrawAllocError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "image data allocation failed".fmt(f)
    }
}

impl error::Error for LibrawAllocError {
    fn description(&self) -> &str {
        "image data allocation failed"
    }
}

#[derive(Debug)]
pub struct LibrawLibraryError;

impl fmt::Display for LibrawLibraryError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "internal libraw library error".fmt(f)
    }
}

impl error::Error for LibrawLibraryError {
    fn description(&self) -> &str {
        "internal libraw library error"
    }
}

// Higher-level unsafe methods
// These methods may change as I find better ways to implement this
// Specifically, it might be better to read the file in Rust and pass
// the resulting buffer to libraw
unsafe fn init_data() -> Result<*mut LibrawData, LibrawError> {
    // 0 = no flags
    // 1 = no memory error callback
    // 2 = non data error callback
    // 3 = both
    let data = libraw_init(3);
    if data.is_null() {
        Err(LibrawError::AllocError(LibrawAllocError))
    } else {
        Ok(data)
    }
}

unsafe fn read_img_at_path(filepath: &str) -> Result<*mut LibrawData, LibrawError> {
    let fpath = match CString::new(filepath) {
        Ok(v) => v,
        Err(e) => return Err(LibrawError::NulError(e)),
    };
    let data = try!(init_data());
    let res: i32 = libraw_open_file(data, fpath.as_ptr());
    if res > 0 {
        Err(LibrawError::IOError(std::io::Error::from_raw_os_error(res)))
    } else if res < 0 {
        Err(LibrawError::LibError(LibrawLibraryError))
    } else {
        Ok(data)
    }
}

// Public interface
pub fn load_raw_at_path<'a>(fpath: &'a path::Path) -> Result<RawData<'a>, LibrawError> {
    let pathstr = match fpath.to_str() {
        Some(v) => v,
        None => return Err(LibrawError::AllocError(LibrawAllocError)),
    };
    unsafe {
        let unsafe_val = match read_img_at_path(pathstr) {
            Ok(v) => v,
            Err(e) => return Err(e),
        };

        let raw_dat: RawData = RawData{
            libraw_data: unsafe_val,
            phantom: PhantomData
        };
        Ok(raw_dat)
    }
}

pub struct RawData<'a> {
    libraw_data: *mut LibrawData, // Needs to be mutable for free()
    phantom: PhantomData<&'a LibrawData>,
}

impl<'a> Drop for RawData<'a> {
    fn drop(&mut self) {
        unsafe {
            free((self.libraw_data as *mut c_void));
        }
    }
}
<commit_msg>Latest modifications to lib<commit_after>extern crate libc;

use std::error;
use std::fmt;
use std::path;
use std::ffi::CString;
use std::marker::PhantomData;
use libc::types::os::arch::c95::{c_char, time_t};
use libc::types::common::c95::c_void;
use libc::funcs::c95::stdlib::free;

// C function definitions
#[link(name = "raw")]
extern {
    fn libraw_init(flags: u32) -> *mut LibrawData;
    fn libraw_open_file(imgdat: *mut LibrawData, fpath: *const libc::c_char) -> i32;
    fn libraw_open_buffer(imgdat: *mut LibrawData, buffer: &[u8], bufsize: libc::size_t) -> i32;
    fn libraw_unpack(imgdat: *mut LibrawData) -> i32;
    fn libraw_unpack_thumb(imgdat: *mut LibrawData) -> i32;
}

// C struct definitions
#[repr(C)]
pub struct LibrawData {
    pub image: [*mut u16; 4],
    pub sizes: LibrawImageSizes,
    pub idata: LibrawIparams,
    pub progress_flags: u32,
    pub process_warnings: u32,
    pub color: LibrawColorData,
    pub other: LibrawImgOther,
    pub thumbnail: LibrawThumb,
    pub rawdata: LibrawRawData,
    pub parent_class: *mut libc::c_void,
}

#[repr(C)]
struct LibrawImageSizes {
    raw_height: u16,
    raw_width: u16,
    height: u16,
    width: u16,
    top_margin: u16,
    left_margin: u16,
    iheight: u16,
    iwidth: u16,
    raw_pitch: u32,
    pixel_aspect: f64,
    flip: i32,
    mask: [[u32; 8]; 4],
}

#[repr(C)]
struct LibrawIparams {
    make: [c_char; 64],
    model: [c_char; 64],
    raw_count: u32,
    dng_version: u32,
    is_foveon: u32,
    colors: i32,
    filters: u32,
    xtrans: [[c_char; 6]; 6],
    cdesc: [c_char; 5],
}

#[repr(C)]
struct LibrawColorData {
    make: [c_char; 64],
    model: [c_char; 64],
    raw_count: u32,
    dng_version: u32,
    is_foveon: u32,
    colors: i32,
    filters: u32,
    xtrans: [[c_char; 6]; 6],
    cdesc: [c_char; 5],
    phase_one_data: LibrawPh1,
    flash_used: f32,
    canon_ev: f32,
    model2: [c_char; 64],
    profile: *mut libc::c_void,
    profile_length: u32,
    black_stat: [u32; 8],
}

#[repr(C)]
struct LibrawPh1 {
    format: i32,
    key_off: i32,
    t_black: i32,
    black_off: i32,
    split_col: i32,
    tag_21a: i32,
    tag_210: f32,
}

#[repr(C)]
struct LibrawImgOther {
    iso_speed: f32,
    shutter: f32,
    aperture: f32,
    focal_len: f32,
    timestamp: time_t,
    shot_order: u32,
    gpsdata: [u32; 32],
    desc: [c_char; 512],
    artist: [c_char; 64],
}

#[repr(C)]
struct LibrawThumb {
    tformat: LibrawThumbnailFormat,
    twidth: u16,
    theight: u16,
    tlength: u32,
    tcolors: i32,
    thumb: *mut c_char,
}

#[repr(C)]
struct LibrawRawData {
    raw_alloc: *mut libc::c_void,
    raw_image: *mut u16,
    color4_image: [*mut u16; 4],
    color3_image: [*mut u16; 3],
    ph1_black: [*mut i16; 2],
    iparams: LibrawIparams,
    sizes: LibrawImageSizes,
    ioparams: LibrawInternalOutputParams,
    color: LibrawColorData,
}

#[repr(C)]
struct LibrawInternalOutputParams {
    mix_green: u32,
    raw_color: u32,
    zero_is_bad: u32,
    shrink: u16,
    fuji_width: u16,
}

// C enum definitions
#[repr(C)]
enum LibrawThumbnailFormat {
    Unknown = 0,
    Jpeg = 1,
    Bitmap = 2,
    Layer = 4,
    Rollei = 5,
}

// Errors
pub enum LibrawError {
    NulError(std::ffi::NulError),
    AllocError(LibrawAllocError),
    IOError(std::io::Error),
    LibError(LibrawLibraryError),
}

#[derive(Debug)]
pub struct LibrawAllocError;

impl fmt::Display for LibrawAllocError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "image data allocation failed".fmt(f)
    }
}

impl error::Error for LibrawAllocError {
    fn description(&self) -> &str {
        "image data allocation failed"
    }
}

#[derive(Debug)]
pub struct LibrawLibraryError;

impl fmt::Display for LibrawLibraryError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "internal libraw library error".fmt(f)
    }
}

impl error::Error for LibrawLibraryError {
    fn description(&self) -> &str {
        "internal libraw library error"
    }
}

// Higher-level unsafe methods
// These methods may change as I find better ways to implement this
// Specifically, it might be better to read the file in Rust and pass
// the resulting buffer to libraw
unsafe fn init_data() -> Result<*mut LibrawData, LibrawError> {
    // 0 = no flags
    // 1 = no memory error callback
    // 2 = non data error callback
    // 3 = both
    let data = libraw_init(3);
    if data.is_null() {
        Err(LibrawError::AllocError(LibrawAllocError))
    } else {
        Ok(data)
    }
}

unsafe fn read_img_at_path(filepath: &str) -> Result<*mut LibrawData, LibrawError> {
    let fpath = match CString::new(filepath) {
        Ok(v) => v,
        Err(e) => return Err(LibrawError::NulError(e)),
    };
    let data = try!(init_data());
    let res: i32 = libraw_open_file(data, fpath.as_ptr());
    if res > 0 {
        Err(LibrawError::IOError(std::io::Error::from_raw_os_error(res)))
    } else if res < 0 {
        Err(LibrawError::LibError(LibrawLibraryError))
    } else {
        Ok(data)
    }
}

// Public interface
pub fn load_raw_at_path<'a>(fpath: &'a path::Path) -> Result<RawData<'a>, LibrawError> {
    let pathstr = match fpath.to_str() {
        Some(v) => v,
        None => return Err(LibrawError::AllocError(LibrawAllocError)),
    };
    unsafe {
        let unsafe_val = match read_img_at_path(pathstr) {
            Ok(v) => v,
            Err(e) => return Err(e),
        };

        let raw_dat: RawData = RawData{
            libraw_data: unsafe_val,
            phantom: PhantomData
        };
        Ok(raw_dat)
    }
}

pub struct RawData<'a> {
    libraw_data: *mut LibrawData, // Needs to be mutable for free()
    phantom: PhantomData<&'a LibrawData>,
}

pub struct RectangleSize {
    width: usize,
    height: usize,
}

impl<'a> Drop for RawData<'a> {
    //! Frees the underlying libraw pointer
    fn drop(&mut self) {
        unsafe {
            free((self.libraw_data as *mut c_void));
        }
    }
}

impl<'a> RawData<'a> {
    /// Get the size of the RAW image with the frame
    pub fn get_raw_size(&self) -> RectangleSize {
        unsafe {
            RectangleSize {
                height: self.libraw_data.sizes.raw_height,
                width: self.libraw_data.sizes.raw_width,
            }
        }
    }

    /// Get the size of the image without the frame
    pub fn get_size(&self) -> RectangleSize {
        unsafe {
            RectangleSize {
                height: self.libraw_data.sizes.height,
                width: self.libraw_data.sizes.width,
            }
        }
    }

    /// Get an arbitrary value from the RAW image array
    pub fn get_raw_value(&self, index: usize) -> u16 {
        // Bounds check for unsafe ptr arithmetic
        let rawsize = self.get_raw_size();
        if (index >= rawsize.height * rawsize.width) {
            panic!("RAW index out of bounds");
        }
        unsafe {
            *self.libraw_data.rawdata.raw_image.offset(index)
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(path, fs, io)]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/tempdir/")]
#![cfg_attr(test, deny(warnings))]

extern crate rand;

use std::env;
use std::io::{self, Error, ErrorKind};
use std::fs;
use std::path::{self, PathBuf, AsPath};
use rand::{thread_rng, Rng};

/// A wrapper for a path to temporary directory implementing automatic
/// scope-based deletion.
pub struct TempDir {
    path: Option<PathBuf>,
}

// How many times should we (re)try finding an unused random name? It should be
// enough that an attacker will run out of luck before we run out of patience.
const NUM_RETRIES: u32 = 1 << 31;
// How many characters should we include in a random file name? It needs to
// be enough to dissuade an attacker from trying to preemptively create names
// of that length, but not so huge that we unnecessarily drain the random number
// generator of entropy.
const NUM_RAND_CHARS: usize = 12;

impl TempDir {
    /// Attempts to make a temporary directory inside of `tmpdir` whose name
    /// will have the prefix `prefix`. The directory will be automatically
    /// deleted once the returned wrapper is destroyed.
    ///
    /// If no directory can be created, `Err` is returned.
    #[allow(deprecated)] // rand usage
    pub fn new_in<P: AsPath + ?Sized>(tmpdir: &P, prefix: &str)
                                      -> io::Result<TempDir> {
        let storage;
        let mut tmpdir = tmpdir.as_path();
        if !tmpdir.is_absolute() {
            let cur_dir = try!(env::current_dir());
            storage = cur_dir.join(tmpdir);
            tmpdir = &storage;
            // return TempDir::new_in(&cur_dir.join(tmpdir), prefix);
        }

        let mut rng = thread_rng();
        for _ in 0..NUM_RETRIES {
            let suffix: String = rng.gen_ascii_chars().take(NUM_RAND_CHARS).collect();
            let leaf = if prefix.len() > 0 {
                format!("{}.{}", prefix, suffix)
            } else {
                // If we're given an empty string for a prefix, then creating a
                // directory starting with "." would lead to it being
                // semi-invisible on some systems.
                suffix
            };
            let path = tmpdir.join(&leaf);
            match fs::create_dir(&path) {
                Ok(_) => return Ok(TempDir { path: Some(path) }),
                Err(ref e) if e.kind() == ErrorKind::PathAlreadyExists => {}
                Err(e) => return Err(e)
            }
        }

        Err(Error::new(ErrorKind::PathAlreadyExists,
                       "too many temporary directories already exist",
                       None))
    }

    /// Attempts to make a temporary directory inside of `env::temp_dir()` whose
    /// name will have the prefix `prefix`. The directory will be automatically
    /// deleted once the returned wrapper is destroyed.
    ///
    /// If no directory can be created, `Err` is returned.
    #[allow(deprecated)]
    pub fn new(prefix: &str) -> io::Result<TempDir> {
        TempDir::new_in(&env::temp_dir(), prefix)
    }

    /// Unwrap the wrapped `std::path::Path` from the `TempDir` wrapper.
    /// This discards the wrapper so that the automatic deletion of the
    /// temporary directory is prevented.
    pub fn into_path(mut self) -> PathBuf {
        self.path.take().unwrap()
    }

    /// Access the wrapped `std::path::Path` to the temporary directory.
    pub fn path(&self) -> &path::Path {
        self.path.as_ref().unwrap()
    }

    /// Close and remove the temporary directory
    ///
    /// Although `TempDir` removes the directory on drop, in the destructor
    /// any errors are ignored. To detect errors cleaning up the temporary
    /// directory, call `close` instead.
    pub fn close(mut self) -> io::Result<()> {
        self.cleanup_dir()
    }

    fn cleanup_dir(&mut self) -> io::Result<()> {
        match self.path {
            Some(ref p) => fs::remove_dir_all(p),
            None => Ok(())
        }
    }
}

impl Drop for TempDir {
    fn drop(&mut self) {
        let _ = self.cleanup_dir();
    }
}

// the tests for this module need to change the path using change_dir,
// and this doesn't play nicely with other tests so these unit tests are located
// in src/test/run-pass/tempfile.rs
<commit_msg>Remove allow(deprecated)<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(path, fs, io)]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/tempdir/")]
#![cfg_attr(test, deny(warnings))]

extern crate rand;

use std::env;
use std::io::{self, Error, ErrorKind};
use std::fs;
use std::path::{self, PathBuf, AsPath};
use rand::{thread_rng, Rng};

/// A wrapper for a path to temporary directory implementing automatic
/// scope-based deletion.
pub struct TempDir {
    path: Option<PathBuf>,
}

// How many times should we (re)try finding an unused random name? It should be
// enough that an attacker will run out of luck before we run out of patience.
const NUM_RETRIES: u32 = 1 << 31;
// How many characters should we include in a random file name? It needs to
// be enough to dissuade an attacker from trying to preemptively create names
// of that length, but not so huge that we unnecessarily drain the random number
// generator of entropy.
const NUM_RAND_CHARS: usize = 12;

impl TempDir {
    /// Attempts to make a temporary directory inside of `tmpdir` whose name
    /// will have the prefix `prefix`. The directory will be automatically
    /// deleted once the returned wrapper is destroyed.
    ///
    /// If no directory can be created, `Err` is returned.
    pub fn new_in<P: AsPath + ?Sized>(tmpdir: &P, prefix: &str)
                                      -> io::Result<TempDir> {
        let storage;
        let mut tmpdir = tmpdir.as_path();
        if !tmpdir.is_absolute() {
            let cur_dir = try!(env::current_dir());
            storage = cur_dir.join(tmpdir);
            tmpdir = &storage;
            // return TempDir::new_in(&cur_dir.join(tmpdir), prefix);
        }

        let mut rng = thread_rng();
        for _ in 0..NUM_RETRIES {
            let suffix: String = rng.gen_ascii_chars().take(NUM_RAND_CHARS).collect();
            let leaf = if prefix.len() > 0 {
                format!("{}.{}", prefix, suffix)
            } else {
                // If we're given an empty string for a prefix, then creating a
                // directory starting with "." would lead to it being
                // semi-invisible on some systems.
                suffix
            };
            let path = tmpdir.join(&leaf);
            match fs::create_dir(&path) {
                Ok(_) => return Ok(TempDir { path: Some(path) }),
                Err(ref e) if e.kind() == ErrorKind::PathAlreadyExists => {}
                Err(e) => return Err(e)
            }
        }

        Err(Error::new(ErrorKind::PathAlreadyExists,
                       "too many temporary directories already exist",
                       None))
    }

    /// Attempts to make a temporary directory inside of `env::temp_dir()` whose
    /// name will have the prefix `prefix`. The directory will be automatically
    /// deleted once the returned wrapper is destroyed.
    ///
    /// If no directory can be created, `Err` is returned.
    pub fn new(prefix: &str) -> io::Result<TempDir> {
        TempDir::new_in(&env::temp_dir(), prefix)
    }

    /// Unwrap the wrapped `std::path::Path` from the `TempDir` wrapper.
    /// This discards the wrapper so that the automatic deletion of the
    /// temporary directory is prevented.
    pub fn into_path(mut self) -> PathBuf {
        self.path.take().unwrap()
    }

    /// Access the wrapped `std::path::Path` to the temporary directory.
    pub fn path(&self) -> &path::Path {
        self.path.as_ref().unwrap()
    }

    /// Close and remove the temporary directory
    ///
    /// Although `TempDir` removes the directory on drop, in the destructor
    /// any errors are ignored. To detect errors cleaning up the temporary
    /// directory, call `close` instead.
    pub fn close(mut self) -> io::Result<()> {
        self.cleanup_dir()
    }

    fn cleanup_dir(&mut self) -> io::Result<()> {
        match self.path {
            Some(ref p) => fs::remove_dir_all(p),
            None => Ok(())
        }
    }
}

impl Drop for TempDir {
    fn drop(&mut self) {
        let _ = self.cleanup_dir();
    }
}

// the tests for this module need to change the path using change_dir,
// and this doesn't play nicely with other tests so these unit tests are located
// in src/test/run-pass/tempfile.rs
<|endoftext|>


<commit_before>extern crate byteorder;
#[cfg(feature = "use-sdl2")]
extern crate sdl2;

pub mod mul_reader;
pub mod utils;

pub mod color;

pub mod art;
pub mod skills;
pub mod hues;
pub mod map;
pub mod tiledata;
pub mod gump;

#[cfg(test)]
mod tests {
    mod test_mul_reader;
    mod test_color;
    mod test_skills;
    mod test_hues;
    mod test_art;
//    mod test_tiledata;
}
<commit_msg>More anim reading logic<commit_after>extern crate byteorder;
#[cfg(feature = "use-sdl2")]
extern crate sdl2;

pub mod mul_reader;
pub mod utils;

pub mod color;

pub mod art;
pub mod skills;
pub mod hues;
pub mod map;
pub mod tiledata;
pub mod gump;
pub mod anim;

#[cfg(test)]
mod tests {
    mod test_mul_reader;
    mod test_color;
    mod test_skills;
    mod test_hues;
    mod test_art;
//    mod test_tiledata;
}
<|endoftext|>


<commit_before>#![crate_name = "piston"]
#![deny(missing_docs)]
#![warn(dead_code)]

//! A user friendly game engine written in Rust.

// Reexported crates.
pub extern crate input;
pub extern crate event_loop;
pub extern crate window;
<commit_msg>Added docs to `piston` library<commit_after>#![crate_name = "piston"]
#![deny(missing_docs)]
#![warn(dead_code)]

//! A modular game engine written in Rust.
//!
//! This is the core library of the Piston Game engine.
//! The `Piston` core library reexports the core modules.
//!
//! If you are looking for a convenient window wrapper,
//! see [piston_window](https://github.com/pistondevelopers/piston_window).
//!
//! For examples, see [piston-examples](https://github.com/pistondevelopers/piston-examples).
//!
//! For more information and an overview, see [Piston's README in the core repository](https://github.com/pistondevelopers/piston).
//!
//! ### About Piston as a Game Engine
//!
//! Piston is a modular game engine with a minimal core abstraction.
//! The core connects input events, window and event loop.
//!
//! Piston is designed for optimal modularity,
//! making it optional to even use the core modules in many cases.
//! The goal is to have as little abstraction as possible,
//! while making larger libraries as independent as possible.
//! The motivation is to encourage diversity and experimentation with various abstractions,
//! without getting tied up to a fixed set of platforms, abstractions or vendors.
//! You can combine Piston with any other library in Rust's ecosystem.
//! This design has worked very well so far.
//!
//! For example (a few libraries, there are many more):
//!
//! - [Image](https://github.com/pistondevelopers/image) library is standalone
//! from both the core and the 2D graphics library,
//! only connected through the 2D graphics backends.
//! - [Piston's 2D graphics](https://github.com/pistondevelopers/graphics) is optional and can be used without a window backend.
//! The window backend can be used without a 2D graphics backend, and so on.
//! - For image processing, see [Imageproc](https://github.com/pistondevelopers/imageproc).
//! - [Dyon](https://github.com/pistondevelopers/dyon) is a Rusty dynamically typed scripting language,
//! using a lifetime checker without garbage collection.
//!
//! For more information and an overview, see [Piston's README in the core repository](https://github.com/pistondevelopers/piston).
//!
//! When writing a library, please depend directly on the core module needed.
//! This makes it less likely that the library will break.
//!
//! When writing an application, it is acceptable to use the `Piston` core.
//! To use it you usually need a window backend:
//!
//! - [pistoncore-glutin_window](https://github.com/pistondevelopers/glutin_window)
//! - [pistoncore-sdl2_window](https://github.com/pistondevelopers/sdl2_window)
//! - [pistoncore-glfw_window](https://github.com/pistondevelopers/glfw_window)
//!
//! There are a [few other window backends as well](https://crates.io/search?q=piston%20window).
//!
//! Plus a 2D graphics backend (optional):
//!
//! - [piston2d-opengl_graphics](https://github.com/pistondevelopers/opengl_graphics)
//! - [piston2d-gfx_graphics](https://github.com/pistondevelopers/gfx_graphics)
//! - [piston2d-glium_graphics](https://github.com/pistondevelopers/glium_graphics)
//!
//! There are a [few other graphics backends as well](https://crates.io/search?q=piston%20graphics).
//!
//! You will find examples of how to get started in each 2D graphics backend repository.
//!
//! ### About Piston as a Project
//!
//! The Piston project is a huge collaboration across many projects,
//! mainly focused on maintenance of libraries and research.
//! Since this has been going on since 2014, there is too much out there
//! to summarize here, but rougly the project is organized into two open source organizations:
//!
//! - [PistonDevelopers](https://github.com/pistondevelopers/) - everything game engine related
//! - [AdvancedResearch](https://github.com/advancedresearch/) - everything advanced math related
//!
//! In addition we collaborate across organizations with other projects, mainly:
//!
//! - [Gfx-rs](https://github.com/gfx-rs/) - everything 3D graphics related
//! - [RustAudio](https://github.com/rustaudio) - everything audio related
//!
//! In addition there are many other projects and organizations.
//!
//! For more information and an overview, see [Piston's README in the core repository](https://github.com/pistondevelopers/piston).

// Reexported crates.
pub extern crate input;
pub extern crate event_loop;
pub extern crate window;
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

#![crate_name = "sysinfo"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![doc = include_str!("../README.md")]
#![allow(unknown_lints)]
#![deny(missing_docs)]
#![deny(rustdoc::broken_intra_doc_links)]
#![allow(clippy::upper_case_acronyms)]
#![allow(renamed_and_removed_lints)]

#[cfg(feature = "debug")]
#[doc(hidden)]
#[allow(unused)]
macro_rules! sysinfo_debug {
    ($($x:tt)*) => {{
        eprintln!($($x)*);
    }}
}

#[cfg(not(feature = "debug"))]
#[doc(hidden)]
#[allow(unused)]
macro_rules! sysinfo_debug {
    ($($x:tt)*) => {{}};
}

cfg_if::cfg_if! {
    if #[cfg(any(target_os = "macos", target_os = "ios"))] {
        mod apple;
        use apple as sys;
        extern crate core_foundation_sys;

        #[cfg(test)]
        pub(crate) const MIN_USERS: usize = 1;
    } else if #[cfg(windows)] {
        mod windows;
        use windows as sys;
        extern crate winapi;
        extern crate ntapi;

        #[cfg(test)]
        pub(crate) const MIN_USERS: usize = 1;
    } else if #[cfg(any(target_os = "linux", target_os = "android"))] {
        mod linux;
        use linux as sys;

        #[cfg(test)]
        pub(crate) const MIN_USERS: usize = 1;
    } else {
        mod unknown;
        use unknown as sys;

        #[cfg(test)]
        pub(crate) const MIN_USERS: usize = 0;
    }
}

pub use common::{
    AsU32, DiskType, DiskUsage, Gid, LoadAvg, NetworksIter, Pid, RefreshKind, Signal, Uid, User,
};
pub use sys::{Component, Disk, NetworkData, Networks, Process, ProcessStatus, Processor, System};
pub use traits::{
    ComponentExt, DiskExt, NetworkExt, NetworksExt, ProcessExt, ProcessorExt, SystemExt, UserExt,
};

#[cfg(feature = "c-interface")]
pub use c_interface::*;
pub use utils::get_current_pid;

#[cfg(feature = "c-interface")]
mod c_interface;
mod common;
mod debug;
mod system;
mod traits;
mod utils;

/// This function is only used on linux targets, on the other platforms it does nothing and returns
/// `false`.
///
/// On linux, to improve performance, we keep a `/proc` file open for each process we index with
/// a maximum number of files open equivalent to half of the system limit.
///
/// The problem is that some users might need all the available file descriptors so we need to
/// allow them to change this limit.
///
/// Note that if you set a limit bigger than the system limit, the system limit will be set.
///
/// Returns `true` if the new value has been set.
///
/// ```no_run
/// use sysinfo::{System, SystemExt, set_open_files_limit};
///
/// // We call the function before any call to the processes update.
/// if !set_open_files_limit(10) {
///     // It'll always return false on non-linux targets.
///     eprintln!("failed to update the open files limit...");
/// }
/// let s = System::new_all();
/// ```
pub fn set_open_files_limit(mut _new_limit: isize) -> bool {
    #[cfg(any(target_os = "linux", target_os = "android"))]
    {
        if _new_limit < 0 {
            _new_limit = 0;
        }
        let max = sys::system::get_max_nb_fds();
        if _new_limit > max {
            _new_limit = max;
        }
        if let Ok(ref mut x) = unsafe { sys::system::REMAINING_FILES.lock() } {
            // If files are already open, to be sure that the number won't be bigger when those
            // files are closed, we subtract the current number of opened files to the new limit.
            let diff = max - **x;
            **x = _new_limit - diff;
            true
        } else {
            false
        }
    }
    #[cfg(all(not(target_os = "linux"), not(target_os = "android")))]
    {
        false
    }
}

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

    #[test]
    fn check_process_memory_usage() {
        let mut s = System::new();
        s.refresh_all();

        if System::IS_SUPPORTED {
            // No process should have 0 as memory usage.
            #[cfg(not(feature = "apple-sandbox"))]
            assert!(!s.processes().iter().all(|(_, proc_)| proc_.memory() == 0));
        } else {
            // There should be no process, but if there is one, its memory usage should be 0.
            assert!(s.processes().iter().all(|(_, proc_)| proc_.memory() == 0));
        }
    }

    #[test]
    fn check_memory_usage() {
        let mut s = System::new();

        assert_eq!(s.total_memory(), 0);
        assert_eq!(s.free_memory(), 0);
        assert_eq!(s.available_memory(), 0);
        assert_eq!(s.used_memory(), 0);
        assert_eq!(s.total_swap(), 0);
        assert_eq!(s.free_swap(), 0);
        assert_eq!(s.used_swap(), 0);

        s.refresh_memory();
        if System::IS_SUPPORTED {
            assert!(s.total_memory() > 0);
            assert!(s.used_memory() > 0);
            if s.total_swap() > 0 {
                // I think it's pretty safe to assume that there is still some swap left...
                assert!(s.free_swap() > 0);
            }
        } else {
            assert_eq!(s.total_memory(), 0);
            assert_eq!(s.used_memory(), 0);
            assert_eq!(s.total_swap(), 0);
            assert_eq!(s.free_swap(), 0);
        }
    }

    #[cfg(target_os = "linux")]
    #[test]
    fn check_cpu_usage() {
        let mut s = System::new();

        s.refresh_all();
        // All CPU usage will start at zero until the second refresh
        assert!(s
            .processes()
            .iter()
            .all(|(_, proc_)| proc_.cpu_usage() == 0.0));

        // Wait a bit to update CPU usage values
        std::thread::sleep(std::time::Duration::from_millis(100));
        s.refresh_all();
        assert!(s
            .processes()
            .iter()
            .all(|(_, proc_)| proc_.cpu_usage() >= 0.0
                && proc_.cpu_usage() <= (s.processors().len() as f32) * 100.0));
    }

    #[test]
    fn check_users() {
        let mut s = System::new();
        assert!(s.users().is_empty());
        s.refresh_users_list();
        assert!(s.users().len() >= MIN_USERS);

        let mut s = System::new();
        assert!(s.users().is_empty());
        s.refresh_all();
        assert!(s.users().is_empty());

        let s = System::new_all();
        assert!(s.users().len() >= MIN_USERS);
    }

    #[test]
    fn check_uid_gid() {
        let mut s = System::new();
        assert!(s.users().is_empty());
        s.refresh_users_list();
        let users = s.users();
        assert!(users.len() >= MIN_USERS);

        if System::IS_SUPPORTED {
            #[cfg(not(target_os = "windows"))]
            {
                let user = users
                    .iter()
                    .find(|u| u.name() == "root")
                    .expect("no root user");
                assert_eq!(*user.uid(), 0);
                assert_eq!(*user.gid(), 0);
                if let Some(user) = users.iter().find(|u| *u.gid() > 0) {
                    assert!(*user.uid() > 0);
                    assert!(*user.gid() > 0);
                }
            }
            #[cfg(not(target_os = "windows"))]
            {
                assert!(users.iter().filter(|u| *u.uid() > 0).count() > 0);
            }
        }
    }

    #[test]
    fn check_system_info() {
        // We don't want to test on unsupported systems.
        if System::IS_SUPPORTED {
            let s = System::new();
            assert!(!s.name().expect("Failed to get system name").is_empty());

            assert!(!s
                .kernel_version()
                .expect("Failed to get kernel version")
                .is_empty());

            assert!(!s.os_version().expect("Failed to get os version").is_empty());

            assert!(!s
                .long_os_version()
                .expect("Failed to get long OS version")
                .is_empty());
        }
    }

    #[test]
    fn check_host_name() {
        // We don't want to test on unsupported systems.
        if System::IS_SUPPORTED {
            let s = System::new();
            assert!(!s.host_name().expect("Failed to get host name").is_empty());
        }
    }

    #[test]
    fn check_refresh_process_return_value() {
        // We don't want to test on unsupported systems.
        if System::IS_SUPPORTED {
            let _pid = get_current_pid().expect("Failed to get current PID");

            #[cfg(not(feature = "apple-sandbox"))]
            {
                let mut s = System::new();
                // First check what happens in case the process isn't already in our process list.
                assert!(s.refresh_process(_pid));
                // Then check that it still returns true if the process is already in our process list.
                assert!(s.refresh_process(_pid));
            }
        }
    }

    #[test]
    fn ensure_is_supported_is_set_correctly() {
        if MIN_USERS > 0 {
            assert!(System::IS_SUPPORTED);
        } else {
            assert!(!System::IS_SUPPORTED);
        }
    }

    #[test]
    fn check_processors_number() {
        let s = System::new();

        if System::IS_SUPPORTED {
            assert!(!s.processors().is_empty());
            // In case we are running inside a VM, it's possible to not have a physical core, only
            // logical ones, which is why we don't test `physical_cores_count > 0`.
            let physical_cores_count = s
                .physical_core_count()
                .expect("failed to get number of physical cores");
            assert!(physical_cores_count <= s.processors().len());
        } else {
            assert!(s.processors().is_empty());
            assert_eq!(s.physical_core_count(), None);
        }
    }
}

// Used to check that System is Send and Sync.
#[cfg(doctest)]
/// ```
/// fn is_send<T: Send>() {}
/// is_send::<sysinfo::System>();
/// ```
///
/// ```
/// fn is_sync<T: Sync>() {}
/// is_sync::<sysinfo::System>();
/// ```
pub mod check_if_system_is_send_and_sync {}
<commit_msg>Extend processor test<commit_after>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

#![crate_name = "sysinfo"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![doc = include_str!("../README.md")]
#![allow(unknown_lints)]
#![deny(missing_docs)]
#![deny(rustdoc::broken_intra_doc_links)]
#![allow(clippy::upper_case_acronyms)]
#![allow(renamed_and_removed_lints)]

#[cfg(feature = "debug")]
#[doc(hidden)]
#[allow(unused)]
macro_rules! sysinfo_debug {
    ($($x:tt)*) => {{
        eprintln!($($x)*);
    }}
}

#[cfg(not(feature = "debug"))]
#[doc(hidden)]
#[allow(unused)]
macro_rules! sysinfo_debug {
    ($($x:tt)*) => {{}};
}

cfg_if::cfg_if! {
    if #[cfg(any(target_os = "macos", target_os = "ios"))] {
        mod apple;
        use apple as sys;
        extern crate core_foundation_sys;

        #[cfg(test)]
        pub(crate) const MIN_USERS: usize = 1;
    } else if #[cfg(windows)] {
        mod windows;
        use windows as sys;
        extern crate winapi;
        extern crate ntapi;

        #[cfg(test)]
        pub(crate) const MIN_USERS: usize = 1;
    } else if #[cfg(any(target_os = "linux", target_os = "android"))] {
        mod linux;
        use linux as sys;

        #[cfg(test)]
        pub(crate) const MIN_USERS: usize = 1;
    } else {
        mod unknown;
        use unknown as sys;

        #[cfg(test)]
        pub(crate) const MIN_USERS: usize = 0;
    }
}

pub use common::{
    AsU32, DiskType, DiskUsage, Gid, LoadAvg, NetworksIter, Pid, RefreshKind, Signal, Uid, User,
};
pub use sys::{Component, Disk, NetworkData, Networks, Process, ProcessStatus, Processor, System};
pub use traits::{
    ComponentExt, DiskExt, NetworkExt, NetworksExt, ProcessExt, ProcessorExt, SystemExt, UserExt,
};

#[cfg(feature = "c-interface")]
pub use c_interface::*;
pub use utils::get_current_pid;

#[cfg(feature = "c-interface")]
mod c_interface;
mod common;
mod debug;
mod system;
mod traits;
mod utils;

/// This function is only used on linux targets, on the other platforms it does nothing and returns
/// `false`.
///
/// On linux, to improve performance, we keep a `/proc` file open for each process we index with
/// a maximum number of files open equivalent to half of the system limit.
///
/// The problem is that some users might need all the available file descriptors so we need to
/// allow them to change this limit.
///
/// Note that if you set a limit bigger than the system limit, the system limit will be set.
///
/// Returns `true` if the new value has been set.
///
/// ```no_run
/// use sysinfo::{System, SystemExt, set_open_files_limit};
///
/// // We call the function before any call to the processes update.
/// if !set_open_files_limit(10) {
///     // It'll always return false on non-linux targets.
///     eprintln!("failed to update the open files limit...");
/// }
/// let s = System::new_all();
/// ```
pub fn set_open_files_limit(mut _new_limit: isize) -> bool {
    #[cfg(any(target_os = "linux", target_os = "android"))]
    {
        if _new_limit < 0 {
            _new_limit = 0;
        }
        let max = sys::system::get_max_nb_fds();
        if _new_limit > max {
            _new_limit = max;
        }
        if let Ok(ref mut x) = unsafe { sys::system::REMAINING_FILES.lock() } {
            // If files are already open, to be sure that the number won't be bigger when those
            // files are closed, we subtract the current number of opened files to the new limit.
            let diff = max - **x;
            **x = _new_limit - diff;
            true
        } else {
            false
        }
    }
    #[cfg(all(not(target_os = "linux"), not(target_os = "android")))]
    {
        false
    }
}

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

    #[test]
    fn check_process_memory_usage() {
        let mut s = System::new();
        s.refresh_all();

        if System::IS_SUPPORTED {
            // No process should have 0 as memory usage.
            #[cfg(not(feature = "apple-sandbox"))]
            assert!(!s.processes().iter().all(|(_, proc_)| proc_.memory() == 0));
        } else {
            // There should be no process, but if there is one, its memory usage should be 0.
            assert!(s.processes().iter().all(|(_, proc_)| proc_.memory() == 0));
        }
    }

    #[test]
    fn check_memory_usage() {
        let mut s = System::new();

        assert_eq!(s.total_memory(), 0);
        assert_eq!(s.free_memory(), 0);
        assert_eq!(s.available_memory(), 0);
        assert_eq!(s.used_memory(), 0);
        assert_eq!(s.total_swap(), 0);
        assert_eq!(s.free_swap(), 0);
        assert_eq!(s.used_swap(), 0);

        s.refresh_memory();
        if System::IS_SUPPORTED {
            assert!(s.total_memory() > 0);
            assert!(s.used_memory() > 0);
            if s.total_swap() > 0 {
                // I think it's pretty safe to assume that there is still some swap left...
                assert!(s.free_swap() > 0);
            }
        } else {
            assert_eq!(s.total_memory(), 0);
            assert_eq!(s.used_memory(), 0);
            assert_eq!(s.total_swap(), 0);
            assert_eq!(s.free_swap(), 0);
        }
    }

    #[cfg(target_os = "linux")]
    #[test]
    fn check_cpu_usage() {
        let mut s = System::new();

        s.refresh_all();
        // All CPU usage will start at zero until the second refresh
        assert!(s
            .processes()
            .iter()
            .all(|(_, proc_)| proc_.cpu_usage() == 0.0));

        // Wait a bit to update CPU usage values
        std::thread::sleep(std::time::Duration::from_millis(100));
        s.refresh_all();
        assert!(s
            .processes()
            .iter()
            .all(|(_, proc_)| proc_.cpu_usage() >= 0.0
                && proc_.cpu_usage() <= (s.processors().len() as f32) * 100.0));
    }

    #[test]
    fn check_users() {
        let mut s = System::new();
        assert!(s.users().is_empty());
        s.refresh_users_list();
        assert!(s.users().len() >= MIN_USERS);

        let mut s = System::new();
        assert!(s.users().is_empty());
        s.refresh_all();
        assert!(s.users().is_empty());

        let s = System::new_all();
        assert!(s.users().len() >= MIN_USERS);
    }

    #[test]
    fn check_uid_gid() {
        let mut s = System::new();
        assert!(s.users().is_empty());
        s.refresh_users_list();
        let users = s.users();
        assert!(users.len() >= MIN_USERS);

        if System::IS_SUPPORTED {
            #[cfg(not(target_os = "windows"))]
            {
                let user = users
                    .iter()
                    .find(|u| u.name() == "root")
                    .expect("no root user");
                assert_eq!(*user.uid(), 0);
                assert_eq!(*user.gid(), 0);
                if let Some(user) = users.iter().find(|u| *u.gid() > 0) {
                    assert!(*user.uid() > 0);
                    assert!(*user.gid() > 0);
                }
            }
            #[cfg(not(target_os = "windows"))]
            {
                assert!(users.iter().filter(|u| *u.uid() > 0).count() > 0);
            }
        }
    }

    #[test]
    fn check_system_info() {
        // We don't want to test on unsupported systems.
        if System::IS_SUPPORTED {
            let s = System::new();
            assert!(!s.name().expect("Failed to get system name").is_empty());

            assert!(!s
                .kernel_version()
                .expect("Failed to get kernel version")
                .is_empty());

            assert!(!s.os_version().expect("Failed to get os version").is_empty());

            assert!(!s
                .long_os_version()
                .expect("Failed to get long OS version")
                .is_empty());
        }
    }

    #[test]
    fn check_host_name() {
        // We don't want to test on unsupported systems.
        if System::IS_SUPPORTED {
            let s = System::new();
            assert!(!s.host_name().expect("Failed to get host name").is_empty());
        }
    }

    #[test]
    fn check_refresh_process_return_value() {
        // We don't want to test on unsupported systems.
        if System::IS_SUPPORTED {
            let _pid = get_current_pid().expect("Failed to get current PID");

            #[cfg(not(feature = "apple-sandbox"))]
            {
                let mut s = System::new();
                // First check what happens in case the process isn't already in our process list.
                assert!(s.refresh_process(_pid));
                // Then check that it still returns true if the process is already in our process list.
                assert!(s.refresh_process(_pid));
            }
        }
    }

    #[test]
    fn ensure_is_supported_is_set_correctly() {
        if MIN_USERS > 0 {
            assert!(System::IS_SUPPORTED);
        } else {
            assert!(!System::IS_SUPPORTED);
        }
    }

    #[test]
    fn check_processors_number() {
        let s = System::new();

        if System::IS_SUPPORTED {
            assert!(!s.processors().is_empty());
            // In case we are running inside a VM, it's possible to not have a physical core, only
            // logical ones, which is why we don't test `physical_cores_count > 0`.
            let physical_cores_count = s
                .physical_core_count()
                .expect("failed to get number of physical cores");
            assert!(physical_cores_count <= s.processors().len());
        } else {
            assert!(s.processors().is_empty());
            assert_eq!(s.physical_core_count(), None);
        }
        assert!(s.physical_core_count().unwrap_or(0) <= s.processors().len());
    }
}

// Used to check that System is Send and Sync.
#[cfg(doctest)]
/// ```
/// fn is_send<T: Send>() {}
/// is_send::<sysinfo::System>();
/// ```
///
/// ```
/// fn is_sync<T: Sync>() {}
/// is_sync::<sysinfo::System>();
/// ```
pub mod check_if_system_is_send_and_sync {}
<|endoftext|>


<commit_before>//! MySQL Proxy Server

#[macro_use]
extern crate log;
extern crate env_logger;
#[macro_use]
extern crate futures;
#[macro_use]
extern crate tokio_core;
extern crate futures_cpupool;

use std::cell::RefCell;
use std::rc::Rc;
use std::env;
use std::io::{self, Read, Write};
use std::net::{SocketAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
use std::net::Shutdown;
use std::str;
use std::time::Duration;

use futures::{Future, Poll};
use futures::stream::Stream;
use futures_cpupool::CpuPool;
use tokio_core::{Loop, LoopHandle, TcpStream};
use tokio_core::io::{read_exact, write_all, Window};

fn parse_packet_length(header: &[u8]) -> usize {
    (((header[2] as u32) << 16) |
    ((header[1] as u32) << 8) |
    header[0] as u32) as usize
}

pub struct Client {
    pub pool: CpuPool,
    pub handle: LoopHandle,
}

impl Client {

    pub fn serve(self, conn: TcpStream) -> Box<Future<Item = (u64, u64), Error = io::Error>> {

        let addr = Ipv4Addr::new(127, 0, 0, 1);
        let port = 3306;
        let addr = SocketAddr::V4(SocketAddrV4::new(addr, port));

        let handle = self.handle.clone();
        let connected = handle.tcp_connect(&addr);

        // perform handshake
        let pair = connected.and_then(move |server| {
            read_exact(server, [0u8; 4]).and_then(move |(s,hdr)| {
                let l = parse_packet_length(&hdr);
                read_exact(s, vec![0u8; l]).and_then(move |(s2,payload)| {
                    write_all(conn, hdr).and_then(move |(c2,_)| {
                        write_all(c2, payload).and_then(move |(c3,_)| {
                            Ok((c3, s2))
                        })
                    })
                })
            })
        });

        Box::new(pair.and_then(|(c1, c2)| {
            let c1 = Rc::new(c1);
            let c2 = Rc::new(c2);

            let half1 = Transfer::new(c1.clone(), c2.clone(), Direction::Request);
            let half2 = Transfer::new(c2, c1, Direction::Response);
            half1.join(half2)
        }))
    }
}

struct Transfer {
    reader: Rc<TcpStream>,
    writer: Rc<TcpStream>,
    direction: Direction,
    buf: Vec<u8>,
    pos: usize,
    amt: u64,
}

#[derive(Debug)]
enum Direction {
    Request, Response
}

impl Transfer {
    fn new(reader: Rc<TcpStream>,
           writer: Rc<TcpStream>,
    direction: Direction) -> Transfer {
        Transfer {
            reader: reader,
            writer: writer,
            direction: direction,
            buf: vec![0u8; 4096],
            pos: 0,
            amt: 0,
        }
    }
}

impl Future for Transfer {
    type Item = u64;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<u64, io::Error> {

        loop {
            try_ready!(self.reader.poll_read());
            try_ready!(self.writer.poll_write());

            //TODO: ensure there is capacity in the buffer for further reads
            let n = try_nb!((&*self.reader).read(&mut self.buf[self.pos..]));
            if n == 0 {
                println!("{:?} EOF", self.direction);
                try!(self.writer.shutdown(Shutdown::Write));
                return Ok(self.amt.into())
            }
            self.amt += n as u64;
            self.pos += n;

            // do we have a header
            while self.pos > 3 {
                let l = parse_packet_length(&self.buf);
                println!("{:?} packet_len = {}", self.direction, l);

                // do we have the whole packet?
                let s = 4 + l;
                if self.pos >= s {

                    println!("{:?} Writing MySQL packet: ", self.direction);
                    print_packet_bytes(&self.buf[0..s]);
                    print_packet_chars(&self.buf[0..s]);

                    let m = try!((&*self.writer).write(&self.buf[0..s]));
                    assert_eq!(s, m);

                    //TODO: must be more efficient way to do this
                    for _ in 0..s {
                        self.buf.remove(0);
                    }

                    self.pos -= s;
                } else {
                    println!("not enough bytes for packet");
                    break;
                }
            }
        }
    }
}

#[allow(dead_code)]
fn print_packet_chars(buf: &[u8]) {
    print!("[");
    for i in 0..buf.len() {
        print!("{} ", buf[i] as char);
    }
    println!("]");
}

#[allow(dead_code)]
fn print_packet_bytes(buf: &[u8]) {
    print!("[");
    for i in 0..buf.len() {
        if i%8==0 { println!(""); }
        print!("{:#04x} ",buf[i]);
    }
    println!("]");
}

<commit_msg>add PacketHandler trait object<commit_after>//! MySQL Proxy Server

#[macro_use]
extern crate log;
extern crate env_logger;
#[macro_use]
extern crate futures;
#[macro_use]
extern crate tokio_core;
extern crate futures_cpupool;

use std::cell::RefCell;
use std::rc::Rc;
use std::env;
use std::io::{self, Read, Write};
use std::net::{SocketAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
use std::net::Shutdown;
use std::str;
use std::time::Duration;

use futures::{Future, Poll};
use futures::stream::Stream;
use futures_cpupool::CpuPool;
use tokio_core::{Loop, LoopHandle, TcpStream};
use tokio_core::io::{read_exact, write_all, Window};

pub struct Packet<'a> {
    pub header: &'a [u8],
    pub payload: &'a [u8],
}

pub trait PacketHandler {
    fn handle(&self, p: Packet);
}

fn parse_packet_length(header: &[u8]) -> usize {
    (((header[2] as u32) << 16) |
    ((header[1] as u32) << 8) |
    header[0] as u32) as usize
}

pub struct Client {
    pub pool: CpuPool,
    pub handle: LoopHandle,
}

impl Client {

    pub fn serve(self, conn: TcpStream) -> Box<Future<Item = (u64, u64), Error = io::Error>> {

        let addr = Ipv4Addr::new(127, 0, 0, 1);
        let port = 3306;
        let addr = SocketAddr::V4(SocketAddrV4::new(addr, port));

        let handle = self.handle.clone();
        let connected = handle.tcp_connect(&addr);

        // perform handshake
        let pair = connected.and_then(move |server| {
            read_exact(server, [0u8; 4]).and_then(move |(s,hdr)| {
                let l = parse_packet_length(&hdr);
                read_exact(s, vec![0u8; l]).and_then(move |(s2,payload)| {
                    write_all(conn, hdr).and_then(move |(c2,_)| {
                        write_all(c2, payload).and_then(move |(c3,_)| {
                            Ok((c3, s2))
                        })
                    })
                })
            })
        });

        Box::new(pair.and_then(|(c1, c2)| {
            let c1 = Rc::new(c1);
            let c2 = Rc::new(c2);

            let half1 = Transfer::new(c1.clone(), c2.clone(), Direction::Request);
            let half2 = Transfer::new(c2, c1, Direction::Response);
            half1.join(half2)
        }))
    }
}

struct Transfer {
    reader: Rc<TcpStream>,
    writer: Rc<TcpStream>,
    direction: Direction,
    buf: Vec<u8>,
    pos: usize,
    amt: u64,
}

#[derive(Debug)]
enum Direction {
    Request, Response
}

impl Transfer {
    fn new(reader: Rc<TcpStream>,
           writer: Rc<TcpStream>,
    direction: Direction) -> Transfer {
        Transfer {
            reader: reader,
            writer: writer,
            direction: direction,
            buf: vec![0u8; 4096],
            pos: 0,
            amt: 0,
        }
    }
}

impl Future for Transfer {
    type Item = u64;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<u64, io::Error> {

        loop {
            try_ready!(self.reader.poll_read());
            try_ready!(self.writer.poll_write());

            //TODO: ensure there is capacity in the buffer for further reads
            let n = try_nb!((&*self.reader).read(&mut self.buf[self.pos..]));
            if n == 0 {
                println!("{:?} EOF", self.direction);
                try!(self.writer.shutdown(Shutdown::Write));
                return Ok(self.amt.into())
            }
            self.amt += n as u64;
            self.pos += n;

            // do we have a header
            while self.pos > 3 {
                let l = parse_packet_length(&self.buf);
                println!("{:?} packet_len = {}", self.direction, l);

                // do we have the whole packet?
                let s = 4 + l;
                if self.pos >= s {

                    println!("{:?} Writing MySQL packet: ", self.direction);
                    print_packet_bytes(&self.buf[0..s]);
                    print_packet_chars(&self.buf[0..s]);

                    let m = try!((&*self.writer).write(&self.buf[0..s]));
                    assert_eq!(s, m);

                    //TODO: must be more efficient way to do this
                    for _ in 0..s {
                        self.buf.remove(0);
                    }

                    self.pos -= s;
                } else {
                    println!("not enough bytes for packet");
                    break;
                }
            }
        }
    }
}

#[allow(dead_code)]
fn print_packet_chars(buf: &[u8]) {
    print!("[");
    for i in 0..buf.len() {
        print!("{} ", buf[i] as char);
    }
    println!("]");
}

#[allow(dead_code)]
fn print_packet_bytes(buf: &[u8]) {
    print!("[");
    for i in 0..buf.len() {
        if i%8==0 { println!(""); }
        print!("{:#04x} ",buf[i]);
    }
    println!("]");
}

<|endoftext|>


<commit_before>pub mod env_reader;
pub mod sleeper;
pub mod tcp;

pub struct Config {
    pub hosts: String,
    pub timeout : u64,
    pub wait_before : u64,
    pub wait_after : u64,
    pub wait_sleep_interval : u64
}

pub fn wait(sleep: &sleeper::Sleeper, config: &Config, on_timeout : &mut FnMut() ) {

    println!("Docker-compose-wait starting with configuration:");
    println!("------------------------------------------------");
    println!(" - Hosts to be waiting for: [{}]", config.hosts);
    println!(" - Timeout before failure: {} seconds ", config.timeout);
    println!(" - Sleeping time before checking for hosts availability: {} seconds", config.wait_before);
    println!(" - Sleeping time once all hosts are available: {} seconds", config.wait_after);
    println!("------------------------------------------------");

    if config.wait_before > 0 {
        println!("Waiting {} seconds before checking for hosts availability", config.wait_before);
        sleep.sleep(config.wait_before);
    }

    if !config.hosts.trim().is_empty() {
        let mut count = 0;
        //let start = Instant::now();
        for host in config.hosts.trim().split(',') {
            println!("Checking availability of {}", host);
            while !tcp::is_reachable(&host.trim().to_string()) {
                println!("Host {} not yet available", host);
                count = count + 1;
                if count > config.timeout {
                //if (start.elapsed().as_secs() > wait_timeout) {
                    println!("Timeout! After {} seconds some hosts are still not reachable", config.timeout);
                    on_timeout();
                    return;
                }
                sleep.sleep(config.wait_sleep_interval);
            }
            println!("Host {} is now available", host);
        }
    }

    if config.wait_after > 0 {
        println!("Waiting {} seconds after hosts availability", config.wait_after);
        sleep.sleep(config.wait_after);
    }
}

pub fn config_from_env() -> Config {
    Config {
        hosts: env_reader::env_var(&"WAIT_HOSTS".to_string(), "".to_string()),
        timeout: to_int(env_reader::env_var(&"WAIT_HOSTS_TIMEOUT".to_string(), "".to_string()), 30),
        wait_before: to_int(env_reader::env_var(&"WAIT_BEFORE_HOSTS".to_string(), "".to_string()), 0),
        wait_after: to_int(env_reader::env_var(&"WAIT_AFTER_HOSTS".to_string(), "".to_string()), 0),
        wait_sleep_interval: to_int(env_reader::env_var(&"WAIT_SLEEP_INTERVAL".to_string(), "".to_string()), 1),
    }
}

fn to_int(number: String, default : u64) -> u64 {
    match number.parse::<u64>() {
        Ok(value) => value,
        Err(_e) => default
    }
}

#[cfg(test)]
mod test {

    use std::env;
    use super::*;

    #[test]
    fn should_return_int_value() {
        let value = to_int("32".to_string(), 0);
        assert!(32 == value)
    }

    #[test]
    fn should_return_zero_when_negative_value() {
        let value = to_int("-32".to_string(), 10);
        assert!(10 == value)
    }

    #[test]
    fn should_return_zero_when_invalid_value() {
        let value = to_int("hello".to_string(), 0);
        assert!(0 == value)
    }

    #[test]
    fn should_return_zero_when_empty_value() {
        let value = to_int("".to_string(), 11);
        assert!(11 == value)
    }

/*
    #[test]
    fn default_timeout_should_be_30() {
        set_env("", "", "10o", "10");
        let config = config_from_env();
        assert_eq!("".to_string(), config.hosts);
        assert_eq!(30, config.timeout);
        assert_eq!(0, config.wait_before);
        assert_eq!(10, config.wait_after);
    }
*/

    #[test]
    fn should_get_config_values_from_env() {
        set_env("localhost:1234", "", "2", "3", "");
        let config = config_from_env();
        assert_eq!("localhost:1234".to_string(), config.hosts);
        assert_eq!(30, config.timeout);
        assert_eq!(2, config.wait_before);
        assert_eq!(3, config.wait_after);
        assert_eq!(1, config.wait_sleep_interval);
    }

    fn set_env(hosts: &str, timeout: &str, before: &str, after: &str, sleep: &str) {
        env::set_var("WAIT_BEFORE_HOSTS", before.to_string());
        env::set_var("WAIT_AFTER_HOSTS", after.to_string());
        env::set_var("WAIT_HOSTS_TIMEOUT", timeout.to_string());
        env::set_var("WAIT_HOSTS", hosts.to_string());
        env::set_var("WAIT_SLEEP_INTERVAL", sleep.to_string());
    }
}
<commit_msg>Added requested unit-test, attempted to add additional unit-test to assert the defaults, this fails.<commit_after>pub mod env_reader;
pub mod sleeper;
pub mod tcp;

pub struct Config {
    pub hosts: String,
    pub timeout : u64,
    pub wait_before : u64,
    pub wait_after : u64,
    pub wait_sleep_interval : u64
}

pub fn wait(sleep: &sleeper::Sleeper, config: &Config, on_timeout : &mut FnMut() ) {

    println!("Docker-compose-wait starting with configuration:");
    println!("------------------------------------------------");
    println!(" - Hosts to be waiting for: [{}]", config.hosts);
    println!(" - Timeout before failure: {} seconds ", config.timeout);
    println!(" - Sleeping time before checking for hosts availability: {} seconds", config.wait_before);
    println!(" - Sleeping time once all hosts are available: {} seconds", config.wait_after);
    println!("------------------------------------------------");

    if config.wait_before > 0 {
        println!("Waiting {} seconds before checking for hosts availability", config.wait_before);
        sleep.sleep(config.wait_before);
    }

    if !config.hosts.trim().is_empty() {
        let mut count = 0;
        //let start = Instant::now();
        for host in config.hosts.trim().split(',') {
            println!("Checking availability of {}", host);
            while !tcp::is_reachable(&host.trim().to_string()) {
                println!("Host {} not yet available", host);
                count = count + 1;
                if count > config.timeout {
                //if (start.elapsed().as_secs() > wait_timeout) {
                    println!("Timeout! After {} seconds some hosts are still not reachable", config.timeout);
                    on_timeout();
                    return;
                }
                sleep.sleep(config.wait_sleep_interval);
            }
            println!("Host {} is now available", host);
        }
    }

    if config.wait_after > 0 {
        println!("Waiting {} seconds after hosts availability", config.wait_after);
        sleep.sleep(config.wait_after);
    }
}

pub fn config_from_env() -> Config {
    Config {
        hosts: env_reader::env_var(&"WAIT_HOSTS".to_string(), "".to_string()),
        timeout: to_int(env_reader::env_var(&"WAIT_HOSTS_TIMEOUT".to_string(), "".to_string()), 30),
        wait_before: to_int(env_reader::env_var(&"WAIT_BEFORE_HOSTS".to_string(), "".to_string()), 0),
        wait_after: to_int(env_reader::env_var(&"WAIT_AFTER_HOSTS".to_string(), "".to_string()), 0),
        wait_sleep_interval: to_int(env_reader::env_var(&"WAIT_SLEEP_INTERVAL".to_string(), "".to_string()), 1),
    }
}

fn to_int(number: String, default : u64) -> u64 {
    match number.parse::<u64>() {
        Ok(value) => value,
        Err(_e) => default
    }
}

#[cfg(test)]
mod test {

    use std::env;
    use super::*;

    #[test]
    fn should_return_int_value() {
        let value = to_int("32".to_string(), 0);
        assert!(32 == value)
    }

    #[test]
    fn should_return_zero_when_negative_value() {
        let value = to_int("-32".to_string(), 10);
        assert!(10 == value)
    }

    #[test]
    fn should_return_zero_when_invalid_value() {
        let value = to_int("hello".to_string(), 0);
        assert!(0 == value)
    }

    #[test]
    fn should_return_zero_when_empty_value() {
        let value = to_int("".to_string(), 11);
        assert!(11 == value)
    }

/*
    #[test]
    fn default_timeout_should_be_30() {
        set_env("", "", "10o", "10");
        let config = config_from_env();
        assert_eq!("".to_string(), config.hosts);
        assert_eq!(30, config.timeout);
        assert_eq!(0, config.wait_before);
        assert_eq!(10, config.wait_after);
    }
*/

    #[test]
    fn should_get_config_values_from_env() {
        set_env("localhost:1234", "20", "2", "3", "4");
        let config = config_from_env();
        assert_eq!("localhost:1234".to_string(), config.hosts);
        assert_eq!(20, config.timeout);
        assert_eq!(2, config.wait_before);
        assert_eq!(3, config.wait_after);
        assert_eq!(4, config.wait_sleep_interval);
    }

/*     #[test]
    fn should_get_default_config_values() {
        set_env("localhost:1234", "", "", "", "");
        let config = config_from_env();
        assert_eq!("localhost:1234".to_string(), config.hosts);
        assert_eq!(30, config.timeout);
        assert_eq!(0, config.wait_before);
        assert_eq!(0, config.wait_after);
        assert_eq!(1, config.wait_sleep_interval);
    }
 */
    fn set_env(hosts: &str, timeout: &str, before: &str, after: &str, sleep: &str) {
        env::set_var("WAIT_BEFORE_HOSTS", before.to_string());
        env::set_var("WAIT_AFTER_HOSTS", after.to_string());
        env::set_var("WAIT_HOSTS_TIMEOUT", timeout.to_string());
        env::set_var("WAIT_HOSTS", hosts.to_string());
        env::set_var("WAIT_SLEEP_INTERVAL", sleep.to_string());
    }
}
<|endoftext|>


<commit_before>//! # aHash
//!
//! This hashing algorithm is intended to be a high perfromance, (hardware specific), keyed hash function.
//! This can be seen as a DOS resistant alternative to FxHash, or a fast equivalent to SipHash.
//! It provides a high speed hash algorithm, but where the result is not predictable without knowing a Key.
//! This allows it to be used in a HashMap without allowing for the possibility that an malicious user can
//! induce a collision.
//!
//! # How aHash works
//!
//! aHash uses the hardware AES instruction on x86 processors to provide a keyed hash function.
//! It uses two rounds of AES per hash. So it should not be considered cryptographically secure.

mod convert;

use crate::convert::Convert;
use std::collections::HashMap;
use std::default::Default;
use std::hash::{BuildHasherDefault, Hasher, BuildHasher};
use std::mem::transmute;

/// A `HashMap` using a `LocationBasedState` BuildHasher to hash the items.
pub type AHashMap<K, V> = HashMap<K, V, LocationBasedState>;

const DEFAULT_KEYS: [u64; 2] = [0x6c62_272e_07bb_0142, 0x517c_c1b7_2722_0a95];

/// Provides a [BuildHasher] is typically used (e.g. by [HashMap]) to create
/// [AHasher]s for each key such that they are hashed independently of one
/// another, since [AHasher]s contain state.
///
/// LocationBasedState uses it's in-memory location to see the AHasher. This
/// is more predictable than true random values, but does not require generating
/// randomness.
///
/// For each instance of [LocationBasedState], the [AHasher]s created by
/// [BuildHasher] should be identical. That is, if the same stream of bytes
/// is fed into each hasher, the same output will also be generated.
///
/// # Examples
///
/// ```
/// use ahash::LocationBasedState;
/// use std::hash::{BuildHasher, Hasher};
///
/// let s = LocationBasedState::new();
/// let mut hasher_1 = s.build_hasher();
/// let mut hasher_2 = s.build_hasher();
///
/// hasher_1.write_u32(8128);
/// hasher_2.write_u32(8128);
///
/// assert_eq!(hasher_1.finish(), hasher_2.finish());
/// ```
/// [BuildHasher]: std::hash::BuildHasher
/// [Hasher]: std::hash::Hasher
pub struct LocationBasedState {}

impl LocationBasedState {
    pub fn new() -> LocationBasedState {
        LocationBasedState {}
    }
}

impl BuildHasher for LocationBasedState {
    type Hasher = AHasher;

    fn build_hasher(&self) -> AHasher {
        let location = self as *const Self as u64;
        AHasher { buffer: [location, location.rotate_left(8)] }
    }
}

impl Default for LocationBasedState {
    fn default() -> LocationBasedState {
        LocationBasedState {}
    }
}

/// A `Hasher` for hashing an arbitrary stream of bytes.
///
/// Instances of [AHasher] represent state that is updated while hashing data.
///
/// Each method updates the internal state based on the new data provided. Once
/// all of the data has been provided, the resulting hash can be obtained by calling
/// `finish()`
///
/// #Example
///
/// ```
/// use std::hash::Hasher;
/// use ahash::AHasher;
///
/// let mut hasher = AHasher::new_with_keys(123, 456);
///
/// hasher.write_u32(1989);
/// hasher.write_u8(11);
/// hasher.write_u8(9);
/// hasher.write(b"Huh?");
///
/// println!("Hash is {:x}!", hasher.finish());
/// ```
/// [Clone] is also provided in case you wish to calculate hashes for two different items that
/// start with the same data.
///
#[derive(Debug, Clone)]
pub struct AHasher {
    buffer: [u64; 2],
}

impl AHasher {
    pub fn new_with_keys(key0: u64, key1: u64) -> AHasher {
        AHasher { buffer: [key0, key1] }
    }
}

/// Constructs a new [AHasher] with fixed constant keys.
/// (This is not recommended in situations where a DOS attack is a concern)
impl Default for AHasher {
    #[inline]
    fn default() -> AHasher {
        AHasher { buffer: [DEFAULT_KEYS[0], DEFAULT_KEYS[1]] }
    }
}

macro_rules! as_array {
    ($input:expr, $len:expr) => {{
        {
            #[inline]
            fn as_array<T>(slice: &[T]) -> &[T; $len] {
                assert_eq!(slice.len(), $len);
                unsafe {
                    &*(slice.as_ptr() as *const [_; $len])
                }
            }
            as_array($input)
        }
    }}
}

/// Provides methods to hash all of the primitive types.
impl Hasher for AHasher {
    //Implementation note: each of the write_XX methods passes the arguments slightly differently to hash.
    //This is done so that an u8 and a u64 that both contain the same value will produce different hashes.
    #[inline]
    fn write_u8(&mut self, i: u8) {
        self.buffer = hash([self.buffer[1], self.buffer[0] ^ i as u64].convert(), self.buffer.convert()).convert();
    }

    #[inline]
    fn write_u16(&mut self, i: u16) {
        self.buffer = hash([self.buffer[1] ^ i as u64, self.buffer[0]].convert(), self.buffer.convert()).convert();
    }

    #[inline]
    fn write_u32(&mut self, i: u32) {
        self.buffer = hash([self.buffer[0], self.buffer[1] ^ i as u64].convert(), self.buffer.convert()).convert();
    }

    #[inline]
    fn write_u128(&mut self, i: u128) {
        let buffer: u128 = self.buffer.convert();
        self.buffer = hash((buffer ^ i).convert(), self.buffer.convert()).convert();
    }

    #[inline]
    fn write_usize(&mut self, i: usize) {
        self.write_u64(i as u64);
    }

    #[inline]
    fn write_u64(&mut self, i: u64) {
        self.buffer = hash([self.buffer[0] ^ i, self.buffer[1]].convert(), self.buffer.convert()).convert();
    }
    #[inline]
    fn write(&mut self, input: &[u8]) {
        let mut data = input;
        let mut remainder_low: u64 = self.buffer[0];
        let mut remainder_hi: u64 = self.buffer[1];
        if data.len() >= 16 {
            while data.len() >= 16 {
                let (block, rest) = data.split_at(16);
                let block: &[u8; 16] = as_array!(block, 16);
                self.buffer = hash(self.buffer.convert(), *block).convert();
                data = rest;
            }
            self.buffer = hash(self.buffer.convert(), self.buffer.convert()).convert();
        }
        if data.len() >= 8 {
            let (block, rest) = data.split_at(8);
            let val: u64 = as_array!(block, 8).convert();
            remainder_hi ^= val;
            remainder_hi = remainder_hi.rotate_left(32);
            data = rest;
        }
        if data.len() >= 4 {
            let (block, rest) = data.split_at(4);
            let val: u32 = as_array!(block, 4).convert();
            remainder_low ^= val as u64;
            remainder_low = remainder_low.rotate_left(32);
            data = rest;
        }
        if data.len() >= 2 {
            let (block, rest) = data.split_at(2);
            let val: u16 = as_array!(block, 2).convert();
            remainder_low ^= val as u64;
            remainder_low = remainder_low.rotate_left(16);
            data = rest;
        }
        if data.len() >= 1 {
            remainder_low ^= data[0] as u64;
            remainder_low = remainder_low.rotate_left(8);
        }
        self.buffer = hash([remainder_low, remainder_hi].convert(), self.buffer.convert()).convert();
    }
    #[inline]
    fn finish(&self) -> u64 {
        let result: [u64; 2] = hash(self.buffer.convert(), self.buffer.convert()).convert();
        result[0]//.wrapping_add(result[1])
    }
}

#[inline(always)]
fn hash(value: [u8; 16], xor: [u8; 16]) -> [u8; 16] {
    #[cfg(target_arch = "x86")]
    use core::arch::x86::*;
    #[cfg(target_arch = "x86_64")]
    use std::arch::x86_64::*;
    unsafe {
        let value = transmute(value);
        transmute(_mm_aesenc_si128(value, transmute(xor)))
    }
}

#[cfg(all(
any(target_arch = "x86", target_arch = "x86_64"),
target_feature = "aes"
))]
#[cfg(test)]
mod tests {
    use crate::convert::Convert;
    use crate::*;

    #[test]
    fn test_builder() {
        let mut map = HashMap::<u32, u64, LocationBasedState>::default();
        map.insert(1, 3);
    }

    #[test]
    fn test_location_based_state() {
        let state = LocationBasedState::new();
        let hasher_a = state.build_hasher();
        assert_ne!(0, hasher_a.buffer[0]);
        assert_ne!(0, hasher_a.buffer[1]);
        assert_ne!(hasher_a.buffer[0], AHasher::default().buffer[0]);
        assert_ne!(hasher_a.buffer[1], AHasher::default().buffer[1]);
        let hasher_b = state.build_hasher();
        assert_eq!(hasher_a.buffer[0], hasher_b.buffer[0]);
        assert_eq!(hasher_a.buffer[1], hasher_b.buffer[1]);
    }

    #[test]
    fn test_hash() {
        let mut result: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
        let value: [u64; 2] = [1 << 32, 0xFEDCBA9876543210];
        result = hash(value.convert(), result.convert()).convert();
        result = hash(result.convert(), result.convert()).convert();
        let mut result2: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
        let value2: [u64; 2] = [1, 0xFEDCBA9876543210];
        result2 = hash(value2.convert(), result2.convert()).convert();
        result2 = hash(result2.convert(), result.convert()).convert();
        let result: [u8; 16] = result.convert();
        let result2: [u8; 16] = result2.convert();
        assert_ne!(hex::encode(result), hex::encode(result2));
    }

    #[test]
    fn test_conversion() {
        let input: &[u8] = "dddddddd".as_bytes();
        let bytes: u64 = as_array!(input, 8).convert();
        assert_eq!(bytes, 0x6464646464646464);
    }
}
<commit_msg>Change how memory address is used to obtain key. Add some comments<commit_after>//! # aHash
//!
//! This hashing algorithm is intended to be a high perfromance, (hardware specific), keyed hash function.
//! This can be seen as a DOS resistant alternative to FxHash, or a fast equivalent to SipHash.
//! It provides a high speed hash algorithm, but where the result is not predictable without knowing a Key.
//! This allows it to be used in a HashMap without allowing for the possibility that an malicious user can
//! induce a collision.
//!
//! # How aHash works
//!
//! aHash uses the hardware AES instruction on x86 processors to provide a keyed hash function.
//! It uses two rounds of AES per hash. So it should not be considered cryptographically secure.

mod convert;

use crate::convert::Convert;
use std::collections::HashMap;
use std::default::Default;
use std::hash::{BuildHasherDefault, Hasher, BuildHasher};
use std::mem::transmute;

/// A `HashMap` using a `LocationBasedState` BuildHasher to hash the items.
pub type AHashMap<K, V> = HashMap<K, V, LocationBasedState>;

//These values are not special
const DEFAULT_KEYS: [u64; 2] = [0x6c62_272e_07bb_0142, 0x517c_c1b7_2722_0a95];

/// Provides a [BuildHasher] is typically used (e.g. by [HashMap]) to create
/// [AHasher]s for each key such that they are hashed independently of one
/// another, since [AHasher]s contain state.
///
/// LocationBasedState uses it's in-memory location to see the AHasher. This
/// is more predictable than true random values, but does not require generating
/// randomness.
///
/// For each instance of [LocationBasedState], the [AHasher]s created by
/// [BuildHasher] should be identical. That is, if the same stream of bytes
/// is fed into each hasher, the same output will also be generated.
///
/// # Examples
///
/// ```
/// use ahash::LocationBasedState;
/// use std::hash::{BuildHasher, Hasher};
///
/// let s = LocationBasedState::new();
/// let mut hasher_1 = s.build_hasher();
/// let mut hasher_2 = s.build_hasher();
///
/// hasher_1.write_u32(8128);
/// hasher_2.write_u32(8128);
///
/// assert_eq!(hasher_1.finish(), hasher_2.finish());
/// ```
/// [BuildHasher]: std::hash::BuildHasher
/// [Hasher]: std::hash::Hasher
pub struct LocationBasedState {}

impl LocationBasedState {
    pub fn new() -> LocationBasedState {
        LocationBasedState {}
    }
}

impl BuildHasher for LocationBasedState {
    type Hasher = AHasher;

    fn build_hasher(&self) -> AHasher {
        let location = self as *const Self as u64;
        AHasher { buffer: [location, location.wrapping_mul(DEFAULT_KEYS[1])] }
    }
}

impl Default for LocationBasedState {
    fn default() -> LocationBasedState {
        LocationBasedState {}
    }
}

/// A `Hasher` for hashing an arbitrary stream of bytes.
///
/// Instances of [AHasher] represent state that is updated while hashing data.
///
/// Each method updates the internal state based on the new data provided. Once
/// all of the data has been provided, the resulting hash can be obtained by calling
/// `finish()`
///
/// #Example
///
/// ```
/// use std::hash::Hasher;
/// use ahash::AHasher;
///
/// let mut hasher = AHasher::new_with_keys(123, 456);
///
/// hasher.write_u32(1989);
/// hasher.write_u8(11);
/// hasher.write_u8(9);
/// hasher.write(b"Huh?");
///
/// println!("Hash is {:x}!", hasher.finish());
/// ```
/// [Clone] is also provided in case you wish to calculate hashes for two different items that
/// start with the same data.
///
#[derive(Debug, Clone)]
pub struct AHasher {
    buffer: [u64; 2],
}

impl AHasher {
    pub fn new_with_keys(key0: u64, key1: u64) -> AHasher {
        AHasher { buffer: [key0, key1] }
    }
}

/// Constructs a new [AHasher] with fixed constant keys.
/// (This is not recommended in situations where a DOS attack is a concern)
impl Default for AHasher {
    #[inline]
    fn default() -> AHasher {
        AHasher { buffer: [DEFAULT_KEYS[0], DEFAULT_KEYS[1]] }
    }
}

macro_rules! as_array {
    ($input:expr, $len:expr) => {{
        {
            #[inline]
            fn as_array<T>(slice: &[T]) -> &[T; $len] {
                assert_eq!(slice.len(), $len);
                unsafe {
                    &*(slice.as_ptr() as *const [_; $len])
                }
            }
            as_array($input)
        }
    }}
}

/// Provides methods to hash all of the primitive types.
impl Hasher for AHasher {
    //Implementation note: each of the write_XX methods passes the arguments slightly differently to hash.
    //This is done so that an u8 and a u64 that both contain the same value will produce different hashes.
    #[inline]
    fn write_u8(&mut self, i: u8) {
        self.buffer = hash([self.buffer[1], self.buffer[0] ^ i as u64].convert(), self.buffer.convert()).convert();
    }

    #[inline]
    fn write_u16(&mut self, i: u16) {
        self.buffer = hash([self.buffer[1] ^ i as u64, self.buffer[0]].convert(), self.buffer.convert()).convert();
    }

    #[inline]
    fn write_u32(&mut self, i: u32) {
        self.buffer = hash([self.buffer[0], self.buffer[1] ^ i as u64].convert(), self.buffer.convert()).convert();
    }

    #[inline]
    fn write_u128(&mut self, i: u128) {
        let buffer: u128 = self.buffer.convert();
        self.buffer = hash((buffer ^ i).convert(), self.buffer.convert()).convert();
    }

    #[inline]
    fn write_usize(&mut self, i: usize) {
        self.write_u64(i as u64);
    }

    #[inline]
    fn write_u64(&mut self, i: u64) {
        self.buffer = hash([self.buffer[0] ^ i, self.buffer[1]].convert(), self.buffer.convert()).convert();
    }
    #[inline]
    fn write(&mut self, input: &[u8]) {
        let mut data = input;
        let mut remainder_low: u64 = self.buffer[0];
        let mut remainder_hi: u64 = self.buffer[1];
        if data.len() >= 16 {
            while data.len() >= 16 {
                let (block, rest) = data.split_at(16);
                let block: &[u8; 16] = as_array!(block, 16);
                self.buffer = hash(self.buffer.convert(), *block).convert();
                data = rest;
            }
            //This is to hash the final block read in the loop. Note the argument order to hash in the loop.
            self.buffer = hash(self.buffer.convert(), self.buffer.convert()).convert();
        }
        if data.len() >= 8 {
            let (block, rest) = data.split_at(8);
            let val: u64 = as_array!(block, 8).convert();
            remainder_hi ^= val;
            // This rotate is done to prevent someone from creating a collision by adding 8 nulls to a value.
            remainder_hi = remainder_hi.rotate_left(32);
            data = rest;
        }
        if data.len() >= 4 {
            let (block, rest) = data.split_at(4);
            let val: u32 = as_array!(block, 4).convert();
            remainder_low ^= val as u64;
            remainder_low = remainder_low.rotate_left(32);
            data = rest;
        }
        if data.len() >= 2 {
            let (block, rest) = data.split_at(2);
            let val: u16 = as_array!(block, 2).convert();
            remainder_low ^= val as u64;
            remainder_low = remainder_low.rotate_left(16);
            data = rest;
        }
        if data.len() >= 1 {
            remainder_low ^= data[0] as u64;
            remainder_low = remainder_low.rotate_left(8);
        }
        self.buffer = hash([remainder_low, remainder_hi].convert(), self.buffer.convert()).convert();
    }
    #[inline]
    fn finish(&self) -> u64 {
        let result: [u64; 2] = hash(self.buffer.convert(), self.buffer.convert()).convert();
        result[0]//.wrapping_add(result[1])
    }
}

#[inline(always)]
fn hash(value: [u8; 16], xor: [u8; 16]) -> [u8; 16] {
    #[cfg(target_arch = "x86")]
    use core::arch::x86::*;
    #[cfg(target_arch = "x86_64")]
    use std::arch::x86_64::*;
    unsafe {
        let value = transmute(value);
        transmute(_mm_aesenc_si128(value, transmute(xor)))
    }
}

#[cfg(all(
any(target_arch = "x86", target_arch = "x86_64"),
target_feature = "aes"
))]
#[cfg(test)]
mod tests {
    use crate::convert::Convert;
    use crate::*;

    #[test]
    fn test_builder() {
        let mut map = HashMap::<u32, u64, LocationBasedState>::default();
        map.insert(1, 3);
    }

    #[test]
    fn test_location_based_state() {
        let state = LocationBasedState::new();
        let hasher_a = state.build_hasher();
        assert_ne!(0, hasher_a.buffer[0]);
        assert_ne!(0, hasher_a.buffer[1]);
        assert_ne!(hasher_a.buffer[0], AHasher::default().buffer[0]);
        assert_ne!(hasher_a.buffer[1], AHasher::default().buffer[1]);
        let hasher_b = state.build_hasher();
        assert_eq!(hasher_a.buffer[0], hasher_b.buffer[0]);
        assert_eq!(hasher_a.buffer[1], hasher_b.buffer[1]);
    }

    #[test]
    fn test_hash() {
        let mut result: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
        let value: [u64; 2] = [1 << 32, 0xFEDCBA9876543210];
        result = hash(value.convert(), result.convert()).convert();
        result = hash(result.convert(), result.convert()).convert();
        let mut result2: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
        let value2: [u64; 2] = [1, 0xFEDCBA9876543210];
        result2 = hash(value2.convert(), result2.convert()).convert();
        result2 = hash(result2.convert(), result.convert()).convert();
        let result: [u8; 16] = result.convert();
        let result2: [u8; 16] = result2.convert();
        assert_ne!(hex::encode(result), hex::encode(result2));
    }

    #[test]
    fn test_conversion() {
        let input: &[u8] = "dddddddd".as_bytes();
        let bytes: u64 = as_array!(input, 8).convert();
        assert_eq!(bytes, 0x6464646464646464);
    }
}
<|endoftext|>