<commit_before>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

#![cfg_attr(not(feature = "v1_12"), allow(unused_imports))]

use libc::{c_double, c_int, c_uint};
use std::mem::transmute;
use ffi::enums::{
    Extend,
    Filter,
    Status,
    PatternType
};
use ffi;
use ffi::{
    cairo_pattern_t
};
use ::{
    Path
};

//Quite some changes from the C api but all suggested by the cairo devs.
//See http://cairographics.org/manual/bindings-patterns.html for more info

//TODO Does anyone know a way to do this without dynamic dispatch -- @mthq
pub fn wrap_pattern<'a>(ptr: *mut cairo_pattern_t) -> Box<Pattern + 'a> {
    let pattern_type = unsafe{ ffi::cairo_pattern_get_type(ptr) };

    match pattern_type {
        PatternType::Solid            => Box::new(SolidPattern::wrap(ptr))   as Box<Pattern>,
        PatternType::Surface          => Box::new(SurfacePattern::wrap(ptr)) as Box<Pattern>,
        PatternType::LinearGradient   => Box::new(LinearGradient::wrap(ptr)) as Box<Pattern>,
        PatternType::RadialGradient   => Box::new(RadialGradient::wrap(ptr)) as Box<Pattern>,
        #[cfg(feature = "v1_12")]
        PatternType::Mesh             => Box::new(Mesh::wrap(ptr))           as Box<Pattern>,
        #[cfg(feature = "v1_12")]
        PatternType::RasterSource     => panic!("Not implemented")
    }
}

pub trait Pattern {
    #[doc(hidden)]
    fn get_ptr(&self) -> *mut cairo_pattern_t;

    fn ensure_status(&self) {
        self.status().ensure_valid();
    }

    fn status(&self) -> Status {
        unsafe {
            ffi::cairo_pattern_status(self.get_ptr())
        }
    }

    fn get_reference_count(&self) -> isize {
        unsafe {
            ffi::cairo_pattern_get_reference_count(self.get_ptr()) as isize
        }
    }

    fn set_extend(&self, extend: Extend) {
        unsafe {
            ffi::cairo_pattern_set_extend(self.get_ptr(), extend)
        }
    }

    fn get_extend(&self) -> Extend {
        unsafe {
            ffi::cairo_pattern_get_extend(self.get_ptr())
        }
    }

    fn set_filter(&self, filter: Filter) {
        unsafe {
            ffi::cairo_pattern_set_filter(self.get_ptr(), filter)
        }
    }

    fn get_filter(&self) -> Filter {
        unsafe {
            ffi::cairo_pattern_get_filter(self.get_ptr())
        }
    }

    //fn cairo_pattern_set_matrix(pattern: *mut cairo_pattern_t, matrix: *mut cairo_matrix_t);

    //fn cairo_pattern_get_matrix(pattern: *mut cairo_pattern_t, matrix: *mut cairo_matrix_t);
}

macro_rules! pattern_type(
    //Signals without arguments
    ($pattern_type:ident) => (

        pub struct $pattern_type {
            pointer: *mut cairo_pattern_t
        }

        impl $pattern_type {
            pub fn wrap(pointer: *mut cairo_pattern_t) -> $pattern_type {
                $pattern_type{
                    pointer: pointer
                }
            }

            pub fn reference(&self) -> $pattern_type {
                $pattern_type{
                    pointer: unsafe {
                        ffi::cairo_pattern_reference(self.pointer)
                    }
                }
            }
        }

        impl Pattern for $pattern_type {
            fn get_ptr(&self) -> *mut cairo_pattern_t{
                self.pointer
            }
        }

        impl Drop for $pattern_type {
            fn drop(&mut self){
                unsafe {
                    ffi::cairo_pattern_destroy(self.pointer)
                }
            }
        }
    );
);

pattern_type!(SolidPattern);

impl SolidPattern {
    pub fn from_rgb(red: f64, green: f64, blue: f64) -> SolidPattern {
        SolidPattern::wrap(unsafe {
            ffi::cairo_pattern_create_rgb(red, green, blue)
        })
    }

    pub fn from_rgba(red: f64, green: f64, blue: f64, alpha: f64) -> SolidPattern {
        SolidPattern::wrap(unsafe {
            ffi::cairo_pattern_create_rgba(red, green, blue, alpha)
        })
    }

    pub fn get_rgba(&self) -> (f64, f64, f64, f64) {
        unsafe {
            let red  : *mut c_double = transmute(Box::new(0.0f64));
            let green: *mut c_double = transmute(Box::new(0.0f64));
            let blue : *mut c_double = transmute(Box::new(0.0f64));
            let alpha: *mut c_double = transmute(Box::new(0.0f64));

            ffi::cairo_pattern_get_rgba(self.pointer, red, green, blue, alpha).ensure_valid();

            (*red, *green, *blue, *alpha)
        }
    }
}

pub trait Gradient : Pattern {
    fn add_color_stop_rgb(&self, offset: f64, red: f64, green: f64, blue: f64) {
        unsafe {
            ffi::cairo_pattern_add_color_stop_rgb(self.get_ptr(), offset, red, green, blue)
        }
    }

    fn add_color_stop_rgba(&self, offset: f64, red: f64, green: f64, blue: f64, alpha: f64) {
        unsafe {
            ffi::cairo_pattern_add_color_stop_rgba(self.get_ptr(), offset, red, green, blue, alpha)
        }
    }

    fn get_color_stop_count(&self) -> isize {
        unsafe {
            let count : *mut c_int = transmute(Box::new(0i32));
            let result = ffi::cairo_pattern_get_color_stop_count(self.get_ptr(), count);

            result.ensure_valid(); // Not sure if these are needed
            count as isize
        }
    }

    fn get_color_stop_rgba(&self, index: isize) -> (f64, f64, f64, f64, f64) {
        unsafe {
            let offset: *mut c_double = transmute(Box::new(0.0f64));
            let red   : *mut c_double = transmute(Box::new(0.0f64));
            let green : *mut c_double = transmute(Box::new(0.0f64));
            let blue  : *mut c_double = transmute(Box::new(0.0f64));
            let alpha : *mut c_double = transmute(Box::new(0.0f64));

            ffi::cairo_pattern_get_color_stop_rgba(self.get_ptr(), index as c_int, offset, red, green, blue, alpha).ensure_valid();
            (*offset, *red, *green, *blue, *alpha)
        }
    }
}

pattern_type!(LinearGradient);

impl LinearGradient {
    pub fn new(x0: f64, y0: f64, x1: f64, y1: f64) -> LinearGradient {
        LinearGradient::wrap(unsafe {
            ffi::cairo_pattern_create_linear(x0, y0, x1, y1)
        })
    }

    pub fn get_linear_points(&self) -> (f64, f64, f64, f64) {
        unsafe {
            let x0 : *mut c_double = transmute(Box::new(0.0f64));
            let y0 : *mut c_double = transmute(Box::new(0.0f64));
            let x1 : *mut c_double = transmute(Box::new(0.0f64));
            let y1 : *mut c_double = transmute(Box::new(0.0f64));

            ffi::cairo_pattern_get_linear_points(self.pointer, x0, y0, x1, y1).ensure_valid();
            (*x0, *y0, *x1, *y1)
        }
    }
}

impl Gradient for LinearGradient{}

pattern_type!(RadialGradient);

impl RadialGradient {
    pub fn new(x0: f64, y0: f64, r0: f64, x1: f64, y1: f64, r1: f64) -> RadialGradient {
        RadialGradient::wrap(unsafe{
            ffi::cairo_pattern_create_radial(x0, y0, r0, x1, y1, r1)
        })
    }

    pub fn get_radial_circles(&self) -> (f64,f64,f64,f64) {
        unsafe{
            let x0 : *mut c_double = transmute(Box::new(0.0f64));
            let y0 : *mut c_double = transmute(Box::new(0.0f64));
            let r0 : *mut c_double = transmute(Box::new(0.0f64));
            let x1 : *mut c_double = transmute(Box::new(0.0f64));
            let y1 : *mut c_double = transmute(Box::new(0.0f64));
            let r1 : *mut c_double = transmute(Box::new(0.0f64));

            ffi::cairo_pattern_get_radial_circles(self.pointer, x0, y0, r0, x1, y1, r1).ensure_valid();
            (*x0, *y0, *x1, *y1)
        }
    }
}

pattern_type!(SurfacePattern);

impl SurfacePattern {
    //pub fn cairo_pattern_create_for_surface(surface: *mut cairo_surface_t) -> *mut cairo_pattern_t;

    //pub fn cairo_pattern_get_surface(pattern: *mut cairo_pattern_t, surface: **mut cairo_surface_t) -> Status;
}

#[cfg(feature = "v1_12")]
#[derive(Clone, PartialEq, PartialOrd, Copy)]
pub enum MeshCorner {
    MeshCorner0,
    MeshCorner1,
    MeshCorner2,
    MeshCorner3
}

#[cfg(feature = "v1_12")]
pattern_type!(Mesh);

#[cfg(feature = "v1_12")]
impl Mesh {
    pub fn new() -> Mesh {
        Mesh::wrap(unsafe {
            ffi::cairo_pattern_create_mesh()
        })
    }

    pub fn begin_patch(&self) {
        unsafe {
            ffi::cairo_mesh_pattern_begin_patch(self.pointer)
        }
        self.ensure_status();
    }

    pub fn end_patch(&self) {
        unsafe {
            ffi::cairo_mesh_pattern_end_patch(self.pointer)
        }
        self.ensure_status();
    }

    pub fn move_to(&self, x: f64, y: f64) {
        unsafe {
            ffi::cairo_mesh_pattern_move_to(self.pointer, x, y)
        }
        self.ensure_status();
    }

    pub fn line_to(&self, x: f64, y: f64) {
        unsafe {
            ffi::cairo_mesh_pattern_line_to(self.pointer, x, y)
        }
        self.ensure_status();
    }

    pub fn curve_to(&self, x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64) {
        unsafe {
            ffi::cairo_mesh_pattern_curve_to(self.pointer, x1, y1, x2, y2, x3, y3)
        }
        self.ensure_status();
    }

    pub fn set_control_point(&self, corner: MeshCorner, x: f64, y: f64) {
        unsafe {
            ffi::cairo_mesh_pattern_set_control_point(self.pointer, corner as c_uint, x, y)
        }
        self.ensure_status();
    }

    pub fn get_control_point(&self, patch_num: usize, corner: MeshCorner) -> (f64, f64) {
        let mut x: c_double = 0.0;
        let mut y: c_double = 0.0;

        let status = unsafe {
            ffi::cairo_mesh_pattern_get_control_point(self.pointer, patch_num as c_uint, corner as c_uint, &mut x, &mut y)
        };
        status.ensure_valid();
        (x, y)
    }

    pub fn set_corner_color_rgb(&self, corner: MeshCorner, red: f64, green: f64, blue: f64) {
        unsafe {
            ffi::cairo_mesh_pattern_set_corner_color_rgb(self.pointer, corner as c_uint, red, green, blue)
        }
        self.ensure_status();
    }

