<commit_before>// Standard library imports
use std::mem;
use std::ops;

// srmat imports
use matelt::{MatrixElt};
use matrix::{Matrix};
use materr::*;
use discrete::*;

#[doc = "
Defines a view on a matrix.

A view on a matrix is a subset of
chosen rows and columns.

"]
pub struct MatrixView<'a, T:'a+MatrixElt>{
    // Reference to the associated matrix
    m : &'a Matrix<T>,
    // start row
    start_row : uint,
    // number or rows
    rows  : uint,
    // skip between rows (by default 1)
    row_skip : uint,
    // start column
    start_col : uint,
    // Number of columns
    cols : uint,
    // Skip between columns (by default 1)
    col_skip : uint
}

/// Static functions for creating  a view
impl<'a, T:MatrixElt> MatrixView<'a, T> {
    pub fn new(m : &Matrix<T>, start_row : int, start_col : int , num_rows: uint, num_cols : uint) -> MatrixView<T> {
        let r = mod_n(start_row, m.num_rows() as int);
        let c = mod_n(start_col, m.num_cols() as int);
        let row_skip = 1u;
        let col_skip = 1u;
        assert!(r + row_skip*num_rows <= m.num_rows());
        assert!(c + col_skip*num_cols <= m.num_cols());
        let result : MatrixView<T> = MatrixView{
            m : m,
            start_row : r,
            start_col : c,
            rows: num_rows,
            cols : num_cols,
            row_skip : row_skip,
            col_skip : col_skip
        };
        result
    }
    //// Returns the number of rows in the view
    pub fn num_rows(&self) -> uint {
        self.rows
    }

    /// Returns the number of columns in the view
    pub fn num_cols(&self) -> uint {
        self.cols
    }

    /// Returns the size of view in an (r, c) tuple
    pub fn size (&self)-> (uint, uint){
        (self.rows, self.cols)
    }
    /// Returns the number of cells in view
    pub fn num_cells(&self)->uint {
        self.rows * self.cols
    }
    /// Indicates if the view is a row vector
    pub fn is_row(&self) -> bool {
        self.rows == 1
    }

    /// Indicates if the view is a column vector
    pub fn is_col(&self) -> bool {
        self.cols == 1
    }

    /// Indicates if the view is a scalar actually
    pub fn is_scalar(&self) -> bool {
        self.num_cells() == 1
    }

    /// Indicates if the view is a vector
    pub fn is_vector(&self) -> bool {
        (self.rows == 1) ^ (self.cols == 1)
    }

    /// Indicates if the view is empty
    pub fn is_empty(&self) -> bool {
        self.rows * self.cols == 0
    }

    /// Indicates if the view is square
    pub fn is_square(&self) -> bool {
        self.rows == self.cols
    }

    /// Gets an element in the view
    #[inline]
    pub fn get(&self, r : uint, c : uint) -> T  {
        assert!(r < self.rows);
        assert!(c < self.cols);
        let ptr = self.m.as_ptr();
        let offset = self.cell_to_offset(r, c);
        assert!((offset as uint) < self.m.capacity());
        unsafe {
            *ptr.offset(offset)
        }
    }

    /// Sets an element in the view
    #[inline]
    pub fn set(&mut self, r : uint, c : uint, value : T) {
        assert!(r < self.rows);
        assert!(c < self.cols);
        let ptr = self.m.as_ptr();
        // I know more than the compiler
        // I am allowing modification of the underlying buffer
        let ptr : *mut T = unsafe { mem::transmute(ptr) };
        let offset = self.cell_to_offset(r, c);
        assert!((offset as uint) < self.m.capacity());
        unsafe {
            *ptr.offset(offset) = value;
        }
    }

    /// Converts an index to cell address (row, column)
    #[inline]
    pub fn index_to_cell(&self, index : uint) -> (uint, uint){
        assert!(index < self.num_cells());
        let c = index / self.rows;
        let r = index - c*self.rows;
        (r, c)
    }

    /// Converts a cell address to an index (r, c) to index
    #[inline]
    pub fn cell_to_index(&self, r : uint,  c: uint) -> uint{
        assert!(r < self.rows);
        assert!(c < self.cols);
        c * self.rows + r
    }

    /******************************************************
     *
     *   Private implementation of MatrixView
     *
     *******************************************************/

    /// Maps a cell index to actual offset in the internal buffer
    #[inline]
    fn cell_to_offset(&self, r : uint,  c: uint)-> int {
        let r = self.start_row + r * self.row_skip;
        let c = self.start_col + c * self.col_skip;
        (c * self.m.stride() + r) as int
    }

}

/// Functions to construct new views out of a view and other conversions
impl<'a, T:MatrixElt> MatrixView<'a, T> {
    /// Converts the view to vector from standard library
    pub fn to_std_vec(&self) -> Vec<T> {
        let mut vec: Vec<T> = Vec::with_capacity(self.num_cells());
        // We iterate over elements in matrix and push in the vector
        let ptr = self.m.as_ptr();
        for c in range(0, self.cols){
            for r in range (0, self.rows){
                let offset = self.cell_to_offset(r, c);
                vec.push(unsafe{*ptr.offset(offset)});
            }
        }
        vec
    }
}

impl<'a, T:MatrixElt> MatrixView<'a, T> {
}

impl<'a, T:MatrixElt> MatrixView<'a, T> {
}

/// View + View =  Matrix addition
impl<'a, 'b, T:MatrixElt> ops::Add<MatrixView<'b, T>, Matrix<T>> for MatrixView<'a, T> {
    fn add(&self, rhs: &MatrixView<T>) -> Matrix<T> {
        // Validate dimensions are same.
        if self.size() != rhs.size(){
            fail!(DimensionsMismatch.to_string());
        }
        let mut result : Matrix<T> = Matrix::new(self.rows, self.cols);
        let pa = self.m.as_ptr();
        let pb = rhs.m.as_ptr();
        let pc = result.as_mut_ptr();
        for c in range (0, self.cols){
            for r in range(0, self.rows){
                let dst_offset = result.cell_to_offset(r, c);
                let a_offset  = self.cell_to_offset(r, c);
                let b_offset = rhs.cell_to_offset(r, c);
                unsafe{
                    *pc.offset(dst_offset) = *pa.offset(a_offset) + *pb.offset(b_offset);
                }
            }
        }
        result
    }
}

/******************************************************
 *
 *   Unit tests follow.
 *
 *******************************************************/

#[cfg(test)]
mod test{
    use matrix::{Matrix, MatrixI64};

    #[test]
    fn test_basic(){
        let m1 :  MatrixI64 = Matrix::from_iter(10, 8, range(1, 100));
        let mut v1 = m1.view(2, 3, 4, 4);
        assert_eq!(v1.size(), (4u, 4u));
        assert_eq!(v1.num_rows(), 4);
        assert_eq!(v1.num_cols(), 4);
        assert_eq!(v1.is_scalar(), false);
        assert_eq!(v1.is_vector(), false);
        assert_eq!(v1.is_row(), false);
        assert_eq!(v1.is_col(), false);
        assert_eq!(v1.get(1,1), 44);
        v1.set(1,1, 300);
        assert_eq!(v1.get(1,1), 300);
    }
    #[test]
    fn test_view_multiple(){
        let m1 :  MatrixI64 = Matrix::from_iter(10, 8, range(1, 100));
        // We can create multiple views easily.
        let v1 = m1.view(1, 1, 4, 4);
        let v2 = m1.view(2, 2, 4, 4);
        let v3 = m1.view(2, 3, 4, 4);
        assert_eq!(v1.get(0, 0), 12);
        assert_eq!(v2.get(0, 0), 23);
        assert_eq!(v3.get(0, 0), 33);
    }

    #[test]
    fn test_view_matrix_mutability(){
        let mut m1 :  MatrixI64 = Matrix::from_iter(10, 8, range(1, 100));
        {
            let v1 = m1.view(2, 2, 4, 4);
            // The following line doesn't compile since we have borrowed an
            // immutable reference of m1 in v1.
            //m1.set(0, 0, 2);
            assert_eq!(v1.get(0, 0), 23);
        }
        m1.set(0, 0, 2);
    }

    #[test]
    fn test_cell_index_mapping(){
        let rows = 20;
        let cols = 10;
        let m : MatrixI64 = Matrix::new(rows, cols);
        let vrows = 4;
        let vcols = 3;
        let v = m.view(1, 1, vrows, vcols);
        assert_eq!(v.index_to_cell(3 + 2*vrows), (3, 2));
        assert_eq!(v.cell_to_index(3, 2), 3 + 2*vrows);
        assert_eq!(v.cell_to_index(3, 2), 11);
        assert_eq!(v.index_to_cell(11), (3, 2));
    }

    #[test]
    fn test_to_std_vec(){
        let m :  MatrixI64 = Matrix::from_iter(10, 8, range(1, 100));
        let vrows = 4;
        let vcols = 3;
        let mv = m.view(1, 1, vrows, vcols);
        let vv : Vec<i64> = vec![12, 13, 14, 15,
        22, 23, 24, 25,
        32, 33, 34, 35];
        assert_eq!(mv.to_std_vec(), vv);
    }

    #[test]
    fn test_addition(){
        let m :  MatrixI64 = Matrix::from_iter(10, 10, range(1, 200));
        let v1   = m.view(2, 2, 2, 2); // 23 , 24 , 33, 34
        let v2 = m.view(1, 1, 2, 2);  // 12, 13, 22, 33
        let m2 = v1 + v2; //
        let m3 : MatrixI64 = Matrix::from_slice(2, 2, vec![35, 37, 55, 57].as_slice());
        assert_eq!(m2, m3);
    }
}

<commit_msg>added max min abs_max abs_min scalar functions.<commit_after>// Standard library imports
use std::mem;
use std::ops;
use std::num;
use std::fmt;

// srmat imports
use matelt::{MatrixElt};
use matrix::{Matrix};
use materr::*;
use discrete::*;

#[doc = "
Defines a view on a matrix.

A view on a matrix is a subset of
chosen rows and columns.

"]
pub struct MatrixView<'a, T:'a+MatrixElt>{
    // Reference to the associated matrix
    m : &'a Matrix<T>,
    // start row
    start_row : uint,
    // number or rows
    rows  : uint,
    // skip between rows (by default 1)
    row_skip : uint,
    // start column
    start_col : uint,
    // Number of columns
    cols : uint,
    // Skip between columns (by default 1)
    col_skip : uint
}

/// Static functions for creating  a view
impl<'a, T:MatrixElt> MatrixView<'a, T> {
    pub fn new(m : &Matrix<T>, start_row : int, start_col : int , num_rows: uint, num_cols : uint) -> MatrixView<T> {
        let r = mod_n(start_row, m.num_rows() as int);
        let c = mod_n(start_col, m.num_cols() as int);
        let row_skip = 1u;
        let col_skip = 1u;
        assert!(r + row_skip*num_rows <= m.num_rows());
        assert!(c + col_skip*num_cols <= m.num_cols());
        let result : MatrixView<T> = MatrixView{
            m : m,
            start_row : r,
            start_col : c,
            rows: num_rows,
            cols : num_cols,
            row_skip : row_skip,
            col_skip : col_skip
        };
        result
    }
    //// Returns the number of rows in the view
    pub fn num_rows(&self) -> uint {
        self.rows
    }

    /// Returns the number of columns in the view
    pub fn num_cols(&self) -> uint {
        self.cols
    }

