<commit_before>//! Image processing, see [OpenCV
//! imgproc](http://docs.opencv.org/3.1.0/d7/dbd/group__imgproc.html).

use libc::{c_float, c_int, c_double};
use super::core::*;

// =============================================================================
//  Imgproc
// =============================================================================
extern "C" {
    fn cv_rectangle(cmat: *mut CMat, rect: Rect, color: Scalar, thickness: c_int, linetype: c_int);
    fn cv_cvt_color(cmat: *const CMat, output: *mut CMat, code: i32);
    fn cv_pyr_down(cmat: *const CMat, output: *mut CMat);
    fn cv_resize(from: *const CMat,
                     to: *mut CMat,
                     dsize: Size2i,
                     fx: c_double,
                     fy: c_double,
                     interpolation: c_int);
    fn cv_calc_hist(cimages: *const CMat,
                        nimages: i32,
                        channels: *const c_int,
                        cmask: *const CMat,
                        chist: *mut CMat,
                        dims: c_int,
                        hist_size: *const c_int,
                        ranges: *const *const c_float);
    fn cv_calc_back_project(cimages: *const CMat,
                                nimages: c_int,
                                channels: *const c_int,
                                chist: *const CMat,
                                cback_project: *mut CMat,
                                ranges: *const *const c_float);
}

/// Color conversion code used in
/// [cvt_color](../struct.Mat.html#method.cvt_color).
#[allow(non_camel_case_types, missing_docs)]
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum ColorConversionCodes {
    BGR2BGRA = 0,
    BGRA2BGR = 1,
    BGR2RGBA = 2,
    RGBA2BGR = 3,
    BGR2RGB = 4,
    BGRA2RGBA = 5,
    BGR2GRAY = 6,
    RGB2GRAY = 7,
    GRAY2BGR = 8,
    GRAY2BGRA = 9,
    BGRA2GRAY = 10,
    RGBA2GRAY = 11,
    BGR2BGR565 = 12,
    RGB2BGR565 = 13,
    BGR5652BGR = 14,
    BGR5652RGB = 15,
    BGRA2BGR565 = 16,
    RGBA2BGR565 = 17,
    BGR5652BGRA = 18,
    BGR5652RGBA = 19,
    GRAY2BGR565 = 20,
    BGR5652GRAY = 21,
    BGR2BGR555 = 22,
    RGB2BGR555 = 23,
    BGR5552BGR = 24,
    BGR5552RGB = 25,
    BGRA2BGR555 = 26,
    RGBA2BGR555 = 27,
    BGR5552BGRA = 28,
    BGR5552RGBA = 29,
    GRAY2BGR555 = 30,
    BGR5552GRAY = 31,
    BGR2XYZ = 32,
    RGB2XYZ = 33,
    XYZ2BGR = 34,
    XYZ2RGB = 35,
    BGR2YCrCb = 36,
    RGB2YCrCb = 37,
    YCrCb2BGR = 38,
    YCrCb2RGB = 39,
    BGR2HSV = 40,
    RGB2HSV = 41,
    BGR2Lab = 44,
    RGB2Lab = 45,
    BGR2Luv = 50,
    RGB2Luv = 51,
    BGR2HLS = 52,
    RGB2HLS = 53,
    HSV2BGR = 54,
    HSV2RGB = 55,
    Lab2BGR = 56,
    Lab2RGB = 57,
    Luv2BGR = 58,
    Luv2RGB = 59,
    HLS2BGR = 60,
    HLS2RGB = 61,
    BGR2HSV_FULL = 66,
    RGB2HSV_FULL = 67,
    BGR2HLS_FULL = 68,
    RGB2HLS_FULL = 69,
    HSV2BGR_FULL = 70,
    HSV2RGB_FULL = 71,
    HLS2BGR_FULL = 72,
    HLS2RGB_FULL = 73,
    LBGR2Lab = 74,
    LRGB2Lab = 75,
    LBGR2Luv = 76,
    LRGB2Luv = 77,
    Lab2LBGR = 78,
    Lab2LRGB = 79,
    Luv2LBGR = 80,
    Luv2LRGB = 81,
    BGR2YUV = 82,
    RGB2YUV = 83,
    YUV2BGR = 84,
    YUV2RGB = 85,
    YUV2RGB_NV12 = 90,
    YUV2BGR_NV12 = 91,
    YUV2RGB_NV21 = 92,
    YUV2BGR_NV21 = 93,
    YUV2RGBA_NV12 = 94,
    YUV2BGRA_NV12 = 95,
    YUV2RGBA_NV21 = 96,
    YUV2BGRA_NV21 = 97,
    YUV2RGB_YV12 = 98,
    YUV2BGR_YV12 = 99,
    YUV2RGB_IYUV = 100,
    YUV2BGR_IYUV = 101,
    YUV2RGBA_YV12 = 102,
    YUV2BGRA_YV12 = 103,
    YUV2RGBA_IYUV = 104,
    YUV2BGRA_IYUV = 105,
    YUV2GRAY_420 = 106,
    YUV2RGB_UYVY = 107,
    YUV2BGR_UYVY = 108,
    YUV2RGBA_UYVY = 111,
    YUV2BGRA_UYVY = 112,
    YUV2RGB_YUY2 = 115,
    YUV2BGR_YUY2 = 116,
    YUV2RGB_YVYU = 117,
    YUV2BGR_YVYU = 118,
    YUV2RGBA_YUY2 = 119,
    YUV2BGRA_YUY2 = 120,
    YUV2RGBA_YVYU = 121,
    YUV2BGRA_YVYU = 122,
    YUV2GRAY_UYVY = 123,
    YUV2GRAY_YUY2 = 124,
    RGBA2mRGBA = 125,
    mRGBA2RGBA = 126,
    RGB2YUV_I420 = 127,
    BGR2YUV_I420 = 128,
    RGBA2YUV_I420 = 129,
    BGRA2YUV_I420 = 130,
    RGB2YUV_YV12 = 131,
    BGR2YUV_YV12 = 132,
    RGBA2YUV_YV12 = 133,
    BGRA2YUV_YV12 = 134,
    BayerBG2BGR = 46,
    BayerGB2BGR = 47,
    BayerRG2BGR = 48,
    BayerGR2BGR = 49,
    BayerBG2GRAY = 86,
    BayerGB2GRAY = 87,
    BayerRG2GRAY = 88,
    BayerGR2GRAY = 89,
    BayerBG2BGR_VNG = 62,
    BayerGB2BGR_VNG = 63,
    BayerRG2BGR_VNG = 64,
    BayerGR2BGR_VNG = 65,
    BayerBG2BGR_EA = 135,
    BayerGB2BGR_EA = 136,
    BayerRG2BGR_EA = 137,
    BayerGR2BGR_EA = 138,
    COLORCVT_MAX = 139,
}

/// Interpolation algorithm
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum InterpolationFlag {
    /// nearest neighbor interpolation
    InterNearst = 0,

    /// bilinear interpolation
    InterLinear = 1,

    /// bicubic interpolation
    InterCubic = 2,

    /// resampling using pixel area relation. It may be a preferred method for
    /// image decimation, as it gives moire'-free results. But when the image is
    /// zoomed, it is similar to the INTER_NEAREST method.
    InterArea = 3,

    /// Lanczos interpolation over 8x8 neighborhood
    InterLanczos4 = 4,

    /// mask for interpolation codes
    InterMax = 7,

    /// flag, fills all of the destination image pixels. If some of them
    /// correspond to outliers in the source image, they are set to zero
    WarpFillOutliers = 8,

    /// flag, inverse transformation
    WarpInverseMap = 16,
}

impl Mat {
    /// Draws a simple, thick, or filled up-right rectangle.
    pub fn rectangle(&self, rect: Rect) {
        self.rectangle_custom(rect, Scalar::new(255, 255, 0, 255), 1, LineTypes::Line8);
    }

    /// Draws a simple, thick, or filled up-right rectangle.
    pub fn rectangle_custom(&self, rect: Rect, color: Scalar, thickness: i32, linetype: LineTypes) {
        unsafe { cv_rectangle(self.inner, rect, color, thickness, linetype as i32) }
    }

    /// Draw a simple, thick, or filled up-right rectangle.
    pub fn rectangle2f(&self, rect: Rect2f) {
        let abs_rect = rect.normalize_to_mat(self);
        self.rectangle(abs_rect);
    }

    /// Convert an image from one color space to another.
    pub fn cvt_color(&self, code: ColorConversionCodes) -> Mat {
        let m = CMat::new();
        unsafe { cv_cvt_color(self.inner, m, code as i32) }
        Mat::from_raw(m)
    }

    /// Blurs an image and downsamples it. This function performs the
    /// downsampling step of the Gaussian pyramid construction.
    pub fn pyr_down(&self) -> Mat {
        let m = CMat::new();
        unsafe { cv_pyr_down(self.inner, m) }
        Mat::from_raw(m)
    }

    /// Resizes an image.
    ///
    /// The function resize resizes the image down to or up to the specified
    /// size.
    pub fn resize_to(&self, dsize: Size2i, interpolation: InterpolationFlag) -> Mat {
        let m = CMat::new();
        unsafe { cv_resize(self.inner, m, dsize, 0.0, 0.0, interpolation as c_int) }
        Mat::from_raw(m)
    }

    /// Resizes an image.
    ///
    /// The function resize resizes the image down to or up to the specified
    /// size.
    pub fn resize_by(&self, fx: f64, fy: f64, interpolation: InterpolationFlag) -> Mat {
        let m = CMat::new();
        unsafe {
            cv_resize(self.inner,
                          m,
                          Size2i::default(),
                          fx,
                          fy,
                          interpolation as c_int)
        }
        Mat::from_raw(m)
    }

    /// Calculate a histogram of an image.
    pub fn calc_hist(&self,
                     channels: *const c_int,
                     mask: Mat,
                     dims: c_int,
                     hist_size: *const c_int,
                     ranges: *const *const f32)
                     -> Mat {
        let m = CMat::new();
        unsafe {
            cv_calc_hist(self.inner,
                             1,
                             channels,
                             mask.inner,
                             m,
                             dims,
                             hist_size,
                             ranges);
        }
        Mat::from_raw(m)
    }

    /// Calculate the back projection of a histogram. The function calculates
    /// the back project of the histogram.
    pub fn calc_back_project(&self, channels: *const i32, hist: &Mat, ranges: *const *const f32) -> Mat {
        let m = CMat::new();
        unsafe {
            cv_calc_back_project(self.inner, 1, channels, (*hist).inner, m, ranges);
        }
        Mat::from_raw(m)
    }
}
<commit_msg>style: reformat<commit_after>//! Image processing, see [OpenCV
//! imgproc](http://docs.opencv.org/3.1.0/d7/dbd/group__imgproc.html).

use libc::{c_float, c_int, c_double};
use super::core::*;

// =============================================================================
//  Imgproc
// =============================================================================
extern "C" {
    fn cv_rectangle(cmat: *mut CMat, rect: Rect, color: Scalar, thickness: c_int, linetype: c_int);
    fn cv_cvt_color(cmat: *const CMat, output: *mut CMat, code: i32);
    fn cv_pyr_down(cmat: *const CMat, output: *mut CMat);
    fn cv_resize(from: *const CMat, to: *mut CMat, dsize: Size2i, fx: c_double, fy: c_double, interpolation: c_int);
    fn cv_calc_hist(cimages: *const CMat,
                    nimages: i32,
                    channels: *const c_int,
                    cmask: *const CMat,
                    chist: *mut CMat,
                    dims: c_int,
                    hist_size: *const c_int,
                    ranges: *const *const c_float);
    fn cv_calc_back_project(cimages: *const CMat,
                            nimages: c_int,
                            channels: *const c_int,
                            chist: *const CMat,
                            cback_project: *mut CMat,
                            ranges: *const *const c_float);
}