    pub fn set_corner_color_rgba(&self, corner: MeshCorner, red: f64, green: f64, blue: f64, alpha: f64) {
        unsafe {
            ffi::cairo_mesh_pattern_set_corner_color_rgba(self.pointer, corner as c_uint, red, green, blue, alpha)
        }
        self.ensure_status();
    }

    pub fn get_corner_color_rgba(&self, patch_num: usize, corner: MeshCorner) -> (f64, f64, f64, f64) {
        let mut red: c_double = 0.0;
        let mut green: c_double = 0.0;
        let mut blue: c_double = 0.0;
        let mut alpha: c_double = 0.0;

        let status = unsafe {
            ffi::cairo_mesh_pattern_get_corner_color_rgba(self.pointer, patch_num as c_uint, corner as c_uint, &mut red, &mut green, &mut blue, &mut alpha)
        };
        status.ensure_valid();
        (red, green, blue, alpha)
    }

    pub fn get_patch_count(&self) -> usize {
        let mut count: c_uint = 0;
        unsafe {
            ffi::cairo_mesh_pattern_get_patch_count(self.pointer, &mut count).ensure_valid();
        }
        count as usize
    }

    pub fn get_path(&self, patch_num: usize) -> Path {
        let path: Path = Path::wrap(unsafe {
            ffi::cairo_mesh_pattern_get_path(self.pointer, patch_num as c_uint)
        });
        path.ensure_status();
        path
    }
}
<commit_msg>Implement Gradient trait for RadialGradient<commit_after>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

#![cfg_attr(not(feature = "v1_12"), allow(unused_imports))]

use libc::{c_double, c_int, c_uint};
use std::mem::transmute;
use ffi::enums::{
    Extend,
    Filter,
    Status,
    PatternType
};
use ffi;
use ffi::{
    cairo_pattern_t
};
use ::{
    Path
};

//Quite some changes from the C api but all suggested by the cairo devs.
//See http://cairographics.org/manual/bindings-patterns.html for more info

//TODO Does anyone know a way to do this without dynamic dispatch -- @mthq
pub fn wrap_pattern<'a>(ptr: *mut cairo_pattern_t) -> Box<Pattern + 'a> {
    let pattern_type = unsafe{ ffi::cairo_pattern_get_type(ptr) };

    match pattern_type {
        PatternType::Solid            => Box::new(SolidPattern::wrap(ptr))   as Box<Pattern>,
        PatternType::Surface          => Box::new(SurfacePattern::wrap(ptr)) as Box<Pattern>,
        PatternType::LinearGradient   => Box::new(LinearGradient::wrap(ptr)) as Box<Pattern>,
        PatternType::RadialGradient   => Box::new(RadialGradient::wrap(ptr)) as Box<Pattern>,
        #[cfg(feature = "v1_12")]
        PatternType::Mesh             => Box::new(Mesh::wrap(ptr))           as Box<Pattern>,
        #[cfg(feature = "v1_12")]
        PatternType::RasterSource     => panic!("Not implemented")
    }
}

pub trait Pattern {
    #[doc(hidden)]
    fn get_ptr(&self) -> *mut cairo_pattern_t;

    fn ensure_status(&self) {
        self.status().ensure_valid();
    }

    fn status(&self) -> Status {
        unsafe {
            ffi::cairo_pattern_status(self.get_ptr())
        }
    }

    fn get_reference_count(&self) -> isize {
        unsafe {
            ffi::cairo_pattern_get_reference_count(self.get_ptr()) as isize
        }
    }

    fn set_extend(&self, extend: Extend) {
        unsafe {
            ffi::cairo_pattern_set_extend(self.get_ptr(), extend)
        }
    }

    fn get_extend(&self) -> Extend {
        unsafe {
            ffi::cairo_pattern_get_extend(self.get_ptr())
        }
    }

    fn set_filter(&self, filter: Filter) {
        unsafe {
            ffi::cairo_pattern_set_filter(self.get_ptr(), filter)
        }
    }

    fn get_filter(&self) -> Filter {
        unsafe {
            ffi::cairo_pattern_get_filter(self.get_ptr())
        }
    }

    //fn cairo_pattern_set_matrix(pattern: *mut cairo_pattern_t, matrix: *mut cairo_matrix_t);

    //fn cairo_pattern_get_matrix(pattern: *mut cairo_pattern_t, matrix: *mut cairo_matrix_t);
}

macro_rules! pattern_type(
    //Signals without arguments
    ($pattern_type:ident) => (

        pub struct $pattern_type {
            pointer: *mut cairo_pattern_t
        }

        impl $pattern_type {
            pub fn wrap(pointer: *mut cairo_pattern_t) -> $pattern_type {
                $pattern_type{
                    pointer: pointer
                }
            }

            pub fn reference(&self) -> $pattern_type {
                $pattern_type{
                    pointer: unsafe {
                        ffi::cairo_pattern_reference(self.pointer)
                    }
                }
            }
        }

        impl Pattern for $pattern_type {
            fn get_ptr(&self) -> *mut cairo_pattern_t{
                self.pointer
            }
        }

        impl Drop for $pattern_type {
            fn drop(&mut self){
                unsafe {
                    ffi::cairo_pattern_destroy(self.pointer)
                }
            }
        }
    );
);

pattern_type!(SolidPattern);

impl SolidPattern {
    pub fn from_rgb(red: f64, green: f64, blue: f64) -> SolidPattern {
        SolidPattern::wrap(unsafe {
            ffi::cairo_pattern_create_rgb(red, green, blue)
        })
    }

    pub fn from_rgba(red: f64, green: f64, blue: f64, alpha: f64) -> SolidPattern {
        SolidPattern::wrap(unsafe {
            ffi::cairo_pattern_create_rgba(red, green, blue, alpha)
        })
    }

    pub fn get_rgba(&self) -> (f64, f64, f64, f64) {
        unsafe {
            let red  : *mut c_double = transmute(Box::new(0.0f64));
            let green: *mut c_double = transmute(Box::new(0.0f64));
            let blue : *mut c_double = transmute(Box::new(0.0f64));
            let alpha: *mut c_double = transmute(Box::new(0.0f64));

            ffi::cairo_pattern_get_rgba(self.pointer, red, green, blue, alpha).ensure_valid();

            (*red, *green, *blue, *alpha)
        }
    }
}

pub trait Gradient : Pattern {
    fn add_color_stop_rgb(&self, offset: f64, red: f64, green: f64, blue: f64) {
        unsafe {
            ffi::cairo_pattern_add_color_stop_rgb(self.get_ptr(), offset, red, green, blue)
        }
    }

    fn add_color_stop_rgba(&self, offset: f64, red: f64, green: f64, blue: f64, alpha: f64) {
        unsafe {
            ffi::cairo_pattern_add_color_stop_rgba(self.get_ptr(), offset, red, green, blue, alpha)
        }
    }

    fn get_color_stop_count(&self) -> isize {
        unsafe {
            let count : *mut c_int = transmute(Box::new(0i32));
            let result = ffi::cairo_pattern_get_color_stop_count(self.get_ptr(), count);

            result.ensure_valid(); // Not sure if these are needed
            count as isize
        }
    }

    fn get_color_stop_rgba(&self, index: isize) -> (f64, f64, f64, f64, f64) {
        unsafe {
            let offset: *mut c_double = transmute(Box::new(0.0f64));
            let red   : *mut c_double = transmute(Box::new(0.0f64));
            let green : *mut c_double = transmute(Box::new(0.0f64));
            let blue  : *mut c_double = transmute(Box::new(0.0f64));
            let alpha : *mut c_double = transmute(Box::new(0.0f64));

            ffi::cairo_pattern_get_color_stop_rgba(self.get_ptr(), index as c_int, offset, red, green, blue, alpha).ensure_valid();
            (*offset, *red, *green, *blue, *alpha)
        }
    }
}

pattern_type!(LinearGradient);

impl LinearGradient {
    pub fn new(x0: f64, y0: f64, x1: f64, y1: f64) -> LinearGradient {
        LinearGradient::wrap(unsafe {
            ffi::cairo_pattern_create_linear(x0, y0, x1, y1)
        })
    }

    pub fn get_linear_points(&self) -> (f64, f64, f64, f64) {
        unsafe {
            let x0 : *mut c_double = transmute(Box::new(0.0f64));
            let y0 : *mut c_double = transmute(Box::new(0.0f64));
            let x1 : *mut c_double = transmute(Box::new(0.0f64));
            let y1 : *mut c_double = transmute(Box::new(0.0f64));

            ffi::cairo_pattern_get_linear_points(self.pointer, x0, y0, x1, y1).ensure_valid();
            (*x0, *y0, *x1, *y1)
        }
    }
}

impl Gradient for LinearGradient{}

pattern_type!(RadialGradient);

impl RadialGradient {
    pub fn new(x0: f64, y0: f64, r0: f64, x1: f64, y1: f64, r1: f64) -> RadialGradient {
        RadialGradient::wrap(unsafe{
            ffi::cairo_pattern_create_radial(x0, y0, r0, x1, y1, r1)
        })
    }

    pub fn get_radial_circles(&self) -> (f64,f64,f64,f64) {
        unsafe{
            let x0 : *mut c_double = transmute(Box::new(0.0f64));
            let y0 : *mut c_double = transmute(Box::new(0.0f64));
            let r0 : *mut c_double = transmute(Box::new(0.0f64));
            let x1 : *mut c_double = transmute(Box::new(0.0f64));
            let y1 : *mut c_double = transmute(Box::new(0.0f64));
            let r1 : *mut c_double = transmute(Box::new(0.0f64));

            ffi::cairo_pattern_get_radial_circles(self.pointer, x0, y0, r0, x1, y1, r1).ensure_valid();
            (*x0, *y0, *x1, *y1)
        }
    }
}

impl Gradient for RadialGradient{}

pattern_type!(SurfacePattern);

impl SurfacePattern {
    //pub fn cairo_pattern_create_for_surface(surface: *mut cairo_surface_t) -> *mut cairo_pattern_t;

    //pub fn cairo_pattern_get_surface(pattern: *mut cairo_pattern_t, surface: **mut cairo_surface_t) -> Status;
}

#[cfg(feature = "v1_12")]
#[derive(Clone, PartialEq, PartialOrd, Copy)]
pub enum MeshCorner {
    MeshCorner0,
    MeshCorner1,
    MeshCorner2,
    MeshCorner3
}

#[cfg(feature = "v1_12")]
pattern_type!(Mesh);

#[cfg(feature = "v1_12")]
impl Mesh {
    pub fn new() -> Mesh {
        Mesh::wrap(unsafe {
            ffi::cairo_pattern_create_mesh()
        })
    }

    pub fn begin_patch(&self) {
        unsafe {
            ffi::cairo_mesh_pattern_begin_patch(self.pointer)
        }
        self.ensure_status();
    }

    pub fn end_patch(&self) {
        unsafe {
            ffi::cairo_mesh_pattern_end_patch(self.pointer)
        }
        self.ensure_status();
    }

