<commit_before>use crate::syntax::atom::Atom::{self, *};
use crate::syntax::{error, ident, Api, ExternFn, Ty1, Type, Types, Var};
use proc_macro2::Ident;
use syn::{Error, Result};

pub(crate) fn typecheck(apis: &[Api], types: &Types) -> Result<()> {
    let mut errors = Vec::new();

    for ty in types {
        match ty {
            Type::Ident(ident) => {
                if Atom::from(ident).is_none()
                    && !types.structs.contains_key(ident)
                    && !types.cxx.contains(ident)
                    && !types.rust.contains(ident)
                {
                    errors.push(unsupported_type(ident));
                }
            }
            Type::RustBox(ptr) => {
                if let Type::Ident(ident) = &ptr.inner {
                    if types.cxx.contains(ident) {
                        errors.push(unsupported_cxx_type_in_box(ptr));
                    }
                    if Atom::from(ident).is_none() {
                        continue;
                    }
                }
                errors.push(unsupported_box_target(ptr));
            }
            Type::UniquePtr(ptr) => {
                if let Type::Ident(ident) = &ptr.inner {
                    if types.rust.contains(ident) {
                        errors.push(unsupported_rust_type_in_unique_ptr(ptr));
                    }
                    match Atom::from(ident) {
                        None | Some(CxxString) => continue,
                        _ => {}
                    }
                }
                errors.push(unsupported_unique_ptr_target(ptr));
            }
            _ => {}
        }
    }

    for api in apis {
        match api {
            Api::Struct(strct) => {
                for field in &strct.fields {
                    if is_unsized(&field.ty, types) {
                        errors.push(field_by_value(field, types));
                    }
                }
            }
            Api::CxxFunction(efn) | Api::RustFunction(efn) => {
                for arg in &efn.args {
                    if is_unsized(&arg.ty, types) {
                        errors.push(argument_by_value(arg, types));
                    }
                }
                if let Some(ty) = &efn.ret {
                    if is_unsized(ty, types) {
                        errors.push(return_by_value(ty, types));
                    }
                }
            }
            _ => {}
        }
    }

    for api in apis {
        if let Api::CxxFunction(efn) = api {
            errors.extend(check_mut_return_restriction(efn).err());
        }
        if let Api::CxxFunction(efn) | Api::RustFunction(efn) = api {
            errors.extend(check_multiple_arg_lifetimes(efn).err());
        }
    }

    ident::check_all(apis, &mut errors);

    let mut iter = errors.into_iter();
    let mut all_errors = match iter.next() {
        Some(err) => err,
        None => return Ok(()),
    };
    for err in iter {
        all_errors.combine(err);
    }
    Err(all_errors)
}

fn is_unsized(ty: &Type, types: &Types) -> bool {
    let ident = match ty {
        Type::Ident(ident) => ident,
        _ => return false,
    };
    ident == CxxString || types.cxx.contains(ident) || types.rust.contains(ident)
}

fn check_mut_return_restriction(efn: &ExternFn) -> Result<()> {
    match &efn.ret {
        Some(Type::Ref(ty)) if ty.mutability.is_some() => {}
        _ => return Ok(()),
    }

    for arg in &efn.args {
        if let Type::Ref(ty) = &arg.ty {
            if ty.mutability.is_some() {
                return Ok(());
            }
        }
    }

    Err(Error::new_spanned(
        efn,
        "&mut return type is not allowed unless there is a &mut argument",
    ))
}

fn check_multiple_arg_lifetimes(efn: &ExternFn) -> Result<()> {
    match &efn.ret {
        Some(Type::Ref(_)) => {}
        _ => return Ok(()),
    }

    let mut reference_args = 0;
    for arg in &efn.args {
        if let Type::Ref(_) = &arg.ty {
            reference_args += 1;
        }
    }

    if reference_args == 1 {
        Ok(())
    } else {
        Err(Error::new_spanned(
            efn,
            "functions that return a reference must take exactly one input reference",
        ))
    }
}

fn describe(ty: &Type, types: &Types) -> String {
    match ty {
        Type::Ident(ident) => {
            if types.structs.contains_key(ident) {
                "struct".to_owned()
            } else if types.cxx.contains(ident) {
                "C++ type".to_owned()
            } else if types.rust.contains(ident) {
                "opaque Rust type".to_owned()
            } else if Atom::from(ident) == Some(CxxString) {
                "C++ string".to_owned()
            } else {
                ident.to_string()
            }
        }
        Type::RustBox(_) => "Box".to_owned(),
        Type::UniquePtr(_) => "unique_ptr".to_owned(),
        Type::Ref(_) => "reference".to_owned(),
        Type::Str(_) => "&str".to_owned(),
        Type::Void(_) => "()".to_owned(),
    }
}

fn unsupported_type(ident: &Ident) -> Error {
    Error::new(ident.span(), "unsupported type")
}

fn unsupported_cxx_type_in_box(unique_ptr: &Ty1) -> Error {
    Error::new_spanned(unique_ptr, error::BOX_CXX_TYPE.msg)
}

fn unsupported_box_target(unique_ptr: &Ty1) -> Error {
    Error::new_spanned(unique_ptr, "unsupported target type of Box")
}

fn unsupported_rust_type_in_unique_ptr(unique_ptr: &Ty1) -> Error {
    Error::new_spanned(unique_ptr, "unique_ptr of a Rust type is not supported yet")
}

fn unsupported_unique_ptr_target(unique_ptr: &Ty1) -> Error {
    Error::new_spanned(unique_ptr, "unsupported unique_ptr target type")
}

fn field_by_value(field: &Var, types: &Types) -> Error {
    let desc = describe(&field.ty, types);
    let message = format!("using {} by value is not supported", desc);
    Error::new_spanned(field, message)
}

fn argument_by_value(arg: &Var, types: &Types) -> Error {
    let desc = describe(&arg.ty, types);
    let message = format!("passing {} by value is not supported", desc);
    Error::new_spanned(arg, message)
}

fn return_by_value(ty: &Type, types: &Types) -> Error {
    let desc = describe(ty, types);
    let message = format!("returning {} by value is not supported", desc);
    Error::new_spanned(ty, message)
}
<commit_msg>Implement restrictions on placement of ()<commit_after>use crate::syntax::atom::Atom::{self, *};
use crate::syntax::{error, ident, Api, ExternFn, Ref, Ty1, Type, Types, Var};
use proc_macro2::Ident;
use syn::{Error, Result};

pub(crate) fn typecheck(apis: &[Api], types: &Types) -> Result<()> {
    let mut errors = Vec::new();

    for ty in types {
        match ty {
            Type::Ident(ident) => {
                if Atom::from(ident).is_none()
                    && !types.structs.contains_key(ident)
                    && !types.cxx.contains(ident)
                    && !types.rust.contains(ident)
                {
                    errors.push(unsupported_type(ident));
                }
            }
            Type::RustBox(ptr) => {
                if let Type::Ident(ident) = &ptr.inner {
                    if types.cxx.contains(ident) {
                        errors.push(unsupported_cxx_type_in_box(ptr));
                    }
                    if Atom::from(ident).is_none() {
                        continue;
                    }
                }
                errors.push(unsupported_box_target(ptr));
            }
            Type::UniquePtr(ptr) => {
                if let Type::Ident(ident) = &ptr.inner {
                    if types.rust.contains(ident) {
                        errors.push(unsupported_rust_type_in_unique_ptr(ptr));
                    }
                    match Atom::from(ident) {
                        None | Some(CxxString) => continue,
                        _ => {}
                    }
                }
                errors.push(unsupported_unique_ptr_target(ptr));
            }
            Type::Ref(ty) => {
                if let Type::Void(_) = ty.inner {
                    errors.push(unsupported_reference_type(ty));
                }
            }
            _ => {}
        }
    }

    for api in apis {
        match api {
            Api::Struct(strct) => {
                for field in &strct.fields {
                    if is_unsized(&field.ty, types) {
                        errors.push(field_by_value(field, types));
                    }
                }
            }
            Api::CxxFunction(efn) | Api::RustFunction(efn) => {
                for arg in &efn.args {
                    if is_unsized(&arg.ty, types) {
                        errors.push(argument_by_value(arg, types));
                    }
                }
                if let Some(ty) = &efn.ret {
                    if is_unsized(ty, types) {
                        errors.push(return_by_value(ty, types));
                    }
                }
            }
            _ => {}
        }
    }

    for api in apis {
        if let Api::CxxFunction(efn) = api {
            errors.extend(check_mut_return_restriction(efn).err());
        }
        if let Api::CxxFunction(efn) | Api::RustFunction(efn) = api {
            errors.extend(check_multiple_arg_lifetimes(efn).err());
        }
    }

    ident::check_all(apis, &mut errors);

    let mut iter = errors.into_iter();
    let mut all_errors = match iter.next() {
        Some(err) => err,
        None => return Ok(()),
    };
    for err in iter {
        all_errors.combine(err);
    }
    Err(all_errors)
}

fn is_unsized(ty: &Type, types: &Types) -> bool {
    let ident = match ty {
        Type::Ident(ident) => ident,
        Type::Void(_) => return true,
        _ => return false,
    };
    ident == CxxString || types.cxx.contains(ident) || types.rust.contains(ident)
}

fn check_mut_return_restriction(efn: &ExternFn) -> Result<()> {
    match &efn.ret {
        Some(Type::Ref(ty)) if ty.mutability.is_some() => {}
        _ => return Ok(()),
    }

    for arg in &efn.args {
        if let Type::Ref(ty) = &arg.ty {
            if ty.mutability.is_some() {
                return Ok(());
            }
        }
    }

    Err(Error::new_spanned(
        efn,
        "&mut return type is not allowed unless there is a &mut argument",
    ))
}

fn check_multiple_arg_lifetimes(efn: &ExternFn) -> Result<()> {
    match &efn.ret {
        Some(Type::Ref(_)) => {}
        _ => return Ok(()),
    }

    let mut reference_args = 0;
    for arg in &efn.args {
        if let Type::Ref(_) = &arg.ty {
            reference_args += 1;
        }
    }

    if reference_args == 1 {
        Ok(())
    } else {
        Err(Error::new_spanned(
            efn,
            "functions that return a reference must take exactly one input reference",
        ))
    }
}

fn describe(ty: &Type, types: &Types) -> String {
    match ty {
        Type::Ident(ident) => {
            if types.structs.contains_key(ident) {
                "struct".to_owned()
            } else if types.cxx.contains(ident) {
                "C++ type".to_owned()
            } else if types.rust.contains(ident) {
                "opaque Rust type".to_owned()
            } else if Atom::from(ident) == Some(CxxString) {
                "C++ string".to_owned()
            } else {
                ident.to_string()
            }
        }
        Type::RustBox(_) => "Box".to_owned(),
        Type::UniquePtr(_) => "unique_ptr".to_owned(),
        Type::Ref(_) => "reference".to_owned(),
        Type::Str(_) => "&str".to_owned(),
        Type::Void(_) => "()".to_owned(),
    }
}

fn unsupported_type(ident: &Ident) -> Error {
    Error::new(ident.span(), "unsupported type")
}

fn unsupported_reference_type(ty: &Ref) -> Error {
    Error::new_spanned(ty, "unsupported reference type")
}

fn unsupported_cxx_type_in_box(unique_ptr: &Ty1) -> Error {
    Error::new_spanned(unique_ptr, error::BOX_CXX_TYPE.msg)
}

fn unsupported_box_target(unique_ptr: &Ty1) -> Error {
    Error::new_spanned(unique_ptr, "unsupported target type of Box")
}

fn unsupported_rust_type_in_unique_ptr(unique_ptr: &Ty1) -> Error {
    Error::new_spanned(unique_ptr, "unique_ptr of a Rust type is not supported yet")
}

fn unsupported_unique_ptr_target(unique_ptr: &Ty1) -> Error {
    Error::new_spanned(unique_ptr, "unsupported unique_ptr target type")
}

fn field_by_value(field: &Var, types: &Types) -> Error {
    let desc = describe(&field.ty, types);
    let message = format!("using {} by value is not supported", desc);
    Error::new_spanned(field, message)
}

fn argument_by_value(arg: &Var, types: &Types) -> Error {
    let desc = describe(&arg.ty, types);
    let message = format!("passing {} by value is not supported", desc);
    Error::new_spanned(arg, message)
}

fn return_by_value(ty: &Type, types: &Types) -> Error {
    let desc = describe(ty, types);
    let message = format!("returning {} by value is not supported", desc);
    Error::new_spanned(ty, message)
}
<|endoftext|>