    /// Returns the size of view in an (r, c) tuple
    pub fn size (&self)-> (uint, uint){
        (self.rows, self.cols)
    }
    /// Returns the number of cells in view
    pub fn num_cells(&self)->uint {
        self.rows * self.cols
    }
    /// Indicates if the view is a row vector
    pub fn is_row(&self) -> bool {
        self.rows == 1
    }

    /// Indicates if the view is a column vector
    pub fn is_col(&self) -> bool {
        self.cols == 1
    }

    /// Indicates if the view is a scalar actually
    pub fn is_scalar(&self) -> bool {
        self.num_cells() == 1
    }

    /// Indicates if the view is a vector
    pub fn is_vector(&self) -> bool {
        (self.rows == 1) ^ (self.cols == 1)
    }

    /// Indicates if the view is empty
    pub fn is_empty(&self) -> bool {
        self.rows * self.cols == 0
    }

    /// Indicates if the view is square
    pub fn is_square(&self) -> bool {
        self.rows == self.cols
    }

    /// Gets an element in the view
    #[inline]
    pub fn get(&self, r : uint, c : uint) -> T  {
        assert!(r < self.rows);
        assert!(c < self.cols);
        let ptr = self.m.as_ptr();
        let offset = self.cell_to_offset(r, c);
        assert!((offset as uint) < self.m.capacity());
        unsafe {
            *ptr.offset(offset)
        }
    }

    /// Sets an element in the view
    #[inline]
    pub fn set(&mut self, r : uint, c : uint, value : T) {
        assert!(r < self.rows);
        assert!(c < self.cols);
        let ptr = self.m.as_ptr();
        // I know more than the compiler
        // I am allowing modification of the underlying buffer
        let ptr : *mut T = unsafe { mem::transmute(ptr) };
        let offset = self.cell_to_offset(r, c);
        assert!((offset as uint) < self.m.capacity());
        unsafe {
            *ptr.offset(offset) = value;
        }
    }

    /// Converts an index to cell address (row, column)
    #[inline]
    pub fn index_to_cell(&self, index : uint) -> (uint, uint){
        assert!(index < self.num_cells());
        let c = index / self.rows;
        let r = index - c*self.rows;
        (r, c)
    }

    /// Converts a cell address to an index (r, c) to index
    #[inline]
    pub fn cell_to_index(&self, r : uint,  c: uint) -> uint{
        assert!(r < self.rows);
        assert!(c < self.cols);
        c * self.rows + r
    }

    /******************************************************
     *
     *   Private implementation of MatrixView
     *
     *******************************************************/

    /// Maps a cell index to actual offset in the internal buffer
    #[inline]
    fn cell_to_offset(&self, r : uint,  c: uint)-> int {
        let r = self.start_row + r * self.row_skip;
        let c = self.start_col + c * self.col_skip;
        (c * self.m.stride() + r) as int
    }

}

/// Functions to construct new views out of a view and other conversions
impl<'a, T:MatrixElt> MatrixView<'a, T> {
    /// Converts the view to vector from standard library
    pub fn to_std_vec(&self) -> Vec<T> {
        let mut vec: Vec<T> = Vec::with_capacity(self.num_cells());
        // We iterate over elements in matrix and push in the vector
        let ptr = self.m.as_ptr();
        for c in range(0, self.cols){
            for r in range (0, self.rows){
                let offset = self.cell_to_offset(r, c);
                vec.push(unsafe{*ptr.offset(offset)});
            }
        }
        vec
    }
}

impl<'a, T:MatrixElt> MatrixView<'a, T> {
}

impl<'a, T:MatrixElt+PartialOrd> MatrixView<'a, T> {
    // Returns the minimum scalar value
    pub fn min_scalar(&self) -> (T, uint, uint){
        if self.is_empty(){
            fail!(EmptyMatrix.to_string());
        }
        let mut v = self.get(0, 0);
        // The location
        let mut rr = 0;
        let mut cc = 0;
        let ps = self.m.as_ptr();
        for c in range(0, self.cols){
            for r in range(0, self.rows){
                let src_offset = self.cell_to_offset(r, c);
                let s = unsafe{*ps.offset(src_offset)};
                if s < v {
                    v = s;
                    rr = r;
                    cc = c;
                }
            }
        }
        (v, rr, cc)
    }

    // Returns the maximum scalar value
    pub fn max_scalar(&self) -> (T, uint, uint){
        if self.is_empty(){
            fail!(EmptyMatrix.to_string());
        }
        let mut v = self.get(0, 0);
        // The location
        let mut rr = 0;
        let mut cc = 0;
        let ps = self.m.as_ptr();
        for c in range(0, self.cols){
            for r in range(0, self.rows){
                let src_offset = self.cell_to_offset(r, c);
                let s = unsafe{*ps.offset(src_offset)};
                if s > v {
                    v = s;
                    rr = r;
                    cc = c;
                }
            }
        }
        (v, rr, cc)
    }

}

impl<'a, T:MatrixElt+PartialOrd+Signed> MatrixView<'a, T> {

    // Returns the absolute minimum scalar value
    pub fn abs_min_scalar(&self) -> (T, uint, uint){
        if self.is_empty(){
            fail!(EmptyMatrix.to_string());
        }
        let mut v = num::abs(self.get(0, 0));
        // The location
        let mut rr = 0;
        let mut cc = 0;
        let ps = self.m.as_ptr();
        for c in range(0, self.cols){
            for r in range(0, self.rows){
                let src_offset = self.cell_to_offset(r, c);
                let s = num::abs(unsafe{*ps.offset(src_offset)});
                if s < v {
                    v = s;
                    rr = r;
                    cc = c;
                };
            }
        }
        (v, rr, cc)
    }

    // Returns the maximum scalar value
    pub fn abs_max_scalar(&self) -> (T, uint, uint){
        if self.is_empty(){
            fail!(EmptyMatrix.to_string());
        }
        let mut v = num::abs(self.get(0, 0));
        // The location
        let mut rr = 0;
        let mut cc = 0;
        let ps = self.m.as_ptr();
        for c in range(0, self.cols){
            for r in range(0, self.rows){
                let src_offset = self.cell_to_offset(r, c);
                let s = num::abs(unsafe{*ps.offset(src_offset)});
                if s > v {
                    v  = s;
                    rr = r;
                    cc = c;
                }
            }
        }
        (v, rr, cc)
    }

}

/// View + View =  Matrix addition
impl<'a, 'b, T:MatrixElt> ops::Add<MatrixView<'b, T>, Matrix<T>> for MatrixView<'a, T> {
    fn add(&self, rhs: &MatrixView<T>) -> Matrix<T> {
        // Validate dimensions are same.
        if self.size() != rhs.size(){
            fail!(DimensionsMismatch.to_string());
        }
        let mut result : Matrix<T> = Matrix::new(self.rows, self.cols);
        let pa = self.m.as_ptr();
        let pb = rhs.m.as_ptr();
        let pc = result.as_mut_ptr();
        for c in range (0, self.cols){
            for r in range(0, self.rows){
                let dst_offset = result.cell_to_offset(r, c);
                let a_offset  = self.cell_to_offset(r, c);
                let b_offset = rhs.cell_to_offset(r, c);
                unsafe{
                    *pc.offset(dst_offset) = *pa.offset(a_offset) + *pb.offset(b_offset);
                }
            }
        }
        result
    }
}

impl <'a, T:MatrixElt> fmt::Show for MatrixView<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let ptr = self.m.as_ptr();
        try!(write!(f, "["));
        // Here we print row by row
        for r in range (0, self.rows) {
           try!(write!(f, "\n  "));
            for c in range (0, self.cols){
                let offset = self.cell_to_offset(r, c);
                let v = unsafe {*ptr.offset(offset)};
                try!(write!(f, "{} ", v));
            }
        }
        try!(write!(f, "\n]"));
        Ok(())
    }
}

/******************************************************
 *
 *   Unit tests follow.
 *
 *******************************************************/

#[cfg(test)]
mod test{
    use matrix::{Matrix, MatrixI64};

    #[test]
    fn test_basic(){
        let m1 :  MatrixI64 = Matrix::from_iter(10, 8, range(1, 100));
        let mut v1 = m1.view(2, 3, 4, 4);
        assert_eq!(v1.size(), (4u, 4u));
        assert_eq!(v1.num_rows(), 4);
        assert_eq!(v1.num_cols(), 4);
        assert_eq!(v1.is_scalar(), false);
        assert_eq!(v1.is_vector(), false);
        assert_eq!(v1.is_row(), false);
        assert_eq!(v1.is_col(), false);
        assert_eq!(v1.get(1,1), 44);
        v1.set(1,1, 300);
        assert_eq!(v1.get(1,1), 300);
    }
    #[test]
    fn test_view_multiple(){
        let m1 :  MatrixI64 = Matrix::from_iter(10, 8, range(1, 100));
        // We can create multiple views easily.
        let v1 = m1.view(1, 1, 4, 4);
        let v2 = m1.view(2, 2, 4, 4);
        let v3 = m1.view(2, 3, 4, 4);
        assert_eq!(v1.get(0, 0), 12);
        assert_eq!(v2.get(0, 0), 23);
        assert_eq!(v3.get(0, 0), 33);
    }

    #[test]
    fn test_view_matrix_mutability(){
        let mut m1 :  MatrixI64 = Matrix::from_iter(10, 8, range(1, 100));
        {
            let v1 = m1.view(2, 2, 4, 4);
            // The following line doesn't compile since we have borrowed an
            // immutable reference of m1 in v1.
            //m1.set(0, 0, 2);
            assert_eq!(v1.get(0, 0), 23);
        }
        m1.set(0, 0, 2);
    }

    #[test]
    fn test_cell_index_mapping(){
        let rows = 20;
        let cols = 10;
        let m : MatrixI64 = Matrix::new(rows, cols);
        let vrows = 4;
        let vcols = 3;
        let v = m.view(1, 1, vrows, vcols);
        assert_eq!(v.index_to_cell(3 + 2*vrows), (3, 2));
        assert_eq!(v.cell_to_index(3, 2), 3 + 2*vrows);
        assert_eq!(v.cell_to_index(3, 2), 11);
        assert_eq!(v.index_to_cell(11), (3, 2));
    }

    #[test]
    fn test_to_std_vec(){
        let m :  MatrixI64 = Matrix::from_iter(10, 8, range(1, 100));
        let vrows = 4;
        let vcols = 3;
        let mv = m.view(1, 1, vrows, vcols);
        let vv : Vec<i64> = vec![12, 13, 14, 15,
        22, 23, 24, 25,
        32, 33, 34, 35];
        assert_eq!(mv.to_std_vec(), vv);
    }

    #[test]
    fn test_addition(){
        let m :  MatrixI64 = Matrix::from_iter(10, 10, range(1, 200));
        let v1   = m.view(2, 2, 2, 2); // 23 , 24 , 33, 34
        let v2 = m.view(1, 1, 2, 2);  // 12, 13, 22, 33
        let m2 = v1 + v2; //
        let m3 : MatrixI64 = Matrix::from_slice(2, 2, vec![35, 37, 55, 57].as_slice());
        assert_eq!(m2, m3);
    }