    pub fn move_to(&self, x: f64, y: f64) {
        unsafe {
            ffi::cairo_mesh_pattern_move_to(self.pointer, x, y)
        }
        self.ensure_status();
    }

    pub fn line_to(&self, x: f64, y: f64) {
        unsafe {
            ffi::cairo_mesh_pattern_line_to(self.pointer, x, y)
        }
        self.ensure_status();
    }

    pub fn curve_to(&self, x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64) {
        unsafe {
            ffi::cairo_mesh_pattern_curve_to(self.pointer, x1, y1, x2, y2, x3, y3)
        }
        self.ensure_status();
    }

    pub fn set_control_point(&self, corner: MeshCorner, x: f64, y: f64) {
        unsafe {
            ffi::cairo_mesh_pattern_set_control_point(self.pointer, corner as c_uint, x, y)
        }
        self.ensure_status();
    }

    pub fn get_control_point(&self, patch_num: usize, corner: MeshCorner) -> (f64, f64) {
        let mut x: c_double = 0.0;
        let mut y: c_double = 0.0;

        let status = unsafe {
            ffi::cairo_mesh_pattern_get_control_point(self.pointer, patch_num as c_uint, corner as c_uint, &mut x, &mut y)
        };
        status.ensure_valid();
        (x, y)
    }

    pub fn set_corner_color_rgb(&self, corner: MeshCorner, red: f64, green: f64, blue: f64) {
        unsafe {
            ffi::cairo_mesh_pattern_set_corner_color_rgb(self.pointer, corner as c_uint, red, green, blue)
        }
        self.ensure_status();
    }

    pub fn set_corner_color_rgba(&self, corner: MeshCorner, red: f64, green: f64, blue: f64, alpha: f64) {
        unsafe {
            ffi::cairo_mesh_pattern_set_corner_color_rgba(self.pointer, corner as c_uint, red, green, blue, alpha)
        }
        self.ensure_status();
    }

    pub fn get_corner_color_rgba(&self, patch_num: usize, corner: MeshCorner) -> (f64, f64, f64, f64) {
        let mut red: c_double = 0.0;
        let mut green: c_double = 0.0;
        let mut blue: c_double = 0.0;
        let mut alpha: c_double = 0.0;

        let status = unsafe {
            ffi::cairo_mesh_pattern_get_corner_color_rgba(self.pointer, patch_num as c_uint, corner as c_uint, &mut red, &mut green, &mut blue, &mut alpha)
        };
        status.ensure_valid();
        (red, green, blue, alpha)
    }

    pub fn get_patch_count(&self) -> usize {
        let mut count: c_uint = 0;
        unsafe {
            ffi::cairo_mesh_pattern_get_patch_count(self.pointer, &mut count).ensure_valid();
        }
        count as usize
    }

    pub fn get_path(&self, patch_num: usize) -> Path {
        let path: Path = Path::wrap(unsafe {
            ffi::cairo_mesh_pattern_get_path(self.pointer, patch_num as c_uint)
        });
        path.ensure_status();
        path
    }
}
<|endoftext|>


<commit_before>//! This module provides implementations of common hashing algorithms.
//!
//! # Related Links
//! *http://tools.ietf.org/html/rfc1950 - Adler-32 checksum specification
//!
//! *http://en.wikipedia.org/wiki/Cyclic_redundancy_check - Cyclic Redundancy Check

use std::old_path::BytesContainer;

/// An Implementation of the Adler-32 checksum
#[derive(Copy)]
pub struct Adler32 {
    s1: u32,
    s2: u32
}

impl Adler32 {
    /// Create a new hasher.
    pub fn new() -> Adler32 {
        Adler32 {s1: 1, s2: 0}
    }

    /// Update the internal hasher with the bytes from ```buf```
    pub fn update<T: BytesContainer>(&mut self, buf: T) {
        for &byte in buf.container_as_bytes().iter() {
            self.s1 = self.s1 + byte as u32;
            self.s2 = self.s1 + self.s2;

            self.s1 %= 65521;
            self.s2 %= 65521;
        }
    }

    /// Return the computed hash.
    pub fn checksum(&self) -> u32 {
        (self.s2 << 16) | self.s1
    }

    /// Reset this hasher to its initial state.
    pub fn reset(&mut self) {
        self.s1 = 1;
        self.s2 = 0;
    }
}

static CRC_TABLE: [u32; 256] = [
    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
    0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
    0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
    0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
    0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
    0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
    0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
    0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
    0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
    0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
    0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
    0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
    0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
    0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
    0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
    0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
    0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
    0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
    0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
    0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
    0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
    0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
    0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
    0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
    0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
    0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
    0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
    0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
    0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
    0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
    0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
    0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
    0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
    0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
    0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
    0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
    0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
    0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
    0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
    0x2d02ef8d
];

/// An Implementation of the Crc-32 checksum
#[derive(Copy)]
pub struct Crc32 {
    crc: u32,
}

impl Crc32 {
    /// Create a new hasher.
    pub fn new() -> Crc32 {
        Crc32 {crc: 0xFFFFFFFF}
    }

    /// Update the internal hasher with the bytes from ```buf```
    pub fn update<T: BytesContainer>(&mut self, buf: T) {
        for &byte in buf.container_as_bytes().iter() {
            let a = (self.crc ^ byte as u32) & 0xFF;
            let b = self.crc >> 8;

            self.crc = CRC_TABLE[a as usize] ^ b;
        }
    }

    /// Return the computed hash.
    pub fn checksum(&self) -> u32 {
        self.crc ^ 0xFFFFFFFF
    }

    /// Reset this hasher to its initial state.
    pub fn reset(&mut self) {
        self.crc = 0xFFFFFFFF;
    }
}
<commit_msg>Fix deprecation warning<commit_after>//! This module provides implementations of common hashing algorithms.
//!
//! # Related Links
//! *http://tools.ietf.org/html/rfc1950 - Adler-32 checksum specification
//!
//! *http://en.wikipedia.org/wiki/Cyclic_redundancy_check - Cyclic Redundancy Check

use std::old_path::BytesContainer;

/// An Implementation of the Adler-32 checksum
#[derive(Copy)]
pub struct Adler32 {
    s1: u32,
    s2: u32
}

impl Adler32 {
    /// Create a new hasher.
    pub fn new() -> Adler32 {
        Adler32 {s1: 1, s2: 0}
    }

    /// Update the internal hasher with the bytes from ```buf```
    pub fn update(&mut self, buf: &[u8]) {
        for &byte in buf {
            self.s1 = self.s1 + byte as u32;
            self.s2 = self.s1 + self.s2;

            self.s1 %= 65521;
            self.s2 %= 65521;
        }
    }

    /// Return the computed hash.
    pub fn checksum(&self) -> u32 {
        (self.s2 << 16) | self.s1
    }

    /// Reset this hasher to its initial state.
    pub fn reset(&mut self) {
        self.s1 = 1;
        self.s2 = 0;
    }
}

static CRC_TABLE: [u32; 256] = [
    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
    0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
    0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
    0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
    0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
    0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
    0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
    0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
    0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
    0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
    0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
    0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
    0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
    0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
    0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
    0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
    0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
    0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
    0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
    0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
    0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
    0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
    0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
    0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
    0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
    0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
    0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
    0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
    0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
    0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
    0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
    0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
    0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
    0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
    0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
    0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
    0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
    0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
    0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
    0x2d02ef8d
];

/// An Implementation of the Crc-32 checksum
#[derive(Copy)]
pub struct Crc32 {
    crc: u32,
}

impl Crc32 {
    /// Create a new hasher.
    pub fn new() -> Crc32 {
        Crc32 {crc: 0xFFFFFFFF}
    }

    /// Update the internal hasher with the bytes from ```buf```
    pub fn update<T: BytesContainer>(&mut self, buf: T) {
        for &byte in buf.container_as_bytes().iter() {
            let a = (self.crc ^ byte as u32) & 0xFF;
            let b = self.crc >> 8;

            self.crc = CRC_TABLE[a as usize] ^ b;
        }
    }

    /// Return the computed hash.
    pub fn checksum(&self) -> u32 {
        self.crc ^ 0xFFFFFFFF
    }

    /// Reset this hasher to its initial state.
    pub fn reset(&mut self) {
        self.crc = 0xFFFFFFFF;
    }
}
<|endoftext|>


<commit_before>use actix_http::HttpService;
use actix_http_test::TestServer;
use actix_web::{http, App, HttpResponse, Responder};
use actix_web_codegen::get;
use futures::{future, Future};

#[get("/test")]
fn test() -> impl Responder {
    HttpResponse::Ok()
}

#[get("/test")]
fn auto_async() -> impl Future<Item = HttpResponse, Error = actix_web::Error> {
    future::ok(HttpResponse::Ok().finish())
}

#[get("/test")]
fn auto_sync() -> impl Future<Item = HttpResponse, Error = actix_web::Error> {
    future::ok(HttpResponse::Ok().finish())
}

#[test]
fn test_body() {
    let mut srv = TestServer::new(|| HttpService::new(App::new().service(test)));
    let request = srv.request(http::Method::GET, srv.url("/test"));
    let response = srv.block_on(request.send()).unwrap();
    assert!(response.status().is_success());

    let mut srv = TestServer::new(|| HttpService::new(App::new().service(auto_sync)));
    let request = srv.request(http::Method::GET, srv.url("/test"));
    let response = srv.block_on(request.send()).unwrap();
    assert!(response.status().is_success());
}

#[test]
fn test_auto_async() {
    let mut srv = TestServer::new(|| HttpService::new(App::new().service(auto_async)));

    let request = srv.request(http::Method::GET, srv.url("/test"));
    let response = srv.block_on(request.send()).unwrap();
    assert!(response.status().is_success());
}
<commit_msg>add more tests<commit_after>use actix_http::HttpService;
use actix_http_test::TestServer;
use actix_web::{http, App, HttpResponse, Responder};
use actix_web_codegen::{get, post, put};
use futures::{future, Future};

#[get("/test")]
fn test() -> impl Responder {
    HttpResponse::Ok()
}

#[put("/test")]
fn put_test() -> impl Responder {
    HttpResponse::Created()
}

#[post("/test")]
fn post_test() -> impl Responder {
    HttpResponse::NoContent()
}

#[get("/test")]
fn auto_async() -> impl Future<Item = HttpResponse, Error = actix_web::Error> {
    future::ok(HttpResponse::Ok().finish())
}

#[get("/test")]
fn auto_sync() -> impl Future<Item = HttpResponse, Error = actix_web::Error> {
    future::ok(HttpResponse::Ok().finish())
}