<commit_before>//! Slices for the `Matrix` struct.
//!
//! These slices provide a view into the matrix data.
//! The view must be a contiguous block of the matrix.
//!
//! ```
//! use rusty_machine::linalg::matrix::Matrix;
//! use rusty_machine::linalg::matrix::MatrixSlice;
//!
//! let a = Matrix::new(3,3, (0..9).collect::<Vec<usize>>());
//!
//! // Manually create our slice - [[4,5],[7,8]].
//! let mat_slice = MatrixSlice::from_matrix(&a, [1,1], 2, 2);
//!
//! // We can perform arithmetic with slices.
//! let new_mat = &mat_slice * &mat_slice;
//! ```

use super::Matrix;
use super::MatrixSlice;
use super::MatrixSliceMut;

use std::marker::PhantomData;
use std::mem;

/// Trait for Matrix Slices.
pub trait BaseSlice<T> {
    /// Rows in the slice.
    fn rows(&self) -> usize;

    /// Columns in the slice.
    fn cols(&self) -> usize;

    /// Row stride in the slice.
    fn row_stride(&self) -> usize;

    /// Top left index of the slice.
    fn as_ptr(&self) -> *const T;

    /// Get a reference to a point in the slice without bounds checking.
    unsafe fn get_unchecked(&self, index: [usize; 2]) -> &T;
}

impl<T> BaseSlice<T> for MatrixSlice<T> {
    fn rows(&self) -> usize {
        self.rows
    }

    fn cols(&self) -> usize {
        self.cols
    }

    fn row_stride(&self) -> usize {
        self.row_stride
    }

    fn as_ptr(&self) -> *const T {
        self.ptr
    }

    unsafe fn get_unchecked(&self, index: [usize; 2]) -> &T {
        &*(self.ptr.offset((index[0] * self.row_stride + index[1]) as isize))
    }
}

impl<T> BaseSlice<T> for MatrixSliceMut<T> {
    fn rows(&self) -> usize {
        self.rows
    }

    fn cols(&self) -> usize {
        self.cols
    }

    fn row_stride(&self) -> usize {
        self.row_stride
    }

    fn as_ptr(&self) -> *const T {
        self.ptr as *const T
    }

    unsafe fn get_unchecked(&self, index: [usize; 2]) -> &T {
        &*(self.ptr.offset((index[0] * self.row_stride + index[1]) as isize))
    }
}

impl<T> MatrixSlice<T> {
    /// Produce a matrix slice from a matrix
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    /// use rusty_machine::linalg::matrix::MatrixSlice;
    ///
    /// let a = Matrix::new(3,3, (0..9).collect::<Vec<usize>>());
    /// let slice = MatrixSlice::from_matrix(&a, [1,1], 2, 2);
    /// ```
    pub fn from_matrix(mat: &Matrix<T>,
                       start: [usize; 2],
                       rows: usize,
                       cols: usize)
                       -> MatrixSlice<T> {
        assert!(start[0] + rows <= mat.rows(),
                "View dimensions exceed matrix dimensions.");
        assert!(start[1] + cols <= mat.cols(),
                "View dimensions exceed matrix dimensions.");
        unsafe {
            MatrixSlice {
                ptr: mat.data().get_unchecked(start[0] * mat.cols + start[1]) as *const T,
                rows: rows,
                cols: cols,
                row_stride: mat.cols,
            }
        }
    }

    /// Produce a matrix slice from an existing matrix slice.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    /// use rusty_machine::linalg::matrix::MatrixSlice;
    ///
    /// let a = Matrix::new(3,3, (0..9).collect::<Vec<usize>>());
    /// let slice = MatrixSlice::from_matrix(&a, [1,1], 2, 2);
    /// let new_slice = slice.reslice([0,0], 1, 1);
    /// ```
    pub fn reslice(mut self,
                            start: [usize; 2],
                            rows: usize,
                            cols: usize)
                            -> MatrixSlice<T> {
        assert!(start[0] + rows <= self.rows,
            "View dimensions exceed matrix dimensions.");
        assert!(start[1] + cols <= self.cols,
                "View dimensions exceed matrix dimensions.");

        unsafe {
            self.ptr = self.ptr.offset((start[0] * self.cols + start[1]) as isize);
        }
        self.rows = rows;
        self.cols = cols;

        self
    }

    /// Returns an iterator over the matrix slice.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    /// use rusty_machine::linalg::matrix::MatrixSlice;
    ///
    /// let a = Matrix::new(3,3, (0..9).collect::<Vec<usize>>());
    /// let slice = MatrixSlice::from_matrix(&a, [1,1], 2, 2);
    ///
    /// let slice_data = slice.iter().map(|v| *v).collect::<Vec<usize>>();
    /// assert_eq!(slice_data, vec![4,5,7,8]);
    /// ```
    pub fn iter(&self) -> SliceIter<T> {
        SliceIter {
            slice_start: self.ptr,
            row_pos: 0,
            col_pos: 0,
            slice_rows: self.rows,
            slice_cols: self.cols,
            row_diff: self.row_stride as isize - self.cols as isize + 1,
            _marker: PhantomData::<&T>,
        }
    }
}

impl<T: Copy> MatrixSlice<T> {
    /// Convert the matrix slice into a new Matrix.
    pub fn into_matrix(self) -> Matrix<T> {
        let slice_data = self.iter().map(|v| *v).collect::<Vec<T>>();
        Matrix {
            rows: self.rows,
            cols: self.cols,
            data: slice_data,
        }
    }
}

impl<T> MatrixSliceMut<T> {

    /// Produce a matrix slice from a matrix
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    /// use rusty_machine::linalg::matrix::MatrixSliceMut;
    ///
    /// let mut a = Matrix::new(3,3, (0..9).collect::<Vec<usize>>());
    /// let slice = MatrixSliceMut::from_matrix(&mut a, [1,1], 2, 2);
    /// ```
    pub fn from_matrix(mat: &mut Matrix<T>,
                       start: [usize; 2],
                       rows: usize,
                       cols: usize)
                       -> MatrixSliceMut<T> {
        assert!(start[0] + rows <= mat.rows(),
                "View dimensions exceed matrix dimensions.");
        assert!(start[1] + cols <= mat.cols(),
                "View dimensions exceed matrix dimensions.");

        let mat_cols = mat.cols();

        unsafe {
            MatrixSliceMut {
                ptr: mat.mut_data().get_unchecked_mut(start[0] * mat_cols + start[1]) as *mut T,
                rows: rows,
                cols: cols,
                row_stride: mat_cols,
            }
        }
    }

    /// Produce a matrix slice from an existing matrix slice.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    /// use rusty_machine::linalg::matrix::MatrixSliceMut;
    ///
    /// let mut a = Matrix::new(3,3, (0..9).collect::<Vec<usize>>());
    /// let slice = MatrixSliceMut::from_matrix(&mut a, [1,1], 2, 2);
    /// let new_slice = slice.reslice([0,0], 1, 1);
    /// ```
    pub fn reslice(mut self,
                            start: [usize; 2],
                            rows: usize,
                            cols: usize)
                            -> MatrixSliceMut<T> {
        assert!(start[0] + rows <= self.rows,
            "View dimensions exceed matrix dimensions.");
        assert!(start[1] + cols <= self.cols,
                "View dimensions exceed matrix dimensions.");

        unsafe {
            self.ptr = self.ptr.offset((start[0] * self.cols + start[1]) as isize);
        }
        self.rows = rows;
        self.cols = cols;

        self
    }

    /// Returns an iterator over the matrix slice.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    /// use rusty_machine::linalg::matrix::MatrixSliceMut;
    ///
    /// let mut a = Matrix::new(3,3, (0..9).collect::<Vec<usize>>());
    /// let slice = MatrixSliceMut::from_matrix(&mut a, [1,1], 2, 2);
    ///
    /// let slice_data = slice.iter().map(|v| *v).collect::<Vec<usize>>();
    /// assert_eq!(slice_data, vec![4,5,7,8]);
    /// ```
    pub fn iter(&self) -> SliceIter<T> {
        let row_diff = self.row_stride as isize - self.cols as isize + 1;
        SliceIter {
            slice_start: self.ptr as *const T,
            row_pos: 0,
            col_pos: 0,
            slice_rows: self.rows,
            slice_cols: self.cols,
            row_diff: row_diff,
            _marker: PhantomData::<&T>,
        }
    }

    /// Returns a mutable iterator over the matrix slice.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    /// use rusty_machine::linalg::matrix::MatrixSliceMut;
    ///
    /// let mut a = Matrix::new(3,3, (0..9).collect::<Vec<usize>>());
    ///
    /// {
    ///     let mut slice = MatrixSliceMut::from_matrix(&mut a, [1,1], 2, 2);
    ///
    ///     for d in slice.iter_mut() {
    ///         *d = *d + 2;
    ///     }
    /// }
    ///
    /// // Only the matrix slice is updated.
    /// assert_eq!(a.into_vec(), vec![0,1,2,3,6,7,6,9,10]);
    /// ```
    pub fn iter_mut(&mut self) -> SliceIterMut<T> {
        let row_diff = self.row_stride as isize - self.cols as isize + 1;
        SliceIterMut {
            slice_start: self.ptr,
            row_pos: 0,
            col_pos: 0,
            slice_rows: self.rows,
            slice_cols: self.cols,
            row_diff: row_diff,
            _marker: PhantomData::<&mut T>,
        }
    }
}

impl<T: Copy> MatrixSliceMut<T> {
    /// Convert the matrix slice into a new Matrix.
    pub fn into_matrix(self) -> Matrix<T> {
        let slice_data = self.iter().map(|v| *v).collect::<Vec<T>>();
        Matrix {
            rows: self.rows,
            cols: self.cols,
            data: slice_data,
        }
    }
}

/// Iterator for the MatrixSlice
///
/// Iterates over the underlying slice data
/// in row-major order.
#[derive(Debug)]
pub struct SliceIter<'a, T: 'a> {
    slice_start: *const T,
    row_pos: usize,
    col_pos: usize,
    slice_rows: usize,
    slice_cols: usize,
    row_diff: isize,
    _marker: PhantomData<&'a T>,
}

/// Iterates over the matrix slice data in row-major order.
impl<'a, T> Iterator for SliceIter<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        // Set the position of the next element
        if self.row_pos < self.slice_rows {
            unsafe {
                let ret_ptr = self.slice_start;
                // If end of row, set to start of next row
                if self.col_pos == self.slice_cols - 1 {
                    self.row_pos += 1usize;
                    self.col_pos = 0usize;
                    self.slice_start = self.slice_start.offset(self.row_diff);
                } else {
                    self.col_pos += 1usize;
                    self.slice_start = self.slice_start.offset(1);
                }

                Some(mem::transmute(ret_ptr))
            }
        } else {
            None
        }
    }
}

/// Iterator for MatrixSliceMut.
///
/// Iterates over the underlying slice data
/// in row-major order.
#[derive(Debug)]
pub struct SliceIterMut<'a, T: 'a> {
    slice_start: *mut T,
    row_pos: usize,
    col_pos: usize,
    slice_rows: usize,
    slice_cols: usize,
    row_diff: isize,
    _marker: PhantomData<&'a mut T>,
}

/// Iterates over the matrix slice data in row-major order.
impl<'a, T> Iterator for SliceIterMut<'a, T> {
    type Item = &'a mut T;

    fn next(&mut self) -> Option<Self::Item> {
        // Set the position of the next element
        if self.row_pos < self.slice_rows {
            unsafe {
                let ret_ptr = self.slice_start;
                // If end of row, set to start of next row
                if self.col_pos == self.slice_cols - 1 {
                    self.row_pos += 1usize;
                    self.col_pos = 0usize;
                    self.slice_start = self.slice_start.offset(self.row_diff);
                } else {
                    self.col_pos += 1usize;
                    self.slice_start = self.slice_start.offset(1);
                }
                Some(mem::transmute(ret_ptr))
            }
        } else {
            None
        }
    }
}

#[cfg(test)]
mod tests {
    use super::BaseSlice;
    use super::super::MatrixSlice;
    use super::super::MatrixSliceMut;
	use super::super::Matrix;

	#[test]
	#[should_panic]
	fn make_slice_bad_dim() {
		let a = Matrix::new(3,3, vec![2.0; 9]);
		let _ = MatrixSlice::from_matrix(&a, [1,1], 3, 2);
	}

    #[test]
    fn make_slice() {
        let a = Matrix::new(3,3, vec![2.0; 9]);
        let b = MatrixSlice::from_matrix(&a, [1,1], 2, 2);

        assert_eq!(b.rows(), 2);
        assert_eq!(b.cols(), 2);
    }