    #[test]
    fn test_min_max(){
        let m :  MatrixI64 = Matrix::from_iter(20, 20, range(-100, 400));
        let v1   = m.view(2, 2, 6, 6);
        println!("v1 : {}", v1);
        assert_eq!(v1.max_scalar(), (47, 5, 5));
        assert_eq!(v1.min_scalar(), (-58, 0, 0));
        let (abs_max, rr, cc) = v1.abs_max_scalar();
        assert_eq!(abs_max, 58);
        assert_eq!((rr, cc), (0, 0));
        let (abs_min, rr, cc) = v1.abs_min_scalar();
        assert_eq!(abs_min, 2);
        assert_eq!((rr, cc), (0, 3));
    }

}

<|endoftext|>


<commit_before>//! Ordering and hashing for floating point data.
//!
//! This module provides tools to ease the creation of geometry data that can
//! be ordered and hashed. For Plexus, this is most useful for quickly
//! identifying unique geometry in an iterator expression or `Mesh`.
//!
//! This code is best used with the
//! [derivative](https://crates.io/crates/derivative) crate, which can be used
//! to specify a particular hashing function for a given field.
//!
//! # Examples
//!
//! Creating a basic vertex type that can be used for rendering and implements
//! `Hash`:
//!
//! ```no_run,rust
//! use plexus::ordered;
//!
//! // TODO: The `derive` and `derivative` attributes are commented out to prevent
//! //       build errors when running doc tests.
//! //#[derive(Derivative)]
//! //#[derivative(Hash)]
//! pub struct Vertex {
//!     //#[derivative(Hash(hash_with="ordered::hash_float_array"))]
//!     pub position: [f32; 3],
//! }
//! ```

use num::Float;
use ordered_float;
use std::hash::{Hash, Hasher};

// TODO: https://github.com/reem/rust-ordered-float/pull/28
pub type NotNan<T> = ordered_float::NotNaN<T>;
pub use ordered_float::OrderedFloat;

#[allow(non_camel_case_types)]
pub type r32 = NotNan<f32>;
#[allow(non_camel_case_types)]
pub type r64 = NotNan<f64>;

pub mod prelude {
    pub use ordered::HashConjugate;
}

pub trait HashConjugate: Sized {
    type Hash: Eq + Hash;

    fn into_hash(self) -> Self::Hash;
    fn from_hash(hash: Self::Hash) -> Self;
}

#[inline(always)]
pub fn hash_float<F, H>(f: &F, state: &mut H)
where
    F: Float,
    H: Hasher,
{
    OrderedFloat::from(*f).hash(state)
}

pub fn hash_float_slice<F, H>(slice: &[F], state: &mut H)
where
    F: Float,
    H: Hasher,
{
    for f in slice {
        hash_float(f, state);
    }
}

pub trait HashFloatArray {
    fn hash<H>(&self, state: &mut H)
    where
        H: Hasher;
}

pub fn hash_float_array<F, H>(array: &F, state: &mut H)
where
    F: HashFloatArray,
    H: Hasher,
{
    array.hash(state);
}

macro_rules! hash_float_array {
    (lengths => $($N:expr),*) => {$(
        impl<T> HashFloatArray for [T; $N]
        where
            T: Float,
        {
            fn hash<H>(&self, state: &mut H)
            where
                H: Hasher
            {
                for f in self.iter() {
                    hash_float(f, state)
                }
            }
        }
    )*};
}
hash_float_array!(lengths => 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
<commit_msg>Use `hash_float_slice` to implement `hash_float_array`.<commit_after>//! Ordering and hashing for floating point data.
//!
//! This module provides tools to ease the creation of geometry data that can
//! be ordered and hashed. For Plexus, this is most useful for quickly
//! identifying unique geometry in an iterator expression or `Mesh`, such as
//! using a `HashIndexer`.
//!
//! This code is best used with the
//! [derivative](https://crates.io/crates/derivative) crate, which can be used
//! to specify a particular hashing function for a given field.
//!
//! # Examples
//!
//! Creating a basic vertex type that can be used for rendering and implements
//! `Hash`:
//!
//! ```no_run,rust
//! use plexus::ordered;
//!
//! // TODO: The `derive` and `derivative` attributes are commented out to prevent
//! //       build errors when running doc tests.
//! //#[derive(Derivative)]
//! //#[derivative(Hash)]
//! pub struct Vertex {
//!     //#[derivative(Hash(hash_with="ordered::hash_float_array"))]
//!     pub position: [f32; 3],
//! }
//! ```

use num::Float;
use ordered_float;
use std::hash::{Hash, Hasher};

// TODO: https://github.com/reem/rust-ordered-float/pull/28
pub type NotNan<T> = ordered_float::NotNaN<T>;
pub use ordered_float::OrderedFloat;

#[allow(non_camel_case_types)]
pub type r32 = NotNan<f32>;
#[allow(non_camel_case_types)]
pub type r64 = NotNan<f64>;

pub mod prelude {
    pub use ordered::HashConjugate;
}

pub trait HashConjugate: Sized {
    type Hash: Eq + Hash;

    fn into_hash(self) -> Self::Hash;
    fn from_hash(hash: Self::Hash) -> Self;
}

#[inline(always)]
pub fn hash_float<F, H>(f: &F, state: &mut H)
where
    F: Float,
    H: Hasher,
{
    OrderedFloat::from(*f).hash(state)
}

pub fn hash_float_slice<F, H>(slice: &[F], state: &mut H)
where
    F: Float,
    H: Hasher,
{
    for f in slice {
        hash_float(f, state);
    }
}

pub trait HashFloatArray {
    fn hash<H>(&self, state: &mut H)
    where
        H: Hasher;
}

pub fn hash_float_array<F, H>(array: &F, state: &mut H)
where
    F: HashFloatArray,
    H: Hasher,
{
    array.hash(state);
}

macro_rules! hash_float_array {
    (lengths => $($N:expr),*) => {$(
        impl<T> HashFloatArray for [T; $N]
        where
            T: Float,
        {
            fn hash<H>(&self, state: &mut H)
            where
                H: Hasher
            {
                hash_float_slice(self, state)
            }
        }
    )*};
}
hash_float_array!(lengths => 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
<|endoftext|>


<commit_before>use {CreationError, Event};
use CreationError::OsError;
use libc;
use std::sync::atomic::AtomicBool;

#[cfg(feature = "window")]
use WindowBuilder;

#[cfg(feature = "headless")]
use HeadlessRendererBuilder;

use cocoa::base::{id, NSUInteger, nil};
use cocoa::appkit;
use cocoa::appkit::*;

use core_foundation::base::TCFType;
use core_foundation::string::CFString;
use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName};

use std::c_str::CString;

use events::Event::{MouseInput, MouseMoved, ReceivedCharacter, KeyboardInput};
use events::ElementState::{Pressed, Released};
use events::MouseButton::{LeftMouseButton, RightMouseButton};
use events;

pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor};

mod monitor;
mod event;

static mut shift_pressed: bool = false;
static mut ctrl_pressed: bool = false;
static mut win_pressed: bool = false;
static mut alt_pressed: bool = false;

pub struct Window {
    view: id,
    window: id,
    context: id,
    is_closed: AtomicBool,
}

pub struct HeadlessContext(Window);

impl Deref<Window> for HeadlessContext {
    fn deref(&self) -> &Window {
        &self.0
    }
}

#[cfg(feature = "window")]
impl Window {
    pub fn new(builder: WindowBuilder) -> Result<Window, CreationError> {
        Window::new_impl(builder.dimensions, builder.title.as_slice(), builder.monitor, true)
    }
}

#[cfg(feature = "headless")]
impl HeadlessContext {
    pub fn new(builder: HeadlessRendererBuilder) -> Result<HeadlessContext, CreationError> {
        Window::new_impl(Some(builder.dimensions), "", None, false)
            .map(|w| HeadlessContext(w))
    }
}

impl Window {
    fn new_impl(dimensions: Option<(uint, uint)>, title: &str, monitor: Option<MonitorID>, visible: bool) -> Result<Window, CreationError> {
        let app = match Window::create_app() {
            Some(app) => app,
            None      => { return Err(OsError(format!("Couldn't create NSApplication"))); },
        };
        let window = match Window::create_window(dimensions.unwrap_or((800, 600)), title, monitor) {
            Some(window) => window,
            None         => { return Err(OsError(format!("Couldn't create NSWindow"))); },
        };
        let view = match Window::create_view(window) {
            Some(view) => view,
            None       => { return Err(OsError(format!("Couldn't create NSView"))); },
        };

        let context = match Window::create_context(view) {
            Some(context) => context,
            None          => { return Err(OsError(format!("Couldn't create OpenGL context"))); },
        };

        unsafe {
            app.activateIgnoringOtherApps_(true);
            window.makeKeyAndOrderFront_(nil);
        }

        let window = Window {
            view: view,
            window: window,
            context: context,
            is_closed: AtomicBool::new(false),
        };

        Ok(window)
    }

    fn create_app() -> Option<id> {
        unsafe {
            let app = NSApp();
            if app == nil {
                None
            } else {
                app.setActivationPolicy_(NSApplicationActivationPolicyRegular);
                app.finishLaunching();
                Some(app)
            }
        }
    }

    fn create_window(dimensions: (uint, uint), title: &str, monitor: Option<MonitorID>) -> Option<id> {
        unsafe {
            let scr_frame = match monitor {
                Some(_) => {
                    let screen = NSScreen::mainScreen(nil);
                    NSScreen::frame(screen)
                }
                None    => {
                    let (width, height) = dimensions;
                    NSRect::new(NSPoint::new(0., 0.), NSSize::new(width as f64, height as f64))
                }
            };

             let masks = match monitor {
                Some(_) => NSBorderlessWindowMask as NSUInteger,
                None    => NSTitledWindowMask as NSUInteger | NSClosableWindowMask as NSUInteger | NSMiniaturizableWindowMask as NSUInteger,
            };

            let window = NSWindow::alloc(nil).initWithContentRect_styleMask_backing_defer_(
                scr_frame,
                masks,
                NSBackingStoreBuffered,
                false,
            );

            if window == nil {
                None
            } else {
                let title = NSString::alloc(nil).init_str(title);
                window.setTitle_(title);
                window.center();
                window.setAcceptsMouseMovedEvents_(true);
                if monitor.is_some() {
                    window.setLevel_(NSMainMenuWindowLevel as i64 + 1);
                }
                Some(window)
            }
        }
    }

    fn create_view(window: id) -> Option<id> {
        unsafe {
            let view = NSView::alloc(nil).init();
            if view == nil {
                None
            } else {
                view.setWantsBestResolutionOpenGLSurface_(true);
                window.setContentView_(view);
                Some(view)
            }
        }
    }

    fn create_context(view: id) -> Option<id> {
        unsafe {
            let attributes = [
                NSOpenGLPFADoubleBuffer as uint,
                NSOpenGLPFAClosestPolicy as uint,
                NSOpenGLPFAColorSize as uint, 24,
                NSOpenGLPFAAlphaSize as uint, 8,
                NSOpenGLPFADepthSize as uint, 24,
                NSOpenGLPFAStencilSize as uint, 8,
                0
            ];

            let pixelformat = NSOpenGLPixelFormat::alloc(nil).initWithAttributes_(&attributes);
            if pixelformat == nil {
                return None;
            }

            let context = NSOpenGLContext::alloc(nil).initWithFormat_shareContext_(pixelformat, nil);
            if context == nil {
                None
            } else {
                context.setView_(view);
                Some(context)
            }
        }
    }

    pub fn is_closed(&self) -> bool {
        use std::sync::atomic::Relaxed;
        self.is_closed.load(Relaxed)
    }

    pub fn set_title(&self, title: &str) {
        unsafe {
            let title = NSString::alloc(nil).init_str(title);
            self.window.setTitle_(title);
        }
    }