#[test]
fn test_body() {
    let mut srv = TestServer::new(|| {
        HttpService::new(
            App::new()
                .service(post_test)
                .service(put_test)
                .service(test),
        )
    });
    let request = srv.request(http::Method::GET, srv.url("/test"));
    let response = srv.block_on(request.send()).unwrap();
    assert!(response.status().is_success());

    let request = srv.request(http::Method::PUT, srv.url("/test"));
    let response = srv.block_on(request.send()).unwrap();
    assert!(response.status().is_success());
    assert_eq!(response.status(), http::StatusCode::CREATED);

    let request = srv.request(http::Method::POST, srv.url("/test"));
    let response = srv.block_on(request.send()).unwrap();
    assert!(response.status().is_success());
    assert_eq!(response.status(), http::StatusCode::NO_CONTENT);

    let mut srv = TestServer::new(|| HttpService::new(App::new().service(auto_sync)));
    let request = srv.request(http::Method::GET, srv.url("/test"));
    let response = srv.block_on(request.send()).unwrap();
    assert!(response.status().is_success());
}

#[test]
fn test_auto_async() {
    let mut srv = TestServer::new(|| HttpService::new(App::new().service(auto_async)));

    let request = srv.request(http::Method::GET, srv.url("/test"));
    let response = srv.block_on(request.send()).unwrap();
    assert!(response.status().is_success());
}
<|endoftext|>


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

pub struct MMU
{
    pub mem_map: Vec<u8>,
    pub memory_banks: Vec<Vec<u8>>,
    pub cartridge_type: u8,
    pub rom_size: u8,
    pub ram_size: u8,
    pub rom_bank: u8,
}

impl MMU
{
    pub fn new() -> MMU
    {
        return MMU
        {
            mem_map: vec![0; 0x10000],
            memory_banks: vec![vec![0; 0x4000]; 0x100],
            cartridge_type: 0,
            rom_size: 0x00,
            ram_size: 0x00,
            rom_bank: 1,
        }
    }

    pub fn set_to_memory(&mut self, location: usize, value: u8, masked_set: bool)
    {
        let mut rom_flag = false;
        if masked_set
        {
            match self.cartridge_type
            {
                0x00 => (),
                0x01 => rom_flag = self.mbc1_parse(location, value),
                _ => (),
            }
        }
        if !rom_flag
        {
            self.mem_map[location] = value;
        }
    }

    pub fn get_from_memory(&self, location: usize, masked_read: bool) -> u8
    {
        // if masked_read == true && location < 0x8000
        // {
        //     println!("DEBUG: Masked Read Location-{:04x}", location);
        // }
        return self.mem_map[location];
    }

    fn mbc1_parse(&mut self, location: usize, value: u8) -> bool
    {
        match location
        {
            0x0000...0x1FFF =>
            {
                println!("DEBUG: ram enable` {}", value);
                return true;
            },
            0x2000...0x3FFF =>
            {
                let mut bank = value & 0x1F;
                if bank == 0
                {
                    bank += 1;
                }
                self.rom_bank &= 0xE0;
                self.rom_bank |= bank;
                self.update_rom_bank();
                return true;
            },
            0x4000...0x5FFF =>
            {
                self.rom_bank &= 0x1F;
                self.rom_bank |= (value & 0x03) << 5;
                self.update_rom_bank();
                return true;
            },
            0x6000...0x7FFF =>
            {
                println!("DEBUG: mode {}", value);
                return true;
            },
            _ => return false,
        }
    }

    fn update_rom_bank(&mut self)
    {
        let bank = self.rom_bank as usize;
        println!("Rom-bank switch: {}", bank);
        for i in 0..0x4000
        {
            self.mem_map[(i as usize) + 0x4000] = self.memory_banks[bank][i];
        }
    }

    pub fn read_gb_file(&self, file_name: &str) -> Vec<u8>
    {
    let mut buffer : Vec<u8> = vec![0; 0x10000];
    let file = File::open(file_name);
    if file.is_ok()
    {
        if file.unwrap().read(&mut buffer).is_ok()
        {
            return buffer;
        }
    }
    return buffer;
    }

    pub fn initialize_cartridge(&mut self, file_name: &str)
    {
        let mut buffer: Vec<u8> = Vec::new();
        let file = File::open(file_name);
        if file.is_ok()
        {
            if file.unwrap().read_to_end(&mut buffer).is_ok()
            {
                self.memory_banks[0] = buffer[0..0x4000].to_vec();
                self.cartridge_type = self.memory_banks[0][0x0147];
                let rom_tag = self.memory_banks[0][0x0148];
                self.rom_size = self.parse_rom_size(rom_tag);
                let ram_tag = self.memory_banks[0][0x0149];
                self.ram_size = self.parse_ram_size(ram_tag);
                if self.rom_size == 0
                {
                    self.memory_banks[1] = buffer[0x4000..0x8000].to_vec();
                }
                else
                {
                    for i in 1..self.rom_size
                    {
                        let start: usize = 0x4000 * (i as usize);
                        let end: usize = 0x4000 * ((i as usize) + 1);
                        self.memory_banks[i as usize] = buffer[start..end].to_vec();
                    }
                }
                for i in 0..0x4000
                {
                    self.mem_map[i] = self.memory_banks[0][i];
                    self.mem_map[(i as usize) + 0x4000] = self.memory_banks[1][i];
                }

            }
        }
    }

    fn parse_rom_size(&mut self, rom_tag: u8) -> u8
    {
        match rom_tag
        {
            0x00 => return 0,
            0x01 => return 4,
            0x02 => return 8,
            0x03 => return 16,
            0x04 => return 32,
            0x05 => return 64,
            0x06 => return 128,
            0x07 => return 256,
            0x52 => return 72,
            0x53 => return 80,
            0x54 => return 96,
            _ => return 0,
        }
    }

    fn parse_ram_size(&mut self, ram_tag: u8) -> u8
    {
        match ram_tag
        {
            0x00 => return 0,
            0x01 => return 2,
            0x02 => return 8,
            0x03 => return 32,
            _ => return 0,
        }
    }
}

#[cfg(test)]
mod mmu_tests
{
    use MMU;

    #[test]
    fn get_and_set_legal_memory_test() {
        let mut mmu = MMU::new();
        mmu.set_to_memory(0x1234, 0xFF, false);
        assert_eq!(mmu.mem_map[0x1234], 0xFF);
        assert_eq!(mmu.get_from_memory(0x1234, false), 0xFF);
    }

    //#[test]
    fn mbc1_test() {
        let mut mmu = MMU::new();
        mmu.cartridge_type = 0x01;

        let memory_locations: Vec<usize> = vec![0x00, 0x2000, 0x3000, 0x3FFF, 0x4000];
        let values: Vec<u8> = vec![0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x03];
        let rom_bank_values: Vec<u8> = vec![0x01, 0x1F, 0x01, 0x1F, 0x61];
        let mem_loc_values: Vec<u8> = vec![0xFF, 0x00, 0x00, 0x00, 0x00];

        for i in 0..memory_locations.len()
        {
            mmu.rom_bank = 0x01;
            mmu.mem_map[memory_locations[i]] = 0;
            mmu.set_to_memory(memory_locations[i], values[i], true);
            assert_eq!(mmu.rom_bank, rom_bank_values[i]);
            assert_eq!(mmu.mem_map[memory_locations[i]], mem_loc_values[i]);
        }
    }

    #[test]
    fn passing_bad_filename_to_read_gb_file_return_empty_vec()
    {
        let mut mmu = MMU::new();
        let return_vector : Vec<u8> = mmu.read_gb_file("");
        assert_eq!(return_vector, vec![0;0x10000]);
    }

    #[test]
    fn initialize_catridge_test()
    {
        let mut mmu = MMU::new();
        mmu.initialize_cartridge("roms/cpu_instrs.gb");
        assert_eq!(mmu.rom_size, 4);
        assert_eq!(mmu.ram_size, 0);
        assert_eq!(mmu.cartridge_type, 1);
        assert_eq!(mmu.memory_banks[0][0x0000], 0x3C);
        assert_eq!(mmu.memory_banks[1][0x0000], 0xC3);
        assert_eq!(mmu.memory_banks[2][0x0000], 0xC3);
        assert_eq!(mmu.memory_banks[3][0x0000], 0xC3);
    }
}<commit_msg>Added banking mode to mbc1<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::io;

pub struct MMU
{
    pub mem_map: Vec<u8>,
    pub memory_banks: Vec<Vec<u8>>,
    pub cartridge_type: u8,
    pub rom_size: u8,
    pub ram_size: u8,
    pub rom_bank: u8,
    pub banking_mode: u8,
}

impl MMU
{
    pub fn new() -> MMU
    {
        return MMU
        {
            mem_map: vec![0; 0x10000],
            memory_banks: vec![vec![0; 0x4000]; 0x100],
            cartridge_type: 0,
            rom_size: 0x00,
            ram_size: 0x00,
            rom_bank: 1,
            banking_mode: 0,
        }
    }

    pub fn set_to_memory(&mut self, location: usize, value: u8, masked_set: bool)
    {
        let mut rom_flag = false;
        if masked_set
        {
            match self.cartridge_type
            {
                0x00 => (),
                0x01 => rom_flag = self.mbc1_parse(location, value),
                _ => (),
            }
        }
        if !rom_flag
        {
            self.mem_map[location] = value;
        }
    }

    pub fn get_from_memory(&self, location: usize, masked_read: bool) -> u8
    {
        // if masked_read == true && location < 0x8000
        // {
        //     println!("DEBUG: Masked Read Location-{:04x}", location);
        // }
        return self.mem_map[location];
    }

    fn mbc1_parse(&mut self, location: usize, value: u8) -> bool
    {

        match location
        {
            0x0000...0x1FFF =>
            {
                println!("Value: 0x{:02X} Location: 0x{:04X}", value, location);
                println!("DEBUG: ram enable` {}", value);
                return true;
            },
            0x2000...0x3FFF =>
            {
            //     for i in 0..0x4000
            //     {
            //         self.memory_banks[self.rom_bank as usize][i] = self.mem_map[(i as usize) + 0x4000];
            //     }
            println!("Value: 0x{:02X} Location: 0x{:04X}", value, location);
                let mut bank = value & 0x1F;
                if bank == 0
                {
                    bank += 1;
                }
                self.rom_bank &= 0xE0;
                self.rom_bank |= bank;
                self.update_rom_bank();
                return true;
            },
            0x4000...0x5FFF =>
            {
                // for i in 0..0x4000
                // {
                //     self.memory_banks[self.rom_bank as usize][i] = self.mem_map[(i as usize) + 0x4000];
                // }
                println!("Value: 0x{:02X} -- {} Location: 0x{:04X}", value, (value & 0x03) << 5 ,location);
                self.rom_bank &= 0x1F;
                if self.banking_mode == 0{
                    self.rom_bank |= ((value & 0x03) << 5);
                }
                self.update_rom_bank();
                return true;
            },
            0x6000...0x7FFF =>
            {
                println!("Value: 0x{:02X} Location: 0x{:04X}", value, location);
                println!("DEBUG: mode {}", value);
                self.banking_mode = value;
                return true;
            },
            _ =>
            {
                 //println!("Value: 0x{:02X} Location: 0x{:04X}", value, location);
                 //io::stdin().read_line(&mut String::new());
                 return false;
            },
        }
    }