/// Color conversion code used in
/// [cvt_color](../struct.Mat.html#method.cvt_color).
#[allow(non_camel_case_types, missing_docs)]
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum ColorConversionCodes {
    BGR2BGRA = 0,
    BGRA2BGR = 1,
    BGR2RGBA = 2,
    RGBA2BGR = 3,
    BGR2RGB = 4,
    BGRA2RGBA = 5,
    BGR2GRAY = 6,
    RGB2GRAY = 7,
    GRAY2BGR = 8,
    GRAY2BGRA = 9,
    BGRA2GRAY = 10,
    RGBA2GRAY = 11,
    BGR2BGR565 = 12,
    RGB2BGR565 = 13,
    BGR5652BGR = 14,
    BGR5652RGB = 15,
    BGRA2BGR565 = 16,
    RGBA2BGR565 = 17,
    BGR5652BGRA = 18,
    BGR5652RGBA = 19,
    GRAY2BGR565 = 20,
    BGR5652GRAY = 21,
    BGR2BGR555 = 22,
    RGB2BGR555 = 23,
    BGR5552BGR = 24,
    BGR5552RGB = 25,
    BGRA2BGR555 = 26,
    RGBA2BGR555 = 27,
    BGR5552BGRA = 28,
    BGR5552RGBA = 29,
    GRAY2BGR555 = 30,
    BGR5552GRAY = 31,
    BGR2XYZ = 32,
    RGB2XYZ = 33,
    XYZ2BGR = 34,
    XYZ2RGB = 35,
    BGR2YCrCb = 36,
    RGB2YCrCb = 37,
    YCrCb2BGR = 38,
    YCrCb2RGB = 39,
    BGR2HSV = 40,
    RGB2HSV = 41,
    BGR2Lab = 44,
    RGB2Lab = 45,
    BGR2Luv = 50,
    RGB2Luv = 51,
    BGR2HLS = 52,
    RGB2HLS = 53,
    HSV2BGR = 54,
    HSV2RGB = 55,
    Lab2BGR = 56,
    Lab2RGB = 57,
    Luv2BGR = 58,
    Luv2RGB = 59,
    HLS2BGR = 60,
    HLS2RGB = 61,
    BGR2HSV_FULL = 66,
    RGB2HSV_FULL = 67,
    BGR2HLS_FULL = 68,
    RGB2HLS_FULL = 69,
    HSV2BGR_FULL = 70,
    HSV2RGB_FULL = 71,
    HLS2BGR_FULL = 72,
    HLS2RGB_FULL = 73,
    LBGR2Lab = 74,
    LRGB2Lab = 75,
    LBGR2Luv = 76,
    LRGB2Luv = 77,
    Lab2LBGR = 78,
    Lab2LRGB = 79,
    Luv2LBGR = 80,
    Luv2LRGB = 81,
    BGR2YUV = 82,
    RGB2YUV = 83,
    YUV2BGR = 84,
    YUV2RGB = 85,
    YUV2RGB_NV12 = 90,
    YUV2BGR_NV12 = 91,
    YUV2RGB_NV21 = 92,
    YUV2BGR_NV21 = 93,
    YUV2RGBA_NV12 = 94,
    YUV2BGRA_NV12 = 95,
    YUV2RGBA_NV21 = 96,
    YUV2BGRA_NV21 = 97,
    YUV2RGB_YV12 = 98,
    YUV2BGR_YV12 = 99,
    YUV2RGB_IYUV = 100,
    YUV2BGR_IYUV = 101,
    YUV2RGBA_YV12 = 102,
    YUV2BGRA_YV12 = 103,
    YUV2RGBA_IYUV = 104,
    YUV2BGRA_IYUV = 105,
    YUV2GRAY_420 = 106,
    YUV2RGB_UYVY = 107,
    YUV2BGR_UYVY = 108,
    YUV2RGBA_UYVY = 111,
    YUV2BGRA_UYVY = 112,
    YUV2RGB_YUY2 = 115,
    YUV2BGR_YUY2 = 116,
    YUV2RGB_YVYU = 117,
    YUV2BGR_YVYU = 118,
    YUV2RGBA_YUY2 = 119,
    YUV2BGRA_YUY2 = 120,
    YUV2RGBA_YVYU = 121,
    YUV2BGRA_YVYU = 122,
    YUV2GRAY_UYVY = 123,
    YUV2GRAY_YUY2 = 124,
    RGBA2mRGBA = 125,
    mRGBA2RGBA = 126,
    RGB2YUV_I420 = 127,
    BGR2YUV_I420 = 128,
    RGBA2YUV_I420 = 129,
    BGRA2YUV_I420 = 130,
    RGB2YUV_YV12 = 131,
    BGR2YUV_YV12 = 132,
    RGBA2YUV_YV12 = 133,
    BGRA2YUV_YV12 = 134,
    BayerBG2BGR = 46,
    BayerGB2BGR = 47,
    BayerRG2BGR = 48,
    BayerGR2BGR = 49,
    BayerBG2GRAY = 86,
    BayerGB2GRAY = 87,
    BayerRG2GRAY = 88,
    BayerGR2GRAY = 89,
    BayerBG2BGR_VNG = 62,
    BayerGB2BGR_VNG = 63,
    BayerRG2BGR_VNG = 64,
    BayerGR2BGR_VNG = 65,
    BayerBG2BGR_EA = 135,
    BayerGB2BGR_EA = 136,
    BayerRG2BGR_EA = 137,
    BayerGR2BGR_EA = 138,
    COLORCVT_MAX = 139,
}

/// Interpolation algorithm
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum InterpolationFlag {
    /// nearest neighbor interpolation
    InterNearst = 0,

    /// bilinear interpolation
    InterLinear = 1,

    /// bicubic interpolation
    InterCubic = 2,

    /// resampling using pixel area relation. It may be a preferred method for
    /// image decimation, as it gives moire'-free results. But when the image is
    /// zoomed, it is similar to the INTER_NEAREST method.
    InterArea = 3,

    /// Lanczos interpolation over 8x8 neighborhood
    InterLanczos4 = 4,

    /// mask for interpolation codes
    InterMax = 7,

    /// flag, fills all of the destination image pixels. If some of them
    /// correspond to outliers in the source image, they are set to zero
    WarpFillOutliers = 8,

    /// flag, inverse transformation
    WarpInverseMap = 16,
}

impl Mat {
    /// Draws a simple, thick, or filled up-right rectangle.
    pub fn rectangle(&self, rect: Rect) {
        self.rectangle_custom(rect, Scalar::new(255, 255, 0, 255), 1, LineTypes::Line8);
    }

    /// Draws a simple, thick, or filled up-right rectangle.
    pub fn rectangle_custom(&self, rect: Rect, color: Scalar, thickness: i32, linetype: LineTypes) {
        unsafe { cv_rectangle(self.inner, rect, color, thickness, linetype as i32) }
    }

    /// Draw a simple, thick, or filled up-right rectangle.
    pub fn rectangle2f(&self, rect: Rect2f) {
        let abs_rect = rect.normalize_to_mat(self);
        self.rectangle(abs_rect);
    }

    /// Convert an image from one color space to another.
    pub fn cvt_color(&self, code: ColorConversionCodes) -> Mat {
        let m = CMat::new();
        unsafe { cv_cvt_color(self.inner, m, code as i32) }
        Mat::from_raw(m)
    }

    /// Blurs an image and downsamples it. This function performs the
    /// downsampling step of the Gaussian pyramid construction.
    pub fn pyr_down(&self) -> Mat {
        let m = CMat::new();
        unsafe { cv_pyr_down(self.inner, m) }
        Mat::from_raw(m)
    }

    /// Resizes an image.
    ///
    /// The function resize resizes the image down to or up to the specified
    /// size.
    pub fn resize_to(&self, dsize: Size2i, interpolation: InterpolationFlag) -> Mat {
        let m = CMat::new();
        unsafe { cv_resize(self.inner, m, dsize, 0.0, 0.0, interpolation as c_int) }
        Mat::from_raw(m)
    }

    /// Resizes an image.
    ///
    /// The function resize resizes the image down to or up to the specified
    /// size.
    pub fn resize_by(&self, fx: f64, fy: f64, interpolation: InterpolationFlag) -> Mat {
        let m = CMat::new();
        unsafe {
            cv_resize(self.inner,
                      m,
                      Size2i::default(),
                      fx,
                      fy,
                      interpolation as c_int)
        }
        Mat::from_raw(m)
    }

    /// Calculate a histogram of an image.
    pub fn calc_hist(&self,
                     channels: *const c_int,
                     mask: Mat,
                     dims: c_int,
                     hist_size: *const c_int,
                     ranges: *const *const f32)
                     -> Mat {
        let m = CMat::new();
        unsafe {
            cv_calc_hist(self.inner,
                         1,
                         channels,
                         mask.inner,
                         m,
                         dims,
                         hist_size,
                         ranges);
        }
        Mat::from_raw(m)
    }

    /// Calculate the back projection of a histogram. The function calculates
    /// the back project of the histogram.
    pub fn calc_back_project(&self, channels: *const i32, hist: &Mat, ranges: *const *const f32) -> Mat {
        let m = CMat::new();
        unsafe {
            cv_calc_back_project(self.inner, 1, channels, (*hist).inner, m, ranges);
        }
        Mat::from_raw(m)
    }
}
<|endoftext|>


<commit_before>#![crate_id = "github.com/TomBebbington/js.rs#js:0.1"]
#![comment = "Javascript parsing, compilation and execution using LibJIT"]
#![license = "MIT"]
#![crate_type = "lib"]
#![doc(
    html_favicon_url = "http://tombebbington.github.io/favicon.png"
#![experimental]
#![feature(phase, macro_rules, globs)]
#![deny(non_uppercase_statics, missing_doc, unnecessary_parens, unrecognized_lint,
	unreachable_code, unnecessary_allocation, unnecessary_typecast, unnecessary_allocation,
	uppercase_variables, non_camel_case_types, unused_must_use)]
//! This is a library with seperate modules for Javascript parsing, the Javascript
//! standard library, and Javascript execution through LibJIT
extern crate collections;
extern crate jit;
#[phase(plugin, link)]
extern crate log;
extern crate serialize;
extern crate time;
extern crate url;
/// The backend-defining traits and the Javascript standard library
pub mod front {
	#[macro_escape]
	/// A macro which makes Javascript objects with pretty Rust syntax
	pub mod macro;
	/// Backend-defining traits
	pub mod run {
		/// For compiling Javascript values
		pub mod compiler;
		/// For executing the compiled Javascript values
		pub mod executor;
	}
	/// The Javascript standard library
	pub mod stdlib {
		/// The `Array` global object
		pub mod array;
		/// The `Boolean` global object
		pub mod boolean;
		/// The `console` global object
		pub mod console;
		/// The `Error` global objects
		pub mod error;
		/// The `Function` global object
		pub mod function;
		/// The `JSON` global object
		pub mod json;
		/// The `Math` global object
		pub mod math;
		/// The `Number` global object and related global methods
		pub mod number;
		/// The `Object` global object
		pub mod object;
		/// The `String` global object
		pub mod string;
		/// The global URI methods
		pub mod uri;
		/// An arbritary Javascript value
		pub mod value;
	}
}
/// The default backend implemented on top of LibJIT
pub mod back {
	/// The compiler, which transforms Javascript expressions to LibJIT IR
	pub mod compiler;
	/// The executor, which runs the LibJIT IR by compiling it then running it
	pub mod executor;
}
/// Javascript parsing and syntax
pub mod syntax {
	/// The Javascript Abstract Syntax Tree
	pub mod ast {
		/// Constants
		pub mod constant;
		/// Expressions
		pub mod expr;
		/// Keywords
		pub mod keyword;
		/// Operators
		pub mod op;
		/// Positions
		pub mod pos;
		/// Punctuators
		pub mod punc;
		/// Tokens
		pub mod token;
		/// An expression typer
		pub mod typer;
		/// Types
		pub mod types;
	}
	/// Parses a string stream into a sequence of tokens
	pub mod lexer;
	/// Parses a sequence of tokens into expressions
	pub mod parser;
}<commit_msg>Close doc delimeter<commit_after>#![crate_id = "github.com/TomBebbington/js.rs#js:0.1"]
#![comment = "Javascript parsing, compilation and execution using LibJIT"]
#![license = "MIT"]
#![crate_type = "lib"]
#![doc(
    html_favicon_url = "http://tombebbington.github.io/favicon.png"
  )
#![experimental]
#![feature(phase, macro_rules, globs)]
#![deny(non_uppercase_statics, missing_doc, unnecessary_parens, unrecognized_lint,
	unreachable_code, unnecessary_allocation, unnecessary_typecast, unnecessary_allocation,
	uppercase_variables, non_camel_case_types, unused_must_use)]
//! This is a library with seperate modules for Javascript parsing, the Javascript
//! standard library, and Javascript execution through LibJIT
extern crate collections;
extern crate jit;
#[phase(plugin, link)]
extern crate log;
extern crate serialize;
extern crate time;
extern crate url;
/// The backend-defining traits and the Javascript standard library
pub mod front {
	#[macro_escape]
	/// A macro which makes Javascript objects with pretty Rust syntax
	pub mod macro;
	/// Backend-defining traits
	pub mod run {
		/// For compiling Javascript values
		pub mod compiler;
		/// For executing the compiled Javascript values
		pub mod executor;
	}
	/// The Javascript standard library
	pub mod stdlib {
		/// The `Array` global object
		pub mod array;
		/// The `Boolean` global object
		pub mod boolean;
		/// The `console` global object
		pub mod console;
		/// The `Error` global objects
		pub mod error;
		/// The `Function` global object
		pub mod function;
		/// The `JSON` global object
		pub mod json;
		/// The `Math` global object
		pub mod math;
		/// The `Number` global object and related global methods
		pub mod number;
		/// The `Object` global object
		pub mod object;
		/// The `String` global object
		pub mod string;
		/// The global URI methods
		pub mod uri;
		/// An arbritary Javascript value
		pub mod value;
	}
}
/// The default backend implemented on top of LibJIT
pub mod back {
	/// The compiler, which transforms Javascript expressions to LibJIT IR
	pub mod compiler;
	/// The executor, which runs the LibJIT IR by compiling it then running it
	pub mod executor;
}
/// Javascript parsing and syntax
pub mod syntax {
	/// The Javascript Abstract Syntax Tree
	pub mod ast {
		/// Constants
		pub mod constant;
		/// Expressions
		pub mod expr;
		/// Keywords
		pub mod keyword;
		/// Operators
		pub mod op;
		/// Positions
		pub mod pos;
		/// Punctuators
		pub mod punc;
		/// Tokens
		pub mod token;
		/// An expression typer
		pub mod typer;
		/// Types
		pub mod types;
	}
	/// Parses a string stream into a sequence of tokens
	pub mod lexer;
	/// Parses a sequence of tokens into expressions
	pub mod parser;
}<|endoftext|>


<commit_before>use std::mem;
use std::iter::range_inclusive;

use std::rand::{Rng, SeedableRng, Rand};

const DSFMT_LOW_MASK:   u64 = 0x000FFFFFFFFFFFFF;
const DSFMT_HIGH_CONST: u64 = 0x3FF0000000000000;