    pub fn show(&self) {
    }

    pub fn hide(&self) {
    }

    pub fn get_position(&self) -> Option<(int, int)> {
        unimplemented!()
    }

    pub fn set_position(&self, _x: int, _y: int) {
        unimplemented!()
    }

    pub fn get_inner_size(&self) -> Option<(uint, uint)> {
        unimplemented!()
    }

    pub fn get_outer_size(&self) -> Option<(uint, uint)> {
        unimplemented!()
    }

    pub fn set_inner_size(&self, _x: uint, _y: uint) {
        unimplemented!()
    }

    pub fn poll_events(&self) -> Vec<Event> {
        let mut events = Vec::new();

        loop {
            unsafe {
                let event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(
                    NSAnyEventMask as u64,
                    NSDate::distantPast(nil),
                    NSDefaultRunLoopMode,
                    true);
                if event == nil { break; }
                NSApp().sendEvent_(event);

                match event.get_type() {
                    NSLeftMouseDown         => { events.push(MouseInput(Pressed, LeftMouseButton)); },
                    NSLeftMouseUp           => { events.push(MouseInput(Released, LeftMouseButton)); },
                    NSRightMouseDown        => { events.push(MouseInput(Pressed, RightMouseButton)); },
                    NSRightMouseUp          => { events.push(MouseInput(Released, RightMouseButton)); },
                    NSMouseMoved            => {
                        let window_point = event.locationInWindow();
                        let view_point = self.view.convertPoint_fromView_(window_point, nil);
                        events.push(MouseMoved((view_point.x as int, view_point.y as int)));
                    },
                    NSKeyDown               => {
                        let received_str = CString::new(event.characters().UTF8String(), false);
                        for received_char in received_str.as_str().unwrap().chars() {
                            if received_char.is_ascii() {
                                events.push(ReceivedCharacter(received_char));
                            }
                        }

                        let vkey =  event::vkeycode_to_element(event.keycode());
                        events.push(KeyboardInput(Pressed, event.keycode() as u8, vkey));
                    },
                    NSKeyUp                 => {
                        let vkey =  event::vkeycode_to_element(event.keycode());
                        events.push(KeyboardInput(Released, event.keycode() as u8, vkey));
                    },
                    NSFlagsChanged          => {
                        let shift_modifier = Window::modifier_event(event, appkit::NSShiftKeyMask as u64, events::VirtualKeyCode::LShift, shift_pressed);
                        if shift_modifier.is_some() {
                            shift_pressed = !shift_pressed;
                            events.push(shift_modifier.unwrap());
                        }
                        let ctrl_modifier = Window::modifier_event(event, appkit::NSControlKeyMask as u64, events::VirtualKeyCode::LControl, ctrl_pressed);
                        if ctrl_modifier.is_some() {
                            ctrl_pressed = !ctrl_pressed;
                            events.push(ctrl_modifier.unwrap());
                        }
                        let win_modifier = Window::modifier_event(event, appkit::NSCommandKeyMask as u64, events::VirtualKeyCode::LWin, win_pressed);
                        if win_modifier.is_some() {
                            win_pressed = !win_pressed;
                            events.push(win_modifier.unwrap());
                        }
                        let alt_modifier = Window::modifier_event(event, appkit::NSAlternateKeyMask as u64, events::VirtualKeyCode::LAlt, alt_pressed);
                        if alt_modifier.is_some() {
                            alt_pressed = !alt_pressed;
                            events.push(alt_modifier.unwrap());
                        }
                    },
                    NSScrollWheel           => { },
                    NSOtherMouseDown        => { },
                    NSOtherMouseUp          => { },
                    NSOtherMouseDragged     => { },
                    _                       => { },
                }
            }
        }
        events
    }

    unsafe fn modifier_event(event: id, keymask: u64, key: events::VirtualKeyCode, key_pressed: bool) -> Option<Event> {
        if !key_pressed && Window::modifier_key_pressed(event, keymask) {
            return Some(KeyboardInput(Pressed, event.keycode() as u8, Some(key)));
        }
        else if key_pressed && !Window::modifier_key_pressed(event, keymask) {
            return Some(KeyboardInput(Released, event.keycode() as u8, Some(key)));
        }

        return None;
    }

    unsafe fn modifier_key_pressed(event: id, modifier: u64) -> bool {
        event.modifierFlags() & modifier != 0
    }

    pub fn wait_events(&self) -> Vec<Event> {
        unsafe {
            let event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(
                NSAnyEventMask as u64,
                NSDate::distantFuture(nil),
                NSDefaultRunLoopMode,
                false);
            NSApp().sendEvent_(event);

            self.poll_events()
        }
    }

    pub unsafe fn make_current(&self) {
        self.context.makeCurrentContext();
    }

    pub fn get_proc_address(&self, _addr: &str) -> *const () {
        let symbol_name: CFString = from_str(_addr).unwrap();
        let framework_name: CFString = from_str("com.apple.opengl").unwrap();
        let framework = unsafe {
            CFBundleGetBundleWithIdentifier(framework_name.as_concrete_TypeRef())
        };
        let symbol = unsafe {
            CFBundleGetFunctionPointerForName(framework, symbol_name.as_concrete_TypeRef())
        };
        symbol as *const ()
    }

    pub fn swap_buffers(&self) {
        unsafe { self.context.flushBuffer(); }
    }

    pub fn platform_display(&self) -> *mut libc::c_void {
        unimplemented!()
    }
}
<commit_msg>Add support for setting a window delegate, and implement close event on mac.<commit_after>use {CreationError, Event};
use CreationError::OsError;
use libc;

#[cfg(feature = "window")]
use WindowBuilder;

#[cfg(feature = "headless")]
use HeadlessRendererBuilder;

use cocoa::base::{id, NSUInteger, nil, objc_allocateClassPair, class, objc_registerClassPair};
use cocoa::base::{selector, msg_send, class_addMethod, class_addIvar};
use cocoa::base::{object_setInstanceVariable, object_getInstanceVariable};
use cocoa::appkit;
use cocoa::appkit::*;

use core_foundation::base::TCFType;
use core_foundation::string::CFString;
use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName};

use std::c_str::CString;
use std::mem;
use std::ptr;
use std::sync::atomic::{AtomicBool, Relaxed};

use events::Event::{MouseInput, MouseMoved, ReceivedCharacter, KeyboardInput};
use events::ElementState::{Pressed, Released};
use events::MouseButton::{LeftMouseButton, RightMouseButton};
use events;

pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor};

mod monitor;
mod event;

static mut shift_pressed: bool = false;
static mut ctrl_pressed: bool = false;
static mut win_pressed: bool = false;
static mut alt_pressed: bool = false;

static DELEGATE_NAME: &'static [u8] = b"glutin_window_delegate\0";
static DELEGATE_THIS_IVAR: &'static [u8] = b"glutin_this";

struct InternalState {
    is_closed: AtomicBool,
}

impl InternalState {
    fn new() -> InternalState {
        InternalState {
            is_closed: AtomicBool::new(false),
        }
    }
}

pub struct Window {
    view: id,
    window: id,
    context: id,
    state: Box<InternalState>,
}

pub struct HeadlessContext(Window);

impl Deref<Window> for HeadlessContext {
    fn deref(&self) -> &Window {
        &self.0
    }
}

#[cfg(feature = "window")]
impl Window {
    pub fn new(builder: WindowBuilder) -> Result<Window, CreationError> {
        Window::new_impl(builder.dimensions, builder.title.as_slice(), builder.monitor, true)
    }
}

#[cfg(feature = "headless")]
impl HeadlessContext {
    pub fn new(builder: HeadlessRendererBuilder) -> Result<HeadlessContext, CreationError> {
        Window::new_impl(Some(builder.dimensions), "", None, false)
            .map(|w| HeadlessContext(w))
    }
}

extern fn window_should_close(this: id, _: id) -> id {
    unsafe {
        let mut stored_value = ptr::null_mut();
        object_getInstanceVariable(this, DELEGATE_THIS_IVAR.as_ptr() as *const i8, &mut stored_value);
        let state = stored_value as *mut InternalState;
        (*state).is_closed.store(true, Relaxed);
    }
    0
}

impl Window {
    fn new_impl(dimensions: Option<(uint, uint)>, title: &str, monitor: Option<MonitorID>, visible: bool) -> Result<Window, CreationError> {
        let app = match Window::create_app() {
            Some(app) => app,
            None      => { return Err(OsError(format!("Couldn't create NSApplication"))); },
        };
        let window = match Window::create_window(dimensions.unwrap_or((800, 600)), title, monitor) {
            Some(window) => window,
            None         => { return Err(OsError(format!("Couldn't create NSWindow"))); },
        };
        let view = match Window::create_view(window) {
            Some(view) => view,
            None       => { return Err(OsError(format!("Couldn't create NSView"))); },
        };

        let context = match Window::create_context(view) {
            Some(context) => context,
            None          => { return Err(OsError(format!("Couldn't create OpenGL context"))); },
        };

        unsafe {
            app.activateIgnoringOtherApps_(true);
            window.makeKeyAndOrderFront_(nil);
        }

        let window = Window {
            view: view,
            window: window,
            context: context,
            state: box InternalState::new(),
        };

        // Set up the window delegate to receive events
        let ptr_size = mem::size_of::<libc::intptr_t>() as u64;
        let ns_object = class("NSObject");

        unsafe {
            // Create a delegate class, add callback methods and store InternalState as user data.
            let delegate = objc_allocateClassPair(ns_object, DELEGATE_NAME.as_ptr() as *const i8, 0);
            class_addMethod(delegate, selector("windowShouldClose:"), window_should_close, "B@:@".to_c_str().as_ptr());
            class_addIvar(delegate, DELEGATE_THIS_IVAR.as_ptr() as *const i8, ptr_size, 3, "?".to_c_str().as_ptr());
            objc_registerClassPair(delegate);

            let del_obj = msg_send()(delegate, selector("alloc"));
            let del_obj: id = msg_send()(del_obj, selector("init"));
            object_setInstanceVariable(del_obj, DELEGATE_THIS_IVAR.as_ptr() as *const i8,
                                        &*window.state as *const InternalState as *mut libc::c_void);
            let _: id = msg_send()(window.window, selector("setDelegate:"), del_obj);
        }

        Ok(window)
    }

    fn create_app() -> Option<id> {
        unsafe {
            let app = NSApp();
            if app == nil {
                None
            } else {
                app.setActivationPolicy_(NSApplicationActivationPolicyRegular);
                app.finishLaunching();
                Some(app)
            }
        }
    }

    fn create_window(dimensions: (uint, uint), title: &str, monitor: Option<MonitorID>) -> Option<id> {
        unsafe {
            let scr_frame = match monitor {
                Some(_) => {
                    let screen = NSScreen::mainScreen(nil);
                    NSScreen::frame(screen)
                }
                None    => {
                    let (width, height) = dimensions;
                    NSRect::new(NSPoint::new(0., 0.), NSSize::new(width as f64, height as f64))
                }
            };

             let masks = match monitor {
                Some(_) => NSBorderlessWindowMask as NSUInteger,
                None    => NSTitledWindowMask as NSUInteger |
                           NSClosableWindowMask as NSUInteger |
                           NSMiniaturizableWindowMask as NSUInteger |
                           NSResizableWindowMask as NSUInteger,
            };

            let window = NSWindow::alloc(nil).initWithContentRect_styleMask_backing_defer_(
                scr_frame,
                masks,
                NSBackingStoreBuffered,
                false,
            );

            if window == nil {
                None
            } else {
                let title = NSString::alloc(nil).init_str(title);
                window.setTitle_(title);
                window.center();
                window.setAcceptsMouseMovedEvents_(true);
                if monitor.is_some() {
                    window.setLevel_(NSMainMenuWindowLevel as i64 + 1);
                }
                Some(window)
            }
        }
    }