    #[test]
    fn reslice() {
        let mut a = Matrix::new(4,4, (0..16).collect());
        let b = MatrixSlice::from_matrix(&a, [1,1], 3, 3);
        {
            let c = b.reslice([0,1], 2, 2);

            assert_eq!(c.rows(), 2);
            assert_eq!(c.cols(), 2);

            assert_eq!(c[[0,0]], 6);
            assert_eq!(c[[0,1]], 7);
            assert_eq!(c[[1,0]], 10);
            assert_eq!(c[[1,1]], 11);
        }

        let b = MatrixSliceMut::from_matrix(&mut a, [1,1], 3, 3);

        let c = b.reslice([0,1], 2, 2);

        assert_eq!(c.rows(), 2);
        assert_eq!(c.cols(), 2);

        assert_eq!(c[[0,0]], 6);
        assert_eq!(c[[0,1]], 7);
        assert_eq!(c[[1,0]], 10);
        assert_eq!(c[[1,1]], 11);
    }

    #[test]
    fn slice_into_matrix() {
        let mut a = Matrix::new(3,3, vec![2.0; 9]);

        let b = MatrixSlice::from_matrix(&a, [1,1], 2, 2);
        let c = b.into_matrix();
        assert_eq!(c.rows(), 2);
        assert_eq!(c.cols(), 2);

        let d = MatrixSliceMut::from_matrix(&mut a, [1,1], 2, 2);
        let e = d.into_matrix();
        assert_eq!(e.rows(), 2);
        assert_eq!(e.cols(), 2);
    }
}<commit_msg>Making iterator pointers totally safe.<commit_after>//! Slices for the `Matrix` struct.
//!
//! These slices provide a view into the matrix data.
//! The view must be a contiguous block of the matrix.
//!
//! ```
//! use rusty_machine::linalg::matrix::Matrix;
//! use rusty_machine::linalg::matrix::MatrixSlice;
//!
//! let a = Matrix::new(3,3, (0..9).collect::<Vec<usize>>());
//!
//! // Manually create our slice - [[4,5],[7,8]].
//! let mat_slice = MatrixSlice::from_matrix(&a, [1,1], 2, 2);
//!
//! // We can perform arithmetic with slices.
//! let new_mat = &mat_slice * &mat_slice;
//! ```

use super::Matrix;
use super::MatrixSlice;
use super::MatrixSliceMut;

use std::marker::PhantomData;
use std::mem;

/// Trait for Matrix Slices.
pub trait BaseSlice<T> {
    /// Rows in the slice.
    fn rows(&self) -> usize;

    /// Columns in the slice.
    fn cols(&self) -> usize;

    /// Row stride in the slice.
    fn row_stride(&self) -> usize;

    /// Top left index of the slice.
    fn as_ptr(&self) -> *const T;

    /// Get a reference to a point in the slice without bounds checking.
    unsafe fn get_unchecked(&self, index: [usize; 2]) -> &T;
}

impl<T> BaseSlice<T> for MatrixSlice<T> {
    fn rows(&self) -> usize {
        self.rows
    }

    fn cols(&self) -> usize {
        self.cols
    }

    fn row_stride(&self) -> usize {
        self.row_stride
    }

    fn as_ptr(&self) -> *const T {
        self.ptr
    }

    unsafe fn get_unchecked(&self, index: [usize; 2]) -> &T {
        &*(self.ptr.offset((index[0] * self.row_stride + index[1]) as isize))
    }
}

impl<T> BaseSlice<T> for MatrixSliceMut<T> {
    fn rows(&self) -> usize {
        self.rows
    }

    fn cols(&self) -> usize {
        self.cols
    }

    fn row_stride(&self) -> usize {
        self.row_stride
    }

    fn as_ptr(&self) -> *const T {
        self.ptr as *const T
    }

    unsafe fn get_unchecked(&self, index: [usize; 2]) -> &T {
        &*(self.ptr.offset((index[0] * self.row_stride + index[1]) as isize))
    }
}

impl<T> MatrixSlice<T> {
    /// Produce a matrix slice from a matrix
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    /// use rusty_machine::linalg::matrix::MatrixSlice;
    ///
    /// let a = Matrix::new(3,3, (0..9).collect::<Vec<usize>>());
    /// let slice = MatrixSlice::from_matrix(&a, [1,1], 2, 2);
    /// ```
    pub fn from_matrix(mat: &Matrix<T>,
                       start: [usize; 2],
                       rows: usize,
                       cols: usize)
                       -> MatrixSlice<T> {
        assert!(start[0] + rows <= mat.rows(),
                "View dimensions exceed matrix dimensions.");
        assert!(start[1] + cols <= mat.cols(),
                "View dimensions exceed matrix dimensions.");
        unsafe {
            MatrixSlice {
                ptr: mat.data().get_unchecked(start[0] * mat.cols + start[1]) as *const T,
                rows: rows,
                cols: cols,
                row_stride: mat.cols,
            }
        }
    }

    /// Produce a matrix slice from an existing matrix slice.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    /// use rusty_machine::linalg::matrix::MatrixSlice;
    ///
    /// let a = Matrix::new(3,3, (0..9).collect::<Vec<usize>>());
    /// let slice = MatrixSlice::from_matrix(&a, [1,1], 2, 2);
    /// let new_slice = slice.reslice([0,0], 1, 1);
    /// ```
    pub fn reslice(mut self,
                            start: [usize; 2],
                            rows: usize,
                            cols: usize)
                            -> MatrixSlice<T> {
        assert!(start[0] + rows <= self.rows,
            "View dimensions exceed matrix dimensions.");
        assert!(start[1] + cols <= self.cols,
                "View dimensions exceed matrix dimensions.");

        unsafe {
            self.ptr = self.ptr.offset((start[0] * self.cols + start[1]) as isize);
        }
        self.rows = rows;
        self.cols = cols;

        self
    }

    /// Returns an iterator over the matrix slice.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    /// use rusty_machine::linalg::matrix::MatrixSlice;
    ///
    /// let a = Matrix::new(3,3, (0..9).collect::<Vec<usize>>());
    /// let slice = MatrixSlice::from_matrix(&a, [1,1], 2, 2);
    ///
    /// let slice_data = slice.iter().map(|v| *v).collect::<Vec<usize>>();
    /// assert_eq!(slice_data, vec![4,5,7,8]);
    /// ```
    pub fn iter(&self) -> SliceIter<T> {
        SliceIter {
            slice_start: self.ptr,
            row_pos: 0,
            col_pos: 0,
            slice_rows: self.rows,
            slice_cols: self.cols,
            row_stride: self.row_stride,
            _marker: PhantomData::<&T>,
        }
    }
}

impl<T: Copy> MatrixSlice<T> {
    /// Convert the matrix slice into a new Matrix.
    pub fn into_matrix(self) -> Matrix<T> {
        let slice_data = self.iter().map(|v| *v).collect::<Vec<T>>();
        Matrix {
            rows: self.rows,
            cols: self.cols,
            data: slice_data,
        }
    }
}

impl<T> MatrixSliceMut<T> {

    /// Produce a matrix slice from a matrix
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    /// use rusty_machine::linalg::matrix::MatrixSliceMut;
    ///
    /// let mut a = Matrix::new(3,3, (0..9).collect::<Vec<usize>>());
    /// let slice = MatrixSliceMut::from_matrix(&mut a, [1,1], 2, 2);
    /// ```
    pub fn from_matrix(mat: &mut Matrix<T>,
                       start: [usize; 2],
                       rows: usize,
                       cols: usize)
                       -> MatrixSliceMut<T> {
        assert!(start[0] + rows <= mat.rows(),
                "View dimensions exceed matrix dimensions.");
        assert!(start[1] + cols <= mat.cols(),
                "View dimensions exceed matrix dimensions.");

        let mat_cols = mat.cols();

        unsafe {
            MatrixSliceMut {
                ptr: mat.mut_data().get_unchecked_mut(start[0] * mat_cols + start[1]) as *mut T,
                rows: rows,
                cols: cols,
                row_stride: mat_cols,
            }
        }
    }

    /// Produce a matrix slice from an existing matrix slice.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    /// use rusty_machine::linalg::matrix::MatrixSliceMut;
    ///
    /// let mut a = Matrix::new(3,3, (0..9).collect::<Vec<usize>>());
    /// let slice = MatrixSliceMut::from_matrix(&mut a, [1,1], 2, 2);
    /// let new_slice = slice.reslice([0,0], 1, 1);
    /// ```
    pub fn reslice(mut self,
                            start: [usize; 2],
                            rows: usize,
                            cols: usize)
                            -> MatrixSliceMut<T> {
        assert!(start[0] + rows <= self.rows,
            "View dimensions exceed matrix dimensions.");
        assert!(start[1] + cols <= self.cols,
                "View dimensions exceed matrix dimensions.");

        unsafe {
            self.ptr = self.ptr.offset((start[0] * self.cols + start[1]) as isize);
        }
        self.rows = rows;
        self.cols = cols;

        self
    }

    /// Returns an iterator over the matrix slice.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    /// use rusty_machine::linalg::matrix::MatrixSliceMut;
    ///
    /// let mut a = Matrix::new(3,3, (0..9).collect::<Vec<usize>>());
    /// let slice = MatrixSliceMut::from_matrix(&mut a, [1,1], 2, 2);
    ///
    /// let slice_data = slice.iter().map(|v| *v).collect::<Vec<usize>>();
    /// assert_eq!(slice_data, vec![4,5,7,8]);
    /// ```
    pub fn iter(&self) -> SliceIter<T> {
        SliceIter {
            slice_start: self.ptr as *const T,
            row_pos: 0,
            col_pos: 0,
            slice_rows: self.rows,
            slice_cols: self.cols,
            row_stride: self.row_stride,
            _marker: PhantomData::<&T>,
        }
    }

    /// Returns a mutable iterator over the matrix slice.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    /// use rusty_machine::linalg::matrix::MatrixSliceMut;
    ///
    /// let mut a = Matrix::new(3,3, (0..9).collect::<Vec<usize>>());
    ///
    /// {
    ///     let mut slice = MatrixSliceMut::from_matrix(&mut a, [1,1], 2, 2);
    ///
    ///     for d in slice.iter_mut() {
    ///         *d = *d + 2;
    ///     }
    /// }
    ///
    /// // Only the matrix slice is updated.
    /// assert_eq!(a.into_vec(), vec![0,1,2,3,6,7,6,9,10]);
    /// ```
    pub fn iter_mut(&mut self) -> SliceIterMut<T> {
        SliceIterMut {
            slice_start: self.ptr,
            row_pos: 0,
            col_pos: 0,
            slice_rows: self.rows,
            slice_cols: self.cols,
            row_stride: self.row_stride,
            _marker: PhantomData::<&mut T>,
        }
    }
}

impl<T: Copy> MatrixSliceMut<T> {
    /// Convert the matrix slice into a new Matrix.
    pub fn into_matrix(self) -> Matrix<T> {
        let slice_data = self.iter().map(|v| *v).collect::<Vec<T>>();
        Matrix {
            rows: self.rows,
            cols: self.cols,
            data: slice_data,
        }
    }
}

/// Iterator for the MatrixSlice
///
/// Iterates over the underlying slice data
/// in row-major order.
#[derive(Debug)]
pub struct SliceIter<'a, T: 'a> {
    slice_start: *const T,
    row_pos: usize,
    col_pos: usize,
    slice_rows: usize,
    slice_cols: usize,
    row_stride: usize,
    _marker: PhantomData<&'a T>,
}

/// Iterator for MatrixSliceMut.
///
/// Iterates over the underlying slice data
/// in row-major order.
#[derive(Debug)]
pub struct SliceIterMut<'a, T: 'a> {
    slice_start: *mut T,
    row_pos: usize,
    col_pos: usize,
    slice_rows: usize,
    slice_cols: usize,
    row_stride: usize,
    _marker: PhantomData<&'a mut T>,
}

macro_rules! impl_slice_iter (
    ($slice_iter:ident, $data_type:ty) => (
/// Iterates over the matrix slice data in row-major order.
impl<'a, T> Iterator for $slice_iter<'a, T> {
    type Item = $data_type;

    fn next(&mut self) -> Option<Self::Item> {
        // Set the position of the next element
        if self.row_pos < self.slice_rows {
            unsafe {
                let iter_ptr = self.slice_start.offset((self.row_pos * self.row_stride + self.col_pos) as isize);

                // If end of row, set to start of next row
                if self.col_pos == self.slice_cols - 1 {
                    self.row_pos += 1usize;
                    self.col_pos = 0usize;
                } else {
                    self.col_pos += 1usize;
                }

                Some(mem::transmute(iter_ptr))
            }
        } else {
            None
        }
    }
}
    );
);