const DSFMT_F32_MANTISSA_MASK: u64 = 0x00000000007FFFFF;
const DSFMT_HIGH_CONST32:      u32 = 0x3F800000;

const DSFMT_MEXP:uint = 19937;
const DSFMT_N:   uint = ((DSFMT_MEXP - 128) / 104 + 1);
const DSFMT_N64: uint = (DSFMT_N * 2);
const DSFMT_SR:  uint = 12;

const DSFMT_POS1: uint = 117;
const DSFMT_SL1:  uint = 19;
const DSFMT_PCV1: u64  = 0x3d84e1ac0dc82880;
const DSFMT_PCV2: u64  = 0x0000000000000001;
const DSFMT_FIX1: u64  = 0x90014964b32f4329;
const DSFMT_FIX2: u64  = 0x3b8d12ac548a7c7a;
const DSFMT_MSK1: u64  = 0x000ffafffffffb3f;
const DSFMT_MSK2: u64  = 0x000ffdfffc90fffd;

const SSE2_PARAMS_MASK: u64x2 = u64x2{x: DSFMT_MSK1, y: DSFMT_MSK2};
const SSE2_SL: u64x2 = u64x2{x: DSFMT_SL1 as u64, y: DSFMT_SL1 as u64};
const SSE2_SR: u64x2 = u64x2{x: DSFMT_SR as u64, y: DSFMT_SR as u64};

pub struct DSFMTRng{
    status: [u64x2, ..DSFMT_N + 1],
    idx: uint,
}

#[repr(C)]
#[simd]
#[deriving(Show, Copy)]
struct u32x4{
    x: u32,
    y: u32,
    z: u32,
    w: u32,
}

#[repr(C)]
#[simd]
#[deriving(Show, Copy)]
struct u64x2{
    x: u64,
    y: u64,
}

impl Index<uint, u64> for u64x2{
    #[inline(always)]
    fn index(&self, _rhs: &uint) -> &u64{
        match *_rhs{
            0 => &self.x,
            _ => &self.y,
        }
    }
}

impl IndexMut<uint, u64> for u64x2{
    #[inline(always)]
    fn index_mut(&mut self, _rhs: &uint) -> &mut u64{
        match *_rhs{
            0 => &mut self.x,
            _ => &mut self.y,
        }
    }
}

impl Index<uint, u32> for u32x4{
    #[inline(always)]
    fn index(&self, _rhs: &uint) -> &u32{
        match *_rhs{
            0 => &self.x,
            1 => &self.y,
            2 => &self.z,
            _ => &self.w,
        }
    }
}

impl IndexMut<uint, u32> for u32x4{
    #[inline(always)]
    fn index_mut(&mut self, _rhs: &uint) -> &mut u32{
        match *_rhs{
            0 => &mut self.x,
            1 => &mut self.y,
            2 => &mut self.z,
            _ => &mut self.w,
        }
    }
}

#[cfg(target_endian = "big")]
fn idxof(i: uint) -> uint {
    i ^ 1
}

#[cfg(target_endian = "little")]
fn idxof(i: uint) -> uint {
    i
}

//#[allow(unused)]
//#[inline(always)]
//fn do_recursion(r: &mut u64x2, a: u64x2, b: u64x2, lung: &mut u64x2){
//
//    let u64x2{x: t0, y: t1} = a;
//    let u64x2{x: l0, y: l1} = *lung;
//
//    lung[0] = (t0 << DSFMT_SL1) ^ (l1 >> 32) ^ (l1 << 32) ^ b[0];
//    lung[1] = (t1 << DSFMT_SL1) ^ (l0 >> 32) ^ (l0 << 32) ^ b[1];
//
//    r[0] = ((*lung)[0] >> DSFMT_SR) ^ ((*lung)[0] & DSFMT_MSK1) ^ t0;
//    r[1] = ((*lung)[1] >> DSFMT_SR) ^ ((*lung)[1] & DSFMT_MSK2) ^ t1;
//}

#[inline(always)]
pub fn reverse_u32s(u: u64x2) -> u64x2 {
    unsafe {
        let tmp = mem::transmute::<_, u32x4>(u);
        let swapped = u32x4 {x: tmp.w, y: tmp.z, z: tmp.y, w: tmp.x};
        mem::transmute::<_, u64x2>(swapped)
    }
}

#[allow(unused)]
#[inline(always)]
fn do_recursion(r: &mut u64x2, a: u64x2, b: u64x2, u: &mut u64x2){
    let swapped = reverse_u32s(*u);
    let uu = (a << SSE2_SL) ^ b ^ swapped;

    *r = (uu >> SSE2_SR) ^ (uu & SSE2_PARAMS_MASK) ^ a;
    *u = uu;
}

impl DSFMTRng{
    /// Create a new unseeded DSFMTRng instance
    pub fn new_unseeded() -> DSFMTRng {
        DSFMTRng{status: [u64x2{x: 0, y: 0}, ..DSFMT_N + 1], idx: 0}
    }

    /// Initializes the internal state array to fit the IEEE 754 format.
    fn initial_mask(&mut self){
        for i in range(0, DSFMT_N * 2){
            let (n, m) = (i / 2, i % 2);
            self.status[n][m] = (self.status[n][m] & DSFMT_LOW_MASK) | DSFMT_HIGH_CONST;
        }
    }

    /// Certifies the period of 2^{SFMT_MEXP}-1.
    fn period_certification(&mut self) {
        let pcv: [u64, ..2] = [DSFMT_PCV1, DSFMT_PCV2];

        {
            let tmp = [self.status[DSFMT_N][0] ^ DSFMT_FIX1, self.status[DSFMT_N][1] ^ DSFMT_FIX2];
            let mut inner = (tmp[0] & pcv[0]) ^ (tmp[1] & pcv[1]);

            let mut i = 32u;
            while i > 0 {
                inner ^= inner >> i;
                i >>= 1;
            }
            inner &= 1;
            /* check OK */
            if inner == 1 {
                return;
            }
        }

        /* check NG, and modification */
        if (DSFMT_PCV2 & 1) == 1 {
            self.status[DSFMT_N][1] ^= 1;
        }
        else{
            for i in range_inclusive(1, 0){
                let mut work = 1u64;
                for _ in range(0i, 64){
                    if (work & pcv[i]) != 0 {
                        self.status[DSFMT_N][i] ^= work;
                        return;
                    }
                    work <<= 1;
                }
            }
        }
    }

    fn init(&mut self, seed: u32) {
        let psfmt: &mut [u32x4, ..DSFMT_N + 1] = unsafe{mem::transmute(&mut self.status)};
        let i = idxof(0);
        psfmt[i / 4][i % 4] = seed;

        for i in range(1u, 4 * (DSFMT_N + 1)){
            let idx1 = idxof(i);
            let idx2 = idxof(i - 1);
            psfmt[idx1 / 4][idx1 % 4] = 1812433253u32 * (psfmt[idx2 / 4][idx2 % 4] ^ (psfmt[idx2 / 4][idx2 % 4] >> 30)) + (i as u32);
        }

        self.initial_mask();
        self.period_certification();
        self.idx = DSFMT_N64;
    }

    #[inline]
    fn gen_rand_all(&mut self){
        let mut lung = self.status[DSFMT_N];
        {
            let a = self.status[0];
            let b = self.status[DSFMT_POS1];
            do_recursion(&mut self.status[0], a, b, &mut lung);
        }
        let mut i = 1u;
        while i < DSFMT_N - DSFMT_POS1 {
            let a = self.status[i];
            let b = self.status[i + DSFMT_POS1];
            do_recursion(&mut self.status[i], a, b, &mut lung);
            i += 1;
        }
        while i < DSFMT_N {
            let a = self.status[i];
            let b = self.status[i + DSFMT_POS1 - DSFMT_N];
            do_recursion(&mut self.status[i], a, b, &mut lung);
            i += 1;
        }
        self.status[DSFMT_N] = lung;
    }

    #[inline(always)]
    fn next(&mut self) -> u64 {
        if self.idx >= DSFMT_N64 {
            self.gen_rand_all();
            self.idx = 0;
        }

        let (n, m) = (self.idx / 2, self.idx % 2);
        self.idx += 1;

        self.status[n][m]
    }

    #[inline]
    pub fn genrand_close1_open2(&mut self) -> f64 {
        unsafe{mem::transmute(self.next())}
    }

    #[inline]
    pub fn genrand_open_open(&mut self) -> f64 {
        unsafe{mem::transmute::<u64, f64>(self.next() | 1u64) - 1.0f64}
    }
}

impl Rng for DSFMTRng {
    #[inline]
    fn next_u32(&mut self) -> u32 {
        (self.next() & 0xffffffffu64) as u32
    }

    #[inline]
    fn next_f32(&mut self) -> f32 {
        unsafe{mem::transmute::<u32, f32>(((self.next() & DSFMT_F32_MANTISSA_MASK)) as u32 | DSFMT_HIGH_CONST32) - 1.0}
    }

    #[inline]
    fn next_f64(&mut self) -> f64 {
        self.genrand_close1_open2() - 1.0
    }
}

impl SeedableRng<u32> for DSFMTRng {
    fn reseed(&mut self, seed: u32){
        self.init(seed);
    }

    fn from_seed(seed: u32) -> DSFMTRng {
        let mut rng = DSFMTRng::new_unseeded();
        rng.init(seed);
        rng
    }
}

impl Rand for DSFMTRng {
    fn rand<R: Rng>(other: &mut R) -> DSFMTRng {
        SeedableRng::from_seed(other.next_u32())
    }
}
<commit_msg>Fix reversed loop bug.<commit_after>use std::mem;
use std::iter::range_inclusive;

use std::rand::{Rng, SeedableRng, Rand};

const DSFMT_LOW_MASK:   u64 = 0x000FFFFFFFFFFFFF;
const DSFMT_HIGH_CONST: u64 = 0x3FF0000000000000;

const DSFMT_F32_MANTISSA_MASK: u64 = 0x00000000007FFFFF;
const DSFMT_HIGH_CONST32:      u32 = 0x3F800000;

const DSFMT_MEXP:uint = 19937;
const DSFMT_N:   uint = ((DSFMT_MEXP - 128) / 104 + 1);
const DSFMT_N64: uint = (DSFMT_N * 2);
const DSFMT_SR:  uint = 12;

const DSFMT_POS1: uint = 117;
const DSFMT_SL1:  uint = 19;
const DSFMT_PCV1: u64  = 0x3d84e1ac0dc82880;
const DSFMT_PCV2: u64  = 0x0000000000000001;
const DSFMT_FIX1: u64  = 0x90014964b32f4329;
const DSFMT_FIX2: u64  = 0x3b8d12ac548a7c7a;
const DSFMT_MSK1: u64  = 0x000ffafffffffb3f;
const DSFMT_MSK2: u64  = 0x000ffdfffc90fffd;

const SSE2_PARAMS_MASK: u64x2 = u64x2{x: DSFMT_MSK1, y: DSFMT_MSK2};
const SSE2_SL: u64x2 = u64x2{x: DSFMT_SL1 as u64, y: DSFMT_SL1 as u64};
const SSE2_SR: u64x2 = u64x2{x: DSFMT_SR as u64, y: DSFMT_SR as u64};

pub struct DSFMTRng{
    status: [u64x2, ..DSFMT_N + 1],
    idx: uint,
}

#[repr(C)]
#[simd]
#[deriving(Show, Copy)]
struct u32x4{
    x: u32,
    y: u32,
    z: u32,
    w: u32,
}

#[repr(C)]
#[simd]
#[deriving(Show, Copy)]
struct u64x2{
    x: u64,
    y: u64,
}

impl Index<uint, u64> for u64x2{
    #[inline(always)]
    fn index(&self, _rhs: &uint) -> &u64{
        match *_rhs{
            0 => &self.x,
            _ => &self.y,
        }
    }
}

impl IndexMut<uint, u64> for u64x2{
    #[inline(always)]
    fn index_mut(&mut self, _rhs: &uint) -> &mut u64{
        match *_rhs{
            0 => &mut self.x,
            _ => &mut self.y,
        }
    }
}

impl Index<uint, u32> for u32x4{
    #[inline(always)]
    fn index(&self, _rhs: &uint) -> &u32{
        match *_rhs{
            0 => &self.x,
            1 => &self.y,
            2 => &self.z,
            _ => &self.w,
        }
    }
}

impl IndexMut<uint, u32> for u32x4{
    #[inline(always)]
    fn index_mut(&mut self, _rhs: &uint) -> &mut u32{
        match *_rhs{
            0 => &mut self.x,
            1 => &mut self.y,
            2 => &mut self.z,
            _ => &mut self.w,
        }
    }
}

#[cfg(target_endian = "big")]
fn idxof(i: uint) -> uint {
    i ^ 1
}

#[cfg(target_endian = "little")]
fn idxof(i: uint) -> uint {
    i
}

//#[allow(unused)]
//#[inline(always)]
//fn do_recursion(r: &mut u64x2, a: u64x2, b: u64x2, lung: &mut u64x2){
//
//    let u64x2{x: t0, y: t1} = a;
//    let u64x2{x: l0, y: l1} = *lung;
//
//    lung[0] = (t0 << DSFMT_SL1) ^ (l1 >> 32) ^ (l1 << 32) ^ b[0];
//    lung[1] = (t1 << DSFMT_SL1) ^ (l0 >> 32) ^ (l0 << 32) ^ b[1];
//
//    r[0] = ((*lung)[0] >> DSFMT_SR) ^ ((*lung)[0] & DSFMT_MSK1) ^ t0;
//    r[1] = ((*lung)[1] >> DSFMT_SR) ^ ((*lung)[1] & DSFMT_MSK2) ^ t1;
//}