    fn create_view(window: id) -> Option<id> {
        unsafe {
            let view = NSView::alloc(nil).init();
            if view == nil {
                None
            } else {
                view.setWantsBestResolutionOpenGLSurface_(true);
                window.setContentView_(view);
                Some(view)
            }
        }
    }

    fn create_context(view: id) -> Option<id> {
        unsafe {
            let attributes = [
                NSOpenGLPFADoubleBuffer as uint,
                NSOpenGLPFAClosestPolicy as uint,
                NSOpenGLPFAColorSize as uint, 24,
                NSOpenGLPFAAlphaSize as uint, 8,
                NSOpenGLPFADepthSize as uint, 24,
                NSOpenGLPFAStencilSize as uint, 8,
                0
            ];

            let pixelformat = NSOpenGLPixelFormat::alloc(nil).initWithAttributes_(&attributes);
            if pixelformat == nil {
                return None;
            }

            let context = NSOpenGLContext::alloc(nil).initWithFormat_shareContext_(pixelformat, nil);
            if context == nil {
                None
            } else {
                context.setView_(view);
                Some(context)
            }
        }
    }

    pub fn is_closed(&self) -> bool {
        self.state.is_closed.load(Relaxed)
    }

    pub fn set_title(&self, title: &str) {
        unsafe {
            let title = NSString::alloc(nil).init_str(title);
            self.window.setTitle_(title);
        }
    }

    pub fn show(&self) {
    }

    pub fn hide(&self) {
    }

    pub fn get_position(&self) -> Option<(int, int)> {
        unimplemented!()
    }

    pub fn set_position(&self, _x: int, _y: int) {
        unimplemented!()
    }

    pub fn get_inner_size(&self) -> Option<(uint, uint)> {
        unimplemented!()
    }

    pub fn get_outer_size(&self) -> Option<(uint, uint)> {
        unimplemented!()
    }

    pub fn set_inner_size(&self, _x: uint, _y: uint) {
        unimplemented!()
    }

    pub fn poll_events(&self) -> Vec<Event> {
        let mut events = Vec::new();

        loop {
            unsafe {
                let event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(
                    NSAnyEventMask as u64,
                    NSDate::distantPast(nil),
                    NSDefaultRunLoopMode,
                    true);
                if event == nil { break; }
                NSApp().sendEvent_(event);

                match event.get_type() {
                    NSLeftMouseDown         => { events.push(MouseInput(Pressed, LeftMouseButton)); },
                    NSLeftMouseUp           => { events.push(MouseInput(Released, LeftMouseButton)); },
                    NSRightMouseDown        => { events.push(MouseInput(Pressed, RightMouseButton)); },
                    NSRightMouseUp          => { events.push(MouseInput(Released, RightMouseButton)); },
                    NSMouseMoved            => {
                        let window_point = event.locationInWindow();
                        let view_point = self.view.convertPoint_fromView_(window_point, nil);
                        events.push(MouseMoved((view_point.x as int, view_point.y as int)));
                    },
                    NSKeyDown               => {
                        let received_str = CString::new(event.characters().UTF8String(), false);
                        for received_char in received_str.as_str().unwrap().chars() {
                            if received_char.is_ascii() {
                                events.push(ReceivedCharacter(received_char));
                            }
                        }

                        let vkey =  event::vkeycode_to_element(event.keycode());
                        events.push(KeyboardInput(Pressed, event.keycode() as u8, vkey));
                    },
                    NSKeyUp                 => {
                        let vkey =  event::vkeycode_to_element(event.keycode());
                        events.push(KeyboardInput(Released, event.keycode() as u8, vkey));
                    },
                    NSFlagsChanged          => {
                        let shift_modifier = Window::modifier_event(event, appkit::NSShiftKeyMask as u64, events::VirtualKeyCode::LShift, shift_pressed);
                        if shift_modifier.is_some() {
                            shift_pressed = !shift_pressed;
                            events.push(shift_modifier.unwrap());
                        }
                        let ctrl_modifier = Window::modifier_event(event, appkit::NSControlKeyMask as u64, events::VirtualKeyCode::LControl, ctrl_pressed);
                        if ctrl_modifier.is_some() {
                            ctrl_pressed = !ctrl_pressed;
                            events.push(ctrl_modifier.unwrap());
                        }
                        let win_modifier = Window::modifier_event(event, appkit::NSCommandKeyMask as u64, events::VirtualKeyCode::LWin, win_pressed);
                        if win_modifier.is_some() {
                            win_pressed = !win_pressed;
                            events.push(win_modifier.unwrap());
                        }
                        let alt_modifier = Window::modifier_event(event, appkit::NSAlternateKeyMask as u64, events::VirtualKeyCode::LAlt, alt_pressed);
                        if alt_modifier.is_some() {
                            alt_pressed = !alt_pressed;
                            events.push(alt_modifier.unwrap());
                        }
                    },
                    NSScrollWheel           => { },
                    NSOtherMouseDown        => { },
                    NSOtherMouseUp          => { },
                    NSOtherMouseDragged     => { },
                    _                       => { },
                }
            }
        }
        events
    }

    unsafe fn modifier_event(event: id, keymask: u64, key: events::VirtualKeyCode, key_pressed: bool) -> Option<Event> {
        if !key_pressed && Window::modifier_key_pressed(event, keymask) {
            return Some(KeyboardInput(Pressed, event.keycode() as u8, Some(key)));
        }
        else if key_pressed && !Window::modifier_key_pressed(event, keymask) {
            return Some(KeyboardInput(Released, event.keycode() as u8, Some(key)));
        }

        return None;
    }

    unsafe fn modifier_key_pressed(event: id, modifier: u64) -> bool {
        event.modifierFlags() & modifier != 0
    }

    pub fn wait_events(&self) -> Vec<Event> {
        unsafe {
            let event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(
                NSAnyEventMask as u64,
                NSDate::distantFuture(nil),
                NSDefaultRunLoopMode,
                false);
            NSApp().sendEvent_(event);

            self.poll_events()
        }
    }

    pub unsafe fn make_current(&self) {
        self.context.makeCurrentContext();
    }

    pub fn get_proc_address(&self, _addr: &str) -> *const () {
        let symbol_name: CFString = from_str(_addr).unwrap();
        let framework_name: CFString = from_str("com.apple.opengl").unwrap();
        let framework = unsafe {
            CFBundleGetBundleWithIdentifier(framework_name.as_concrete_TypeRef())
        };
        let symbol = unsafe {
            CFBundleGetFunctionPointerForName(framework, symbol_name.as_concrete_TypeRef())
        };
        symbol as *const ()
    }

    pub fn swap_buffers(&self) {
        unsafe { self.context.flushBuffer(); }
    }

    pub fn platform_display(&self) -> *mut libc::c_void {
        unimplemented!()
    }
}
<|endoftext|>


<commit_before>//! Traits and essential types inteded for blanket imports.

pub use {
    Cast,
    Continue,
    IsA,
    ObjectExt,
    StaticType,
    StaticVariantType,
    ToValue,
    ToVariant,
};
<commit_msg>Fix spelling.<commit_after>//! Traits and essential types intended for blanket imports.

pub use {
    Cast,
    Continue,
    IsA,
    ObjectExt,
    StaticType,
    StaticVariantType,
    ToValue,
    ToVariant,
};
<|endoftext|>


<commit_before><commit_msg>Updates based on code review by @nastevens<commit_after><|endoftext|>


<commit_before>use crate::git;
use log::{debug, error, info, trace};
use regex::Regex;
use reqwest;
use serde_derive::{Deserialize, Serialize};
use std::fmt;
use std::io::{stdin, stdout, Write};

pub trait Remote {
    /// Get the ID of the project associated with the repository
    fn get_project_id(&mut self) -> Result<&str, &str>;

    /// Get the branch associated with the merge request having the given ID
    fn get_req_branch(&mut self, mr_id: i64) -> Result<String, &str>;
}

/// Print a pretty remote
impl fmt::Display for Remote {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Remote")
    }
}

/// Debug a remote
impl fmt::Debug for Remote {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

#[derive(Debug)]
struct GitHub {
    id: String,
    name: String,
    origin: String,
    api_root: String,
}

impl Remote for GitHub {
    fn get_project_id(&mut self) -> Result<&str, &str> {
        Ok(&self.id)
    }

    fn get_req_branch(&mut self, mr_id: i64) -> Result<String, &str> {
        Ok(format!("pr/{}", mr_id))
    }
}

#[derive(Debug)]
struct GitLab {
    id: String,
    domain: String,
    name: String,
    namespace: String,
    origin: String,
    api_root: String,
    api_key: String,
}

impl Remote for GitLab {
    fn get_project_id(&mut self) -> Result<&str, &str> {
        if self.id.is_empty() {
            self.id = format!("{}", query_gitlab_project_id(self)?);
        }
        Ok(&self.id)
    }

    fn get_req_branch(&mut self, mr_id: i64) -> Result<String, &str> {
        query_gitlab_branch_name(self, mr_id)
    }
}

#[derive(Serialize, Deserialize, Debug)]
struct GitLabProject {
    id: i64,
    description: String,
    name: String,
    path: String,
    path_with_namespace: String,
}

fn query_gitlab_api(url: reqwest::Url, token: String) -> reqwest::Response {
    let client = reqwest::Client::new();
    client
        .get(url)
        .header("PRIVATE-TOKEN", token)
        .send()
        .expect("failed to send request")
}

/// Query the GitLab API for remote's project
fn query_gitlab_project_id(remote: &GitLab) -> Result<i64, &'static str> {
    trace!("Querying GitLab API for {:?}", remote);
    let url = reqwest::Url::parse(&format!(
        "{}/projects/{}%2F{}",
        remote.api_root, remote.namespace, remote.name
    ))
    .unwrap();
    let mut resp = query_gitlab_api(url, remote.api_key.to_string());
    debug!("Project ID query response: {:?}", resp);
    if !resp.status().is_success() {
        match search_gitlab_project_id(remote) {
            Ok(id) => {
                return Ok(id);
            },
            Err(_) => {
                return Err("Unable to get the project ID from the GitLab API.\nFind and configure \
                   your project ID using the instructions at: \
                   https://github.com/arusahni/git-req/wiki/Finding-Project-IDs");
            }
        }
    }
    let buf: GitLabProject = resp.json().expect("failed to read response");
    debug!("{:?}", buf);
    Ok(buf.id)
}

#[derive(Serialize, Deserialize, Debug)]
struct GitLabNamespace {
    id: i64,
    name: String,
    path: String,
    kind: String,
    full_path: String,
}