    fn update_rom_bank(&mut self)
    {
        let bank = self.rom_bank as usize;
        println!("Rom-bank switch: 0x{:02x}", bank);
        for i in 0..0x4000
        {
            self.mem_map[(i as usize) + 0x4000] = self.memory_banks[bank][i];
        }
    }

    pub fn read_gb_file(&self, file_name: &str) -> Vec<u8>
    {
    let mut buffer : Vec<u8> = vec![0; 0x10000];
    let file = File::open(file_name);
    if file.is_ok()
    {
        if file.unwrap().read(&mut buffer).is_ok()
        {
            return buffer;
        }
    }
    return buffer;
    }

    pub fn initialize_cartridge(&mut self, file_name: &str)
    {
        let mut buffer: Vec<u8> = Vec::new();
        let file = File::open(file_name);
        if file.is_ok()
        {
            if file.unwrap().read_to_end(&mut buffer).is_ok()
            {
                self.memory_banks[0] = buffer[0..0x4000].to_vec();
                self.cartridge_type = self.memory_banks[0][0x0147];
                let rom_tag = self.memory_banks[0][0x0148];
                self.rom_size = self.parse_rom_size(rom_tag);
                let ram_tag = self.memory_banks[0][0x0149];
                self.ram_size = self.parse_ram_size(ram_tag);
                if self.rom_size == 0
                {
                    self.memory_banks[1] = buffer[0x4000..0x8000].to_vec();
                }
                else
                {
                    for i in 1..self.rom_size
                    {
                        let start: usize = 0x4000 * (i as usize);
                        let end: usize = 0x4000 * ((i as usize) + 1);
                        self.memory_banks[i as usize] = buffer[start..end].to_vec();
                    }
                }
                for i in 0..0x4000
                {
                    self.mem_map[i] = self.memory_banks[0][i];
                    self.mem_map[(i as usize) + 0x4000] = self.memory_banks[1][i];
                }

            }
        }
    }

    fn parse_rom_size(&mut self, rom_tag: u8) -> u8
    {
        match rom_tag
        {
            0x00 => return 0,
            0x01 => return 4,
            0x02 => return 8,
            0x03 => return 16,
            0x04 => return 32,
            0x05 => return 64,
            0x06 => return 128,
            0x07 => return 256,
            0x52 => return 72,
            0x53 => return 80,
            0x54 => return 96,
            _ => return 0,
        }
    }

    fn parse_ram_size(&mut self, ram_tag: u8) -> u8
    {
        match ram_tag
        {
            0x00 => return 0,
            0x01 => return 2,
            0x02 => return 8,
            0x03 => return 32,
            _ => return 0,
        }
    }
}

#[cfg(test)]
mod mmu_tests
{
    use MMU;

    #[test]
    fn get_and_set_legal_memory_test() {
        let mut mmu = MMU::new();
        mmu.set_to_memory(0x1234, 0xFF, false);
        assert_eq!(mmu.mem_map[0x1234], 0xFF);
        assert_eq!(mmu.get_from_memory(0x1234, false), 0xFF);
    }

    //#[test]
    fn mbc1_test() {
        let mut mmu = MMU::new();
        mmu.cartridge_type = 0x01;

        let memory_locations: Vec<usize> = vec![0x00, 0x2000, 0x3000, 0x3FFF, 0x4000];
        let values: Vec<u8> = vec![0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x03];
        let rom_bank_values: Vec<u8> = vec![0x01, 0x1F, 0x01, 0x1F, 0x61];
        let mem_loc_values: Vec<u8> = vec![0xFF, 0x00, 0x00, 0x00, 0x00];

        for i in 0..memory_locations.len()
        {
            mmu.rom_bank = 0x01;
            mmu.mem_map[memory_locations[i]] = 0;
            mmu.set_to_memory(memory_locations[i], values[i], true);
            assert_eq!(mmu.rom_bank, rom_bank_values[i]);
            assert_eq!(mmu.mem_map[memory_locations[i]], mem_loc_values[i]);
        }
    }

    #[test]
    fn passing_bad_filename_to_read_gb_file_return_empty_vec()
    {
        let mut mmu = MMU::new();
        let return_vector : Vec<u8> = mmu.read_gb_file("");
        assert_eq!(return_vector, vec![0;0x10000]);
    }

    #[test]
    fn initialize_catridge_test()
    {
        let mut mmu = MMU::new();
        mmu.initialize_cartridge("roms/cpu_instrs.gb");
        assert_eq!(mmu.rom_size, 4);
        assert_eq!(mmu.ram_size, 0);
        assert_eq!(mmu.cartridge_type, 1);
        assert_eq!(mmu.memory_banks[0][0x0000], 0x3C);
        assert_eq!(mmu.memory_banks[1][0x0000], 0xC3);
        assert_eq!(mmu.memory_banks[2][0x0000], 0xC3);
        assert_eq!(mmu.memory_banks[3][0x0000], 0xC3);
    }

    #[test]
    fn rom_bank_switch_test()
    {
        let mut mmu = MMU::new();
        mmu.initialize_cartridge("roms/cpu_instrs.gb");
        assert_eq!(mmu.rom_size, 4);
        assert_eq!(mmu.ram_size, 0);
        assert_eq!(mmu.cartridge_type, 1);
        assert_eq!(mmu.mem_map[0x0000], 0x3C);
        assert_eq!(mmu.mem_map[0x4300], 0x3E);
        mmu.mbc1_parse(0x2000, 0x00);
        assert_eq!(mmu.mem_map[0x4300], 0x3E);
        mmu.mbc1_parse(0x2000, 0x02);
        assert_eq!(mmu.mem_map[0x4300], 0xE0);
        mmu.mbc1_parse(0x2000, 0x03);
        assert_eq!(mmu.mem_map[0x4900], 0x72);
        mmu.mbc1_parse(0x2000, 0x00);
        assert_eq!(mmu.mem_map[0x4300], 0x3E);
    }
}<|endoftext|>


<commit_before>#[macro_export]
macro_rules! service {
    (trait_name = $name:ident,
     processor_name = $processor_name:ident,
     client_name = $client_name:ident,
     service_methods = [$($siname:ident -> $soname:ident = $smfname:ident.$smname:ident($($saname:ident: $saty:ty => $said:expr,)*) -> $srty:ty => [$($sename:ident: $sety:ty => $seid:expr,)*],)*],
     parent_methods = [$($piname:ident -> $poname:ident = $pmfname:ident.$pmname:ident($($paname:ident: $paty:ty => $paid:expr,)*) -> $prty:ty => [$($pename:ident: $pety:ty => $peid:expr,)*],)*],
     bounds = [$($boundty:ident: $bound:ident,)*],
     fields = [$($fname:ident: $fty:ty,)*]) => {
        pub trait $name {
            $(fn $smname(&self, $($saname: $saty),*) -> $soname;)*
        }

        service_processor! {
            processor_name = $processor_name,
            service_methods = [$($siname -> $soname = $smfname.$smname($($saname: $saty => $said,)*) -> $srty => [$($sename: $sety => $seid,)*],)*],
            parent_methods = [$($piname -> $poname = $pmfname.$pmname($($paname: $paty => $paid,)*) -> $prty => [$($pename: $pety => $peid,)*],)*],
            bounds = [$($boundty: $bound,)*],
            fields = [$($fname: $fty,)*]
        }

        service_client! {
            client_name = $client_name,
            service_methods = [$($siname -> $soname = $smfname.$smname($($saname: $saty => $said,)*) -> $srty => [$($sename: $sety => $seid,)*],)*],
            parent_methods = [$($piname -> $poname = $pmfname.$pmname($($paname: $paty => $paid,)*) -> $prty => [$($pename: $pety => $peid,)*],)*]
        }
    }
}

#[macro_export]
macro_rules! service_processor {
    (processor_name = $name:ident,
     service_methods = [$($siname:ident -> $soname:ident = $smfname:ident.$smname:ident($($saname:ident: $saty:ty => $said:expr,)*) -> $srty:ty => [$($sename:ident: $sety:ty => $seid:expr,)*],)*],
     parent_methods = [$($piname:ident -> $poname:ident = $pmfname:ident.$pmname:ident($($paname:ident: $paty:ty => $paid:expr,)*) -> $prty:ty => [$($pename:ident: $pety:ty => $peid:expr,)*],)*],
     bounds = [$($boundty:ident: $bound:ident,)*],
     fields = [$($fname:ident: $fty:ty,)*]) => {
        pub struct $name<$($boundty: $bound),*> {
            $($fname: $fty,)*
            _ugh: ()
        }

        $(strukt! { name = $siname, fields = { $($saname: $saty => $said,)* } }
          strukt! { name = $soname, fields = { success: $srty => 0, $($sename: $sety => $seid,)* } })*

        impl<$($boundty: $bound),*> $name<$($boundty),*> {
            pub fn new($($fname: $fty),*) -> Self {
                $name { $($fname: $fname,)* _ugh: () }
            }

            pub fn dispatch<P: $crate::Protocol, T: $crate::Transport>(&self, prot: &mut P, transport: &mut T,
                                                                       name: &str, ty: $crate::protocol::MessageType, id: i32) -> $crate::Result<()> {
                match name {
                    $(stringify!($smname) => self.$smname(prot, transport, ty, id),)*
                    $(stringify!($pmname) => self.$pmname(prot, transport, ty, id),)*
                    _ => Err($crate::Error::from($crate::protocol::Error::ProtocolViolation))
                }
            }

            service_processor_methods! { methods = [$($siname -> $soname = $smfname.$smname($($saname: $saty => $said,)*) -> $srty => [$($sename: $sety => $seid,)*],)*] }
            service_processor_methods! { methods = [$($piname -> $poname = $pmfname.$pmname($($paname: $paty => $paid,)*) -> $prty => [$($pename: $pety => $peid,)*],)*] }
        }

        impl<P: $crate::Protocol, T: $crate::Transport, $($boundty: $bound),*> $crate::Processor<P, T> for $name<$($boundty),*> {
            fn process(&self, protocol: &mut P, transport: &mut T) -> $crate::Result<()> {
                #[allow(unused_imports)]
                use $crate::Protocol;

                let (name, ty, id) = try!(protocol.read_message_begin(transport));
                self.dispatch(protocol, transport, &name, ty, id)
            }
        }
    }
}

#[macro_export]
macro_rules! service_processor_methods {
    (methods = [$($iname:ident -> $oname:ident = $fname:ident.$mname:ident($($aname:ident: $aty:ty => $aid:expr,)*) -> $rty:ty => [$($ename:ident: $ety:ty => $eid:expr,)*],)*]) => {
        $(fn $mname<P: $crate::Protocol, T: $crate::Transport>(&self, prot: &mut P, transport: &mut T,
                                                               ty: $crate::protocol::MessageType, id: i32) -> $crate::Result<()> {
            static MNAME: &'static str = stringify!($mname);

            let mut args = $iname::default();
            try!($crate::protocol::helpers::receive_body(prot, transport, MNAME,
                                                         &mut args, MNAME, ty, id));

            // TODO: Further investigate this unwrap.
            let result = self.$fname.$mname($(args.$aname.unwrap()),*);
            try!($crate::protocol::helpers::send(prot, transport, MNAME,
                                                 $crate::protocol::MessageType::Reply, &result));

            Ok(())
        })*
    }
}