#[inline(always)]
pub fn reverse_u32s(u: u64x2) -> u64x2 {
    unsafe {
        let tmp = mem::transmute::<_, u32x4>(u);
        let swapped = u32x4 {x: tmp.w, y: tmp.z, z: tmp.y, w: tmp.x};
        mem::transmute::<_, u64x2>(swapped)
    }
}

#[allow(unused)]
#[inline(always)]
fn do_recursion(r: &mut u64x2, a: u64x2, b: u64x2, u: &mut u64x2){
    let swapped = reverse_u32s(*u);
    let uu = (a << SSE2_SL) ^ b ^ swapped;

    *r = (uu >> SSE2_SR) ^ (uu & SSE2_PARAMS_MASK) ^ a;
    *u = uu;
}

impl DSFMTRng{
    /// Create a new unseeded DSFMTRng instance
    pub fn new_unseeded() -> DSFMTRng {
        DSFMTRng{status: [u64x2{x: 0, y: 0}, ..DSFMT_N + 1], idx: 0}
    }

    /// Initializes the internal state array to fit the IEEE 754 format.
    fn initial_mask(&mut self){
        for i in range(0, DSFMT_N * 2){
            let (n, m) = (i / 2, i % 2);
            self.status[n][m] = (self.status[n][m] & DSFMT_LOW_MASK) | DSFMT_HIGH_CONST;
        }
    }

    /// Certifies the period of 2^{SFMT_MEXP}-1.
    fn period_certification(&mut self) {
        let pcv: [u64, ..2] = [DSFMT_PCV1, DSFMT_PCV2];

        {
            let tmp = [self.status[DSFMT_N][0] ^ DSFMT_FIX1, self.status[DSFMT_N][1] ^ DSFMT_FIX2];
            let mut inner = (tmp[0] & pcv[0]) ^ (tmp[1] & pcv[1]);

            let mut i = 32u;
            while i > 0 {
                inner ^= inner >> i;
                i >>= 1;
            }
            inner &= 1;
            /* check OK */
            if inner == 1 {
                return;
            }
        }

        /* check NG, and modification */
        if (DSFMT_PCV2 & 1) == 1 {
            self.status[DSFMT_N][1] ^= 1;
        }
        else{
            for i in range_inclusive(0, 1).rev() {
                let mut work = 1u64;
                for _ in range(0i, 64){
                    if (work & pcv[i]) != 0 {
                        self.status[DSFMT_N][i] ^= work;
                        return;
                    }
                    work <<= 1;
                }
            }
        }
    }

    fn init(&mut self, seed: u32) {
        let psfmt: &mut [u32x4, ..DSFMT_N + 1] = unsafe{mem::transmute(&mut self.status)};
        let i = idxof(0);
        psfmt[i / 4][i % 4] = seed;

        for i in range(1u, 4 * (DSFMT_N + 1)){
            let idx1 = idxof(i);
            let idx2 = idxof(i - 1);
            psfmt[idx1 / 4][idx1 % 4] = 1812433253u32 * (psfmt[idx2 / 4][idx2 % 4] ^ (psfmt[idx2 / 4][idx2 % 4] >> 30)) + (i as u32);
        }

        self.initial_mask();
        self.period_certification();
        self.idx = DSFMT_N64;
    }

    #[inline]
    fn gen_rand_all(&mut self){
        let mut lung = self.status[DSFMT_N];
        {
            let a = self.status[0];
            let b = self.status[DSFMT_POS1];
            do_recursion(&mut self.status[0], a, b, &mut lung);
        }
        let mut i = 1u;
        while i < DSFMT_N - DSFMT_POS1 {
            let a = self.status[i];
            let b = self.status[i + DSFMT_POS1];
            do_recursion(&mut self.status[i], a, b, &mut lung);
            i += 1;
        }
        while i < DSFMT_N {
            let a = self.status[i];
            let b = self.status[i + DSFMT_POS1 - DSFMT_N];
            do_recursion(&mut self.status[i], a, b, &mut lung);
            i += 1;
        }
        self.status[DSFMT_N] = lung;
    }

    #[inline(always)]
    fn next(&mut self) -> u64 {
        if self.idx >= DSFMT_N64 {
            self.gen_rand_all();
            self.idx = 0;
        }

        let (n, m) = (self.idx / 2, self.idx % 2);
        self.idx += 1;

        self.status[n][m]
    }

    #[inline]
    pub fn genrand_close1_open2(&mut self) -> f64 {
        unsafe{mem::transmute(self.next())}
    }

    #[inline]
    pub fn genrand_open_open(&mut self) -> f64 {
        unsafe{mem::transmute::<u64, f64>(self.next() | 1u64) - 1.0f64}
    }
}

impl Rng for DSFMTRng {
    #[inline]
    fn next_u32(&mut self) -> u32 {
        (self.next() & 0xffffffffu64) as u32
    }

    #[inline]
    fn next_f32(&mut self) -> f32 {
        unsafe{mem::transmute::<u32, f32>(((self.next() & DSFMT_F32_MANTISSA_MASK)) as u32 | DSFMT_HIGH_CONST32) - 1.0}
    }

    #[inline]
    fn next_f64(&mut self) -> f64 {
        self.genrand_close1_open2() - 1.0
    }
}

impl SeedableRng<u32> for DSFMTRng {
    fn reseed(&mut self, seed: u32){
        self.init(seed);
    }

    fn from_seed(seed: u32) -> DSFMTRng {
        let mut rng = DSFMTRng::new_unseeded();
        rng.init(seed);
        rng
    }
}