impl_slice_iter!(SliceIter, &'a T);
impl_slice_iter!(SliceIterMut, &'a mut T);

#[cfg(test)]
mod tests {
    use super::BaseSlice;
    use super::super::MatrixSlice;
    use super::super::MatrixSliceMut;
	use super::super::Matrix;

	#[test]
	#[should_panic]
	fn make_slice_bad_dim() {
		let a = Matrix::new(3,3, vec![2.0; 9]);
		let _ = MatrixSlice::from_matrix(&a, [1,1], 3, 2);
	}

    #[test]
    fn make_slice() {
        let a = Matrix::new(3,3, vec![2.0; 9]);
        let b = MatrixSlice::from_matrix(&a, [1,1], 2, 2);

        assert_eq!(b.rows(), 2);
        assert_eq!(b.cols(), 2);
    }

    #[test]
    fn reslice() {
        let mut a = Matrix::new(4,4, (0..16).collect());
        let b = MatrixSlice::from_matrix(&a, [1,1], 3, 3);
        {
            let c = b.reslice([0,1], 2, 2);

            assert_eq!(c.rows(), 2);
            assert_eq!(c.cols(), 2);

            assert_eq!(c[[0,0]], 6);
            assert_eq!(c[[0,1]], 7);
            assert_eq!(c[[1,0]], 10);
            assert_eq!(c[[1,1]], 11);
        }

        let b = MatrixSliceMut::from_matrix(&mut a, [1,1], 3, 3);

        let c = b.reslice([0,1], 2, 2);

        assert_eq!(c.rows(), 2);
        assert_eq!(c.cols(), 2);

        assert_eq!(c[[0,0]], 6);
        assert_eq!(c[[0,1]], 7);
        assert_eq!(c[[1,0]], 10);
        assert_eq!(c[[1,1]], 11);
    }

    #[test]
    fn slice_into_matrix() {
        let mut a = Matrix::new(3,3, vec![2.0; 9]);

        let b = MatrixSlice::from_matrix(&a, [1,1], 2, 2);
        let c = b.into_matrix();
        assert_eq!(c.rows(), 2);
        assert_eq!(c.cols(), 2);

        let d = MatrixSliceMut::from_matrix(&mut a, [1,1], 2, 2);
        let e = d.into_matrix();
        assert_eq!(e.rows(), 2);
        assert_eq!(e.cols(), 2);
    }
}<|endoftext|>


<commit_before>#[derive(Default)]
#[repr(packed)]
pub struct ScratchRegisters {
    pub x18: usize,
    pub x17: usize,
    pub x16: usize,
    pub x15: usize,
    pub x14: usize,
    pub x13: usize,
    pub x12: usize,
    pub x11: usize,
    pub x10: usize,
    pub x9: usize,
    pub x8: usize,
    pub x7: usize,
    pub x6: usize,
    pub x5: usize,
    pub x4: usize,
    pub x3: usize,
    pub x2: usize,
    pub x1: usize,
    pub x0: usize,
}

impl ScratchRegisters {
    pub fn dump(&self) {
        println!("X0:    {:>016X}", { self.x0 });
        println!("X1:    {:>016X}", { self.x1 });
        println!("X2:    {:>016X}", { self.x2 });
        println!("X3:    {:>016X}", { self.x3 });
        println!("X4:    {:>016X}", { self.x4 });
        println!("X5:    {:>016X}", { self.x5 });
        println!("X6:    {:>016X}", { self.x6 });
        println!("X7:    {:>016X}", { self.x7 });
        println!("X8:    {:>016X}", { self.x8 });
        println!("X9:    {:>016X}", { self.x9 });
        println!("X10:   {:>016X}", { self.x10 });
        println!("X11:   {:>016X}", { self.x11 });
        println!("X12:   {:>016X}", { self.x12 });
        println!("X13:   {:>016X}", { self.x13 });
        println!("X14:   {:>016X}", { self.x14 });
        println!("X15:   {:>016X}", { self.x15 });
        println!("X16:   {:>016X}", { self.x16 });
        println!("X17:   {:>016X}", { self.x17 });
        println!("X18:   {:>016X}", { self.x18 });
    }
}

#[derive(Default)]
#[repr(packed)]
pub struct PreservedRegisters {
    //TODO: is X30 a preserved register?
    pub x30: usize,
    pub x29: usize,
    pub x28: usize,
    pub x27: usize,
    pub x26: usize,
    pub x25: usize,
    pub x24: usize,
    pub x23: usize,
    pub x22: usize,
    pub x21: usize,
    pub x20: usize,
    pub x19: usize,
}

impl PreservedRegisters {
    pub fn dump(&self) {
        println!("X19:   {:>016X}", { self.x19 });
        println!("X20:   {:>016X}", { self.x20 });
        println!("X21:   {:>016X}", { self.x21 });
        println!("X22:   {:>016X}", { self.x22 });
        println!("X23:   {:>016X}", { self.x23 });
        println!("X24:   {:>016X}", { self.x24 });
        println!("X25:   {:>016X}", { self.x25 });
        println!("X26:   {:>016X}", { self.x26 });
        println!("X27:   {:>016X}", { self.x27 });
        println!("X28:   {:>016X}", { self.x28 });
        println!("X29:   {:>016X}", { self.x29 });
        println!("X30:   {:>016X}", { self.x30 });
    }
}

#[derive(Default)]
#[repr(packed)]
pub struct InterruptStack {
    pub elr_el1: usize,
    //TODO: should this push be removed?
    pub unkknown: usize,
    pub tpidr_el0: usize,
    pub tpidrro_el0: usize,
    pub spsr_el1: usize,
    pub esr_el1: usize,
    pub sp_el0: usize,
    pub preserved: PreservedRegisters,
    pub scratch: ScratchRegisters,
    //TODO: eret registers
}

impl InterruptStack {
    pub fn dump(&self) {
        self.scratch.dump();
        self.preserved.dump();
        println!("SP_EL0:      {:>016X}", { self.sp_el0 });
        println!("ESR_EL1:     {:>016X}", { self.esr_el1 });
        println!("SPSR_EL1:    {:>016X}", { self.spsr_el1 });
        println!("TPIDRRO_EL0: {:>016X}", { self.tpidrro_el0 });
        println!("TPIDR_EL0:   {:>016X}", { self.tpidr_el0 });
        println!("UNKNOWN:     {:>016X}", { self.unkknown });
        println!("ELR_EL1:     {:>016X}", { self.elr_el1 });
    }

    //TODO
    pub fn is_singlestep(&self) -> bool { false }
    pub fn set_singlestep(&mut self, singlestep: bool) {}
}
<commit_msg>Fix typo in InterruptStack parameter<commit_after>#[derive(Default)]
#[repr(packed)]
pub struct ScratchRegisters {
    pub x18: usize,
    pub x17: usize,
    pub x16: usize,
    pub x15: usize,
    pub x14: usize,
    pub x13: usize,
    pub x12: usize,
    pub x11: usize,
    pub x10: usize,
    pub x9: usize,
    pub x8: usize,
    pub x7: usize,
    pub x6: usize,
    pub x5: usize,
    pub x4: usize,
    pub x3: usize,
    pub x2: usize,
    pub x1: usize,
    pub x0: usize,
}

impl ScratchRegisters {
    pub fn dump(&self) {
        println!("X0:    {:>016X}", { self.x0 });
        println!("X1:    {:>016X}", { self.x1 });
        println!("X2:    {:>016X}", { self.x2 });
        println!("X3:    {:>016X}", { self.x3 });
        println!("X4:    {:>016X}", { self.x4 });
        println!("X5:    {:>016X}", { self.x5 });
        println!("X6:    {:>016X}", { self.x6 });
        println!("X7:    {:>016X}", { self.x7 });
        println!("X8:    {:>016X}", { self.x8 });
        println!("X9:    {:>016X}", { self.x9 });
        println!("X10:   {:>016X}", { self.x10 });
        println!("X11:   {:>016X}", { self.x11 });
        println!("X12:   {:>016X}", { self.x12 });
        println!("X13:   {:>016X}", { self.x13 });
        println!("X14:   {:>016X}", { self.x14 });
        println!("X15:   {:>016X}", { self.x15 });
        println!("X16:   {:>016X}", { self.x16 });
        println!("X17:   {:>016X}", { self.x17 });
        println!("X18:   {:>016X}", { self.x18 });
    }
}

#[derive(Default)]
#[repr(packed)]
pub struct PreservedRegisters {
    //TODO: is X30 a preserved register?
    pub x30: usize,
    pub x29: usize,
    pub x28: usize,
    pub x27: usize,
    pub x26: usize,
    pub x25: usize,
    pub x24: usize,
    pub x23: usize,
    pub x22: usize,
    pub x21: usize,
    pub x20: usize,
    pub x19: usize,
}

impl PreservedRegisters {
    pub fn dump(&self) {
        println!("X19:   {:>016X}", { self.x19 });
        println!("X20:   {:>016X}", { self.x20 });
        println!("X21:   {:>016X}", { self.x21 });
        println!("X22:   {:>016X}", { self.x22 });
        println!("X23:   {:>016X}", { self.x23 });
        println!("X24:   {:>016X}", { self.x24 });
        println!("X25:   {:>016X}", { self.x25 });
        println!("X26:   {:>016X}", { self.x26 });
        println!("X27:   {:>016X}", { self.x27 });
        println!("X28:   {:>016X}", { self.x28 });
        println!("X29:   {:>016X}", { self.x29 });
        println!("X30:   {:>016X}", { self.x30 });
    }
}

#[derive(Default)]
#[repr(packed)]
pub struct InterruptStack {
    pub elr_el1: usize,
    //TODO: should this push be removed?
    pub unknown: usize,
    pub tpidr_el0: usize,
    pub tpidrro_el0: usize,
    pub spsr_el1: usize,
    pub esr_el1: usize,
    pub sp_el0: usize,
    pub preserved: PreservedRegisters,
    pub scratch: ScratchRegisters,
    //TODO: eret registers
}

impl InterruptStack {
    pub fn dump(&self) {
        self.scratch.dump();
        self.preserved.dump();
        println!("SP_EL0:      {:>016X}", { self.sp_el0 });
        println!("ESR_EL1:     {:>016X}", { self.esr_el1 });
        println!("SPSR_EL1:    {:>016X}", { self.spsr_el1 });
        println!("TPIDRRO_EL0: {:>016X}", { self.tpidrro_el0 });
        println!("TPIDR_EL0:   {:>016X}", { self.tpidr_el0 });
        println!("UNKNOWN:     {:>016X}", { self.unknown });
        println!("ELR_EL1:     {:>016X}", { self.elr_el1 });
    }

    //TODO
    pub fn is_singlestep(&self) -> bool { false }
    pub fn set_singlestep(&mut self, singlestep: bool) {}
}
<|endoftext|>


<commit_before>#![feature(phase)]

extern crate cargo;
extern crate hammer;
extern crate serialize;
#[phase(plugin, link)]
extern crate log;

use hammer::{FlagConfig,FlagConfiguration};
use std::os;
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use serialize::Encodable;
use cargo::{GlobalFlags, NoFlags, execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::important_paths::find_project;
use cargo::util::{CliError, CliResult, Require, config, human};

fn main() {
    execute();
}

#[deriving(Encodable)]
struct ProjectLocation {
    root: String
}

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute() {
    debug!("executing; cmd=cargo; args={}", os::args());

    let (cmd, args) = process(os::args());

    match cmd.as_slice() {
        "config-for-key" => {
            log!(4, "cmd == config-for-key");
            execute_main_without_stdin(config_for_key)
        },
        "config-list" => {
            log!(4, "cmd == config-list");
            execute_main_without_stdin(config_list)
        },
        "locate-project" => {
            log!(4, "cmd == locate-project");
            execute_main_without_stdin(locate_project)
        },
        "--help" | "-h" | "help" | "-?" => {
            println!("Commands:");
            println!("  build          # compile the current project");
            println!("  test           # run the tests");
            println!("  clean          # remove the target directory");
            println!("  run            # build and execute src/main.rs");
            println!("");

            let (_, options) = hammer::usage::<GlobalFlags>(false);
            println!("Options (for all commands):\n\n{}", options);
        },
        _ => {
            let command = format!("cargo-{}{}", cmd, os::consts::EXE_SUFFIX);
            let mut command = match os::self_exe_path() {
                Some(path) => {
                    let p1 = path.join("../lib/cargo").join(command.as_slice());
                    let p2 = path.join(command.as_slice());
                    println!("{} {}", p1.display(), p2.display());
                    if p1.exists() {
                        Command::new(p1)
                    } else if p2.exists() {
                        Command::new(p2)
                    } else {
                        Command::new(command)
                    }
                }
                None => Command::new(command),
            };
            let command = command
                .args(args.as_slice())
                .stdin(InheritFd(0))
                .stdout(InheritFd(1))
                .stderr(InheritFd(2))
                .status();

            match command {
                Ok(ExitStatus(0)) => (),
                Ok(ExitStatus(i)) | Ok(ExitSignal(i)) => {
                    handle_error(CliError::new("", i as uint), &mut shell(false))
                }
                Err(_) => handle_error(CliError::new("No such subcommand", 127), &mut shell(false))
            }
        }
    }
}

fn process(args: Vec<String>) -> (String, Vec<String>) {
    let mut args = Vec::from_slice(args.tail());
    let head = args.shift().unwrap_or("--help".to_string());

    (head, args)
}

#[deriving(Encodable)]
struct ConfigOut {
    values: std::collections::HashMap<String, config::ConfigValue>
}

#[deriving(Decodable)]
struct ConfigForKeyFlags {
    key: String,
    human: bool
}

impl FlagConfig for ConfigForKeyFlags {
    fn config(_: Option<ConfigForKeyFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_for_key(args: ConfigForKeyFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let value = try!(config::get_config(os::getcwd(),
                                        args.key.as_slice()).map_err(|_| {
        CliError::new("Couldn't load configuration",  1)
    }));

    if args.human {
        println!("{}", value);
        Ok(None)
    } else {
        let mut map = std::collections::HashMap::new();
        map.insert(args.key.clone(), value);
        Ok(Some(ConfigOut { values: map }))
    }
}

#[deriving(Decodable)]
struct ConfigListFlags {
    human: bool
}

impl FlagConfig for ConfigListFlags {
    fn config(_: Option<ConfigListFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_list(args: ConfigListFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let configs = try!(config::all_configs(os::getcwd()).map_err(|_|
        CliError::new("Couldn't load configuration", 1)));

    if args.human {
        for (key, value) in configs.iter() {
            println!("{} = {}", key, value);
        }
        Ok(None)
    } else {
        Ok(Some(ConfigOut { values: configs }))
    }
}

fn locate_project(_: NoFlags, _: &mut MultiShell) -> CliResult<Option<ProjectLocation>> {
    let root = try!(find_project(&os::getcwd(), "Cargo.toml").map_err(|e| {
        CliError::from_boxed(e, 1)
    }));

    let string = try!(root.as_str()
                      .require(|| human("Your project path contains characters \
                                         not representable in Unicode"))
                      .map_err(|e| CliError::from_boxed(e, 1)));

    Ok(Some(ProjectLocation { root: string.to_string() }))
}
<commit_msg>Remove accidental debugging print<commit_after>#![feature(phase)]

extern crate cargo;
extern crate hammer;
extern crate serialize;
#[phase(plugin, link)]
extern crate log;

use hammer::{FlagConfig,FlagConfiguration};
use std::os;
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use serialize::Encodable;
use cargo::{GlobalFlags, NoFlags, execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::important_paths::find_project;
use cargo::util::{CliError, CliResult, Require, config, human};

fn main() {
    execute();
}

#[deriving(Encodable)]
struct ProjectLocation {
    root: String
}

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute() {
    debug!("executing; cmd=cargo; args={}", os::args());

    let (cmd, args) = process(os::args());

    match cmd.as_slice() {
        "config-for-key" => {
            log!(4, "cmd == config-for-key");
            execute_main_without_stdin(config_for_key)
        },
        "config-list" => {
            log!(4, "cmd == config-list");
            execute_main_without_stdin(config_list)
        },
        "locate-project" => {
            log!(4, "cmd == locate-project");
            execute_main_without_stdin(locate_project)
        },
        "--help" | "-h" | "help" | "-?" => {
            println!("Commands:");
            println!("  build          # compile the current project");
            println!("  test           # run the tests");
            println!("  clean          # remove the target directory");
            println!("  run            # build and execute src/main.rs");
            println!("");

            let (_, options) = hammer::usage::<GlobalFlags>(false);
            println!("Options (for all commands):\n\n{}", options);
        },
        _ => {
            let command = format!("cargo-{}{}", cmd, os::consts::EXE_SUFFIX);
            let mut command = match os::self_exe_path() {
                Some(path) => {
                    let p1 = path.join("../lib/cargo").join(command.as_slice());
                    let p2 = path.join(command.as_slice());
                    if p1.exists() {
                        Command::new(p1)
                    } else if p2.exists() {
                        Command::new(p2)
                    } else {
                        Command::new(command)
                    }
                }
                None => Command::new(command),
            };
            let command = command
                .args(args.as_slice())
                .stdin(InheritFd(0))
                .stdout(InheritFd(1))
                .stderr(InheritFd(2))
                .status();

            match command {
                Ok(ExitStatus(0)) => (),
                Ok(ExitStatus(i)) | Ok(ExitSignal(i)) => {
                    handle_error(CliError::new("", i as uint), &mut shell(false))
                }
                Err(_) => handle_error(CliError::new("No such subcommand", 127), &mut shell(false))
            }
        }
    }
}

fn process(args: Vec<String>) -> (String, Vec<String>) {
    let mut args = Vec::from_slice(args.tail());
    let head = args.shift().unwrap_or("--help".to_string());

    (head, args)
}

#[deriving(Encodable)]
struct ConfigOut {
    values: std::collections::HashMap<String, config::ConfigValue>
}

#[deriving(Decodable)]
struct ConfigForKeyFlags {
    key: String,
    human: bool
}

impl FlagConfig for ConfigForKeyFlags {
    fn config(_: Option<ConfigForKeyFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_for_key(args: ConfigForKeyFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let value = try!(config::get_config(os::getcwd(),
                                        args.key.as_slice()).map_err(|_| {
        CliError::new("Couldn't load configuration",  1)
    }));

    if args.human {
        println!("{}", value);
        Ok(None)
    } else {
        let mut map = std::collections::HashMap::new();
        map.insert(args.key.clone(), value);
        Ok(Some(ConfigOut { values: map }))
    }
}

#[deriving(Decodable)]
struct ConfigListFlags {
    human: bool
}

impl FlagConfig for ConfigListFlags {
    fn config(_: Option<ConfigListFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_list(args: ConfigListFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let configs = try!(config::all_configs(os::getcwd()).map_err(|_|
        CliError::new("Couldn't load configuration", 1)));

    if args.human {
        for (key, value) in configs.iter() {
            println!("{} = {}", key, value);
        }
        Ok(None)
    } else {
        Ok(Some(ConfigOut { values: configs }))
    }
}

fn locate_project(_: NoFlags, _: &mut MultiShell) -> CliResult<Option<ProjectLocation>> {
    let root = try!(find_project(&os::getcwd(), "Cargo.toml").map_err(|e| {
        CliError::from_boxed(e, 1)
    }));

    let string = try!(root.as_str()
                      .require(|| human("Your project path contains characters \
                                         not representable in Unicode"))
                      .map_err(|e| CliError::from_boxed(e, 1)));

    Ok(Some(ProjectLocation { root: string.to_string() }))
}
<|endoftext|>


<commit_before>use na::{DefaultAllocator, Dim, VectorN, U1, U2, U3};
use na::allocator::Allocator;
use domain::NPoint;

/// A kd tree
pub struct KdTree<N : Dim>(Box<kd_tree::KdTreeImpl<N>>) where DefaultAllocator: Allocator<f64, N>;

impl<N : Dim> KdTree<N> where DefaultAllocator: Allocator<f64, N> {
    /// Get all the points from the kd-tree
    fn get_points(self) -> Vec<Box<NPoint<N>>>  {
        let mut pts = Vec::new();
        let KdTree(tree) = self;
        kd_tree::add_points_to_vector(tree, &mut pts);
        pts
    }

    fn build<TItem : NPoint<N> + Copy + 'static>(pts : &Vec<TItem>) -> Self where DefaultAllocator: Allocator<f64, N> {
        KdTree(Box::new(kd_tree::build(pts, 0)))
    }
}

mod kd_tree {
    use na::{DefaultAllocator, Dim, Vector3, VectorN, U1, U2, U3};
    use na::allocator::Allocator;
    use std::cmp::Ordering;
    use domain::NPoint;
    use super::{KdTree};

    /// kd-Tree implementation structure
    pub(super) enum KdTreeImpl<N : Dim> where DefaultAllocator: Allocator<f64, N> {
        Node(usize, Box<KdTreeImpl<N>>, Box<NPoint<N>>, Box<KdTreeImpl<N>>),
        Empty()
    }

    /// mutably enunerate points from a kd tree into a vector
    pub(super) fn add_points_to_vector<N : Dim>(tree : Box<KdTreeImpl<N>>, pts : &mut Vec<Box<NPoint<N>>>) where DefaultAllocator: Allocator<f64, N> {
        let unboxed_tree = *tree;
        match unboxed_tree {
            KdTreeImpl::Node(_, l, pt, r) => {
                add_points_to_vector(l, pts);
                pts.push(pt);
                add_points_to_vector(r, pts);
            },
            KdTreeImpl::Empty() => {}
        }
    }

    fn split_vec_with_median<N : Dim, TItem : NPoint<N> + Copy + 'static>(pts : &Vec<TItem>, dim_idx :usize) -> (Option<Vec<TItem>>, Option<TItem>, Option<Vec<TItem>>) where DefaultAllocator: Allocator<f64, N> {
        unsafe {
            let mut pts = pts.to_vec();
            pts.sort_by( |a,b| a.from_origin().get_unchecked(0, dim_idx).partial_cmp(b.from_origin().get_unchecked(0, dim_idx)).unwrap() );
            if pts.len() >= 3 {
                let length = pts.len();
                let mut middle = pts.split_off(length / 2);
                let right = middle.split_off(1);
                (Some(pts), Some(middle[0]), Some(right))
            } else if pts.len() == 2 {
                let length = pts.len();
                let mut middle = pts.split_off(1);
                (Some(pts), Some(middle[0]), None)
            } else if pts.len() == 1 {
                (None, Some(pts[0]), None)
            } else{
                (None, None, None)
            }
        }
    }

    pub(super) fn build<N : Dim, TItem : NPoint<N> + Copy + 'static>(pts : &Vec<TItem>, dimIdx :usize) -> KdTreeImpl<N> where DefaultAllocator: Allocator<f64, N> {
        match pts.first() {
            Some(first_pt) => {
                let next_dim_idx = if dimIdx + 1 >= first_pt.from_origin().ncols() {0} else {dimIdx + 1};
                match split_vec_with_median(pts, dimIdx) {
                    (Some(vec1), Some(pt), Some(vec2))  => KdTreeImpl::Node(next_dim_idx,     Box::new(build(&vec1, next_dim_idx)),   Box::new(pt),     Box::new(build(&vec2, next_dim_idx))),
                    (Some(vec1), Some(pt), None      )  => KdTreeImpl::Node(next_dim_idx,     Box::new(build(&vec1, next_dim_idx)),   Box::new(pt),     Box::new(KdTreeImpl::Empty())),
                    (None,       Some(pt), Some(vec2))  => KdTreeImpl::Node(next_dim_idx,     Box::new(KdTreeImpl::Empty()),        Box::new(pt),     Box::new(build(&vec2, next_dim_idx))),
                    (None,       Some(pt), None      )  => KdTreeImpl::Node(next_dim_idx,     Box::new(KdTreeImpl::Empty()),        Box::new(pt),     Box::new(KdTreeImpl::Empty())),
                    (None,       None,     None      )  => panic!("Should be impossible to have a first point but still split into (None, None, None)."),
                    (_      ,    None,     _         )  => panic!("Meaningless result: point must be contained in a kd-tree node.")
                }
            }
            None => {
                KdTreeImpl::Empty()
            }
        }
    }
}
<commit_msg>fixed off by one<commit_after>use na::{DefaultAllocator, Dim, VectorN, U1, U2, U3};
use na::allocator::Allocator;
use domain::NPoint;

/// A kd tree
pub struct KdTree<N : Dim>(Box<kd_tree::KdTreeImpl<N>>) where DefaultAllocator: Allocator<f64, N>;

impl<N : Dim> KdTree<N> where DefaultAllocator: Allocator<f64, N> {
    /// Get all the points from the kd-tree
    fn get_points(self) -> Vec<Box<NPoint<N>>>  {
        let mut pts = Vec::new();
        let KdTree(tree) = self;
        kd_tree::add_points_to_vector(tree, &mut pts);
        pts
    }

    fn build<TItem : NPoint<N> + Copy + 'static>(pts : &Vec<TItem>) -> Self where DefaultAllocator: Allocator<f64, N> {
        KdTree(Box::new(kd_tree::build(pts, 0)))
    }
}

mod kd_tree {
    use na::{DefaultAllocator, Dim, Vector3, VectorN, U1, U2, U3};
    use na::allocator::Allocator;
    use std::cmp::Ordering;
    use domain::NPoint;
    use super::{KdTree};

    /// kd-Tree implementation structure
    pub(super) enum KdTreeImpl<N : Dim> where DefaultAllocator: Allocator<f64, N> {
        Node(usize, Box<KdTreeImpl<N>>, Box<NPoint<N>>, Box<KdTreeImpl<N>>),
        Empty()
    }

    /// mutably enunerate points from a kd tree into a vector
    pub(super) fn add_points_to_vector<N : Dim>(tree : Box<KdTreeImpl<N>>, pts : &mut Vec<Box<NPoint<N>>>) where DefaultAllocator: Allocator<f64, N> {
        let unboxed_tree = *tree;
        match unboxed_tree {
            KdTreeImpl::Node(_, l, pt, r) => {
                add_points_to_vector(l, pts);
                pts.push(pt);
                add_points_to_vector(r, pts);
            },
            KdTreeImpl::Empty() => {}
        }
    }

    fn split_vec_with_median<N : Dim, TItem : NPoint<N> + Copy + 'static>(pts : &Vec<TItem>, dim_idx :usize) -> (Option<Vec<TItem>>, Option<TItem>, Option<Vec<TItem>>) where DefaultAllocator: Allocator<f64, N> {
        unsafe {
            let mut pts = pts.to_vec();
            pts.sort_by( |a,b| a.from_origin().get_unchecked(0, dim_idx).partial_cmp(b.from_origin().get_unchecked(0, dim_idx)).unwrap() );
            if pts.len() >= 3 {
                let length = pts.len();
                let mut middle = pts.split_off(length / 2);
                let right = middle.split_off(1);
                (Some(pts), Some(middle[0]), Some(right))
            } else if pts.len() == 2 {
                let length = pts.len();
                let mut middle = pts.split_off(1);
                (Some(pts), Some(middle[0]), None)
            } else if pts.len() == 1 {
                (None, Some(pts[0]), None)
            } else{
                (None, None, None)
            }
        }
    }

    pub(super) fn build<N : Dim, TItem : NPoint<N> + Copy + 'static>(pts : &Vec<TItem>, dim_idx :usize) -> KdTreeImpl<N> where DefaultAllocator: Allocator<f64, N> {
        match pts.first() {
            Some(first_pt) => {
                let next_dim_idx = if dim_idx + 1 >= first_pt.from_origin().ncols() {0} else {dim_idx + 1};
                match split_vec_with_median(pts, dim_idx) {
                    (Some(vec1), Some(pt), Some(vec2))  => KdTreeImpl::Node(dim_idx,     Box::new(build(&vec1, next_dim_idx)),   Box::new(pt),     Box::new(build(&vec2, next_dim_idx))),
                    (Some(vec1), Some(pt), None      )  => KdTreeImpl::Node(dim_idx,     Box::new(build(&vec1, next_dim_idx)),   Box::new(pt),     Box::new(KdTreeImpl::Empty())),
                    (None,       Some(pt), Some(vec2))  => KdTreeImpl::Node(dim_idx,     Box::new(KdTreeImpl::Empty()),          Box::new(pt),     Box::new(build(&vec2, next_dim_idx))),
                    (None,       Some(pt), None      )  => KdTreeImpl::Node(dim_idx,     Box::new(KdTreeImpl::Empty()),          Box::new(pt),     Box::new(KdTreeImpl::Empty())),
                    (None,       None,     None      )  => panic!("Should be impossible to have a first point but still split into (None, None, None)."),
                    (_      ,    None,     _         )  => panic!("Meaningless result: point must be contained in a kd-tree node.")
                }
            }
            None => {
                KdTreeImpl::Empty()
            }
        }
    }
}
<|endoftext|>


<commit_before>#![warn(bad_style,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

#![feature(macro_rules, slicing_syntax)]

extern crate glob;
extern crate "rustc-serialize" as rustc_serialize;
extern crate term;
extern crate common;

use std::{io, os, str};
use std::io::{Command, MemReader};
use std::io::process::ExitStatus;
use std::str::{MaybeOwned, SendStr};
use glob::Paths;
use rustc_serialize::{json, Decodable};
use term::color::Color;
use common::SolverResult;

const PROBLEM_EXE_PAT: &'static str = "p[0-9][0-9][0-9]";

macro_rules! try2 {
    ($e:expr) => (try!($e.map_err(|e| e.to_program_error())))
}

type ProgramResult<T> = Result<T, ProgramError>;
type OutputPair<'a> = (Option<Color>, MaybeOwned<'a>);

#[deriving(Show)]
enum ProgramErrorKind {
    IoError(io::IoError),
    JsonSyntaxError(json::ErrorCode, uint, uint),
    JsonDecoderError(json::DecoderError),
    Unknown
}

#[deriving(Show)]
struct ProgramError {
    kind: ProgramErrorKind,
    message: SendStr
}

impl ProgramError {
    pub fn new<T: IntoCow<'static, String, str>>(msg: T, kind: ProgramErrorKind) -> ProgramError {
        ProgramError {
            kind: kind,
            message: msg.into_cow()
        }
    }
}

trait ToProgramError {
    fn to_program_error(self) -> ProgramError;
}

impl ToProgramError for io::IoError {
    fn to_program_error(self) -> ProgramError {
        ProgramError::new(self.desc.into_cow(), ProgramErrorKind::IoError(self))
    }
}

impl ToProgramError for json::ParserError {
    fn to_program_error(self) -> ProgramError {
        match self {
            json::ParserError::SyntaxError(code, line, col) => {
                ProgramError::new(format!("{}:{}:{}", line, col, json::error_str(code)),
                                  ProgramErrorKind::JsonSyntaxError(code, line, col))
            },
            json::ParserError::IoError(kind, desc) => {
                (io::IoError {kind: kind, desc: desc, detail: None })
                    .to_program_error()
            }
        }
    }
}

impl ToProgramError for json::DecoderError {
    fn to_program_error(self: json::DecoderError) -> ProgramError {
        ProgramError::new(format!("{}", self), ProgramErrorKind::JsonDecoderError(self))
    }
}

fn exe_path() -> ProgramResult<Path> {
    match os::self_exe_name() {
        Some(x) => Ok(x),
        None    => Err(ProgramError::new("cannot get self exe name", ProgramErrorKind::Unknown))
    }
}

fn problem_paths(dir_path: Path) -> ProgramResult<Paths> {
    let pat = dir_path.join(PROBLEM_EXE_PAT);
    match pat.as_str() {
        Some(x) => Ok(glob::glob(x)),
        None    => Err(ProgramError::new("path contains non-utf8 character", ProgramErrorKind::Unknown))
    }
}

fn run_problem(path: &Path) -> ProgramResult<SolverResult<String>> {
    let proc_out = try2!(Command::new(path).arg("--json").output());

    if !proc_out.error.is_empty() {
        let _ = match str::from_utf8(proc_out.error[]) {
            Ok(s)  => writeln!(&mut io::stderr(), "{}", s.trim()),
            Err(e) => writeln!(&mut io::stderr(), "{}: {}", proc_out.error, e)
        };
    }

    match proc_out.status {
        ExitStatus(0) | ExitStatus(1) => { } // expected
        st => {
            return Err(ProgramError::new(format!("child process exit with {}", st), ProgramErrorKind::Unknown))
        }
    }

    let json = try2!(json::from_reader(&mut MemReader::new(proc_out.output)));
    Ok(try2!(Decodable::decode(&mut json::Decoder::new(json))))
}

fn run() -> ProgramResult<()> {
    let dir_path = try!(exe_path()).dir_path();
    let mut out = io::stdout();

    let mut is_ok = true;
    let mut num_prob = 0;
    let mut total_time = 0;
    for path in try!(problem_paths(dir_path)) {
        let program = format!("{}", path.filename_display());

        match run_problem(&path) {
            Ok(ref r) => {
                num_prob   += 1;
                total_time += r.time;
                is_ok &= r.is_ok;
                let _ = r.print_pretty(program[], true);
            }
            Err(e) => {
                is_ok = false;
                let _ = writeln!(&mut out, "{}: {}", program, e);
            }
        }
    }

    if num_prob > 0 {
        let r = SolverResult {
            time: total_time / num_prob,
            answer: "".to_string(),
            is_ok: is_ok
        };
        let _ = r.print_pretty(" AVG", true);

        let r = SolverResult {
            time: total_time,
            answer: "".to_string(),
            is_ok: is_ok
        };
        let _ = r.print_pretty(" SUM", false);
    }

    if !is_ok {
        os::set_exit_status(1);
    }

    Ok(())
}

fn main() {
    match run() {
        Ok(()) => {}
        Err(e) => {
            let _ = writeln!(&mut io::stderr(), "{}", e);
            os::set_exit_status(255);
        }
    }
}
<commit_msg>euler: minor fix<commit_after>#![warn(bad_style,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

#![feature(macro_rules, slicing_syntax)]

extern crate glob;
extern crate "rustc-serialize" as rustc_serialize;
extern crate term;
extern crate common;

use std::{io, os, str};
use std::io::{Command, MemReader};
use std::io::process::ExitStatus;
use std::str::{MaybeOwned, SendStr};
use glob::Paths;
use rustc_serialize::{json, Decodable};
use term::color::Color;
use common::SolverResult;

const PROBLEM_EXE_PAT: &'static str = "p[0-9][0-9][0-9]";

macro_rules! try2 {
    ($e:expr) => (try!($e.map_err(|e| e.to_program_error())))
}

type ProgramResult<T> = Result<T, ProgramError>;
type OutputPair<'a> = (Option<Color>, MaybeOwned<'a>);

#[deriving(Show)]
enum ProgramErrorKind {
    IoError(io::IoError),
    JsonSyntaxError(json::ErrorCode, uint, uint),
    JsonDecoderError(json::DecoderError),
    Unknown
}

#[deriving(Show)]
struct ProgramError {
    kind: ProgramErrorKind,
    message: SendStr
}

impl ProgramError {
    pub fn new<T: IntoCow<'static, String, str>>(msg: T, kind: ProgramErrorKind) -> ProgramError {
        ProgramError {
            kind: kind,
            message: msg.into_cow()
        }
    }
}

trait ToProgramError {
    fn to_program_error(self) -> ProgramError;
}

impl ToProgramError for io::IoError {
    fn to_program_error(self) -> ProgramError {
        ProgramError::new(self.desc.into_cow(), ProgramErrorKind::IoError(self))
    }
}

impl ToProgramError for json::ParserError {
    fn to_program_error(self) -> ProgramError {
        match self {
            json::ParserError::SyntaxError(code, line, col) => {
                ProgramError::new(format!("{}:{}:{}", line, col, json::error_str(code)),
                                  ProgramErrorKind::JsonSyntaxError(code, line, col))
            },
            json::ParserError::IoError(kind, desc) => {
                (io::IoError {kind: kind, desc: desc, detail: None })
                    .to_program_error()
            }
        }
    }
}

impl ToProgramError for json::DecoderError {
    fn to_program_error(self: json::DecoderError) -> ProgramError {
        ProgramError::new(format!("{}", self), ProgramErrorKind::JsonDecoderError(self))
    }
}

fn exe_path() -> ProgramResult<Path> {
    match os::self_exe_name() {
        Some(x) => Ok(x),
        None    => Err(ProgramError::new("cannot get self exe name", ProgramErrorKind::Unknown))
    }
}

fn problem_paths(dir_path: Path) -> ProgramResult<Paths> {
    let pat = dir_path.join(PROBLEM_EXE_PAT);
    match pat.as_str() {
        Some(x) => Ok(glob::glob(x)),
        None    => Err(ProgramError::new("path contains non-utf8 character", ProgramErrorKind::Unknown))
    }
}

fn run_problem(path: &Path) -> ProgramResult<SolverResult<String>> {
    let proc_out = try2!(Command::new(path).arg("--json").output());

    if !proc_out.error.is_empty() {
        let _ = match str::from_utf8(proc_out.error[]) {
            Ok(s)  => writeln!(&mut io::stderr(), "{}", s.trim()),
            Err(e) => writeln!(&mut io::stderr(), "{}: {}", proc_out.error, e)
        };
    }

    match proc_out.status {
        ExitStatus(0) | ExitStatus(1) => { } // expected
        st => {
            return Err(ProgramError::new(format!("child process exit with {}", st), ProgramErrorKind::Unknown))
        }
    }

    let json = try2!(json::from_reader(&mut MemReader::new(proc_out.output)));
    Ok(try2!(Decodable::decode(&mut json::Decoder::new(json))))
}

fn run() -> ProgramResult<()> {
    let dir_path = try!(exe_path()).dir_path();
    let mut out = io::stdout();

    let mut is_ok = true;
    let mut num_prob = 0;
    let mut total_time = 0;
    for path in try!(problem_paths(dir_path)) {
        let program = format!("{}", path.filename_display());

        match run_problem(&path) {
            Ok(ref r) => {
                num_prob   += 1;
                total_time += r.time;
                is_ok &= r.is_ok;
                let _ = r.print_pretty(program[], true);
            }
            Err(e) => {
                is_ok = false;
                let _ = writeln!(&mut out, "{}: {}", program, e);
            }
        }
    }

    if num_prob > 0 {
        let r = SolverResult {
            time: total_time / num_prob,
            answer: "".to_string(),
            is_ok: is_ok
        };
        let _ = r.print_pretty(" AVG", true);

        let r = SolverResult {
            time: total_time,
            answer: "".to_string(),
            is_ok: is_ok
        };
        let _ = r.print_pretty(" SUM", false);
    }

    if !is_ok {
        os::set_exit_status(1);
    }

    Ok(())
}

fn main() {
    if let Err(e) = run() {
        let _ = writeln!(&mut io::stderr(), "{}", e);
        os::set_exit_status(255);
    }
}
<|endoftext|>


<commit_before>/*
  Copyright (c) 2015, Al Poole <netstar@gmail.com>

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  PERFORMANCE OF THIS SOFTWARE.
*/

//   This is a HTTP proxy written in Rust!
//   DONE: POST+GET+OPTIONS

use std::string::{String};
use std::net::{SocketAddrV4,Ipv4Addr,TcpListener,TcpStream};
use std::io::{Write, Read};

const REQUEST_LEN: usize = 65535;

fn substr(buf: [u8;REQUEST_LEN], needle: &str, byte: u8) -> String
{
	let mut i = 0;
	let mut x = 0;
	let mut request = String::new();

	let srch = needle.as_bytes();

	if srch.len() == 0 {
		return request;
	}

	while buf[i] as char != '\0' {
		if buf[i] as char == srch[0] as char {
			while x < srch.len() && buf[i] as char  == srch[x] as char {
				i = i + 1;
				x = x + 1;
			}
			break;
		} else {
			i = i + 1;
		}
	}

	if x == srch.len()
	{
		//println!("match");
		let mut end = i;
		while buf[end] as char != byte as char && buf[end] as char != '\n' {
			end = end + 1;
		}

		for y in i..end {
			request.push(buf[y] as char);
		}
	}

	return request;
}

const CHUNK: usize = 4096; // PAGESIZEish

fn get_with_content_length(mut instream: &TcpStream, mut outstream: &TcpStream, total: usize) {
	let mut current = 0;
	let mut buf = [0u8; CHUNK];

	while current < total {
		let bytes = outstream.read(&mut buf). unwrap();
		if bytes == 0 {
			break;
		}

		let mut chunk = 0;

		while chunk < bytes {
			let sent = instream.write(&mut buf[0..bytes]).unwrap();
			if sent <= 0 {
				break;
			}
			chunk = chunk + sent;
			current = current + chunk;
		}
	}
}

fn get_with_no_content_length(mut instream: &TcpStream, mut outstream: &TcpStream)
{
	loop {
		let mut buf = [0u8; CHUNK];

		let bytes = outstream.read(&mut buf).unwrap();
		if bytes == 0 {
			break; // please!!!
		}

		let mut chunk = 0;

		while chunk < bytes {
			let sent = instream.write(&mut buf[0..bytes]).unwrap();
			if sent == 0 {
				break;
			}
			chunk = chunk + sent;
		}
	}
}

fn http_options_request(mut instream: TcpStream)
{
	let allow = "GET,POST,HEAD,CONNECT,OPTIONS";
	let code: String = "HTTP/1.1 200 OK\r\n".to_string();
	let request: String  = "Allow: ".to_string() + allow + "\r\n\r\n";

	let response = format!("{}{}", code, request);

	instream.write(response.as_bytes()).unwrap();
}

fn http_head_request(hdr: Header)
{
	let bogus_fix = &format!("{}:{}", hdr.hostname, 80);

	let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

	let query: String = format!("HEAD /{} HTTP/1.1\r\nHost: {}\r\n\r\n", hdr.resource, hdr.hostname);

	outstream.write(query.as_bytes()).unwrap();
}

fn http_post_request(mut instream: TcpStream, headers: Header)
{
	let bogus_fix = &format!("{}:{}", headers.hostname, 80);
	let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

	let query: String = format!("POST {}Host: {}\r\nContent-Type: {}\r\nContent-Length: {}\r\n\r\n", headers.resource, headers.hostname, headers.content, headers.length);
	outstream.write(query.as_bytes()).unwrap();

	println!("QUERY: {}", query);

	let mut buf = [0u8; CHUNK];
	let mut current = 0;

	while current < headers.length {
		let bytes = instream.read(&mut buf).unwrap();
		if bytes == 0 {
			break;
		}

		let mut chunk = 0;

		while chunk < bytes {
			let sent = outstream.write(&mut buf[0..bytes]).unwrap();
			if sent == 0 {
				break;
			}

			chunk += sent;
			current = current + chunk;
		}
	}

	let terminate = "\r\n\r\n";

	outstream.write(terminate.as_bytes()).unwrap();

	get_with_no_content_length(&instream, &outstream);
}

fn http_get_request(instream: TcpStream, headers: Header)
{
	let bogus_fix = &format!("{}:{}", headers.hostname, 80);

	let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

	let query: String = format!("GET {}Host: {}\r\nConnection: close\r\n\r\n", headers.resource, headers.hostname);
	outstream.write(query.as_bytes()).unwrap();

	println!("QUERY: {}", query);

	if headers.length > 0 {
		get_with_content_length(&instream, &outstream, headers.length);
	} else {
		get_with_no_content_length(&instream, &outstream);
	}
}

fn http_connect_request(instream: TcpStream, hdr: Header)
{
	let bogus_fix = &format!("{}:{}", hdr.hostname, 443);
	// this needs fixing!!!

	let outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

	get_with_no_content_length(&instream, &outstream);
}

fn req_resource(buf: [u8;REQUEST_LEN]) -> String
{
	let mut i = 0;
	let bytes = buf;
	let mut request: String = String::new();

	// FIXME WORDPRESS DOESN't WORK!
	while bytes[i] as char != '\0' {
		request.push(bytes[i] as char);
		i += 1;
	}

	return request;
}

fn req_content(buf: [u8;REQUEST_LEN]) -> String
{
	let content = substr(buf, "Content-Type: ", '\r' as u8);

	return content;
}

fn req_hostname(buf: [u8;REQUEST_LEN]) -> String
{
	let hostname: String = substr(buf, "http://", '/' as u8);

	return hostname;
}

fn req_length(buf: [u8;REQUEST_LEN]) -> usize
{
	let request: String = substr(buf, "Content-Length: ", '\r' as u8);
	if ! request.is_empty() {
		return request.trim().parse().unwrap();
	}

	return 0;
}

struct Header {
	pub hostname: String,
	pub resource: String,
	pub content: String,
	pub length: usize,
	pub method: String,
}

impl Header {

pub fn new() -> Header
{
	let hostname = String::new();
	let resource = String::new();
	let content  = String::new();
	let method   = String::new();
	let length   = 0;

	let h = Header {
		hostname: hostname,
		resource: resource ,
		content: content,
		length: length,
		method: method
	};

	return h;
}

}

fn check_headers(buffer: [u8;REQUEST_LEN], headers: &mut Header) -> bool
{
	if headers.hostname.is_empty() {
		headers.hostname = req_hostname(buffer);
	}

	if headers.resource.is_empty() {
		headers.resource = req_resource(buffer);
	}

	if headers.content.is_empty() {
		headers.content = req_content(buffer);
	}

	if headers.length == 0 {
		headers.length = req_length(buffer);
	}

	if headers.hostname.is_empty() || headers.resource.is_empty() || headers.method.is_empty() {
		return false;
	}

	return true;
}

fn request_headers(mut instream: &TcpStream, headers: &mut Header)
{
	let mut byte = [0u8;1];

	// bit better for now it'll do!
	while byte[0] as char != ' ' {
		instream.read(&mut byte).unwrap();
		if byte[0] as char != ' '
		{
			headers.method.push(byte[0] as char);
		}
	}

	match headers.method.as_ref() {
		"GET" | "POST" | "OPTIONS" | "HEAD" | "CONNECT" =>
		{
			// all good do not return!!!
		}

		_ =>
		{
			return;
		}
	}

	loop {
		let mut buffer = [0u8; REQUEST_LEN];
		let mut byte = [0u8; 1];
		let mut len = 0;

		while byte[0] as char != '\n' {
			let bytes = instream.read(&mut byte).unwrap();
			buffer[len] = byte[0];
			len += bytes;
		}

		buffer[len] = '\0' as u8;

		if check_headers(buffer, headers) && len == 2 {
			let mut i = 0;

			while i < REQUEST_LEN {
				buffer[i] = 0;
				i += 1;
			}
			return;
		}
	}
}

fn proxy(stream: TcpStream) {
	let mut headers: Header = Header::new();
	request_headers(&stream, &mut headers);

	match headers.method.as_ref() {
		"GET" =>
		{
			http_get_request(stream, headers);
		}

		"POST" =>
		{
			http_post_request(stream, headers);
		}

		"HEAD" =>
		{
			http_head_request(headers);
		}

		"OPTIONS" =>
		{
			http_options_request(stream);
		}

		"CONNECT" =>
		{
			println!("here {} and {}", headers.hostname, headers.resource);
			http_connect_request(stream, headers);
		}

		_ =>
		{
			println!("REQUEST UNKNOWN");
		}
	}
}

extern crate threadpool;
use threadpool::ThreadPool;

fn proxy_time(port: u16, threads: usize) {
	let ip = Ipv4Addr::new(127, 0, 0, 1);
	let host = SocketAddrV4::new(ip, port);
	let listener = TcpListener::bind(host).unwrap();

	let pool = ThreadPool::new(threads);

	for stream in listener.incoming()
	{
		match stream
		{
			Ok(stream) =>
			{
				pool.execute(move || { proxy(stream); });
			}

			Err(_) =>
			{
				println!("NET error");
				1 << 7;
			}
		}
	}

	drop (listener);
}

fn main () {
	let threads = 128;
	let port: u16 = 9999;

	println!("Blocking all badness");
	proxy_time(port, threads);
}

<commit_msg>Mess aboot<commit_after>/*
    This is bogus but it's something to msss about with

*/

//   This is a HTTP proxy written in Rust!
//   DONE: POST+GET+OPTIONS

use std::string::{String};
use std::net::{SocketAddrV4,Ipv4Addr,TcpListener,TcpStream};
use std::io::{Write, Read};

const REQUEST_LEN: usize = 65535;

fn substr(buf: [u8;REQUEST_LEN], needle: &str, byte: u8) -> String
{
	let mut i = 0;
	let mut x = 0;
	let mut request = String::new();

	let srch = needle.as_bytes();

	if srch.len() == 0 {
		return request;
	}

	while buf[i] as char != '\0' {
		if buf[i] as char == srch[0] as char {
			while x < srch.len() && buf[i] as char  == srch[x] as char {
				i = i + 1;
				x = x + 1;
			}
			break;
		} else {
			i = i + 1;
		}
	}

	if x == srch.len()
	{
		//println!("match");
		let mut end = i;
		while buf[end] as char != byte as char && buf[end] as char != '\n' {
			end = end + 1;
		}

		for y in i..end {
			request.push(buf[y] as char);
		}
	}

	return request;
}

const CHUNK: usize = 4096; // PAGESIZEish

struct Request {
   pub headers: Header,
}

impl Request {

pub fn new() -> Request
{
        let headers = Header::new();

        let r = Request {
	   headers: headers,
        };

        r
}

fn get_with_content_length(self: &mut Request, mut instream: &TcpStream, mut outstream: &TcpStream) {
	let mut current = 0;
	let mut buf = [0u8; CHUNK];

	while current < self.headers.content_length {
		let bytes = outstream.read(&mut buf). unwrap();
		if bytes == 0 {
			break;
		}

		let mut chunk = 0;

		while chunk < bytes {
			let sent = instream.write(&mut buf[0..bytes]).unwrap();
			if sent <= 0 {
				break;
			}
			chunk = chunk + sent;
			current = current + chunk;
		}
	}
}

fn get_with_no_content_length(self: &mut Request, mut instream: &TcpStream, mut outstream: &TcpStream)
{
	loop {
		let mut buf = [0u8; CHUNK];

		let bytes = outstream.read(&mut buf).unwrap();
		if bytes == 0 {
			break; // please!!!
		}

		let mut chunk = 0;

		while chunk < bytes {
			let sent = instream.write(&mut buf[0..bytes]).unwrap();
			if sent == 0 {
				break;
			}
			chunk = chunk + sent;
		}
	}
}

pub fn options(self: &mut Request, mut instream: TcpStream)
{
	let allow = "GET,POST,HEAD,CONNECT,OPTIONS";
	let code: String = "HTTP/1.1 200 OK\r\n".to_string();
	let request: String  = "Allow: ".to_string() + allow + "\r\n\r\n";

	let response = format!("{}{}", code, request);

	instream.write(response.as_bytes()).unwrap();
}

pub fn head(self: &mut Request)
{
	let bogus_fix = &format!("{}:{}", self.headers.hostname, 80);

	let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

	let query: String = format!("HEAD /{} HTTP/1.1\r\nHost: {}\r\n\r\n", self.headers.resource, self.headers.hostname);

	outstream.write(query.as_bytes()).unwrap();
}

pub fn post(self: &mut Request, mut instream: TcpStream)
{
	let bogus_fix = &format!("{}:{}", self.headers.hostname, 80);
	let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

	let query: String = format!("POST {}Host: {}\r\nContent-Type: {}\r\nContent-Length: {}\r\n\r\n", self.headers.resource, self.headers.hostname, self.headers.content_type, self.headers.content_length);
	outstream.write(query.as_bytes()).unwrap();

	println!("QUERY: {}", query);

	let mut buf = [0u8; CHUNK];
	let mut current = 0;

	while current < self.headers.content_length {
		let bytes = instream.read(&mut buf).unwrap();
		if bytes == 0 {
			break;
		}

		let mut chunk = 0;

		while chunk < bytes {
			let sent = outstream.write(&mut buf[0..bytes]).unwrap();
			if sent == 0 {
				break;
			}

			chunk += sent;
			current = current + chunk;
		}
	}

	let terminate = "\r\n\r\n";

	outstream.write(terminate.as_bytes()).unwrap();

	self.get_with_no_content_length(&instream, &outstream);
}

pub fn get(self: &mut Request, instream: TcpStream)
{

	let bogus_fix = &format!("{}:{}", self.headers.hostname, 80);

	let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

	let query: String = format!("GET {}Host: {}\r\nConnection: close\r\n\r\n", self.headers.resource, self.headers.hostname);
	outstream.write(query.as_bytes()).unwrap();

	println!("QUERY: {}", query);

	if self.headers.content_length > 0 {
		self.get_with_content_length(&instream, &outstream);
	} else {
		self.get_with_no_content_length(&instream, &outstream);
	}
}

pub fn connect(self: &mut Request, instream: TcpStream)
{
	let bogus_fix = &format!("{}:{}", self.headers.hostname, 443);
	// this needs fixing!!!

	let outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

	self.get_with_no_content_length(&instream, &outstream);
}
}

struct Header {
	pub hostname: String,
	pub resource: String,
	pub content_type: String,
	pub content_length: usize,
	pub method: String,
}

impl Header {

pub fn new() -> Header
{
	let hostname = String::new();
	let resource = String::new();
	let content_type  = String::new();
	let content_length = 0;
	let method = String::new();

	let h = Header {
		hostname: hostname,
		resource: resource ,
		content_type: content_type,
		content_length: content_length,
		method: method
	};

	return h;
}

fn check(self: &mut Header, buffer: [u8;REQUEST_LEN]) -> bool
{
	if self.hostname.is_empty() {
	   self.hostname = self.hostname(buffer);
	}

	if self.resource.is_empty() {
		self.resource = self.resource(buffer);
	}

	if self.content_type.is_empty() {
		self.content_type = self.content_type(buffer);
	}

	if self.content_length == 0 {
		self.content_length = self.content_length(buffer);
	}

	if self.hostname.is_empty() || self.resource.is_empty() || self.method.is_empty() {
		return false;
	}

	return true;
}

fn get(self: &mut Header, mut instream: &TcpStream)
{
	let mut byte = [0u8;1];

	// bit better for now it'll do!
	while byte[0] as char != ' ' {
		instream.read(&mut byte).unwrap();
		if byte[0] as char != ' '
		{
			self.method.push(byte[0] as char);
		}
	}

	match self.method.as_ref() {
		"GET" | "POST" | "OPTIONS" | "HEAD" | "CONNECT" =>
		{
			// all good do not return!!!
		}

		_ =>
		{
			return;
		}
	}

	loop {
		let mut buffer = [0u8; REQUEST_LEN];
		let mut byte = [0u8; 1];
		let mut len = 0;

		while byte[0] as char != '\n' {
			let bytes = instream.read(&mut byte).unwrap();
			buffer[len] = byte[0];
			len += bytes;
		}

		buffer[len] = '\0' as u8;

		if self.check(buffer) && len == 2 {
			let mut i = 0;

			while i < REQUEST_LEN {
				buffer[i] = 0;
				i += 1;
			}
			return;
		}
	}
}

fn resource(self: &mut Header, buf: [u8;REQUEST_LEN]) -> String
{
	let mut i = 0;
	let bytes = buf;
	let mut request: String = String::new();

	// FIXME WORDPRESS DOESN't WORK!
	while bytes[i] as char != '\0' {
		request.push(bytes[i] as char);
		i += 1;
	}

	return request;
}

fn content_type(self: &mut Header, buf: [u8;REQUEST_LEN]) -> String
{
	let content = substr(buf, "Content-Type: ", '\r' as u8);

	return content;
}

fn hostname(self: &mut Header, buf: [u8;REQUEST_LEN]) -> String
{
	let hostname: String = substr(buf, "http://", '/' as u8);

	return hostname;
}

fn content_length(self: &mut Header, buf: [u8;REQUEST_LEN]) -> usize
{
	let request: String = substr(buf, "Content-Length: ", '\r' as u8);
	if ! request.is_empty() {
		return request.trim().parse().unwrap();
	}

	return 0;
}

}

fn proxy(stream: TcpStream) {
        let mut http: Request = Request::new();
	http.headers.get(&stream);

	match http.headers.method.as_ref() {
		"GET" =>
		{
			http.get(stream);
		}

		"POST" =>
		{
			http.post(stream);
		}

		"HEAD" =>
		{
			http.head();
		}

		"OPTIONS" =>
		{
			http.options(stream);
		}

		"CONNECT" =>
		{
			http.connect(stream);
		}

		_ =>
		{
			println!("REQUEST UNKNOWN");
		}
	}
}

extern crate threadpool;
use threadpool::ThreadPool;

fn proxy_time(port: u16, threads: usize) {
	let ip = Ipv4Addr::new(127, 0, 0, 1);
	let host = SocketAddrV4::new(ip, port);
	let listener = TcpListener::bind(host).unwrap();

	let pool = ThreadPool::new(threads);

	for stream in listener.incoming()
	{
		match stream
		{
			Ok(stream) =>
			{
				pool.execute(move || { proxy(stream); });
			}

			Err(_) =>
			{
				println!("NET error");
				1 << 7;
			}
		}
	}

	drop (listener);
}

fn main () {
	let threads = 128;
	let port: u16 = 9999;

	println!("Blocking all badness on port {}", port);
	proxy_time(port, threads);
}

<|endoftext|>


<commit_before>
use clap;
use git2::Repository;
use git2::BranchType;
use gerritlib::error::GGRResult;

/// manage subfunction of `topic` command
///
/// Currently implemented sub commands:
///
/// * create
/// * forget
pub fn manage(x: &clap::ArgMatches) -> GGRResult<()> {
    match x.subcommand() {
        ("create", Some(y)) => { create(y) },
        ("forget", Some(y)) => { forget(y) },
        _ => {
            println!("{}", x.usage());
            Ok(())
        },
    }
}

fn create(y: &clap::ArgMatches) -> GGRResult<()> {
    let branchname = y.value_of("branchname").unwrap();

    let repository_names = y.values_of("repo").unwrap();
    let mut repo;
    if repository_names.count() > 0 {
        println!("Create topic branch \"{}\" at repository:", branchname);
        for (_, subrep) in y.values_of("repo").unwrap().enumerate() {
            let (repo_name, reference_name) = split_repo_reference(subrep);

            print!("* {}: ", &repo_name);
            repo = try!(Repository::open(&repo_name));
            match repo.revparse_single(&reference_name) {
                Ok(object) => {
                    let commit = match object.as_commit() {
                        Some(c) => c,
                        None => { println!("fail (not exists)"); continue},
                    };

                    match repo.branch(branchname, commit, false) {
                        Ok(_) => { println!("done") },
                        Err(e) => { println!("fail ({})", e.message()); },
                    };
                },
                Err(e) => {
                    println!("fail ({})", e.message())
                },
            }
        }
    }

    Ok(())
}

fn forget(y: &clap::ArgMatches) -> GGRResult<()> {
    let branchname = y.value_of("branchname").unwrap();

    let repo = try!(Repository::discover("."));

    /* remove branch on the current repository */
    match repo.find_branch(branchname, BranchType::Local) {
        Ok(mut branch) => {
            print!("* current folder: ");
            if branch.delete().is_err() {
                println!("fail");
            } else {
                println!("done");
            }
        },
        Err(_) => {},
    };

    /* remove branch on all submodules */
    if y.is_present("recursive") {
        let submodules = try!(repo.submodules());
        for sm in &submodules {
            let reposub = try!(sm.open());
            match reposub.find_branch(branchname, BranchType::Local) {
                Ok(mut branch) => {
                    print!("* {}: ", sm.path().display());
                    if branch.delete().is_err() {
                        println!("fail");
                    } else {
                        println!("done");
                    }
                },
                Err(_) => {},
            };
        }
    }
    Ok(())
}

fn split_repo_reference(t: &str) -> (String, String) {
    let mut splited = t.split(':');

    let repo = String::from(splited.next().unwrap());
    let mut reference = String::from("origin/master");

    if let Some(x) = splited.next() {
        reference = String::from(x);
    };

    (repo, reference)
}

<commit_msg>topic: add two return pathes<commit_after>
use clap;
use git2::Repository;
use git2::BranchType;
use gerritlib::error::GGRError;
use gerritlib::error::GGRResult;

/// manage subfunction of `topic` command
///
/// Currently implemented sub commands:
///
/// * create
/// * forget
pub fn manage(x: &clap::ArgMatches) -> GGRResult<()> {
    match x.subcommand() {
        ("create", Some(y)) => { create(y) },
        ("forget", Some(y)) => { forget(y) },
        _ => {
            println!("{}", x.usage());
            Ok(())
        },
    }
}

fn create(y: &clap::ArgMatches) -> GGRResult<()> {
    let branchname = y.value_of("branchname").unwrap();

    let repository_names = y.values_of("repo").unwrap();
    let mut repo;
    if repository_names.count() > 0 {
        println!("Create topic branch \"{}\" at repository:", branchname);
        for (_, subrep) in y.values_of("repo").unwrap().enumerate() {
            let (repo_name, reference_name) = split_repo_reference(subrep);

            print!("* {}: ", &repo_name);
            repo = try!(Repository::open(&repo_name));
            match repo.revparse_single(&reference_name) {
                Ok(object) => {
                    let commit = match object.as_commit() {
                        Some(c) => c,
                        None => { println!("fail (not exists)"); continue},
                    };

                    match repo.branch(branchname, commit, false) {
                        Ok(_) => { println!("done") },
                        Err(e) => { println!("fail ({})", e.message()); },
                    };
                },
                Err(e) => {
                    println!("fail ({})", e.message())
                },
            }
        }
    }

    Ok(())
}

fn forget(y: &clap::ArgMatches) -> GGRResult<()> {
    let branchname = y.value_of("branchname").unwrap();

    let repo = try!(Repository::discover("."));

    /* remove branch on the current repository */
    match repo.find_branch(branchname, BranchType::Local) {
        Ok(mut branch) => {
            print!("* current folder: ");
            if branch.delete().is_err() {
                println!("fail");
            } else {
                println!("done");
            }
        },
        Err(err) => {
            return Err(GGRError::from(err));
        }
    };

    /* remove branch on all submodules */
    if y.is_present("recursive") {
        let submodules = try!(repo.submodules());
        for sm in &submodules {
            let reposub = try!(sm.open());
            match reposub.find_branch(branchname, BranchType::Local) {
                Ok(mut branch) => {
                    print!("* {}: ", sm.path().display());
                    if branch.delete().is_err() {
                        println!("fail");
                    } else {
                        println!("done");
                    }
                },
                Err(err) => {
                    return Err(GGRError::from(err));
                }
            };
        }
    }
    Ok(())
}

fn split_repo_reference(t: &str) -> (String, String) {
    let mut splited = t.split(':');

    let repo = String::from(splited.next().unwrap());
    let mut reference = String::from("origin/master");

    if let Some(x) = splited.next() {
        reference = String::from(x);
    };

    (repo, reference)
}

<|endoftext|>