/// Search GitLab for the project ID (if the direct lookup didn't work)
fn search_gitlab_project_id(remote: &GitLab) -> Result<i64, &'static str> {
    trace!("Searching GitLab API for namespace {:?} by project name", remote.namespace);
    let url = reqwest::Url::parse(&format!("{}/namespaces/{}", remote.api_root, remote.namespace)).unwrap();
    let mut resp = query_gitlab_api(url, remote.api_key.to_string());
    debug!("Namespace ID query response: {:?}", resp);
    if !resp.status().is_success() {
        return Err("Couldn't find namespace");
    }
    let ns_buf: GitLabNamespace = resp.json().expect("failed to read response");
    let url = match ns_buf.kind.as_ref() {
        "user" => reqwest::Url::parse(&format!("{}/users/{}/projects", remote.api_root, ns_buf.id)).unwrap(),
        "group" => reqwest::Url::parse(&format!("{}/groups/{}/projects?search={}", remote.api_root, ns_buf.id, remote.name)).unwrap(),
        _ => {
            error!("Unknown namespace kind {:?}", ns_buf.kind);
            return Err("Unknown namespace");
        }
    };
    let mut resp = query_gitlab_api(url, remote.api_key.to_string());
    let projects: Vec<GitLabProject> = resp.json().expect("failed to read projects response");
    match projects.iter().find(|&prj| prj.name == remote.name) {
        Some(project) => Ok(project.id),
        None => Err("Couldn't find project"),
    }
}

#[derive(Serialize, Deserialize, Debug)]
struct GitLabMergeRequest {
    id: i64,
    iid: i64,
    title: String,
    target_branch: String,
    source_branch: String,
    sha: String,
    web_url: String,
}

/// Get the project ID from config
fn load_project_id() -> Option<String> {
    match git::get_config("projectid") {
        Some(project_id) => Some(project_id),
        None => {
            debug!("No project ID found");
            None
        }
    }
}

/// Query the GitLab API for the branch corresponding to the MR
fn query_gitlab_branch_name(remote: &GitLab, mr_id: i64) -> Result<String, &str> {
    let client = reqwest::Client::new();
    let url = reqwest::Url::parse(&format!(
        "{}/projects/{}/merge_requests/{}",
        remote.api_root, remote.id, mr_id
    ))
    .unwrap();
    let mut resp = client
        .get(url)
        .header("PRIVATE-TOKEN", remote.api_key.to_string())
        .send()
        .expect("failed to send request");
    debug!("Response: {:?}", resp);
    let buf: GitLabMergeRequest = match resp.json() {
        Ok(buf) => buf,
        Err(_) => {
            return Err("failed to read response");
        }
    };
    Ok(buf.source_branch)
}

/// Extract the project name from a Github origin URL
fn get_github_project_name(origin: &str) -> String {
    trace!("Getting project name for: {}", origin);
    let project_regex = Regex::new(r".*:(.*/\S+)\.git\w*$").unwrap();
    let captures = project_regex.captures(origin).unwrap();
    String::from(&captures[1])
}

/// Extract the project name from a GitLab origin URL
fn get_gitlab_project_name(origin: &str) -> String {
    trace!("Getting project name for: {}", origin);
    let project_regex = Regex::new(r".*/(\S+)\.git$").unwrap();
    let captures = project_regex.captures(origin).unwrap();
    String::from(&captures[1])
}

/// Extract the project namespace from a GitLab origin URL
fn get_gitlab_project_namespace(origin: &str) -> Option<String> {
    trace!("Getting project namespace for: {}", origin);
    let project_regex = Regex::new(r".*[/:](\S+)/\S+\.git$").unwrap();
    match project_regex.captures(origin) {
        Some(captures) => Some(String::from(&captures[1])),
        None => None
    }
}

/// Get the domain from an origin URL
pub fn get_domain(origin: &str) -> Result<&str, String> {
    let domain_regex = Regex::new(r"((http[s]?|ssh)://)?(\S+@)?(?P<domain>([^:/])+)").unwrap();
    let captures = domain_regex.captures(origin);
    if captures.is_none() {
        return Err(String::from("invalid remote set"));
    }
    Ok(captures.unwrap().name("domain").map_or("", |x| x.as_str()))
}

/// Get a remote struct from an origin URL
pub fn get_remote(origin: &str) -> Result<Box<Remote>, String> {
    let domain = get_domain(origin)?;
    Ok(match domain {
        "github.com" => Box::new(GitHub {
            id: get_github_project_name(origin),
            name: get_github_project_name(origin),
            origin: String::from(origin),
            api_root: String::from("https://api.github.com/repos"),
        }),
        // For now, if not GitHub, then GitLab
        gitlab_domain => {
            let namespace = match get_gitlab_project_namespace(origin) {
                Some(ns) => ns,
                None => {
                    return Err(String::from("Could not parse the GitLab project namespace from the origin."));
                }
            };
            let mut remote = GitLab {
                id: String::from(""),
                domain: String::from(gitlab_domain),
                name: get_gitlab_project_name(origin),
                namespace,
                origin: String::from(origin),
                api_root: format!("https://{}/api/v4", gitlab_domain),
                api_key: String::from(""),
            };
            let apikey = match git::get_req_config(&domain, "apikey") {
                Some(key) => key,
                None => {
                    let mut newkey = String::new();
                    print!("Please enter the read-only API key for {}: ", gitlab_domain);
                    let _ = stdout().flush();
                    stdin()
                        .read_line(&mut newkey)
                        .expect("Did not input a correct key");
                    trace!("New Key: {}", &newkey);
                    git::set_req_config(&domain, "apikey", &newkey.trim());
                    String::from(newkey.trim())
                }
            };
            info!("API Key: {}", &apikey);
            remote.api_key = apikey;
            let project_id = match load_project_id() {
                Some(x) => x,
                None => {
                    let project_id_str = match remote.get_project_id() {
                        Ok(id_str) => Ok(id_str),
                        Err(e) => {
                            info!("Error getting project ID: {:?}", e);
                            Err(e)
                        }
                    }?;
                    git::set_config("projectid", project_id_str);
                    String::from(project_id_str)
                }
            };
            info!("Got project ID: {}", project_id);
            remote.id = project_id;
            Box::new(remote)
        }
    })
}

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

    #[test]
    fn test_get_gitlab_project_namespace_http() {
        let ns = get_gitlab_project_namespace("https://gitlab.com/my_namespace/my_project.git");
        assert!(ns.is_some());
        assert_eq!("my_namespace", ns.unwrap());
    }

    #[test]
    fn test_get_gitlab_project_namespace_git() {
        let ns = get_gitlab_project_namespace("git@gitlab.com:my_namespace/my_project.git");
        assert!(ns.is_some());
        assert_eq!("my_namespace", ns.unwrap());
    }

    #[test]
    fn test_get_gitlab_project_name_http() {
        let ns = get_gitlab_project_name("https://gitlab.com/my_namespace/my_project.git");
        assert_eq!("my_project", ns);
    }

    #[test]
    fn test_get_gitlab_project_name_git() {
        let ns = get_gitlab_project_name("git@gitlab.com:my_namespace/my_project.git");
        assert_eq!("my_project", ns);
    }
}
<commit_msg>Improve debug logging for fallback.<commit_after>use crate::git;
use log::{debug, error, info, trace};
use regex::Regex;
use reqwest;
use serde_derive::{Deserialize, Serialize};
use std::fmt;
use std::io::{stdin, stdout, Write};

pub trait Remote {
    /// Get the ID of the project associated with the repository
    fn get_project_id(&mut self) -> Result<&str, &str>;

    /// Get the branch associated with the merge request having the given ID
    fn get_req_branch(&mut self, mr_id: i64) -> Result<String, &str>;
}

/// Print a pretty remote
impl fmt::Display for Remote {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Remote")
    }
}

/// Debug a remote
impl fmt::Debug for Remote {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

#[derive(Debug)]
struct GitHub {
    id: String,
    name: String,
    origin: String,
    api_root: String,
}

impl Remote for GitHub {
    fn get_project_id(&mut self) -> Result<&str, &str> {
        Ok(&self.id)
    }

    fn get_req_branch(&mut self, mr_id: i64) -> Result<String, &str> {
        Ok(format!("pr/{}", mr_id))
    }
}

#[derive(Debug)]
struct GitLab {
    id: String,
    domain: String,
    name: String,
    namespace: String,
    origin: String,
    api_root: String,
    api_key: String,
}

impl Remote for GitLab {
    fn get_project_id(&mut self) -> Result<&str, &str> {
        if self.id.is_empty() {
            self.id = format!("{}", query_gitlab_project_id(self)?);
        }
        Ok(&self.id)
    }

    fn get_req_branch(&mut self, mr_id: i64) -> Result<String, &str> {
        query_gitlab_branch_name(self, mr_id)
    }
}

#[derive(Serialize, Deserialize, Debug)]
struct GitLabProject {
    id: i64,
    description: String,
    name: String,
    path: String,
    path_with_namespace: String,
}

fn query_gitlab_api(url: reqwest::Url, token: String) -> reqwest::Response {
    let client = reqwest::Client::new();
    client
        .get(url)
        .header("PRIVATE-TOKEN", token)
        .send()
        .expect("failed to send request")
}

/// Query the GitLab API for remote's project
fn query_gitlab_project_id(remote: &GitLab) -> Result<i64, &'static str> {
    trace!("Querying GitLab API for {:?}", remote);
    let url = reqwest::Url::parse(&format!(
        "{}/projects/{}%2F{}",
        remote.api_root, remote.namespace, remote.name
    ))
    .unwrap();
    let mut resp = query_gitlab_api(url, remote.api_key.to_string());
    debug!("Project ID query response: {:?}", resp);
    if !resp.status().is_success() {
        match search_gitlab_project_id(remote) {
            Ok(id) => {
                return Ok(id);
            },
            Err(_) => {
                return Err("Unable to get the project ID from the GitLab API.\nFind and configure \
                   your project ID using the instructions at: \
                   https://github.com/arusahni/git-req/wiki/Finding-Project-IDs");
            }
        }
    }
    let buf: GitLabProject = resp.json().expect("failed to read response");
    debug!("{:?}", buf);
    Ok(buf.id)
}

#[derive(Serialize, Deserialize, Debug)]
struct GitLabNamespace {
    id: i64,
    name: String,
    path: String,
    kind: String,
    full_path: String,
}

/// Search GitLab for the project ID (if the direct lookup didn't work)
fn search_gitlab_project_id(remote: &GitLab) -> Result<i64, &'static str> {
    trace!("Searching GitLab API for namespace {:?} by project name", remote.namespace);
    let url = reqwest::Url::parse(&format!("{}/namespaces/{}", remote.api_root, remote.namespace)).unwrap();
    let mut resp = query_gitlab_api(url, remote.api_key.to_string());
    debug!("Namespace ID query response: {:?}", resp);
    if !resp.status().is_success() {
        return Err("Couldn't find namespace");
    }
    let ns_buf: GitLabNamespace = resp.json().expect("failed to read response");
    debug!("Querying namespace {:?}", ns_buf);
    let url = match ns_buf.kind.as_ref() {
        "user" => reqwest::Url::parse(&format!("{}/users/{}/projects", remote.api_root, ns_buf.id)).unwrap(),
        "group" => reqwest::Url::parse(&format!("{}/groups/{}/projects?search={}", remote.api_root, ns_buf.id, remote.name)).unwrap(),
        _ => {
            error!("Unknown namespace kind {:?}", ns_buf.kind);
            return Err("Unknown namespace");
        }
    };
    let mut resp = query_gitlab_api(url, remote.api_key.to_string());
    debug!("Project ID query response: {:?}", resp);
    let projects: Vec<GitLabProject> = resp.json().expect("failed to read projects response");
    match projects.iter().find(|&prj| prj.name == remote.name) {
        Some(project) => Ok(project.id),
        None => Err("Couldn't find project"),
    }
}