impl Rand for DSFMTRng {
    fn rand<R: Rng>(other: &mut R) -> DSFMTRng {
        SeedableRng::from_seed(other.next_u32())
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Walter Kuppens.
//
// 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.

use io::log;
use nes::memory::Memory;
use nes::memory::MiscRegisterStatus;
use nes::memory::PPURegisterStatus;
use nes::nes::NESRuntimeOptions;

use nes::memory::{
    PPU_CTRL_REGISTERS_SIZE,
    MISC_CTRL_REGISTERS_SIZE,
};

const SPR_RAM_SIZE: usize = 0x00FF;

// Memory map section sizes.
const PATTERN_TABLES_SIZE: usize = 0x2000;
const NAME_TABLES_SIZE:    usize = 0x1000;
const PALETTES_SIZE:       usize = 0x0020;

// Memory map bounds.
const PATTERN_TABLES_START:     usize = 0x0000;
const PATTERN_TABLES_END:       usize = 0x1FFF;
const NAME_TABLES_START:        usize = 0x2000;
const NAME_TABLES_END:          usize = 0x2FFF;
const NAME_TABLES_MIRROR_START: usize = 0x3000;
const NAME_TABLES_MIRROR_END:   usize = 0x3EFF;
const PALETTES_START:           usize = 0x3F00;
const PALETTES_END:             usize = 0x3F1F;
const PALETTES_MIRROR_START:    usize = 0x3F20;
const PALETTES_MIRROR_END:      usize = 0x3FFF;
const MIRROR_START:             usize = 0x4000;
const MIRROR_END:               usize = 0xFFFF;

/// This is an implementation of the 2C02 PPU used in the NES. This piece of
/// hardware is responsible for drawing graphics to the television the console
/// is hooked up to; however in our case we draw to an SDL surface.
pub struct PPU {
    ppu_ctrl: u8,
    ppu_mask: u8,
    ppu_status: u8,

    // The runtime options contain some useful information such as television
    // standard which affect the clock rate of the PPU.
    runtime_options: NESRuntimeOptions,

    // The PPU has 2 pattern tables which store 8x8 pixel tiles which can be
    // drawn to the screen.
    pattern_tables: [u8; PATTERN_TABLES_SIZE],

    // The name tables are matrices of numbers that point to tiles stored in the
    // pattern tables. Each name table has an associated attribute table, which
    // contains the upper 2 bits of colors for each of the associated tiles.
    name_tables: [u8; NAME_TABLES_SIZE],

    // The PPU has 2 color palettes each containing 16 entires selected from the
    // PPU total selection of 52 colors. Because of this all possible colors the
    // PPU can create cannot be shown at once.
    //
    // Another thing to note is that the background color entry is mirrored
    // every 4 bytes so the effective number of color entries is reduced to 13
    // rather than 16.
    palettes: [u8; PALETTES_SIZE],

    // Where sprites are stored (different bus).
    spr_ram: [u8; SPR_RAM_SIZE],
}

impl PPU {
    /// Initializes the PPU and it's internal memory.
    pub fn new(runtime_options: NESRuntimeOptions) -> Self {
        PPU {
            ppu_ctrl: 0,
            ppu_mask: 0,
            ppu_status: 0,

            runtime_options: runtime_options,
            pattern_tables: [0; PATTERN_TABLES_SIZE],
            name_tables: [0; NAME_TABLES_SIZE],
            palettes: [0; PALETTES_SIZE],
            spr_ram: [0; SPR_RAM_SIZE],
        }
    }

    /// Maps a PPU virtual addresses to a physical address used internally by
    /// the PPU emulator.
    fn map(&mut self, addr: usize) -> (&mut [u8], usize) {
        match addr {
            PATTERN_TABLES_START...PATTERN_TABLES_END =>
                (&mut self.pattern_tables, addr),
            NAME_TABLES_START...NAME_TABLES_END =>
                (&mut self.name_tables, addr - NAME_TABLES_START),
            NAME_TABLES_MIRROR_START...NAME_TABLES_MIRROR_END =>
                (&mut self.name_tables, (addr - NAME_TABLES_START) % NAME_TABLES_SIZE),
            PALETTES_START...PALETTES_END =>
                (&mut self.palettes, addr - PALETTES_START),
            PALETTES_MIRROR_START...PALETTES_MIRROR_END =>
                (&mut self.palettes, (addr - PALETTES_START) % PALETTES_SIZE),
            MIRROR_START...MIRROR_END =>
                self.map(addr - MIRROR_START), // Lazy recursion to share nested mirror logic ^^^.
            _ => { panic!("Unable to map virtual address {:#X} to any physical address", addr) },
        }
    }

    /// Reads a byte from PPU memory at the given virtual address.
    fn read_u8(&mut self, addr: usize) -> u8 {
        let (bank, addr) = self.map(addr);
        bank[addr]
    }

    /// Writes a byte to PPU memory at the given virtual address.
    fn write_u8(&mut self, addr: usize, value: u8) {
        let (bank, addr) = self.map(addr);
        bank[addr] = value;
    }

    /// Copy data from main memory to the PPU's internal sprite memory.
    fn exec_dma(&mut self) {
    }

    /// Reads the contents of the DMA register and executes DMA if written since
    /// the last PPU cycle.
    ///
    /// TODO: Implement me!
    fn handle_dma_register<M: Memory>(&mut self, index: usize, state: MiscRegisterStatus, memory: &mut M) {
        if state != MiscRegisterStatus::Written {
            return;
        }
        let register = memory.misc_ctrl_registers()[index];
        println!("{:02X}", register);
        panic!("Implement DMA to continue!");
    }

    /// Updates the internal PPUCTRL register when the I/O register was written
    /// since the last PPU cycle.
    fn handle_ppu_ctrl<M: Memory>(&mut self, index: usize, state: PPURegisterStatus, memory: &mut M) {
        if state != PPURegisterStatus::Written {
            return;
        }
        self.ppu_ctrl = memory.ppu_ctrl_registers()[index];
        memory.ppu_ctrl_registers_status()[index] = PPURegisterStatus::Untouched;
    }

    /// Updates the internal PPUMASK register when the I/O register was written
    /// since the last PPU cycle.
    fn handle_ppu_mask<M: Memory>(&mut self, index: usize, state: PPURegisterStatus, memory: &mut M) {
        if state != PPURegisterStatus::Written {
            return;
        }
        self.ppu_mask = memory.ppu_ctrl_registers()[index];
        memory.ppu_ctrl_registers_status()[index] = PPURegisterStatus::Untouched;
    }

    /// Checks the status of PPU I/O registers and executes PPU functionality
    /// depending on their states.
    fn check_ppu_registers<M: Memory>(&mut self, memory: &mut M) {
        let mut io_registers_state = [PPURegisterStatus::Untouched; PPU_CTRL_REGISTERS_SIZE];
        io_registers_state.clone_from_slice(memory.ppu_ctrl_registers_status());

        for (index, state) in io_registers_state.iter().enumerate() {
            match index {
                0x00 => self.handle_ppu_ctrl(index, state.clone(), memory),
                0x01 => self.handle_ppu_mask(index, state.clone(), memory),
                _ => {
                    if state.clone() != PPURegisterStatus::Untouched {
                        panic!("Unsupported ppu register touched: 0x{:02X}", index);
                    }
                },
            }
        }
    }

    /// Checks the status of misc I/O registers and executes PPU functionality
    /// depending on their states.
    fn check_misc_registers<M: Memory>(&mut self, memory: &mut M) {
        let mut io_registers_state = [MiscRegisterStatus::Untouched; MISC_CTRL_REGISTERS_SIZE];
        io_registers_state.clone_from_slice(memory.misc_ctrl_registers_status());

        for (index, state) in io_registers_state.iter().enumerate() {
            match index {
                0x14 => self.handle_dma_register(index, state.clone(), memory),
                _ => {
                    if state.clone() != MiscRegisterStatus::Untouched {
                        panic!("Unsupported misc register touched: 0x{:02X}", index);
                    }
                },
            };
        }
    }

    /// Executes routine PPU logic and returns stolen cycles from operations
    /// such as DMA transfers if the PPU hogged the main memory bus.
    pub fn execute<M: Memory>(&mut self, memory: &mut M) -> u16 {
        self.check_ppu_registers(memory);
        self.check_misc_registers(memory);
        0
    }
}
<commit_msg>Added some constants for registers<commit_after>// Copyright 2016 Walter Kuppens.
//
// 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.

use io::log;
use nes::memory::Memory;
use nes::memory::MiscRegisterStatus;
use nes::memory::PPURegisterStatus;
use nes::nes::NESRuntimeOptions;

use nes::memory::{
    PPU_CTRL_REGISTERS_SIZE,
    MISC_CTRL_REGISTERS_SIZE,
};

const SPR_RAM_SIZE: usize = 0x00FF;

// Memory map section sizes.
const PATTERN_TABLES_SIZE: usize = 0x2000;
const NAME_TABLES_SIZE:    usize = 0x1000;
const PALETTES_SIZE:       usize = 0x0020;

// Memory map bounds.
const PATTERN_TABLES_START:     usize = 0x0000;
const PATTERN_TABLES_END:       usize = 0x1FFF;
const NAME_TABLES_START:        usize = 0x2000;
const NAME_TABLES_END:          usize = 0x2FFF;
const NAME_TABLES_MIRROR_START: usize = 0x3000;
const NAME_TABLES_MIRROR_END:   usize = 0x3EFF;
const PALETTES_START:           usize = 0x3F00;
const PALETTES_END:             usize = 0x3F1F;
const PALETTES_MIRROR_START:    usize = 0x3F20;
const PALETTES_MIRROR_END:      usize = 0x3FFF;
const MIRROR_START:             usize = 0x4000;
const MIRROR_END:               usize = 0xFFFF;

// Relative addresses of I/O registers handled by the PPU.
const PPUCTRL:    usize = 0x00;
const PPUMASK:    usize = 0x01;
const PPUSTATUS:  usize = 0x02;
const OAMADDR:    usize = 0x03;
const OAMDATA:    usize = 0x04;
const PPUSCROLL:  usize = 0x05;
const PPUADDR:    usize = 0x06;
const PPUDATA:    usize = 0x07;
const OAMDMA:     usize = 0x14;

/// This is an implementation of the 2C02 PPU used in the NES. This piece of
/// hardware is responsible for drawing graphics to the television the console
/// is hooked up to; however in our case we draw to an SDL surface.
pub struct PPU {
    ppu_ctrl: u8,
    ppu_mask: u8,
    ppu_status: u8,

    // The runtime options contain some useful information such as television
    // standard which affect the clock rate of the PPU.
    runtime_options: NESRuntimeOptions,

    // The PPU has 2 pattern tables which store 8x8 pixel tiles which can be
    // drawn to the screen.
    pattern_tables: [u8; PATTERN_TABLES_SIZE],

    // The name tables are matrices of numbers that point to tiles stored in the
    // pattern tables. Each name table has an associated attribute table, which
    // contains the upper 2 bits of colors for each of the associated tiles.
    name_tables: [u8; NAME_TABLES_SIZE],

    // The PPU has 2 color palettes each containing 16 entires selected from the
    // PPU total selection of 52 colors. Because of this all possible colors the
    // PPU can create cannot be shown at once.
    //
    // Another thing to note is that the background color entry is mirrored
    // every 4 bytes so the effective number of color entries is reduced to 13
    // rather than 16.
    palettes: [u8; PALETTES_SIZE],

    // Where sprites are stored (different bus).
    spr_ram: [u8; SPR_RAM_SIZE],
}

impl PPU {
    /// Initializes the PPU and it's internal memory.
    pub fn new(runtime_options: NESRuntimeOptions) -> Self {
        PPU {
            ppu_ctrl: 0,
            ppu_mask: 0,
            ppu_status: 0,

            runtime_options: runtime_options,
            pattern_tables: [0; PATTERN_TABLES_SIZE],
            name_tables: [0; NAME_TABLES_SIZE],
            palettes: [0; PALETTES_SIZE],
            spr_ram: [0; SPR_RAM_SIZE],
        }
    }

    /// Maps a PPU virtual addresses to a physical address used internally by
    /// the PPU emulator.
    fn map(&mut self, addr: usize) -> (&mut [u8], usize) {
        match addr {
            PATTERN_TABLES_START...PATTERN_TABLES_END =>
                (&mut self.pattern_tables, addr),
            NAME_TABLES_START...NAME_TABLES_END =>
                (&mut self.name_tables, addr - NAME_TABLES_START),
            NAME_TABLES_MIRROR_START...NAME_TABLES_MIRROR_END =>
                (&mut self.name_tables, (addr - NAME_TABLES_START) % NAME_TABLES_SIZE),
            PALETTES_START...PALETTES_END =>
                (&mut self.palettes, addr - PALETTES_START),
            PALETTES_MIRROR_START...PALETTES_MIRROR_END =>
                (&mut self.palettes, (addr - PALETTES_START) % PALETTES_SIZE),
            MIRROR_START...MIRROR_END =>
                self.map(addr - MIRROR_START), // Lazy recursion to share nested mirror logic ^^^.
            _ => { panic!("Unable to map virtual address {:#X} to any physical address", addr) },
        }
    }

    /// Reads a byte from PPU memory at the given virtual address.
    fn read_u8(&mut self, addr: usize) -> u8 {
        let (bank, addr) = self.map(addr);
        bank[addr]
    }

    /// Writes a byte to PPU memory at the given virtual address.
    fn write_u8(&mut self, addr: usize, value: u8) {
        let (bank, addr) = self.map(addr);
        bank[addr] = value;
    }

    /// Copy data from main memory to the PPU's internal sprite memory.
    fn exec_dma(&mut self, register: u8) {
        println!("{:02X}", register);
        panic!("DMA unimplemented");
    }

    /// Reads the contents of the DMA register and executes DMA if written since
    /// the last PPU cycle.
    ///
    /// TODO: Implement me!
    fn handle_dma_register<M: Memory>(&mut self, index: usize, state: MiscRegisterStatus, memory: &mut M) {
        if state != MiscRegisterStatus::Written {
            return;
        }
        let register = memory.misc_ctrl_registers()[index];
        self.exec_dma(register);
    }

    /// Updates the internal PPUCTRL register when the I/O register was written
    /// since the last PPU cycle.
    fn handle_ppu_ctrl<M: Memory>(&mut self, index: usize, state: PPURegisterStatus, memory: &mut M) {
        if state != PPURegisterStatus::Written {
            return;
        }
        self.ppu_ctrl = memory.ppu_ctrl_registers()[index];
        memory.ppu_ctrl_registers_status()[index] = PPURegisterStatus::Untouched;
    }

    /// Updates the internal PPUMASK register when the I/O register was written
    /// since the last PPU cycle.
    fn handle_ppu_mask<M: Memory>(&mut self, index: usize, state: PPURegisterStatus, memory: &mut M) {
        if state != PPURegisterStatus::Written {
            return;
        }
        self.ppu_mask = memory.ppu_ctrl_registers()[index];
        memory.ppu_ctrl_registers_status()[index] = PPURegisterStatus::Untouched;
    }

    /// Checks the status of PPU I/O registers and executes PPU functionality
    /// depending on their states.
    fn check_ppu_registers<M: Memory>(&mut self, memory: &mut M) {
        let mut io_registers_state = [PPURegisterStatus::Untouched; PPU_CTRL_REGISTERS_SIZE];
        io_registers_state.clone_from_slice(memory.ppu_ctrl_registers_status());

        for (index, state) in io_registers_state.iter().enumerate() {
            match index {
                PPUCTRL => self.handle_ppu_ctrl(index, state.clone(), memory),
                PPUMASK => self.handle_ppu_mask(index, state.clone(), memory),
                _ => {
                    if state.clone() != PPURegisterStatus::Untouched {
                        panic!("Unsupported ppu register touched: 0x{:02X}", index);
                    }
                },
            }
        }
    }

    /// Checks the status of misc I/O registers and executes PPU functionality
    /// depending on their states.
    fn check_misc_registers<M: Memory>(&mut self, memory: &mut M) {
        let mut io_registers_state = [MiscRegisterStatus::Untouched; MISC_CTRL_REGISTERS_SIZE];
        io_registers_state.clone_from_slice(memory.misc_ctrl_registers_status());

        for (index, state) in io_registers_state.iter().enumerate() {
            match index {
                OAMDMA => self.handle_dma_register(index, state.clone(), memory),
                _ => {
                    // FIXME: PPU does not need to handle all misc I/O
                    // registers. Remove this panic later.
                    if state.clone() != MiscRegisterStatus::Untouched {
                        panic!("Unsupported misc register touched: 0x{:02X}", index);
                    }
                },
            };
        }
    }

    /// Executes routine PPU logic and returns stolen cycles from operations
    /// such as DMA transfers if the PPU hogged the main memory bus.
    pub fn execute<M: Memory>(&mut self, memory: &mut M) -> u16 {
        self.check_ppu_registers(memory);
        self.check_misc_registers(memory);
        0
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2015 Rustcc Developers

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

pub use self::tcp::{TcpListener, TcpStream, TcpSocket};
pub use self::udp::UdpSocket;

use std::io;
use std::net::{ToSocketAddrs, SocketAddr};

pub mod tcp;
pub mod udp;

fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T>
    where F: FnMut(&SocketAddr) -> io::Result<T>
{
    let mut last_err = None;
    for addr in try!(addr.to_socket_addrs()) {
        match f(&addr) {
            Ok(l) => return Ok(l),
            Err(e) => last_err = Some(e),
        }
    }
    Err(last_err.unwrap_or_else(|| {
        io::Error::new(io::ErrorKind::InvalidInput,
                       "could not resolve to any addresses")
    }))
}
<commit_msg>export shutdown<commit_after>// The MIT License (MIT)

// Copyright (c) 2015 Rustcc Developers

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

pub use self::tcp::{TcpListener, TcpStream, TcpSocket, Shutdown};
pub use self::udp::UdpSocket;

use std::io;
use std::net::{ToSocketAddrs, SocketAddr};

pub mod tcp;
pub mod udp;

fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T>
    where F: FnMut(&SocketAddr) -> io::Result<T>
{
    let mut last_err = None;
    for addr in try!(addr.to_socket_addrs()) {
        match f(&addr) {
            Ok(l) => return Ok(l),
            Err(e) => last_err = Some(e),
        }
    }
    Err(last_err.unwrap_or_else(|| {
        io::Error::new(io::ErrorKind::InvalidInput,
                       "could not resolve to any addresses")
    }))
}
<|endoftext|>


<commit_before>// Higher level OpenCL wrappers.

use CL::*;
use CL::ll::*;
use error::check;

struct Platform {
    id: cl_platform_id
}

impl Platform {
    fn get_devices() -> ~[Device] {
        get_devices(self)
    }

    fn name() -> ~str {
        let mut size = 0;

        clGetPlatformInfo(self.id,
                          CL_PLATFORM_NAME,
                          0,
                          ptr::null(),
                          ptr::mut_addr_of(&size));

        let name = str::repeat(" ", size as uint);

        do str::as_buf(name) |p, len| {
            clGetPlatformInfo(self.id,
                              CL_PLATFORM_NAME,
                              len as libc::size_t,
                              p as *libc::c_void,
                              ptr::mut_addr_of(&size));
        };

        move name
    }
}

pub fn get_platforms() -> ~[Platform] {
    let mut num_platforms = 0;

    // TODO: Check result status
    clGetPlatformIDs(0, ptr::null(), ptr::addr_of(&num_platforms));

    let ids = vec::to_mut(vec::from_elem(num_platforms as uint,
                                         0 as cl_platform_id));

    do vec::as_imm_buf(ids) |ids, len| {
        clGetPlatformIDs(len as cl_uint,
                         ids, ptr::addr_of(&num_platforms))
    };

    do ids.map |id| { Platform { id: *id } }
}

struct Device {
    id: cl_device_id
}

pub fn get_devices(platform: Platform) -> ~[Device] {
    let mut num_devices = 0;

    clGetDeviceIDs(platform.id, CL_DEVICE_TYPE_GPU, 0, ptr::null(),
                   ptr::addr_of(&num_devices));

    let ids = vec::to_mut(vec::from_elem(num_devices as uint,
                                         0 as cl_device_id));
    do vec::as_imm_buf(ids) |ids, len| {
        clGetDeviceIDs(platform.id, CL_DEVICE_TYPE_GPU, len as cl_uint,
                       ids, ptr::addr_of(&num_devices));
    };

    do ids.map |id| { Device {id: *id }}
}

struct Context {
    ctx: cl_context,

    drop {
        clReleaseContext(self.ctx);
    }
}

pub fn create_context(device: Device) -> Context {
    // TODO: Support for multiple devices
    let mut errcode = 0;

    // TODO: Proper error messages
    let ctx = clCreateContext(ptr::null(), 1, ptr::addr_of(&device.id),
                              ptr::null(), ptr::null(), ptr::addr_of(&errcode));

    check(errcode, "Failed to create opencl context!");

    Context { ctx: ctx }
}

struct CommandQueue {
    cqueue: cl_command_queue,
    device: Device,

    drop {
        clReleaseCommandQueue(self.cqueue);
    }
}

pub fn create_commandqueue(ctx: & Context, device: Device) -> CommandQueue {
    let mut errcode = 0;

    let cqueue = clCreateCommandQueue(ctx.ctx, device.id, 0, ptr::addr_of(&errcode));

    check(errcode, "Failed to create command queue!");

    CommandQueue {
        cqueue: cqueue,
        device: device
    }
}

struct Buffer {
    buffer: cl_mem,
    size: int,

    drop {
        clReleaseMemObject(self.buffer);
    }
}

// TODO: How to make this function cleaner and nice
pub fn create_buffer(ctx: & Context, size: int, flags: cl_mem_flags) -> Buffer {
    let mut errcode = 0;

    let buffer = clCreateBuffer(ctx.ctx, flags, size as libc::size_t, ptr::null(),
                                ptr::addr_of(&errcode));

    check(errcode, "Failed to create buffer!");

    Buffer { buffer: buffer, size: size }
}

pub fn enqueue_write_buffer<T: KernelArg>(
    cqueue: & CommandQueue,
    buf: & Buffer,
    host_vector: T) unsafe
{
    let ret = clEnqueueWriteBuffer(
        cqueue.cqueue, buf.buffer, CL_TRUE, 0,
        buf.size as libc::size_t,
        host_vector.get_value(),
        0, ptr::null(), ptr::null());
    check(ret, "Failed to enqueue write buffer!");
}

pub fn enqueue_read_buffer<T: KernelArg>(
    cqueue: & CommandQueue,
    buf: & Buffer,
    host_vector: T) unsafe
{
    let ret = clEnqueueReadBuffer(
        cqueue.cqueue, buf.buffer, CL_TRUE, 0,
        buf.size as libc::size_t,
        host_vector.get_value(), 0, ptr::null(), ptr::null());

    check(ret, "Failed to enqueue read buffer!");
}

struct Program {
    prg: cl_program,

    drop {
        clReleaseProgram(self.prg);
    }
}

pub impl Program {
    fn build(&self, device: Device) {
        build_program(self, device);
    }
}

// TODO: Support multiple devices
pub fn create_program_with_binary(ctx: & Context, device: Device,
                                  binary_path: & Path) -> Program {
    let mut errcode = 0;
    let binary = match move io::read_whole_file_str(binary_path) {
        result::Ok(move binary) => move binary,
        Err(e) => fail fmt!("%?", e)
    };
    let program = do str::as_c_str(binary) |kernel_binary| {
        clCreateProgramWithBinary(ctx.ctx, 1, ptr::addr_of(&device.id),
                                  ptr::addr_of(&(binary.len() + 1)) as *libc::size_t,
                                  ptr::addr_of(&kernel_binary) as **libc::c_uchar,
                                  ptr::null(),
                                  ptr::addr_of(&errcode))
    };

    check(errcode, "Failed to create open cl program with binary!");

    Program { prg: program }
}

pub fn build_program(program: & Program, device: Device) {
    let ret = clBuildProgram(program.prg, 1, ptr::addr_of(&device.id),
                             ptr::null(), ptr::null(), ptr::null());
    if ret != CL_SUCCESS as cl_int {
        let mut logv = ~"";
        for uint::range(0,1024*1204) |_i| {
            str::push_char(& mut logv, ' ');
        }
        do str::as_buf(logv) |logs, l| {
            let r = clGetProgramBuildInfo(program.prg, device.id, CL_PROGRAM_BUILD_LOG, l as libc::size_t, logs as *libc::c_void, ptr::null());
            check(r, "failed to get build info!");
        }
        info!("%s", logv);
        //io::println(logv);
        fail fmt!("Failure during program building! %?", ret)
    }
}

struct Kernel {
    kernel: cl_kernel,

    drop {
        clReleaseKernel(self.kernel);
    }
}

impl Kernel {
    fn set_arg<T: KernelArg>(i: uint, x: &T) {
        set_kernel_arg(&self, i as CL::cl_uint, x)
    }
}

pub fn create_kernel(program: & Program, kernel: & str) -> Kernel unsafe{
    let mut errcode = 0;
    let bytes = str::to_bytes(kernel);
    let kernel = clCreateKernel(program.prg, vec::raw::to_ptr(bytes) as *libc::c_char, ptr::addr_of(&errcode));

    check(errcode, "Failed to create kernel!");

    Kernel { kernel: kernel }
}

pub trait KernelArg{
    fn get_value() -> *libc::c_void;
}

pub fn set_kernel_arg<T: KernelArg>(kernel: & Kernel, position: cl_uint, arg: & T) unsafe{
    // TODO: How to set different argument types. Currently only support cl_mem
    let ret = clSetKernelArg(kernel.kernel, position,
                             sys::size_of::<cl_mem>() as libc::size_t,
                             arg.get_value());

    check(ret, "Failed to set kernel arg!");
}

pub fn enqueue_nd_range_kernel(cqueue: & CommandQueue, kernel: & Kernel, work_dim: cl_uint,
                               _global_work_offset: int, global_work_size: int,
                               local_work_size: int) unsafe{
    let ret = clEnqueueNDRangeKernel(cqueue.cqueue, kernel.kernel, work_dim,
                                     // ptr::addr_of(&global_work_offset) as *libc::size_t,
                                     ptr::null(),
                                     ptr::addr_of(&global_work_size) as *libc::size_t,
                                     ptr::addr_of(&local_work_size) as *libc::size_t,
                                     0, ptr::null(), ptr::null());
    check(ret, "Failed to enqueue nd range kernel!");
}

pub impl<T> &~[T]: KernelArg {
    fn get_value() -> *libc::c_void {
        do vec::as_imm_buf(*self) |p, _len| {
            p as *libc::c_void
        }
    }
}

pub impl<T> &~[mut T]: KernelArg {
    fn get_value() -> *libc::c_void {
        do vec::as_imm_buf(*self) |p, _len| {
            p as *libc::c_void
        }
    }
}

pub impl Buffer: KernelArg{
    fn get_value() -> *libc::c_void{
        ptr::addr_of(&self.buffer) as *libc::c_void
    }
}

pub impl *libc::c_void: KernelArg{
    fn get_value() -> *libc::c_void {
        self
    }
}

/**
This packages an OpenCL context, a device, and a command queue to
simplify handling all these structures.
*/
struct ComputeContext {
    ctx: Context,
    device: Device,
    q: CommandQueue
}

impl ComputeContext {
    fn create_program_with_source(src: &str) -> Program {
        do str::as_c_str(src) |src| {
            let mut status = CL_SUCCESS as cl_int;
            let program = clCreateProgramWithSource(
                self.ctx.ctx,
                1,
                ptr::addr_of(&src),
                ptr::null(),
                ptr::addr_of(&status));
            check(status, "Could not create program");

            Program { prg: program }
        }
    }
}

pub fn create_compute_context() -> @ComputeContext {
    // Enumerate all platforms until we find a device that works.

    for get_platforms().each |p| {
        let devices = p.get_devices();
        if devices.len() > 0 {
            let device = devices[0];
            let ctx = create_context(device);
            let q = create_commandqueue(&ctx, device);
            return @ComputeContext {
                ctx: move ctx,
                device: move device,
                q: move q
            }
        }
    }
    fail ~"Could not find an acceptable device."
}

#[cfg(test)]
mod test {
    #[test]
    fn program_build() {
        let src = "__kernel void test(__global int *i) { \
                       *i += 1; \
                   }";
        let ctx = create_compute_context();
        let prog = ctx.create_program_with_source(src);
        prog.build(ctx.device);
    }
}<commit_msg>Renaming create_program_with_source<commit_after>// Higher level OpenCL wrappers.

use CL::*;
use CL::ll::*;
use error::check;

struct Platform {
    id: cl_platform_id
}

impl Platform {
    fn get_devices() -> ~[Device] {
        get_devices(self)
    }

    fn name() -> ~str {
        let mut size = 0;

        clGetPlatformInfo(self.id,
                          CL_PLATFORM_NAME,
                          0,
                          ptr::null(),
                          ptr::mut_addr_of(&size));

        let name = str::repeat(" ", size as uint);

        do str::as_buf(name) |p, len| {
            clGetPlatformInfo(self.id,
                              CL_PLATFORM_NAME,
                              len as libc::size_t,
                              p as *libc::c_void,
                              ptr::mut_addr_of(&size));
        };

        move name
    }
}

pub fn get_platforms() -> ~[Platform] {
    let mut num_platforms = 0;

    // TODO: Check result status
    clGetPlatformIDs(0, ptr::null(), ptr::addr_of(&num_platforms));

    let ids = vec::to_mut(vec::from_elem(num_platforms as uint,
                                         0 as cl_platform_id));

    do vec::as_imm_buf(ids) |ids, len| {
        clGetPlatformIDs(len as cl_uint,
                         ids, ptr::addr_of(&num_platforms))
    };

    do ids.map |id| { Platform { id: *id } }
}

struct Device {
    id: cl_device_id
}

pub fn get_devices(platform: Platform) -> ~[Device] {
    let mut num_devices = 0;

    clGetDeviceIDs(platform.id, CL_DEVICE_TYPE_GPU, 0, ptr::null(),
                   ptr::addr_of(&num_devices));

    let ids = vec::to_mut(vec::from_elem(num_devices as uint,
                                         0 as cl_device_id));
    do vec::as_imm_buf(ids) |ids, len| {
        clGetDeviceIDs(platform.id, CL_DEVICE_TYPE_GPU, len as cl_uint,
                       ids, ptr::addr_of(&num_devices));
    };

    do ids.map |id| { Device {id: *id }}
}

struct Context {
    ctx: cl_context,

    drop {
        clReleaseContext(self.ctx);
    }
}

pub fn create_context(device: Device) -> Context {
    // TODO: Support for multiple devices
    let mut errcode = 0;

    // TODO: Proper error messages
    let ctx = clCreateContext(ptr::null(), 1, ptr::addr_of(&device.id),
                              ptr::null(), ptr::null(), ptr::addr_of(&errcode));

    check(errcode, "Failed to create opencl context!");

    Context { ctx: ctx }
}

struct CommandQueue {
    cqueue: cl_command_queue,
    device: Device,

    drop {
        clReleaseCommandQueue(self.cqueue);
    }
}

pub fn create_commandqueue(ctx: & Context, device: Device) -> CommandQueue {
    let mut errcode = 0;

    let cqueue = clCreateCommandQueue(ctx.ctx, device.id, 0, ptr::addr_of(&errcode));

    check(errcode, "Failed to create command queue!");

    CommandQueue {
        cqueue: cqueue,
        device: device
    }
}

struct Buffer {
    buffer: cl_mem,
    size: int,

    drop {
        clReleaseMemObject(self.buffer);
    }
}

// TODO: How to make this function cleaner and nice
pub fn create_buffer(ctx: & Context, size: int, flags: cl_mem_flags) -> Buffer {
    let mut errcode = 0;

    let buffer = clCreateBuffer(ctx.ctx, flags, size as libc::size_t, ptr::null(),
                                ptr::addr_of(&errcode));

    check(errcode, "Failed to create buffer!");

    Buffer { buffer: buffer, size: size }
}

pub fn enqueue_write_buffer<T: KernelArg>(
    cqueue: & CommandQueue,
    buf: & Buffer,
    host_vector: T) unsafe
{
    let ret = clEnqueueWriteBuffer(
        cqueue.cqueue, buf.buffer, CL_TRUE, 0,
        buf.size as libc::size_t,
        host_vector.get_value(),
        0, ptr::null(), ptr::null());
    check(ret, "Failed to enqueue write buffer!");
}

pub fn enqueue_read_buffer<T: KernelArg>(
    cqueue: & CommandQueue,
    buf: & Buffer,
    host_vector: T) unsafe
{
    let ret = clEnqueueReadBuffer(
        cqueue.cqueue, buf.buffer, CL_TRUE, 0,
        buf.size as libc::size_t,
        host_vector.get_value(), 0, ptr::null(), ptr::null());

    check(ret, "Failed to enqueue read buffer!");
}

struct Program {
    prg: cl_program,

    drop {
        clReleaseProgram(self.prg);
    }
}

pub impl Program {
    fn build(&self, device: Device) {
        build_program(self, device);
    }
}

// TODO: Support multiple devices
pub fn create_program_with_binary(ctx: & Context, device: Device,
                                  binary_path: & Path) -> Program {
    let mut errcode = 0;
    let binary = match move io::read_whole_file_str(binary_path) {
        result::Ok(move binary) => move binary,
        Err(e) => fail fmt!("%?", e)
    };
    let program = do str::as_c_str(binary) |kernel_binary| {
        clCreateProgramWithBinary(ctx.ctx, 1, ptr::addr_of(&device.id),
                                  ptr::addr_of(&(binary.len() + 1)) as *libc::size_t,
                                  ptr::addr_of(&kernel_binary) as **libc::c_uchar,
                                  ptr::null(),
                                  ptr::addr_of(&errcode))
    };

    check(errcode, "Failed to create open cl program with binary!");

    Program { prg: program }
}

pub fn build_program(program: & Program, device: Device) {
    let ret = clBuildProgram(program.prg, 1, ptr::addr_of(&device.id),
                             ptr::null(), ptr::null(), ptr::null());
    if ret != CL_SUCCESS as cl_int {
        let mut logv = ~"";
        for uint::range(0,1024*1204) |_i| {
            str::push_char(& mut logv, ' ');
        }
        do str::as_buf(logv) |logs, l| {
            let r = clGetProgramBuildInfo(program.prg, device.id, CL_PROGRAM_BUILD_LOG, l as libc::size_t, logs as *libc::c_void, ptr::null());
            check(r, "failed to get build info!");
        }
        info!("%s", logv);
        //io::println(logv);
        fail fmt!("Failure during program building! %?", ret)
    }
}

struct Kernel {
    kernel: cl_kernel,

    drop {
        clReleaseKernel(self.kernel);
    }
}

impl Kernel {
    fn set_arg<T: KernelArg>(i: uint, x: &T) {
        set_kernel_arg(&self, i as CL::cl_uint, x)
    }
}

pub fn create_kernel(program: & Program, kernel: & str) -> Kernel unsafe{
    let mut errcode = 0;
    let bytes = str::to_bytes(kernel);
    let kernel = clCreateKernel(program.prg, vec::raw::to_ptr(bytes) as *libc::c_char, ptr::addr_of(&errcode));

    check(errcode, "Failed to create kernel!");

    Kernel { kernel: kernel }
}

pub trait KernelArg{
    fn get_value() -> *libc::c_void;
}

pub fn set_kernel_arg<T: KernelArg>(kernel: & Kernel, position: cl_uint, arg: & T) unsafe{
    // TODO: How to set different argument types. Currently only support cl_mem
    let ret = clSetKernelArg(kernel.kernel, position,
                             sys::size_of::<cl_mem>() as libc::size_t,
                             arg.get_value());

    check(ret, "Failed to set kernel arg!");
}

pub fn enqueue_nd_range_kernel(cqueue: & CommandQueue, kernel: & Kernel, work_dim: cl_uint,
                               _global_work_offset: int, global_work_size: int,
                               local_work_size: int) unsafe{
    let ret = clEnqueueNDRangeKernel(cqueue.cqueue, kernel.kernel, work_dim,
                                     // ptr::addr_of(&global_work_offset) as *libc::size_t,
                                     ptr::null(),
                                     ptr::addr_of(&global_work_size) as *libc::size_t,
                                     ptr::addr_of(&local_work_size) as *libc::size_t,
                                     0, ptr::null(), ptr::null());
    check(ret, "Failed to enqueue nd range kernel!");
}

pub impl<T> &~[T]: KernelArg {
    fn get_value() -> *libc::c_void {
        do vec::as_imm_buf(*self) |p, _len| {
            p as *libc::c_void
        }
    }
}

pub impl<T> &~[mut T]: KernelArg {
    fn get_value() -> *libc::c_void {
        do vec::as_imm_buf(*self) |p, _len| {
            p as *libc::c_void
        }
    }
}

pub impl Buffer: KernelArg{
    fn get_value() -> *libc::c_void{
        ptr::addr_of(&self.buffer) as *libc::c_void
    }
}

pub impl *libc::c_void: KernelArg{
    fn get_value() -> *libc::c_void {
        self
    }
}

/**
This packages an OpenCL context, a device, and a command queue to
simplify handling all these structures.
*/
struct ComputeContext {
    ctx: Context,
    device: Device,
    q: CommandQueue
}

impl ComputeContext {
    fn create_program_from_source(src: &str) -> Program {
        do str::as_c_str(src) |src| {
            let mut status = CL_SUCCESS as cl_int;
            let program = clCreateProgramWithSource(
                self.ctx.ctx,
                1,
                ptr::addr_of(&src),
                ptr::null(),
                ptr::addr_of(&status));
            check(status, "Could not create program");

            Program { prg: program }
        }
    }
}

pub fn create_compute_context() -> @ComputeContext {
    // Enumerate all platforms until we find a device that works.

    for get_platforms().each |p| {
        let devices = p.get_devices();
        if devices.len() > 0 {
            let device = devices[0];
            let ctx = create_context(device);
            let q = create_commandqueue(&ctx, device);
            return @ComputeContext {
                ctx: move ctx,
                device: move device,
                q: move q
            }
        }
    }
    fail ~"Could not find an acceptable device."
}

#[cfg(test)]
mod test {
    #[test]
    fn program_build() {
        let src = "__kernel void test(__global int *i) { \
                       *i += 1; \
                   }";
        let ctx = create_compute_context();
        let prog = ctx.create_program_from_source(src);
        prog.build(ctx.device);
    }
}<|endoftext|>


<commit_before>use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
use std::io::{Write};

pub enum Packet {
    //Status request and response (channel -1)
    StatusRequest(StatusRequest),
    StatusResponse(StatusResponse),

    //Connection handshake (also channel -1).
    Connect,
    Aborted(String),
    Connected(u32),

    //Heartbeat (channel -2).
    Heartbeat(i16),

    //MTU estimation (-3 and -4)
    //These have to record the channel.
    ResetMTUCount {channel: i16},
    MTUCountWasReset {channel: i16},
    MTUEstimate {channel: i16, payload: Vec<u8>},
    MTUResponse {channel: i16, count: u32},
}

pub enum StatusRequest {
    FastnetQuery,
    VersionQuery,
    ExtensionQuery(String),
}

pub enum StatusResponse {
    FastnetResponse(u8),
    VersionResponse(String),
    ExtensionResponse {name: String, supported: u8},
}

pub enum PacketEncodingError {
    //We need to write over 500 bytes to decode.
    TooLarge,
}

pub enum PacketDecodingError {
    //We need more bytes than what we got.
    TooSmall,
    //The packet has a checksum, but we didn't match it.
    ChecksumMismatch,
    UnknownChannel,
    InvalidFormat,
}

//These are the channel constants.

//Status query and connection handshake channel.
const CONNECTION_CHANNEL: i16 = -1;

//Heartbeat channel.
const HEARTBEAT_CHANNEL: i16 = -2;

//Client and server MTU channels.
//These are named for the entity executing the MTU estimation algorithm, not for the entity receiving.
const SERVER_MTU_ESTIMATION_CHANNEL: i16 = -3;
const CLIENT_MTU_ESTIMATION_CHANNEL: i16 = -4;

//Specification mandates that we never send a packet over the maximum size of 500 bytes.
const MAXIMUM_PACKET_SIZE: usize = 500;

//This function writes over the buffer even if it fails.
pub fn encode_packet(packet: &Packet, destination: &mut [u8; MAXIMUM_PACKET_SIZE])->Result<usize, PacketEncodingError> {
    let destinationLen = destination.len();
    let mut writingTo = &mut destination[..];
    match *packet {
        Packet::StatusRequest(ref req) => {
            writingTo.write_i16::<BigEndian>(-1).unwrap();
            writingTo.write_i16::<BigEndian>(0).unwrap();
            match *req {
                StatusRequest::FastnetQuery => {
                    writingTo.write_u8(0).unwrap();
                },
                StatusRequest::VersionQuery => {
                    writingTo.write_u8(1).unwrap();
                },
                StatusRequest::ExtensionQuery(ref name) => {
                    writingTo.write_u8(2).unwrap();
                    let nameAsBytes = name.as_bytes();
                    if nameAsBytes.len() < writingTo.len()-1 {return Err(PacketEncodingError::TooLarge);};
                    writingTo.write(nameAsBytes).unwrap();
                },
            }
        },
        Packet::StatusResponse(ref resp) => {
            writingTo.write_i16::<BigEndian>(-1);
            writingTo.write_u8(1);
            match* resp {
                StatusResponse::FastnetResponse(value) => {
                    writingTo.write_u8(0).unwrap();
                    writingTo.write_u8(value);
                },
                StatusResponse::VersionResponse(ref version) => {
                    writingTo.write_u8(1);
                    let versionAsBytes = version.as_bytes();
                    if writingTo.len() < versionAsBytes.len() {return Err(PacketEncodingError:: TooLarge)};
                    writingTo.write(versionAsBytes).unwrap();
                },
                StatusResponse::ExtensionResponse{name: ref name, supported: supported} => {
                    writingTo.write_u8(2).unwrap();
                    let nameAsBytes = name.as_bytes();
                    //name plus the boolean.
                    if writingTo.len() < nameAsBytes.len()-1 {return Err(PacketEncodingError::TooLarge)};
                    writingTo.write(nameAsBytes).unwrap();
                    writingTo.write_u8(supported);
                },
            }
        },
        Packet::Connect => {
            writingTo.write_i16::<BigEndian>(-1);
            writingTo.write_u8(2);
        },
        Packet::Connected(id) => {
            writingTo.write_i16::<BigEndian>(-1);
            writingTo.write_u8(3);
            writingTo.write_u32::<BigEndian>(id);
        },
        Packet::Aborted(ref msg) => {
            writingTo.write_i16::<BigEndian>(-1);
            writingTo.write_u8(4);
            let msgAsBytes = msg.as_bytes();
            if writingTo.len() < msgAsBytes.len() {return Err(PacketEncodingError::TooLarge)};
            writingTo.write(msgAsBytes).unwrap();
        },
        Packet::Heartbeat(value) => {
            writingTo.write_i16::<BigEndian>(-2);
            writingTo.write_i16::<BigEndian>(value);
        },
        Packet::ResetMTUCount{channel: chan} => {
            writingTo.write_i16::<BigEndian>(chan);
            writingTo.write_u8(0);
        },
        Packet::MTUCountWasReset{channel: chan} => {
            writingTo.write_i16::<BigEndian>(chan).unwrap();
            writingTo.write_u8(1).unwrap();
        },
        Packet::MTUEstimate{channel: chan, payload: ref p} => {
            writingTo.write_i16::<BigEndian>(chan).unwrap();
            writingTo.write_u8(2).unwrap();
            if writingTo.len() < p.len() {return Err(PacketEncodingError::TooLarge)};
            writingTo.write(p).unwrap();
        },
        Packet::MTUResponse{channel: chan, count: c} => {
            writingTo.write_i16::<BigEndian>(chan);
            writingTo.write_u8(3).unwrap();
            writingTo.write_u32::<BigEndian>(c).unwrap();
        },
    }
    Ok(destinationLen-writingTo.len())
}
<commit_msg>Massively clean up the current packet encoder.<commit_after>use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
use std::io::{Write};

pub enum Packet {
    //Status request and response (channel -1)
    StatusRequest(StatusRequest),
    StatusResponse(StatusResponse),

    //Connection handshake (also channel -1).
    Connect,
    Aborted(String),
    Connected(u32),

    //Heartbeat (channel -2).
    Heartbeat(i16),

    //MTU estimation (-3 and -4)
    //These have to record the channel.
    ResetMTUCount {channel: i16},
    MTUCountWasReset {channel: i16},
    MTUEstimate {channel: i16, payload: Vec<u8>},
    MTUResponse {channel: i16, count: u32},
}

pub enum StatusRequest {
    FastnetQuery,
    VersionQuery,
    ExtensionQuery(String),
}

pub enum StatusResponse {
    FastnetResponse(u8),
    VersionResponse(String),
    ExtensionResponse {name: String, supported: u8},
}

pub enum PacketEncodingError {
    //Not enough space in the buffer.
    TooLarge,
    //Data didn't validate.
    Invalid,
}

pub enum PacketDecodingError {
    //We need more bytes than what we got.
    TooSmall,
    //The packet has a checksum, but we didn't match it.
    ChecksumMismatch,
    UnknownChannel,
    InvalidFormat,
}

//These are the channel constants.

//Status query and connection handshake channel.
const CONNECTION_CHANNEL: i16 = -1;

//Heartbeat channel.
const HEARTBEAT_CHANNEL: i16 = -2;

//Client and server MTU channels.
//These are named for the entity executing the MTU estimation algorithm, not for the entity receiving.
const SERVER_MTU_ESTIMATION_CHANNEL: i16 = -3;
const CLIENT_MTU_ESTIMATION_CHANNEL: i16 = -4;

//This overrides the buffer even if it fails.
pub fn encode_packet(packet: &Packet, destination: &mut [u8])->Result<usize, PacketEncodingError> {
    match *packet {
        Packet::StatusRequest(ref req) => {
            return encode_status_request(req, destination);
        },
        Packet::StatusResponse(ref resp) => {
            return encode_status_response(resp, destination);
        },
        Packet::Connect => {
            return encode_connect(destination);
        },
        Packet::Connected(id) => {
            return encode_connected(id, destination);
        },
        Packet::Aborted(ref msg) => {
            return encode_aborted(msg, destination);
        },
        Packet::Heartbeat(value) => {
            return encode_heartbeat(value, destination);
        },
        Packet::ResetMTUCount{channel: chan} => {
            return encode_reset_mtu_count(chan, destination);
        },
        Packet::MTUCountWasReset{channel: chan} => {
            return encode_mtu_count_was_reset(chan, destination);
        },
        Packet::MTUEstimate{channel: chan, payload: ref p} => {
            return encode_mtu_estimate(chan, p, destination);
        },
        Packet::MTUResponse{channel: chan, count: c} => {
            return encode_mtu_response(chan, c, destination);
        },
    }
}

fn encode_status_request(req: &StatusRequest, mut destination: &mut[u8])-> Result<usize, PacketEncodingError> {
    use self::PacketEncodingError::*;
    let initial_count = destination.len();
    try!(destination.write_i16::<BigEndian>(CONNECTION_CHANNEL).or(Err(TooLarge)));
    match *req {
        StatusRequest::FastnetQuery => {
            try!(destination.write_u8(0).or(Err(TooLarge)));
        },
        StatusRequest::VersionQuery => {
            try!(destination.write_u8(1).or(Err(TooLarge)));
        },
        StatusRequest::ExtensionQuery(ref name) => {
            try!(destination.write_u8(2).or(Err(TooLarge)));
            try!(destination.write_all(name.as_bytes()).or(Err(TooLarge)));
        },
    }
    Ok(initial_count-destination.len())
}

fn encode_status_response(resp: &StatusResponse, mut destination: &mut[u8])->Result<usize, PacketEncodingError> {
    use self::PacketEncodingError::*;
    let initial_count = destination.len();
    try!(destination.write_i16::<BigEndian>(CONNECTION_CHANNEL).or(Err(TooLarge)));
    try!(destination.write_u8(1).or(Err(TooLarge)));
    match* resp {
        StatusResponse::FastnetResponse(value) => {
            try!(destination.write_u8(0).or(Err(TooLarge)));
            try!(destination.write_u8(value).or(Err(TooLarge)));
        },
        StatusResponse::VersionResponse(ref version) => {
            try!(destination.write_u8(1).or(Err(TooLarge)));
            try!(destination.write_all(b"1.0").or(Err(TooLarge)));
        },
        StatusResponse::ExtensionResponse{name: ref name, supported: supported} => {
            try!(destination.write_u8(2).or(Err(TooLarge)));
            try!(destination.write(name.as_bytes()).or(Err(TooLarge)));
            try!(destination.write_u8(supported).or(Err(TooLarge)));
        },
    }
    return Ok(initial_count-destination.len());
}

fn encode_connect(mut destination: &mut[u8])->Result<usize, PacketEncodingError> {
    use self::PacketEncodingError::*;
    let initial_count = destination.len();
    try!(destination.write_i16::<BigEndian>(CONNECTION_CHANNEL).or(Err(TooLarge)));
    try!(destination.write_u8(2).or(Err(TooLarge)));
    Ok(initial_count-destination.len())
}

fn encode_connected(id: u32, mut destination: &mut[u8])->Result<usize, PacketEncodingError> {
    use self::PacketEncodingError::*;
    let initial_count = destination.len();
    try!(destination.write_i16::<BigEndian>(CONNECTION_CHANNEL).or(Err(TooLarge)));
    try!(destination.write_u8(3).or(Err(TooLarge)));
    try!(destination.write_u32::<BigEndian>(id).or(Err(TooLarge)));
    Ok(initial_count-destination.len())
}

fn encode_aborted(msg: &String, mut destination: &mut[u8])->Result<usize, PacketEncodingError> {
    use self::PacketEncodingError::*;
    let initial_count = destination.len();
    try!(destination.write_i16::<BigEndian>(CONNECTION_CHANNEL).or(Err(TooLarge)));
    try!(destination.write_u8(4).or(Err(TooLarge)));
    try!(destination.write_all(msg.as_bytes()).or(Err(TooLarge)));;
    Ok(initial_count-destination.len())
}

fn encode_heartbeat(value: i16, mut destination: &mut[u8])->Result<usize, PacketEncodingError> {
    use self::PacketEncodingError::*;
    let initial_count = destination.len();
    try!(destination.write_i16::<BigEndian>(HEARTBEAT_CHANNEL).or(Err(TooLarge)));
    try!(destination.write_i16::<BigEndian>(value).or(Err(TooLarge)));
    Ok(initial_count-destination.len())
}

fn encode_reset_mtu_count(chan: i16, mut destination: &mut[u8])->Result<usize, PacketEncodingError> {
    use self::PacketEncodingError::*;
    if chan != CLIENT_MTU_ESTIMATION_CHANNEL || chan != SERVER_MTU_ESTIMATION_CHANNEL {return Err(Invalid)};
    let initial_count = destination.len();
    try!(destination.write_i16::<BigEndian>(chan).or(Err(TooLarge)));
    try!(destination.write_u8(0).or(Err(TooLarge)));
    Ok(initial_count-destination.len())
}

fn encode_mtu_count_was_reset(chan: i16, mut destination: &mut[u8])->Result<usize, PacketEncodingError> {
    use self::PacketEncodingError::*;
    if chan != CLIENT_MTU_ESTIMATION_CHANNEL || chan != SERVER_MTU_ESTIMATION_CHANNEL {return Err(Invalid)};
    let initial_count = destination.len();
    try!(destination.write_i16::<BigEndian>(chan).or(Err(TooLarge)));
    try!(destination.write_u8(1).or(Err(TooLarge)));
    Ok(initial_count-destination.len())
}

fn encode_mtu_estimate(chan: i16, payload: &[u8], mut destination: &mut[u8])->Result<usize, PacketEncodingError> {
    use self::PacketEncodingError::*;
    if chan != CLIENT_MTU_ESTIMATION_CHANNEL || chan != SERVER_MTU_ESTIMATION_CHANNEL {return Err(Invalid)};
    let initial_count = destination.len();
    try!(destination.write_i16::<BigEndian>(chan).or(Err(TooLarge)));
    try!(destination.write_u8(2).or(Err(TooLarge)));
    try!(destination.write_all(payload).or(Err(TooLarge)));
    Ok(initial_count-destination.len())
}

fn encode_mtu_response(chan: i16, count: u32, mut destination: &mut[u8])->Result<usize, PacketEncodingError> {
    use self::PacketEncodingError::*;
    let initial_count = destination.len();
    try!(destination.write_i16::<BigEndian>(chan).or(Err(TooLarge)));
    try!(destination.write_u8(3).or(Err(TooLarge)));
    try!(destination.write_u32::<BigEndian>(count).or(Err(TooLarge)));
    Ok(initial_count-destination.len())
}
<|endoftext|>


<commit_before>use address::PAYMENT_ADDRESS_PREFIX;
use bs58;
use byteorder::{BigEndian, ByteOrder};
use std::fmt;

#[derive(Clone)]
pub struct Pattern {
    pub prefix: String,
    pub range: (u64, u64),
}

impl fmt::Display for Pattern {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.prefix.as_str())
    }
}

impl Pattern {
    pub fn new(prefix: String) -> Result<Pattern, String> {
        match prefix_to_range_u64(prefix.as_str()) {
            Ok(range) => Ok(Pattern {
                prefix: prefix,
                range: range,
            }),
            Err(err) => Err(err),
        }
    }

    pub fn case_insensitive(&self) -> Vec<Pattern> {
        let prefix_bytes = self.prefix.as_bytes().to_owned();
        let mut patterns = vec![];

        let alpha = bs58::alphabet::DEFAULT;
        let mut rev = [0xff; 128];
        for (i, &c) in alpha.iter().enumerate() {
            rev[c as usize] = i;
        }
        for (i, &c) in alpha.iter().enumerate() {
            let lower = (c as char).to_lowercase().next().unwrap() as usize;
            if lower != c as usize && rev[lower] != 0xff {
                rev[c as usize] = rev[lower];
                rev[lower] = i;
            }
        }

        let mut i = 0;
        let mut max = 1;
        while i < max {
            let mut tmp = prefix_bytes.clone().to_owned();
            let mut k = 1;
            for c in &mut tmp {
                if alpha[rev[*c as usize]] != *c {
                    if i & k != 0 {
                        *c = alpha[rev[*c as usize]];
                    }
                    k *= 2;
                }
            }
            max = k;

            if let Ok(pattern) = Pattern::new(String::from_utf8(tmp).unwrap()) {
                patterns.push(pattern);
            }
            i += 1;
        }
        patterns
    }
}

fn prefix_to_range_u64(prefix: &str) -> Result<(u64, u64), String> {
    // 2-byte prefix, 32-byte a_pk, 32-byte pk_enc, 4-byte check
    let mut address_data = [0u8; 2 + 32 * 2 + 4];
    address_data[..2].copy_from_slice(&PAYMENT_ADDRESS_PREFIX);
    let address_00 = bs58::encode(address_data.as_ref()).into_string();
    for d in address_data.iter_mut().skip(2) { *d = 0xff; }
    let address_ff = bs58::encode(address_data.as_ref()).into_string();

    let suffix_length = address_ff.len() - prefix.len();
    let prefix_1 = prefix.to_owned() + &"1".repeat(suffix_length);
    let prefix_z = prefix.to_owned() + &"z".repeat(suffix_length);

    if prefix_z < address_00 {
        return Err(format!("Invalid z-addr: {} < {}", prefix, &address_00[..prefix.len()]));
    }
    if prefix_1 > address_ff {
        return Err(format!("Invalid z-addr: {} > {}", prefix, &address_ff[..prefix.len()]));
    }

    let pattern_1 = if prefix_1 < address_00 {
        <u64>::min_value()
    } else {
        bs58::decode(prefix_1).into(address_data.as_mut()).unwrap();
        BigEndian::read_u64(&address_data[2..10])
    };

    let pattern_z = if prefix_z > address_ff {
        <u64>::max_value()
    } else {
        bs58::decode(prefix_z).into(address_data.as_mut()).unwrap();
        BigEndian::read_u64(&address_data[2..10])
    };

    Ok((pattern_1, pattern_z))
}
<commit_msg>Add some tests for case-insensitivity.<commit_after>use address::PAYMENT_ADDRESS_PREFIX;
use bs58;
use byteorder::{BigEndian, ByteOrder};
use std::fmt;

#[derive(Clone)]
pub struct Pattern {
    pub prefix: String,
    pub range: (u64, u64),
}

impl fmt::Display for Pattern {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.prefix.as_str())
    }
}