#[macro_export]
macro_rules! service_client {
    (client_name = $client_name:ident,
     service_methods = [$($siname:ident -> $soname:ident = $smfname:ident.$smname:ident($($saname:ident: $saty:ty => $said:expr,)*) -> $srty:ty => [$($sename:ident: $sety:ty => $seid:expr,)*],)*],
     parent_methods = [$($piname:ident -> $poname:ident = $pmfname:ident.$pmname:ident($($paname:ident: $paty:ty => $paid:expr,)*) -> $prty:ty => [$($pename:ident: $pety:ty => $peid:expr,)*],)*]) => {
        pub struct $client_name<P: $crate::Protocol, T: $crate::Transport> {
            pub protocol: P,
            pub transport: T
        }

        impl<P: $crate::Protocol, T: $crate::Transport> $client_name<P, T> {
            pub fn new(protocol: P, transport: T) -> Self {
                $client_name {
                    protocol: protocol,
                    transport: transport
                }
            }

            service_client_methods! { methods = [$($siname -> $soname = $smfname.$smname($($saname: $saty => $said,)*) -> $srty => [$($sename: $sety => $seid,)*],)*] }
            service_client_methods! { methods = [$($piname -> $poname = $pmfname.$pmname($($paname: $paty => $paid,)*) -> $prty => [$($pename: $pety => $peid,)*],)*] }
        }
    }
}

#[macro_export]
macro_rules! service_client_methods {
    (methods = [$($iname:ident -> $oname:ident = $fname:ident.$mname:ident($($aname:ident: $aty:ty => $aid:expr,)*) -> $rty:ty => [$($ename:ident: $ety:ty => $eid:expr,)*],)*]) => {
        $(pub fn $mname(&mut self, $($aname: $aty,)*) -> $crate::Result<$oname> {
            static MNAME: &'static str = stringify!($mname);

            let mut args = $iname::default();
            $(args.$aname = Some($aname);)*
            try!($crate::protocol::helpers::send(&mut self.protocol, &mut self.transport,
                                                 MNAME, $crate::protocol::MessageType::Call, &mut args));

            let mut result = $oname::default();
            try!($crate::protocol::helpers::receive(&mut self.protocol, &mut self.transport,
                                                    MNAME, &mut result));

            Ok(result)
        })*
    }
}

#[macro_export]
macro_rules! strukt {
    (name = $name:ident,
     fields = { $($fname:ident: $fty:ty => $id:expr,)+ }) => {
        #[derive(Debug, Clone, Default)]
        pub struct $name {
            $(pub $fname: Option<$fty>,)+
        }

        impl $crate::protocol::ThriftTyped for $name {
            fn typ() -> $crate::protocol::Type { $crate::protocol::Type::Struct }
        }

        impl $crate::protocol::Encode for $name {
            fn encode<P, T>(&self, protocol: &mut P, transport: &mut T) -> $crate::Result<()>
            where P: $crate::Protocol, T: $crate::Transport {
                #[allow(unused_imports)]
                use $crate::protocol::{Encode, ThriftTyped};
                #[allow(unused_imports)]
                use $crate::{Protocol};

                try!(protocol.write_struct_begin(transport, stringify!($name)));

                $(if let Some(ref x) = self.$fname {
                    try!(protocol.write_field_begin(transport, stringify!($fname), <$fty as ThriftTyped>::typ(), $id));
                    try!(x.encode(protocol, transport));
                    try!(protocol.write_field_end(transport));
                })*

                try!(protocol.write_field_stop(transport));
                try!(protocol.write_struct_end(transport));

                Ok(())
            }
        }

        impl $crate::protocol::Decode for $name {
            fn decode<P, T>(&mut self, protocol: &mut P, transport: &mut T) -> $crate::Result<()>
            where P: $crate::Protocol, T: $crate::Transport {
                #[allow(unused_imports)]
                use $crate::protocol::{Decode, ThriftTyped};
                #[allow(unused_imports)]
                use $crate::Protocol;

                try!(protocol.read_struct_begin(transport));

                loop {
                    let (_, typ, id) = try!(protocol.read_field_begin(transport));

                    if typ == $crate::protocol::Type::Stop {
                        break;
                    } $(else if (typ, id) == (<$fty as ThriftTyped>::typ(), $id) {
                        try!(self.$fname.decode(protocol, transport));
                    })* else {
                        try!(protocol.skip(transport, typ));
                    }

                    try!(protocol.read_field_end(transport));
                }

                try!(protocol.read_struct_end(transport));

                Ok(())
            }
        }
    };
    (name = $name:ident, fields = {}) => {
        #[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
        pub struct $name;

        impl $crate::protocol::ThriftTyped for $name {
            fn typ() -> $crate::protocol::Type { $crate::protocol::Type::Struct }
        }

        impl $crate::protocol::Encode for $name {
            fn encode<P, T>(&self, protocol: &mut P, transport: &mut T) -> $crate::Result<()>
            where P: $crate::Protocol, T: $crate::Transport {
                #[allow(unused_imports)]
                use $crate::Protocol;

                try!(protocol.write_struct_begin(transport, stringify!($name)));
                try!(protocol.write_field_stop(transport));
                try!(protocol.write_struct_end(transport));

                Ok(())
            }
        }

        impl $crate::protocol::Decode for $name {
            fn decode<P, T>(&mut self, protocol: &mut P, transport: &mut T) -> $crate::Result<()>
            where P: $crate::Protocol, T: $crate::Transport {
                #[allow(unused_imports)]
                use $crate::Protocol;

                try!(protocol.read_struct_begin(transport));

                let (_, ty, _) = try!(protocol.read_field_begin(transport));
                if ty != $crate::protocol::Type::Stop {
                     return Err($crate::Error::from($crate::protocol::Error::ProtocolViolation))
                }

                try!(protocol.read_struct_end(transport));

                Ok(())
            }
        }
    }
}

#[macro_export]
macro_rules! enom {
    (name = $name:ident,
     values = [$($vname:ident = $val:expr,)*],
     default = $dname:ident) => {
        #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
        #[repr(i32)]
        pub enum $name {
            $($vname = $val),*
        }

        impl Default for $name {
            fn default() -> Self { $name::$dname }
        }

        impl $crate::protocol::FromNum for $name {
            fn from_num(num: i32) -> Option<Self> {
                match num {
                    $($val => Some($name::$vname)),*,
                    _ => None
                }
            }
        }

        impl $crate::protocol::ThriftTyped for $name {
            fn typ() -> $crate::protocol::Type { $crate::protocol::Type::I32 }
        }

        impl $crate::protocol::Encode for $name {
            fn encode<P, T>(&self, protocol: &mut P, transport: &mut T) -> $crate::Result<()>
            where P: $crate::Protocol, T: $crate::Transport {
                #[allow(unused_imports)]
                use $crate::Protocol;

                protocol.write_i32(transport, *self as i32)
            }
        }

        impl $crate::protocol::Decode for $name {
            fn decode<P, T>(&mut self, protocol: &mut P, transport: &mut T) -> $crate::Result<()>
            where P: $crate::Protocol, T: $crate::Transport {
                *self = try!($crate::protocol::helpers::read_enum(protocol, transport));
                Ok(())
            }
        }
    }
}

<commit_msg>UFCS qualify trait method calls<commit_after>#[macro_export]
macro_rules! service {
    (trait_name = $name:ident,
     processor_name = $processor_name:ident,
     client_name = $client_name:ident,
     service_methods = [$($siname:ident -> $soname:ident = $smfname:ident.$smname:ident($($saname:ident: $saty:ty => $said:expr,)*) -> $srty:ty => [$($sename:ident: $sety:ty => $seid:expr,)*],)*],
     parent_methods = [$($piname:ident -> $poname:ident = $pmfname:ident.$pmname:ident($($paname:ident: $paty:ty => $paid:expr,)*) -> $prty:ty => [$($pename:ident: $pety:ty => $peid:expr,)*],)*],
     bounds = [$($boundty:ident: $bound:ident,)*],
     fields = [$($fname:ident: $fty:ty,)*]) => {
        pub trait $name {
            $(fn $smname(&self, $($saname: $saty),*) -> $soname;)*
        }

        service_processor! {
            processor_name = $processor_name,
            service_methods = [$($siname -> $soname = $smfname.$smname($($saname: $saty => $said,)*) -> $srty => [$($sename: $sety => $seid,)*],)*],
            parent_methods = [$($piname -> $poname = $pmfname.$pmname($($paname: $paty => $paid,)*) -> $prty => [$($pename: $pety => $peid,)*],)*],
            bounds = [$($boundty: $bound,)*],
            fields = [$($fname: $fty,)*]
        }

        service_client! {
            client_name = $client_name,
            service_methods = [$($siname -> $soname = $smfname.$smname($($saname: $saty => $said,)*) -> $srty => [$($sename: $sety => $seid,)*],)*],
            parent_methods = [$($piname -> $poname = $pmfname.$pmname($($paname: $paty => $paid,)*) -> $prty => [$($pename: $pety => $peid,)*],)*]
        }
    }
}

#[macro_export]
macro_rules! service_processor {
    (processor_name = $name:ident,
     service_methods = [$($siname:ident -> $soname:ident = $smfname:ident.$smname:ident($($saname:ident: $saty:ty => $said:expr,)*) -> $srty:ty => [$($sename:ident: $sety:ty => $seid:expr,)*],)*],
     parent_methods = [$($piname:ident -> $poname:ident = $pmfname:ident.$pmname:ident($($paname:ident: $paty:ty => $paid:expr,)*) -> $prty:ty => [$($pename:ident: $pety:ty => $peid:expr,)*],)*],
     bounds = [$($boundty:ident: $bound:ident,)*],
     fields = [$($fname:ident: $fty:ty,)*]) => {
        pub struct $name<$($boundty: $bound),*> {
            $($fname: $fty,)*
            _ugh: ()
        }

        $(strukt! { name = $siname, fields = { $($saname: $saty => $said,)* } }
          strukt! { name = $soname, fields = { success: $srty => 0, $($sename: $sety => $seid,)* } })*

        impl<$($boundty: $bound),*> $name<$($boundty),*> {
            pub fn new($($fname: $fty),*) -> Self {
                $name { $($fname: $fname,)* _ugh: () }
            }

            pub fn dispatch<P: $crate::Protocol, T: $crate::Transport>(&self, prot: &mut P, transport: &mut T,
                                                                       name: &str, ty: $crate::protocol::MessageType, id: i32) -> $crate::Result<()> {
                match name {
                    $(stringify!($smname) => self.$smname(prot, transport, ty, id),)*
                    $(stringify!($pmname) => self.$pmname(prot, transport, ty, id),)*
                    _ => Err($crate::Error::from($crate::protocol::Error::ProtocolViolation))
                }
            }

            service_processor_methods! { methods = [$($siname -> $soname = $smfname.$smname($($saname: $saty => $said,)*) -> $srty => [$($sename: $sety => $seid,)*],)*] }
            service_processor_methods! { methods = [$($piname -> $poname = $pmfname.$pmname($($paname: $paty => $paid,)*) -> $prty => [$($pename: $pety => $peid,)*],)*] }
        }

        impl<P: $crate::Protocol, T: $crate::Transport, $($boundty: $bound),*> $crate::Processor<P, T> for $name<$($boundty),*> {
            fn process(&self, protocol: &mut P, transport: &mut T) -> $crate::Result<()> {
                #[allow(unused_imports)]
                use $crate::Protocol;

                let (name, ty, id) = try!(protocol.read_message_begin(transport));
                self.dispatch(protocol, transport, &name, ty, id)
            }
        }
    }
}