#[derive(Serialize, Deserialize, Debug)]
struct GitLabMergeRequest {
    id: i64,
    iid: i64,
    title: String,
    target_branch: String,
    source_branch: String,
    sha: String,
    web_url: String,
}

/// Get the project ID from config
fn load_project_id() -> Option<String> {
    match git::get_config("projectid") {
        Some(project_id) => Some(project_id),
        None => {
            debug!("No project ID found");
            None
        }
    }
}

/// Query the GitLab API for the branch corresponding to the MR
fn query_gitlab_branch_name(remote: &GitLab, mr_id: i64) -> Result<String, &str> {
    let client = reqwest::Client::new();
    let url = reqwest::Url::parse(&format!(
        "{}/projects/{}/merge_requests/{}",
        remote.api_root, remote.id, mr_id
    ))
    .unwrap();
    let mut resp = client
        .get(url)
        .header("PRIVATE-TOKEN", remote.api_key.to_string())
        .send()
        .expect("failed to send request");
    debug!("Response: {:?}", resp);
    let buf: GitLabMergeRequest = match resp.json() {
        Ok(buf) => buf,
        Err(_) => {
            return Err("failed to read response");
        }
    };
    Ok(buf.source_branch)
}

/// Extract the project name from a Github origin URL
fn get_github_project_name(origin: &str) -> String {
    trace!("Getting project name for: {}", origin);
    let project_regex = Regex::new(r".*:(.*/\S+)\.git\w*$").unwrap();
    let captures = project_regex.captures(origin).unwrap();
    String::from(&captures[1])
}

/// Extract the project name from a GitLab origin URL
fn get_gitlab_project_name(origin: &str) -> String {
    trace!("Getting project name for: {}", origin);
    let project_regex = Regex::new(r".*/(\S+)\.git$").unwrap();
    let captures = project_regex.captures(origin).unwrap();
    String::from(&captures[1])
}

/// Extract the project namespace from a GitLab origin URL
fn get_gitlab_project_namespace(origin: &str) -> Option<String> {
    trace!("Getting project namespace for: {}", origin);
    let project_regex = Regex::new(r".*[/:](\S+)/\S+\.git$").unwrap();
    match project_regex.captures(origin) {
        Some(captures) => Some(String::from(&captures[1])),
        None => None
    }
}

/// Get the domain from an origin URL
pub fn get_domain(origin: &str) -> Result<&str, String> {
    let domain_regex = Regex::new(r"((http[s]?|ssh)://)?(\S+@)?(?P<domain>([^:/])+)").unwrap();
    let captures = domain_regex.captures(origin);
    if captures.is_none() {
        return Err(String::from("invalid remote set"));
    }
    Ok(captures.unwrap().name("domain").map_or("", |x| x.as_str()))
}

/// Get a remote struct from an origin URL
pub fn get_remote(origin: &str) -> Result<Box<Remote>, String> {
    let domain = get_domain(origin)?;
    Ok(match domain {
        "github.com" => Box::new(GitHub {
            id: get_github_project_name(origin),
            name: get_github_project_name(origin),
            origin: String::from(origin),
            api_root: String::from("https://api.github.com/repos"),
        }),
        // For now, if not GitHub, then GitLab
        gitlab_domain => {
            let namespace = match get_gitlab_project_namespace(origin) {
                Some(ns) => ns,
                None => {
                    return Err(String::from("Could not parse the GitLab project namespace from the origin."));
                }
            };
            let mut remote = GitLab {
                id: String::from(""),
                domain: String::from(gitlab_domain),
                name: get_gitlab_project_name(origin),
                namespace,
                origin: String::from(origin),
                api_root: format!("https://{}/api/v4", gitlab_domain),
                api_key: String::from(""),
            };
            let apikey = match git::get_req_config(&domain, "apikey") {
                Some(key) => key,
                None => {
                    let mut newkey = String::new();
                    print!("Please enter the read-only API key for {}: ", gitlab_domain);
                    let _ = stdout().flush();
                    stdin()
                        .read_line(&mut newkey)
                        .expect("Did not input a correct key");
                    trace!("New Key: {}", &newkey);
                    git::set_req_config(&domain, "apikey", &newkey.trim());
                    String::from(newkey.trim())
                }
            };
            info!("API Key: {}", &apikey);
            remote.api_key = apikey;
            let project_id = match load_project_id() {
                Some(x) => x,
                None => {
                    let project_id_str = match remote.get_project_id() {
                        Ok(id_str) => Ok(id_str),
                        Err(e) => {
                            info!("Error getting project ID: {:?}", e);
                            Err(e)
                        }
                    }?;
                    git::set_config("projectid", project_id_str);
                    String::from(project_id_str)
                }
            };
            info!("Got project ID: {}", project_id);
            remote.id = project_id;
            Box::new(remote)
        }
    })
}

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

    #[test]
    fn test_get_gitlab_project_namespace_http() {
        let ns = get_gitlab_project_namespace("https://gitlab.com/my_namespace/my_project.git");
        assert!(ns.is_some());
        assert_eq!("my_namespace", ns.unwrap());
    }

    #[test]
    fn test_get_gitlab_project_namespace_git() {
        let ns = get_gitlab_project_namespace("git@gitlab.com:my_namespace/my_project.git");
        assert!(ns.is_some());
        assert_eq!("my_namespace", ns.unwrap());
    }

    #[test]
    fn test_get_gitlab_project_name_http() {
        let ns = get_gitlab_project_name("https://gitlab.com/my_namespace/my_project.git");
        assert_eq!("my_project", ns);
    }

    #[test]
    fn test_get_gitlab_project_name_git() {
        let ns = get_gitlab_project_name("git@gitlab.com:my_namespace/my_project.git");
        assert_eq!("my_project", ns);
    }
}
<|endoftext|>


<commit_before>
use hyper::server::Request as HyperRequest;
use hyper::method::Method;
use hyper::header::Headers;
use hyper::version::HttpVersion;
use std::collections::HashMap;

pub struct Request {
    raw_request: HyperRequest,

    // only path part of this url
    path: String,
    // query string part of this url
    query_string: String,
    // if has body, keep it as raw here
    raw_body: Option<String>,
    // params pair parsed from url query string
    queries: HashMap<String, String>,
    // params pair parsed from body
    // if body is json, limit it to one level
    body_params: HashMap<String, String>,
    // combined params of queries and body_params
    full_params: HashMap<String, String>,

}

impl Request {
    pub fn new() -> Request {
        // here, we should fill those extra fields from raw_request

    }

    pub fn method(&self) -> &Method {
        self.raw_request.method()
    }

    pub fn version(&self) -> &HttpVersion {
        self.raw_request.version()
    }

    pub fn headers(&self) -> &Headers {
        self.raw_request.headers()
    }

    pub fn path(&self) -> &String {
        &self.path
    }

    pub fn query(&self) -> &HashMap<String, String> {
        &self.queries
    }

    pub fn body(&self) -> &HashMap<String, String> {
        &self.body_params
    }

}

<commit_msg>wip.<commit_after>
use hyper::server::Request as HyperRequest;
use hyper::method::Method;
use hyper::header::Headers;
use hyper::version::HttpVersion;
use std::collections::HashMap;

pub struct Request {
    raw_request: HyperRequest,

    // only path part of this url
    path: String,
    // query string part of this url
    query_string: Option<String>,
    // if has body, keep it as raw here
    raw_body: Option<String>,
    // params pair parsed from url query string
    queries: Option<HashMap<String, String>>,
    // params pair parsed from body
    // if body is json, limit it to one level
    body_params: Option<HashMap<String, String>>,
    // combined params of queries and body_params
    full_params: Option<HashMap<String, String>>,

}

impl Request {
    pub fn new(raw_request: HyperRequest) -> Request {
        // here, we should fill those extra fields from raw_request
        Request {
            raw_request: raw_request,
            path: "/".to_owned(),
            query_string: None,
            raw_body: None,
            queries: None,
            body_params: None,
            full_params: None
        }
    }

    pub fn method(&self) -> &Method {
        self.raw_request.method()
    }

    pub fn version(&self) -> &HttpVersion {
        self.raw_request.version()
    }

    pub fn headers(&self) -> &Headers {
        self.raw_request.headers()
    }

    pub fn path(&self) -> &String {
        &self.path
    }

    pub fn query(&self) -> &Option<HashMap<String, String>> {
        &self.queries
    }

    pub fn body(&self) -> &Option<HashMap<String, String>> {
        &self.body_params
    }

}

<|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::hashmap;

#[deriving(Show, PartialEq)]
pub enum AttributeValue {
  UIntValue(uint),
  StrValue(String),
  RefValue(String),
}

#[deriving(Show)]
pub struct Path {
  pub absolute: bool,
  pub path: Vec<String>,
}

/// Tree node.
#[deriving(Show)]
pub struct Node {
  /// Node name.
  pub name: Option<String>,

  /// Node path.
  pub path: Path,

  /// Node attributes.
  pub attributes: hashmap::HashMap<String, AttributeValue>,

  /// Child nodes.
  pub subnodes: Vec<Box<Node>>,
}

impl Node {
  pub fn new() -> Node {
    Node {
      name: Some(String::from_str("test")),
      path: Path {
        absolute: false,
        path: Vec::new(),
      },
      attributes: hashmap::HashMap::new(),
      subnodes: Vec::new(),
    }
  }
}
<commit_msg>Initialize pt::Node to all empty values.<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::hashmap;

#[deriving(Show, PartialEq)]
pub enum AttributeValue {
  UIntValue(uint),
  StrValue(String),
  RefValue(String),
}

#[deriving(Show)]
pub struct Path {
  pub absolute: bool,
  pub path: Vec<String>,
}

/// Tree node.
#[deriving(Show)]
pub struct Node {
  /// Node name.
  pub name: Option<String>,

  /// Node path.
  pub path: Path,

  /// Node attributes.
  pub attributes: hashmap::HashMap<String, AttributeValue>,

  /// Child nodes.
  pub subnodes: Vec<Box<Node>>,
}

impl Node {
  pub fn new() -> Node {
    Node {
      name: None,
      path: Path {
        absolute: false,
        path: Vec::new(),
      },
      attributes: hashmap::HashMap::new(),
      subnodes: Vec::new(),
    }
  }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::str;

#[derive(Debug)]
pub enum RedisResult {
    Array(Vec<RedisResult>),
    Bytes(Vec<u8>),
    String(String),
    Int(i64),
    Nil,
}

impl RedisResult {
    pub fn convert<T: From<RedisResult>>(self) -> T {
        self.into()
    }
}

impl fmt::Display for RedisResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            RedisResult::Array(ref value) => write!(f, "{:?}", value),
            RedisResult::Bytes(ref value) => write!(f, "{:?}", value),
            RedisResult::String(ref value) => write!(f, "{:?}", value),
            RedisResult::Int(ref value) => write!(f, "{:?}", value),
            RedisResult::Nil => write!(f, "null"),
        }
    }
}

impl From<RedisResult> for String {
    fn from(result: RedisResult) -> String {
        match result {
            RedisResult::Array(_value) => "Array cannot be stringified".to_string(),
            RedisResult::Bytes(value) => str::from_utf8(&value).unwrap().to_string(),
            RedisResult::String(value) => value,
            RedisResult::Int(value) => value.to_string(),
            RedisResult::Nil => "null".to_string(),
        }
    }
}