impl Pattern {
    pub fn new(prefix: String) -> Result<Pattern, String> {
        match prefix_to_range_u64(prefix.as_str()) {
            Ok(range) => Ok(Pattern {
                prefix: prefix,
                range: range,
            }),
            Err(err) => Err(err),
        }
    }

    pub fn case_insensitive(&self) -> Vec<Pattern> {
        let prefix_bytes = self.prefix.as_bytes().to_owned();
        let mut patterns = vec![];

        let alpha = bs58::alphabet::DEFAULT;
        let mut rev = [0xff; 128];
        for (i, &c) in alpha.iter().enumerate() {
            rev[c as usize] = i;
        }
        for (i, &c) in alpha.iter().enumerate() {
            let lower = (c as char).to_lowercase().next().unwrap() as usize;
            if lower != c as usize && rev[lower] != 0xff {
                rev[c as usize] = rev[lower];
                rev[lower] = i;
            }
        }

        let mut i = 0;
        let mut max = 1;
        while i < max {
            let mut tmp = prefix_bytes.clone().to_owned();
            let mut k = 1u64;
            for c in &mut tmp {
                if alpha[rev[*c as usize]] != *c {
                    if i & k != 0 {
                        *c = alpha[rev[*c as usize]];
                    }
                    k <<= 1;
                }
            }
            max = k;

            if let Ok(pattern) = Pattern::new(String::from_utf8(tmp).unwrap()) {
                patterns.push(pattern);
            }
            i += 1;
        }
        patterns
    }
}