#[macro_export]
macro_rules! service_processor_methods {
    (methods = [$($iname:ident -> $oname:ident = $fname:ident.$mname:ident($($aname:ident: $aty:ty => $aid:expr,)*) -> $rty:ty => [$($ename:ident: $ety:ty => $eid:expr,)*],)*]) => {
        $(fn $mname<P: $crate::Protocol, T: $crate::Transport>(&self, prot: &mut P, transport: &mut T,
                                                               ty: $crate::protocol::MessageType, id: i32) -> $crate::Result<()> {
            static MNAME: &'static str = stringify!($mname);

            let mut args = $iname::default();
            try!($crate::protocol::helpers::receive_body(prot, transport, MNAME,
                                                         &mut args, MNAME, ty, id));

            // TODO: Further investigate this unwrap.
            let result = self.$fname.$mname($(args.$aname.unwrap()),*);
            try!($crate::protocol::helpers::send(prot, transport, MNAME,
                                                 $crate::protocol::MessageType::Reply, &result));

            Ok(())
        })*
    }
}

#[macro_export]
macro_rules! service_client {
    (client_name = $client_name:ident,
     service_methods = [$($siname:ident -> $soname:ident = $smfname:ident.$smname:ident($($saname:ident: $saty:ty => $said:expr,)*) -> $srty:ty => [$($sename:ident: $sety:ty => $seid:expr,)*],)*],
     parent_methods = [$($piname:ident -> $poname:ident = $pmfname:ident.$pmname:ident($($paname:ident: $paty:ty => $paid:expr,)*) -> $prty:ty => [$($pename:ident: $pety:ty => $peid:expr,)*],)*]) => {
        pub struct $client_name<P: $crate::Protocol, T: $crate::Transport> {
            pub protocol: P,
            pub transport: T
        }

        impl<P: $crate::Protocol, T: $crate::Transport> $client_name<P, T> {
            pub fn new(protocol: P, transport: T) -> Self {
                $client_name {
                    protocol: protocol,
                    transport: transport
                }
            }

            service_client_methods! { methods = [$($siname -> $soname = $smfname.$smname($($saname: $saty => $said,)*) -> $srty => [$($sename: $sety => $seid,)*],)*] }
            service_client_methods! { methods = [$($piname -> $poname = $pmfname.$pmname($($paname: $paty => $paid,)*) -> $prty => [$($pename: $pety => $peid,)*],)*] }
        }
    }
}

#[macro_export]
macro_rules! service_client_methods {
    (methods = [$($iname:ident -> $oname:ident = $fname:ident.$mname:ident($($aname:ident: $aty:ty => $aid:expr,)*) -> $rty:ty => [$($ename:ident: $ety:ty => $eid:expr,)*],)*]) => {
        $(pub fn $mname(&mut self, $($aname: $aty,)*) -> $crate::Result<$oname> {
            static MNAME: &'static str = stringify!($mname);

            let mut args = $iname::default();
            $(args.$aname = Some($aname);)*
            try!($crate::protocol::helpers::send(&mut self.protocol, &mut self.transport,
                                                 MNAME, $crate::protocol::MessageType::Call, &mut args));

            let mut result = $oname::default();
            try!($crate::protocol::helpers::receive(&mut self.protocol, &mut self.transport,
                                                    MNAME, &mut result));

            Ok(result)
        })*
    }
}

#[macro_export]
macro_rules! strukt {
    (name = $name:ident,
     fields = { $($fname:ident: $fty:ty => $id:expr,)+ }) => {
        #[derive(Debug, Clone, Default)]
        pub struct $name {
            $(pub $fname: Option<$fty>,)+
        }

        impl $crate::protocol::ThriftTyped for $name {
            fn typ() -> $crate::protocol::Type { $crate::protocol::Type::Struct }
        }

        impl $crate::protocol::Encode for $name {
            fn encode<P, T>(&self, protocol: &mut P, transport: &mut T) -> $crate::Result<()>
            where P: $crate::Protocol, T: $crate::Transport {
                #[allow(unused_imports)]
                use $crate::protocol::{Encode, ThriftTyped};
                #[allow(unused_imports)]
                use $crate::{Protocol};

                try!(protocol.write_struct_begin(transport, stringify!($name)));

                $(if let Some(ref x) = self.$fname {
                    try!(protocol.write_field_begin(transport, stringify!($fname), <$fty as ThriftTyped>::typ(), $id));
                    try!($crate::protocol::Encode::encode(x, protocol, transport));
                    try!(protocol.write_field_end(transport));
                })*

                try!(protocol.write_field_stop(transport));
                try!(protocol.write_struct_end(transport));

                Ok(())
            }
        }

        impl $crate::protocol::Decode for $name {
            fn decode<P, T>(&mut self, protocol: &mut P, transport: &mut T) -> $crate::Result<()>
            where P: $crate::Protocol, T: $crate::Transport {
                #[allow(unused_imports)]
                use $crate::protocol::{Decode, ThriftTyped};
                #[allow(unused_imports)]
                use $crate::Protocol;

                try!(protocol.read_struct_begin(transport));

                loop {
                    let (_, typ, id) = try!(protocol.read_field_begin(transport));

                    if typ == $crate::protocol::Type::Stop {
                        break;
                    } $(else if (typ, id) == (<$fty as ThriftTyped>::typ(), $id) {
                        try!($crate::protocol::Decode::decode(&mut self.$fname, protocol, transport));
                    })* else {
                        try!(protocol.skip(transport, typ));
                    }

                    try!(protocol.read_field_end(transport));
                }

                try!(protocol.read_struct_end(transport));

                Ok(())
            }
        }
    };
    (name = $name:ident, fields = {}) => {
        #[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
        pub struct $name;

        impl $crate::protocol::ThriftTyped for $name {
            fn typ() -> $crate::protocol::Type { $crate::protocol::Type::Struct }
        }

        impl $crate::protocol::Encode for $name {
            fn encode<P, T>(&self, protocol: &mut P, transport: &mut T) -> $crate::Result<()>
            where P: $crate::Protocol, T: $crate::Transport {
                #[allow(unused_imports)]
                use $crate::Protocol;

                try!(protocol.write_struct_begin(transport, stringify!($name)));
                try!(protocol.write_field_stop(transport));
                try!(protocol.write_struct_end(transport));

                Ok(())
            }
        }

        impl $crate::protocol::Decode for $name {
            fn decode<P, T>(&mut self, protocol: &mut P, transport: &mut T) -> $crate::Result<()>
            where P: $crate::Protocol, T: $crate::Transport {
                #[allow(unused_imports)]
                use $crate::Protocol;

                try!(protocol.read_struct_begin(transport));

                let (_, ty, _) = try!(protocol.read_field_begin(transport));
                if ty != $crate::protocol::Type::Stop {
                     return Err($crate::Error::from($crate::protocol::Error::ProtocolViolation))
                }

                try!(protocol.read_struct_end(transport));

                Ok(())
            }
        }
    }
}

#[macro_export]
macro_rules! enom {
    (name = $name:ident,
     values = [$($vname:ident = $val:expr,)*],
     default = $dname:ident) => {
        #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
        #[repr(i32)]
        pub enum $name {
            $($vname = $val),*
        }

        impl Default for $name {
            fn default() -> Self { $name::$dname }
        }

        impl $crate::protocol::FromNum for $name {
            fn from_num(num: i32) -> Option<Self> {
                match num {
                    $($val => Some($name::$vname)),*,
                    _ => None
                }
            }
        }

        impl $crate::protocol::ThriftTyped for $name {
            fn typ() -> $crate::protocol::Type { $crate::protocol::Type::I32 }
        }

        impl $crate::protocol::Encode for $name {
            fn encode<P, T>(&self, protocol: &mut P, transport: &mut T) -> $crate::Result<()>
            where P: $crate::Protocol, T: $crate::Transport {
                #[allow(unused_imports)]
                use $crate::Protocol;

                protocol.write_i32(transport, *self as i32)
            }
        }

        impl $crate::protocol::Decode for $name {
            fn decode<P, T>(&mut self, protocol: &mut P, transport: &mut T) -> $crate::Result<()>
            where P: $crate::Protocol, T: $crate::Transport {
                *self = try!($crate::protocol::helpers::read_enum(protocol, transport));
                Ok(())
            }
        }
    }
}

<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};
use std::rc::{Rc, Weak};
use std::cell::RefCell;
use std::convert::AsRef;
use std::collections::BTreeMap;
use image;
use image::GenericImage;
use glium::Display;
use texture::Texture;

pub type Map<T> = BTreeMap<PathBuf, Weak<T>>;

pub trait Resource {
    fn load(&Display, &Path) -> Self;
}

pub struct Manager<'a, T: Resource> {
    pub map: RefCell<Map<T>>,
    path: PathBuf,
    display: &'a Display,
}

impl<'a, T: Resource> Manager<'a, T> {
    pub fn new<P: AsRef<Path>>(display: &'a Display, path: P) -> Manager<'a, T> {
        Manager {
            map: RefCell::new(Map::new()),
            path: path.as_ref().to_path_buf(),
            display: display,
        }
    }

    fn load(&self, key: &PathBuf) -> Rc<T> {
        let mut map = self.map.borrow_mut();
        if map.contains_key(key) { let _ = map.remove(key); }
        let res = Rc::new(T::load(self.display, &key));
        map.insert(key.clone(), Rc::downgrade(&res));
        return res;
    }

    pub fn get<P: AsRef<Path>>(&self, p: P) -> Rc<T> {
        let key = self.path.join(p);
        let pointer = {
            let map = self.map.borrow();
            if map.contains_key(&key) {
                let weak = self.map.borrow()[&key].clone();
                weak.upgrade()
            }
            else { None }
        };
        match pointer {
            None => self.load(&key),
            Some (x) => x,
        }
    }
}

impl Resource for Texture {
    fn load(display: &Display, path: &Path) -> Texture {
        let image = image::open(path).unwrap();
        let image_dimensions = image.dimensions();
        let image = ::glium::texture::RawImage2d::from_raw_rgba_reversed(
            image.raw_pixels(), image_dimensions);
        Texture::new(display, image)
    }
}
<commit_msg>Add persistent resource support<commit_after>use std::path::{Path, PathBuf};
use std::rc::{Rc, Weak};
use std::cell::RefCell;
use std::convert::AsRef;
use std::collections::BTreeMap;
use image;
use image::GenericImage;
use glium::Display;
use texture::Texture;

pub type Map<T> = BTreeMap<PathBuf, Weak<T>>;

pub trait Resource {
    fn load(&Display, &Path) -> Self;
}

pub struct Manager<'a, T: Resource> {
    pub map: RefCell<Map<T>>,
    path: PathBuf,
    display: &'a Display,
    self_ref: RefCell<Vec<Rc<T>>>,
}