impl From<RedisResult> for Vec<u8> {
    fn from(result: RedisResult) -> Vec<u8> {
        match result {
            RedisResult::Array(_value) => vec![],
            RedisResult::Bytes(value) => value,
            RedisResult::String(value) => value.into_bytes(),
            RedisResult::Int(value) => value.to_string().into_bytes(),
            RedisResult::Nil => vec![],
        }
    }
}

impl From<RedisResult> for Vec<String> {
    fn from(result: RedisResult) -> Vec<String> {
        match result {
            RedisResult::Array(value) => {
                let mut retval = Vec::new();
                for res in value {
                    retval.push(res.convert::<String>());
                }
                retval
            },
            RedisResult::Bytes(value) => vec![],
            RedisResult::String(value) => vec![value],
            RedisResult::Int(value) => vec![value.to_string()],
            RedisResult::Nil => vec![],
        }
    }
}

impl From<RedisResult> for i64 {
    fn from(result: RedisResult) -> i64 {
        match result {
            RedisResult::Array(_value) => 0,
            RedisResult::Bytes(_value) => 0,
            RedisResult::String(_value) => 0,
            RedisResult::Int(value) => value,
            RedisResult::Nil => 0,
        }
    }
}

<commit_msg>add convertion from RedisResult to Hashmap<commit_after>use std::collections::HashMap;
use std::fmt;
use std::str;

#[derive(Debug)]
pub enum RedisResult {
    Array(Vec<RedisResult>),
    Bytes(Vec<u8>),
    String(String),
    Int(i64),
    Nil,
}

impl RedisResult {
    pub fn convert<T: From<RedisResult>>(self) -> T {
        self.into()
    }
}

impl fmt::Display for RedisResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            RedisResult::Array(ref value) => write!(f, "{:?}", value),
            RedisResult::Bytes(ref value) => write!(f, "{:?}", value),
            RedisResult::String(ref value) => write!(f, "{:?}", value),
            RedisResult::Int(ref value) => write!(f, "{:?}", value),
            RedisResult::Nil => write!(f, "null"),
        }
    }
}

impl From<RedisResult> for String {
    fn from(result: RedisResult) -> String {
        match result {
            RedisResult::Array(_value) => "Array cannot be stringified".to_string(),
            RedisResult::Bytes(value) => str::from_utf8(&value).unwrap().to_string(),
            RedisResult::String(value) => value,
            RedisResult::Int(value) => value.to_string(),
            RedisResult::Nil => "null".to_string(),
        }
    }
}

impl From<RedisResult> for Vec<u8> {
    fn from(result: RedisResult) -> Vec<u8> {
        match result {
            RedisResult::Array(_value) => vec![],
            RedisResult::Bytes(value) => value,
            RedisResult::String(value) => value.into_bytes(),
            RedisResult::Int(value) => value.to_string().into_bytes(),
            RedisResult::Nil => vec![],
        }
    }
}

impl From<RedisResult> for Vec<String> {
    fn from(result: RedisResult) -> Vec<String> {
        match result {
            RedisResult::Array(value) => {
                let mut retval = Vec::new();
                for res in value {
                    retval.push(res.convert::<String>());
                }
                retval
            },
            RedisResult::Bytes(_value) => vec![],
            RedisResult::String(value) => vec![value],
            RedisResult::Int(value) => vec![value.to_string()],
            RedisResult::Nil => vec![],
        }
    }
}

impl From<RedisResult> for HashMap<String, String> {
    fn from(result: RedisResult) -> HashMap<String, String> {
        match result {
            RedisResult::Array(value) => {
                let mut retval = HashMap::new();
                let mut key = String::new();
                for (index, res) in value.into_iter().enumerate() {
                    if index % 2 == 0 {
                        key = res.convert::<String>();
                    } else {
                        retval.insert(key.to_string(), res.convert::<String>());
                    }
                }
                retval
            },
            _ => HashMap::new(),
        }
    }
}

impl From<RedisResult> for i64 {
    fn from(result: RedisResult) -> i64 {
        match result {
            RedisResult::Array(_value) => 0,
            RedisResult::Bytes(_value) => 0,
            RedisResult::String(_value) => 0,
            RedisResult::Int(value) => value,
            RedisResult::Nil => 0,
        }
    }
}

<|endoftext|>


<commit_before>pub mod builtins;

use std::collections::HashMap;
use std::path::PathBuf;
use std::io;
use std::io::{Read, Write};
use std::collections::hash_map::Entry;

#[derive(PartialEq, Debug, Clone)]
pub struct State {
    cwd: PathBuf,
    environment: HashMap<String, String>,
    aliases: HashMap<String, String>,
    argv: Vec<String>,
    argc: usize,
}

impl State {
    pub fn new(cwd: String) -> State {
        State {
            cwd: PathBuf::from(cwd),
            environment: HashMap::new(),
            aliases: HashMap::new(),
            argv: Vec::new(),
            argc: 0,
        }
    }
}

pub fn run(initial_state: State) {
    let mut builtins = builtins::load();
    let mut s = initial_state.clone();

    println!("Welcome to rsh! {:?}", s);

    loop {

        print!("\n");
        print!("{} -> ", s.cwd.to_str().unwrap());

        // this forces the prompt to print
        io::stdout().flush();

        // read the user input
        let mut input = String::new();
        io::stdin().read_line(&mut input).unwrap();

        s.argv = parse_args(&input);
        s.argc = s.argv.len();

        print!("\n");
        println!("Input: {}\nState: {:?}", input, s);

        let first_arg = s.argv.get(0).unwrap().clone();
        if let Entry::Occupied(f) = builtins.entry(String::from(first_arg)) {
            let bn = f.get();
            s = bn(s.clone());
        }
    }
}

fn parse_args(args: &String) -> Vec<String> {
    let mut result: Vec<String> = Vec::new();

    if args.len() == 0 {
        return result
    }

    let mut building_string: bool = false;
    let mut build_string: String = String::from("");
    for string in args.split_whitespace() {
        if string.starts_with("\"") {
            // the string is surrounded by quotes - "word"
            if string.ends_with("\"") {
                build_string.push_str(string);
                result.push(build_string);

                building_string = false;
                build_string = String::from("");
            // the string only begins with quote - "word
            } else {
                building_string = true;

                build_string.push_str(string);
                build_string.push(' ');
            }
        // the string ends with quote - word"
        } else if string.ends_with("\"") {
            build_string.push_str(string);
            result.push(build_string);

            building_string = false;
            build_string = String::from("");
        } else {
            // the string is inside a quote section
            if building_string {
                build_string.push_str(string);
                build_string.push(' ');
            // the string is not inside a quote section
            } else {
                result.push(string.to_string());
            }
        }
    }

    result
}

#[test]
fn parse_args_test() {
    // parse empty string
    {
        let expected: Vec<String> = Vec::new();
        let result = parse_args(&String::from(""));
        assert_eq!(result, expected);
    }

    // parse single-word string
    {
        let expected: Vec<String> = vec!["echo".to_string()];
        let result = parse_args(&String::from("echo"));
        assert_eq!(result, expected);
    }

    // parse single-word string inside parens
    {
        let expected = vec!["\"echo\"".to_string()];
        let result = parse_args(&String::from("\"echo\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with closed parens section
    {
        let expected = vec!["echo".to_string(), "-n".into(), "\"Hello Dear World\"".into()];
        let result = parse_args(&String::from("echo -n \"Hello Dear World\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with multiple closed parents sections
    {
        let expected = vec!["echo".to_string(), "\"Hello\"".into(), "\"Dear World\"".into()];
        let result = parse_args(&String::from("echo \"Hello\" \"Dear World\""));
        assert_eq!(result, expected);
    }
}
<commit_msg>Re-write parse_args using match<commit_after>pub mod builtins;

use std::collections::HashMap;
use std::path::PathBuf;
use std::io;
use std::io::{Read, Write};
use std::collections::hash_map::Entry;

#[derive(PartialEq, Debug, Clone)]
pub struct State {
    cwd: PathBuf,
    environment: HashMap<String, String>,
    aliases: HashMap<String, String>,
    argv: Vec<String>,
    argc: usize,
}

impl State {
    pub fn new(cwd: String) -> State {
        State {
            cwd: PathBuf::from(cwd),
            environment: HashMap::new(),
            aliases: HashMap::new(),
            argv: Vec::new(),
            argc: 0,
        }
    }
}

pub fn run(initial_state: State) {
    let mut builtins = builtins::load();
    let mut s = initial_state.clone();

    println!("Welcome to rsh! {:?}", s);

    loop {

        print!("\n");
        print!("{} -> ", s.cwd.to_str().unwrap());

        // this forces the prompt to print
        io::stdout().flush();

        // read the user input
        let mut input = String::new();
        io::stdin().read_line(&mut input).unwrap();

        s.argv = parse_args(&input);
        s.argc = s.argv.len();

        print!("\n");
        println!("Input: {}\nState: {:?}", input, s);

        let first_arg = s.argv.get(0).unwrap().clone();
        if let Entry::Occupied(f) = builtins.entry(String::from(first_arg)) {
            let bn = f.get();
            s = bn(s.clone());
        }
    }
}

fn parse_args(args: &String) -> Vec<String> {
    let mut result: Vec<String> = Vec::new();

    if args.len() == 0 {
        return result;
    }

    enum BuildType {
        None,
        Single,
        Double,
    }

    let mut build_type: BuildType = BuildType::None;
    let mut build_string: String = String::from("");

    for c in args.chars() {
        match c {
            '\'' => {
                match build_type {
                    BuildType::Single => {
                        build_type = BuildType::None;
                        result.push(build_string);
                        build_string = String::from("");
                    }

                    BuildType::None => {
                        build_type = BuildType::Single;
                    }

                    _ => {
                        build_string.push(c);
                    }
                }
            }

            '\"' => {
                match build_type {
                    BuildType::Double => {
                        build_type = BuildType::None;
                        result.push(build_string);
                        build_string = String::from("");
                    }

                    BuildType::None => {
                        build_type = BuildType::Double;
                    }

                    _ => {
                        build_string.push(c);
                    }
                }
            }

            ' ' => {
                match build_type {
                    BuildType::None => {
                        result.push(build_string);
                        build_string = String::from("");
                    }

                    _ => {
                        build_string.push(c);
                    }
                }
            }

            _ => {
                build_string.push(c);
            }
        }
    }

    if build_string.len() > 0 {
        result.push(build_string);
    }

    result = result.into_iter()
        .filter(|s| s.len() > 0)
        .collect();

    result
}

#[test]
fn parse_args_test() {
    // parse empty string
    {
        let expected: Vec<String> = Vec::new();
        let result = parse_args(&String::from(""));
        assert_eq!(result, expected);
    }

    // parse single-word string
    {
        let expected: Vec<String> = vec!["echo".to_string()];
        let result = parse_args(&String::from("echo"));
        assert_eq!(result, expected);
    }

    // parse single-word string inside parens
    {
        let expected = vec!["echo".to_string()];
        let result = parse_args(&String::from("\"echo\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with closed parens section
    {
        let expected = vec!["echo".to_string(), "-n".into(), "Hello Dear World".into()];
        let result = parse_args(&String::from("echo -n \"Hello Dear World\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with multiple closed parents sections
    {
        let expected = vec!["echo".to_string(), "Hello".into(), "Dear World".into()];
        let result = parse_args(&String::from("echo \"Hello\" \"Dear World\""));
        assert_eq!(result, expected);
    }
}
<|endoftext|>