fn prefix_to_range_u64(prefix: &str) -> Result<(u64, u64), String> {
    // 2-byte prefix, 32-byte a_pk, 32-byte pk_enc, 4-byte check
    let mut address_data = [0u8; 2 + 32 * 2 + 4];
    address_data[..2].copy_from_slice(&PAYMENT_ADDRESS_PREFIX);
    let address_00 = bs58::encode(address_data.as_ref()).into_string();
    for d in address_data.iter_mut().skip(2) {
        *d = 0xff;
    }
    let address_ff = bs58::encode(address_data.as_ref()).into_string();

    let suffix_length = address_ff.len() - prefix.len();
    let prefix_1 = prefix.to_owned() + &"1".repeat(suffix_length);
    let prefix_z = prefix.to_owned() + &"z".repeat(suffix_length);

    if prefix_z < address_00 {
        return Err(format!(
            "Invalid z-addr: {} < {}",
            prefix,
            &address_00[..prefix.len()]
        ));
    }
    if prefix_1 > address_ff {
        return Err(format!(
            "Invalid z-addr: {} > {}",
            prefix,
            &address_ff[..prefix.len()]
        ));
    }

    let pattern_1 = if prefix_1 < address_00 {
        <u64>::min_value()
    } else {
        bs58::decode(prefix_1).into(address_data.as_mut()).unwrap();
        BigEndian::read_u64(&address_data[2..10])
    };

    let pattern_z = if prefix_z > address_ff {
        <u64>::max_value()
    } else {
        bs58::decode(prefix_z).into(address_data.as_mut()).unwrap();
        BigEndian::read_u64(&address_data[2..10])
    };

    Ok((pattern_1, pattern_z))
}

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

    #[test]
    fn case_insensitive_vanity() {
        let pattern = Pattern::new("zcVANiTY".to_string()).unwrap();
        assert_eq!(
            pattern
                .case_insensitive()
                .iter()
                .map(|p| p.prefix.as_str())
                .collect::<Vec<&str>>(),
            vec![
                "zcVANiTY",
                "zcVaNiTY",
                "zcVAniTY",
                "zcVaniTY",
                "zcVANitY",
                "zcVaNitY",
                "zcVAnitY",
                "zcVanitY",
                "zcVANiTy",
                "zcVaNiTy",
                "zcVAniTy",
                "zcVaniTy",
                "zcVANity",
                "zcVaNity",
                "zcVAnity",
                "zcVanity",
            ]
        );
    }

    #[test]
    fn case_insensitive_a() {
        let pattern = Pattern::new("zcA".to_string()).unwrap();
        assert_eq!(
            pattern
                .case_insensitive()
                .iter()
                .map(|p| p.prefix.as_str())
                .collect::<Vec<&str>>(),
            vec![
                "zcA",
                "zca",
            ]
        );
    }
}
<|endoftext|>