impl<'a, T: Resource> Manager<'a, T> {
    pub fn new<P: AsRef<Path>>(display: &'a Display, path: P) -> Manager<'a, T> {
        Manager {
            map: RefCell::new(Map::new()),
            path: path.as_ref().to_path_buf(),
            display: display,
            self_ref: RefCell::new(Vec::new()),
        }
    }

    fn load(&self, key: &PathBuf) -> Rc<T> {
        let mut map = self.map.borrow_mut();
        if map.contains_key(key) { let _ = map.remove(key); }
        let res = Rc::new(T::load(self.display, &key));
        map.insert(key.clone(), Rc::downgrade(&res));
        return res;
    }

    pub fn load_persistent(&mut self, key: &PathBuf) -> Rc<T> {
        let res = self.load(key);
        {
            let mut refs = self.self_ref.borrow_mut();
            refs.push(res.clone())
        }
        return res;
    }

    pub fn get<P: AsRef<Path>>(&self, p: P) -> Rc<T> {
        let key = self.path.join(p);
        let pointer = {
            let map = self.map.borrow();
            if map.contains_key(&key) {
                let weak = self.map.borrow()[&key].clone();
                weak.upgrade()
            }
            else { None }
        };
        match pointer {
            None => self.load(&key),
            Some (x) => x,
        }
    }

    pub fn release_persistent(&mut self) {
        self.self_ref.borrow_mut().clear();
    }
}

impl Resource for Texture {
    fn load(display: &Display, path: &Path) -> Texture {
        let image = image::open(path).unwrap();
        let image_dimensions = image.dimensions();
        let image = ::glium::texture::RawImage2d::from_raw_rgba_reversed(
            image.raw_pixels(), image_dimensions);
        Texture::new(display, image)
    }
}
<|endoftext|>


<commit_before>//! Events within the *m.room* namespace.

pub mod message;

use core::{Event, RoomEvent, StateEvent};

/// Informs the room about what room aliases it has been given.
pub struct AliasesEvent<'a, 'b> {
    content: AliasesEventContent<'a>,
    event_id: &'a str,
    prev_content: Option<AliasesEventContent<'b>>,
    room_id: &'a str,
    /// The homeserver domain which owns these room aliases.
    state_key: &'a str,
    user_id: &'a str,
}

impl<'a, 'b> Event<'a, AliasesEventContent<'a>> for AliasesEvent<'a, 'b> {
    fn content(&'a self) -> &'a AliasesEventContent<'a> {
        &self.content
    }

    fn event_type(&self) -> &'static str {
        "m.room.aliases"
    }
}

impl<'a, 'b> RoomEvent<'a, AliasesEventContent<'a>> for AliasesEvent<'a, 'b> {
    fn event_id(&'a self) -> &'a str {
        &self.event_id
    }

    fn room_id(&'a self) -> &'a str {
        &self.room_id
    }

    fn user_id(&'a self) -> &'a str {
        &self.user_id
    }
}

impl<'a, 'b> StateEvent<'a, 'b, AliasesEventContent<'a>> for AliasesEvent<'a, 'b> {
    fn prev_content(&'a self) -> Option<&'b AliasesEventContent> {
        match self.prev_content {
            Some(ref prev_content) => Some(prev_content),
            None => None,
        }
    }

    fn state_key(&self) -> &'a str {
        &self.state_key
    }
}

/// The payload of an `AliasesEvent`.
pub struct AliasesEventContent<'a> {
    /// A list of room aliases.
    aliases: &'a[&'a str],
}
<commit_msg>Add CanonicalAliasEvent, CreateEvent, and HistoryVisibilityEvent.<commit_after>//! Events within the *m.room* namespace.

pub mod message;

use core::{Event, RoomEvent, StateEvent};

/// Informs the room about what room aliases it has been given.
pub struct AliasesEvent<'a, 'b> {
    content: AliasesEventContent<'a>,
    event_id: &'a str,
    prev_content: Option<AliasesEventContent<'b>>,
    room_id: &'a str,
    /// The homeserver domain which owns these room aliases.
    state_key: &'a str,
    user_id: &'a str,
}

impl<'a, 'b> Event<'a, AliasesEventContent<'a>> for AliasesEvent<'a, 'b> {
    fn content(&'a self) -> &'a AliasesEventContent<'a> {
        &self.content
    }

    fn event_type(&self) -> &'static str {
        "m.room.aliases"
    }
}

impl<'a, 'b> RoomEvent<'a, AliasesEventContent<'a>> for AliasesEvent<'a, 'b> {
    fn event_id(&'a self) -> &'a str {
        &self.event_id
    }

    fn room_id(&'a self) -> &'a str {
        &self.room_id
    }

    fn user_id(&'a self) -> &'a str {
        &self.user_id
    }
}

impl<'a, 'b> StateEvent<'a, 'b, AliasesEventContent<'a>> for AliasesEvent<'a, 'b> {
    fn prev_content(&'a self) -> Option<&'b AliasesEventContent> {
        match self.prev_content {
            Some(ref prev_content) => Some(prev_content),
            None => None,
        }
    }

    fn state_key(&self) -> &'a str {
        &self.state_key
    }
}

/// The payload of an `AliasesEvent`.
pub struct AliasesEventContent<'a> {
    /// A list of room aliases.
    aliases: &'a[&'a str],
}

/// Informs the room as to which alias is the canonical one.
pub struct CanonicalAliasEvent<'a, 'b> {
    content: CanonicalAliasEventContent<'a>,
    event_id: &'a str,
    prev_content: Option<CanonicalAliasEventContent<'b>>,
    room_id: &'a str,
    user_id: &'a str,
}

impl<'a, 'b> Event<'a, CanonicalAliasEventContent<'a>> for CanonicalAliasEvent<'a, 'b> {
    fn content(&'a self) -> &'a CanonicalAliasEventContent<'a> {
        &self.content
    }

    fn event_type(&self) -> &'static str {
        "m.room.canonical_alias"
    }
}

impl<'a, 'b> RoomEvent<'a, CanonicalAliasEventContent<'a>> for CanonicalAliasEvent<'a, 'b> {
    fn event_id(&'a self) -> &'a str {
        &self.event_id
    }

    fn room_id(&'a self) -> &'a str {
        &self.room_id
    }

    fn user_id(&'a self) -> &'a str {
        &self.user_id
    }
}

impl<'a, 'b> StateEvent<'a, 'b, CanonicalAliasEventContent<'a>> for CanonicalAliasEvent<'a, 'b> {
    fn prev_content(&'a self) -> Option<&'b CanonicalAliasEventContent> {
        match self.prev_content {
            Some(ref prev_content) => Some(prev_content),
            None => None,
        }
    }
}

/// The payload of a `CanonicalAliasEvent`.
pub struct CanonicalAliasEventContent<'a> {
    /// The canonical alias.
    alias: &'a str,
}

/// This is the first event in a room and cannot be changed. It acts as the root of all other
/// events.
pub struct CreateEvent<'a, 'b> {
    content: CreateEventContent<'a>,
    event_id: &'a str,
    prev_content: Option<CreateEventContent<'b>>,
    room_id: &'a str,
    user_id: &'a str,
}

impl<'a, 'b> Event<'a, CreateEventContent<'a>> for CreateEvent<'a, 'b> {
    fn content(&'a self) -> &'a CreateEventContent<'a> {
        &self.content
    }

    fn event_type(&self) -> &'static str {
        "m.room.create"
    }
}

impl<'a, 'b> RoomEvent<'a, CreateEventContent<'a>> for CreateEvent<'a, 'b> {
    fn event_id(&'a self) -> &'a str {
        &self.event_id
    }

    fn room_id(&'a self) -> &'a str {
        &self.room_id
    }

    fn user_id(&'a self) -> &'a str {
        &self.user_id
    }
}

impl<'a, 'b> StateEvent<'a, 'b, CreateEventContent<'a>> for CreateEvent<'a, 'b> {}

/// The payload of a `CreateEvent`.
pub struct CreateEventContent<'a> {
    /// The `user_id` of the room creator. This is set by the homeserver.
    creator: &'a str,
}

/// This event controls whether a member of a room can see the events that happened in a room from
/// before they joined.
pub struct HistoryVisibilityEvent<'a, 'b> {
    content: HistoryVisibilityEventContent<'a>,
    event_id: &'a str,
    prev_content: Option<HistoryVisibilityEventContent<'b>>,
    room_id: &'a str,
    user_id: &'a str,
}

impl<'a, 'b> Event<'a, HistoryVisibilityEventContent<'a>> for HistoryVisibilityEvent<'a, 'b> {
    fn content(&'a self) -> &'a HistoryVisibilityEventContent<'a> {
        &self.content
    }

    fn event_type(&self) -> &'static str {
        "m.room.history_visibility"
    }
}

impl<'a, 'b> RoomEvent<'a, HistoryVisibilityEventContent<'a>> for HistoryVisibilityEvent<'a, 'b> {
    fn event_id(&'a self) -> &'a str {
        &self.event_id
    }

    fn room_id(&'a self) -> &'a str {
        &self.room_id
    }

    fn user_id(&'a self) -> &'a str {
        &self.user_id
    }
}

impl<'a, 'b> StateEvent<'a, 'b, HistoryVisibilityEventContent<'a>>
    for HistoryVisibilityEvent<'a, 'b>
{
    fn prev_content(&'a self) -> Option<&'b HistoryVisibilityEventContent> {
        match self.prev_content {
            Some(ref prev_content) => Some(prev_content),
            None => None,
        }
    }
}

/// The payload of a `HistoryVisibilityEvent`.
pub struct HistoryVisibilityEventContent<'a> {
    /// Who can see the room history.
    history_visibility: &'a HistoryVisibility,
}

/// Who can see a room's history.
pub enum HistoryVisibility {
    /// Previous events are accessible to newly joined members from the point they were invited
    /// onwards. Events stop being accessible when the member's state changes to something other
    /// than *invite* or *join*.
    Invited,
    /// Previous events are accessible to newly joined members from the point they joined the room
    /// onwards. Events stop being accessible when the member's state changes to something other
    /// than *join*.
    Joined,
    /// Previous events are always accessible to newly joined members. All events in the room are
    /// accessible, even those sent when the member was not a part of the room.
    Shared,
    /// All events while this is the `HistoryVisibility` value may be shared by any
    /// participating homeserver with anyone, regardless of whether they have ever joined the room.
    WorldReadable,
}
<|endoftext|>