<commit_before>/* Cymbalum, Molecular Simulation in Rust - Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 */
//! Array types, for storage of data in multidimentional arrays. The types in
//! this module are only intented for data storage, and do not provide any
//! mathematical operations.
use std::ops::{Index, IndexMut};
use std::cmp;

/// Trait bound for data in the array types
pub trait Data: Clone + PartialEq + Default {}
impl<T: Clone + PartialEq + Default> Data for T {}

/******************************************************************************/
/// Bidimensional array, with cache locality and runtime size. This type is
/// intended for storage of data only, and do not provide any mathematical
/// operations.
#[derive(Debug, Clone, PartialEq)]
pub struct Array2<T: Data> {
    /// Data storage
    data: Vec<T>,
    /// Size of the array
    size: (usize, usize)
}

impl<T: Data> Array2<T> {
    /// Get the size of the array
    pub fn size(&self) -> (usize, usize) {
        self.size
    }

    /// Create a new empty `Array2`.
    pub fn new() -> Array2<T> {
        Array2{
            data: Vec::new(),
            size: (0, 0)
        }
    }

    /// Create a new `Array2` of size `size` filed with `T::default()` values.
    pub fn with_size(size: (usize, usize)) -> Array2<T> {
        Array2::<T>::check_size(size);
        let data_size = size.0 * size.1;
        let vec = vec![T::default(); data_size];
        Array2{
            data: vec,
            size: size
        }
    }

    /// Get the index in the `data` vector corresponding to the point `i, j`
    #[inline] fn get_index(&self, i: usize, j: usize) -> usize {
        Array2::<T>::get_index_for_size(i, j, self.size)
    }

    /// Get the index in the `data` vector corresponding to the point `i, j`,
    /// and the size `size`.
    #[inline] fn get_index_for_size(i: usize, j: usize, size: (usize, usize)) -> usize {
        i * size.1 + j
    }

    fn check_size(size: (usize, usize)) {
        assert!(size.0 != 0, "size can not be null in dimmension 0");
        assert!(size.1 != 0, "size can not be null in dimmension 1");
    }

    /// Resize the array to be of size `new_size * new_size`. If the new size
    /// is bigger than the old size, the new values inserted are `T::default()`.
    /// Old values are preseved.
    pub fn resize(&mut self, size: (usize, usize)) {
        Array2::<T>::check_size(size);
        if size == self.size {return;}
        let mut new_data = vec![T::default(); size.0 * size.1];
        let n0 = cmp::min(self.size.0, size.0);
        let n1 = cmp::min(self.size.1, size.1);
        for i0 in 0..n0 {
            for i1 in 0..n1 {
                let new_idx = Array2::<T>::get_index_for_size(i0, i1, size);
                new_data[new_idx] = self[(i0, i1)].clone();
            }
        }
        self.data = new_data;
        self.size = size;
    }
}

impl<T: Data> Index<(usize, usize)> for Array2<T> {
    type Output = T;
    #[inline]
    fn index(&self, index: (usize, usize)) -> &T {
        assert!(index.0 < self.size.0, format!("index out of bounds in dimmension 0: the len is {} but the index is {}", self.size.0, index.0));
        assert!(index.1 < self.size.1, format!("index out of bounds in dimmension 1: the len is {} but the index is {}", self.size.1, index.1));
        let idx = self.get_index(index.0, index.1);
        return &self.data[idx];
    }
}

impl<T: Data> IndexMut<(usize, usize)> for Array2<T> {
    #[inline]
    fn index_mut(&mut self, index: (usize, usize)) -> &mut T {
        assert!(index.0 < self.size.0, format!("index out of bounds in dimmension 0: the len is {} but the index is {}", self.size.0, index.0));
        assert!(index.1 < self.size.1, format!("index out of bounds in dimmension 1: the len is {} but the index is {}", self.size.1, index.1));
        let idx = self.get_index(index.0, index.1);
        return &mut self.data[idx];
    }
}

/******************************************************************************/
/// 3 dimmensional array type with cache locality, and runtime size. This type
/// is intended for storage of data only, and do not provide any mathematical
/// operations.
#[derive(Debug, Clone, PartialEq)]
pub struct Array3<T: Data> {
    data: Vec<T>,
    size: (usize, usize, usize),
}

impl<T: Data> Array3<T> {
    /// Create a new empty tensor
    pub fn new() -> Array3<T> {
        Array3 {
            data: Vec::new(),
            size: (0, 0, 0),
        }
    }

    /// Get the current size of the array
    pub fn size(&self) -> (usize, usize, usize) {
        self.size
    }

    /// Create a new `Array3` of size `size` filed with `T::default()` values.
    pub fn with_size(size: (usize, usize, usize)) -> Array3<T> {
        Array3::<T>::check_size(size);
        let data_size = size.0 * size.1 * size.2;
        let vec = vec![T::default(); data_size];
        Array3 {
            data: vec,
            size: size,
        }
    }

    /// Get the index in the `data` vector corresponding to the point `i, j, k`
    #[inline] fn get_index(&self, i: usize, j: usize, k: usize) -> usize {
        Array3::<T>::get_index_for_size(i, j, k, self.size)
    }

    /// Get the index in the `data` vector corresponding to the point `i, j`,
    /// and the size `size`.
    #[inline] fn get_index_for_size(i: usize, j: usize, k:usize, size: (usize, usize, usize)) -> usize {
        i * size.1 * size.2 + j * size.2 + k
    }

    fn check_size(size: (usize, usize, usize)) {
        assert!(size.0 != 0, "size can not be null in dimmension 0");
        assert!(size.1 != 0, "size can not be null in dimmension 1");
        assert!(size.2 != 0, "size can not be null in dimmension 2");
    }

    /// Resize the array to be of size `new_size * new_size`. If the new size
    /// is bigger than the old size, the new values inserted are `T::default()`.
    /// Old values are preseved.
    pub fn resize(&mut self, size: (usize, usize, usize)) {
        Array3::<T>::check_size(size);
        if size == self.size {return;}
        let mut new_data = vec![T::default(); size.0 * size.1 * size.2];
        let n0 = cmp::min(self.size.0, size.0);
        let n1 = cmp::min(self.size.1, size.1);
        let n2 = cmp::min(self.size.2, size.2);
        for i0 in 0..n0 {
            for i1 in 0..n1 {
                for i2 in 0..n2 {
                    let new_idx = Array3::<T>::get_index_for_size(i0, i1, i2, size);
                    new_data[new_idx] = self[(i0, i1, i2)].clone();
                }
            }
        }
        self.data = new_data;
        self.size = size;
    }
}

impl<T: Data> Index<(usize, usize, usize)> for Array3<T> {
    type Output = T;
    #[inline]
    fn index(&self, index: (usize, usize, usize)) -> &T {
        assert!(index.0 < self.size.0, format!("index out of bounds in dimmension 0: the len is {} but the index is {}", self.size.0, index.0));
        assert!(index.1 < self.size.1, format!("index out of bounds in dimmension 1: the len is {} but the index is {}", self.size.1, index.1));
        assert!(index.2 < self.size.2, format!("index out of bounds in dimmension 2: the len is {} but the index is {}", self.size.2, index.2));
        let idx = self.get_index(index.0, index.1, index.2);
        return &self.data[idx];
    }
}

impl<T: Data> IndexMut<(usize, usize, usize)> for Array3<T> {
    #[inline]
    fn index_mut(&mut self, index: (usize, usize, usize)) -> &mut T {
        assert!(index.0 < self.size.0, format!("index out of bounds in dimmension 0: the len is {} but the index is {}", self.size.0, index.0));
        assert!(index.1 < self.size.1, format!("index out of bounds in dimmension 1: the len is {} but the index is {}", self.size.1, index.1));
        assert!(index.2 < self.size.2, format!("index out of bounds in dimmension 2: the len is {} but the index is {}", self.size.2, index.2));
        let idx = self.get_index(index.0, index.1, index.2);
        return &mut self.data[idx];
    }
}

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

    mod array_2 {
        use super::*;

        #[test]
        #[should_panic]
        fn out_of_bounds_dim_1() {
            let a = Array2::<f64>::with_size((4, 5));
            let _ = a[(6, 1)];
        }

        #[test]
        #[should_panic]
        fn out_of_bounds_dim_2() {
            let a = Array2::<f64>::with_size((4, 5));
            let _ = a[(1, 6)];
        }

        #[test]
        fn size() {
            let a = Array2::<f64>::with_size((6, 4));
            assert_eq!(a.size(), (6, 4));
        }

        #[test]
        fn index() {
            let mut a = Array2::<f64>::with_size((4, 8));
            for i in 0..4 {
                for j in 0..8 {
                    assert_eq!(a[(i, j)], 0.0);
                }
            }

            a[(2, 3)] = 7.0;
            assert_eq!(a[(2, 3)], 7.0);
        }

        #[test]
        fn resize() {
            let mut a = Array2::<f64>::with_size((6, 5));
            assert_eq!(a.size(), (6, 5));
            a[(2, 3)] = 42.0;

            a.resize((9, 7));
            assert_eq!(a.size(), (9, 7));
            assert_eq!(a[(2, 3)], 42.0);

            a.resize((3, 4));
            assert_eq!(a.size(), (3, 4));
            assert_eq!(a[(2, 3)], 42.0);
        }

        #[test]
        #[should_panic]
        fn resize_to_zero() {
            let mut a = Array2::<f64>::with_size((6, 5));
            a.resize((0, 3));
        }
    }

    mod array_3 {
        use super::*;

        #[test]
        #[should_panic]
        fn out_of_bounds_dim_1() {
            let a = Array3::<f64>::with_size((4, 5, 6));
            let _ = a[(6, 1, 3)];
        }

        #[test]
        #[should_panic]
        fn out_of_bounds_dim_2() {
            let a = Array3::<f64>::with_size((4, 5, 6));
            let _ = a[(1, 7, 3)];
        }

        #[test]
        #[should_panic]
        fn out_of_bounds_dim_3() {
            let a = Array3::<f64>::with_size((4, 5, 6));
            let _ = a[(0, 1, 8)];
        }

        #[test]
        fn size() {
            let a = Array3::<f64>::with_size((6, 4, 9));
            assert_eq!(a.size(), (6, 4, 9));
        }

        #[test]
        fn index() {
            let mut a = Array3::<f64>::with_size((4, 5, 3));
            for i in 0..4 {
                for j in 0..5 {
                    for k in 0..3 {
                        assert_eq!(a[(i, j, k)], 0.0);
                    }
                }
            }

            a[(2, 3, 0)] = 7.0;
            assert_eq!(a[(2, 3, 0)], 7.0);
        }

        #[test]
        fn resize() {
            let mut a = Array3::<f64>::with_size((6, 6, 8));
            assert_eq!(a.size(), (6, 6, 8));
            a[(2, 3, 0)] = 42.0;

            a.resize((9, 10, 2));
            assert_eq!(a.size(), (9, 10, 2));
            assert_eq!(a[(2, 3, 0)], 42.0);

            a.resize((3, 4, 1));
            assert_eq!(a.size(), (3, 4, 1));
            assert_eq!(a[(2, 3, 0)], 42.0);
        }

        #[test]
        #[should_panic]
        fn resize_to_zero() {
            let mut a = Array3::<f64>::with_size((6, 5, 7));
            a.resize((0, 3, 2));
        }
    }
}
<commit_msg>Remove bound checking in Array types<commit_after>/* Cymbalum, Molecular Simulation in Rust - Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 */
//! Array types, for storage of data in multidimentional arrays. The types in
//! this module are only intented for data storage, and do not provide any
//! mathematical operations.
use std::ops::{Index, IndexMut};
use std::cmp;

/// Trait bound for data in the array types
pub trait Data: Clone + PartialEq + Default {}
impl<T: Clone + PartialEq + Default> Data for T {}

/******************************************************************************/
/// Bidimensional array, with cache locality and runtime size. This type is
/// intended for storage of data only, and do not provide any mathematical
/// operations.
#[derive(Debug, Clone, PartialEq)]
pub struct Array2<T: Data> {
    /// Data storage
    data: Vec<T>,
    /// Size of the array
    size: (usize, usize)
}

impl<T: Data> Array2<T> {
    /// Get the size of the array
    pub fn size(&self) -> (usize, usize) {
        self.size
    }

    /// Create a new empty `Array2`.
    pub fn new() -> Array2<T> {
        Array2{
            data: Vec::new(),
            size: (0, 0)
        }
    }

    /// Create a new `Array2` of size `size` filed with `T::default()` values.
    pub fn with_size(size: (usize, usize)) -> Array2<T> {
        Array2::<T>::check_size(size);
        let data_size = size.0 * size.1;
        let vec = vec![T::default(); data_size];
        Array2{
            data: vec,
            size: size
        }
    }

    /// Get the index in the `data` vector corresponding to the point `i, j`
    #[inline] fn get_index(&self, i: usize, j: usize) -> usize {
        Array2::<T>::get_index_for_size(i, j, self.size)
    }

    /// Get the index in the `data` vector corresponding to the point `i, j`,
    /// and the size `size`.
    #[inline] fn get_index_for_size(i: usize, j: usize, size: (usize, usize)) -> usize {
        i * size.1 + j
    }

    fn check_size(size: (usize, usize)) {
        assert!(size.0 != 0, "size can not be null in dimmension 0");
        assert!(size.1 != 0, "size can not be null in dimmension 1");
    }

    /// Resize the array to be of size `new_size * new_size`. If the new size
    /// is bigger than the old size, the new values inserted are `T::default()`.
    /// Old values are preseved.
    pub fn resize(&mut self, size: (usize, usize)) {
        Array2::<T>::check_size(size);
        if size == self.size {return;}
        let mut new_data = vec![T::default(); size.0 * size.1];
        let n0 = cmp::min(self.size.0, size.0);
        let n1 = cmp::min(self.size.1, size.1);
        for i0 in 0..n0 {
            for i1 in 0..n1 {
                let new_idx = Array2::<T>::get_index_for_size(i0, i1, size);
                new_data[new_idx] = self[(i0, i1)].clone();
            }
        }
        self.data = new_data;
        self.size = size;
    }
}

impl<T: Data> Index<(usize, usize)> for Array2<T> {
    type Output = T;
    #[inline]
    fn index(&self, index: (usize, usize)) -> &T {
        debug_assert!(index.0 < self.size.0, format!("index out of bounds in dimmension 0: the len is {} but the index is {}", self.size.0, index.0));
        debug_assert!(index.1 < self.size.1, format!("index out of bounds in dimmension 1: the len is {} but the index is {}", self.size.1, index.1));
        let idx = self.get_index(index.0, index.1);
        unsafe {
            return self.data.get_unchecked(idx);
        }
    }
}

impl<T: Data> IndexMut<(usize, usize)> for Array2<T> {
    #[inline]
    fn index_mut(&mut self, index: (usize, usize)) -> &mut T {
        debug_assert!(index.0 < self.size.0, format!("index out of bounds in dimmension 0: the len is {} but the index is {}", self.size.0, index.0));
        debug_assert!(index.1 < self.size.1, format!("index out of bounds in dimmension 1: the len is {} but the index is {}", self.size.1, index.1));
        let idx = self.get_index(index.0, index.1);
        unsafe {
            return self.data.get_unchecked_mut(idx);
        }
    }
}

/******************************************************************************/
/// 3 dimmensional array type with cache locality, and runtime size. This type
/// is intended for storage of data only, and do not provide any mathematical
/// operations.
#[derive(Debug, Clone, PartialEq)]
pub struct Array3<T: Data> {
    data: Vec<T>,
    size: (usize, usize, usize),
}

impl<T: Data> Array3<T> {
    /// Create a new empty tensor
    pub fn new() -> Array3<T> {
        Array3 {
            data: Vec::new(),
            size: (0, 0, 0),
        }
    }

    /// Get the current size of the array
    pub fn size(&self) -> (usize, usize, usize) {
        self.size
    }

    /// Create a new `Array3` of size `size` filed with `T::default()` values.
    pub fn with_size(size: (usize, usize, usize)) -> Array3<T> {
        Array3::<T>::check_size(size);
        let data_size = size.0 * size.1 * size.2;
        let vec = vec![T::default(); data_size];
        Array3 {
            data: vec,
            size: size,
        }
    }

    /// Get the index in the `data` vector corresponding to the point `i, j, k`
    #[inline] fn get_index(&self, i: usize, j: usize, k: usize) -> usize {
        Array3::<T>::get_index_for_size(i, j, k, self.size)
    }

    /// Get the index in the `data` vector corresponding to the point `i, j`,
    /// and the size `size`.
    #[inline] fn get_index_for_size(i: usize, j: usize, k:usize, size: (usize, usize, usize)) -> usize {
        i * size.1 * size.2 + j * size.2 + k
    }

    fn check_size(size: (usize, usize, usize)) {
        assert!(size.0 != 0, "size can not be null in dimmension 0");
        assert!(size.1 != 0, "size can not be null in dimmension 1");
        assert!(size.2 != 0, "size can not be null in dimmension 2");
    }

    /// Resize the array to be of size `new_size * new_size`. If the new size
    /// is bigger than the old size, the new values inserted are `T::default()`.
    /// Old values are preseved.
    pub fn resize(&mut self, size: (usize, usize, usize)) {
        Array3::<T>::check_size(size);
        if size == self.size {return;}
        let mut new_data = vec![T::default(); size.0 * size.1 * size.2];
        let n0 = cmp::min(self.size.0, size.0);
        let n1 = cmp::min(self.size.1, size.1);
        let n2 = cmp::min(self.size.2, size.2);
        for i0 in 0..n0 {
            for i1 in 0..n1 {
                for i2 in 0..n2 {
                    let new_idx = Array3::<T>::get_index_for_size(i0, i1, i2, size);
                    new_data[new_idx] = self[(i0, i1, i2)].clone();
                }
            }
        }
        self.data = new_data;
        self.size = size;
    }
}

impl<T: Data> Index<(usize, usize, usize)> for Array3<T> {
    type Output = T;
    #[inline]
    fn index(&self, index: (usize, usize, usize)) -> &T {
        debug_assert!(index.0 < self.size.0, format!("index out of bounds in dimmension 0: the len is {} but the index is {}", self.size.0, index.0));
        debug_assert!(index.1 < self.size.1, format!("index out of bounds in dimmension 1: the len is {} but the index is {}", self.size.1, index.1));
        debug_assert!(index.2 < self.size.2, format!("index out of bounds in dimmension 2: the len is {} but the index is {}", self.size.2, index.2));
        let idx = self.get_index(index.0, index.1, index.2);
        unsafe {
            return self.data.get_unchecked(idx);
        }
    }
}

impl<T: Data> IndexMut<(usize, usize, usize)> for Array3<T> {
    #[inline]
    fn index_mut(&mut self, index: (usize, usize, usize)) -> &mut T {
        debug_assert!(index.0 < self.size.0, format!("index out of bounds in dimmension 0: the len is {} but the index is {}", self.size.0, index.0));
        debug_assert!(index.1 < self.size.1, format!("index out of bounds in dimmension 1: the len is {} but the index is {}", self.size.1, index.1));
        debug_assert!(index.2 < self.size.2, format!("index out of bounds in dimmension 2: the len is {} but the index is {}", self.size.2, index.2));
        let idx = self.get_index(index.0, index.1, index.2);
        unsafe {
            return self.data.get_unchecked_mut(idx);
        }
    }
}

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

    mod array_2 {
        use super::*;

        #[test]
        #[should_panic]
        fn out_of_bounds_dim_1() {
            let a = Array2::<f64>::with_size((4, 5));
            let _ = a[(6, 1)];
        }

        #[test]
        #[should_panic]
        fn out_of_bounds_dim_2() {
            let a = Array2::<f64>::with_size((4, 5));
            let _ = a[(1, 6)];
        }

        #[test]
        fn size() {
            let a = Array2::<f64>::with_size((6, 4));
            assert_eq!(a.size(), (6, 4));
        }

        #[test]
        fn index() {
            let mut a = Array2::<f64>::with_size((4, 8));
            for i in 0..4 {
                for j in 0..8 {
                    assert_eq!(a[(i, j)], 0.0);
                }
            }

            a[(2, 3)] = 7.0;
            assert_eq!(a[(2, 3)], 7.0);
        }

        #[test]
        fn resize() {
            let mut a = Array2::<f64>::with_size((6, 5));
            assert_eq!(a.size(), (6, 5));
            a[(2, 3)] = 42.0;

            a.resize((9, 7));
            assert_eq!(a.size(), (9, 7));
            assert_eq!(a[(2, 3)], 42.0);

            a.resize((3, 4));
            assert_eq!(a.size(), (3, 4));
            assert_eq!(a[(2, 3)], 42.0);
        }

        #[test]
        #[should_panic]
        fn resize_to_zero() {
            let mut a = Array2::<f64>::with_size((6, 5));
            a.resize((0, 3));
        }
    }

    mod array_3 {
        use super::*;

        #[test]
        #[should_panic]
        fn out_of_bounds_dim_1() {
            let a = Array3::<f64>::with_size((4, 5, 6));
            let _ = a[(6, 1, 3)];
        }

        #[test]
        #[should_panic]
        fn out_of_bounds_dim_2() {
            let a = Array3::<f64>::with_size((4, 5, 6));
            let _ = a[(1, 7, 3)];
        }

        #[test]
        #[should_panic]
        fn out_of_bounds_dim_3() {
            let a = Array3::<f64>::with_size((4, 5, 6));
            let _ = a[(0, 1, 8)];
        }

        #[test]
        fn size() {
            let a = Array3::<f64>::with_size((6, 4, 9));
            assert_eq!(a.size(), (6, 4, 9));
        }

        #[test]
        fn index() {
            let mut a = Array3::<f64>::with_size((4, 5, 3));
            for i in 0..4 {
                for j in 0..5 {
                    for k in 0..3 {
                        assert_eq!(a[(i, j, k)], 0.0);
                    }
                }
            }

            a[(2, 3, 0)] = 7.0;
            assert_eq!(a[(2, 3, 0)], 7.0);
        }

        #[test]
        fn resize() {
            let mut a = Array3::<f64>::with_size((6, 6, 8));
            assert_eq!(a.size(), (6, 6, 8));
            a[(2, 3, 0)] = 42.0;

            a.resize((9, 10, 2));
            assert_eq!(a.size(), (9, 10, 2));
            assert_eq!(a[(2, 3, 0)], 42.0);

            a.resize((3, 4, 1));
            assert_eq!(a.size(), (3, 4, 1));
            assert_eq!(a[(2, 3, 0)], 42.0);
        }

        #[test]
        #[should_panic]
        fn resize_to_zero() {
            let mut a = Array3::<f64>::with_size((6, 5, 7));
            a.resize((0, 3, 2));
        }
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(maud_macros)]

extern crate maud;
extern crate iron;
extern crate router;
extern crate logger;
extern crate pulldown_cmark;
extern crate git_appraise;
extern crate persistent;
extern crate typemap;
extern crate chrono;
extern crate maud_pulldown_cmark;

use maud::PreEscaped;
use std::env;
use iron::prelude::*;
use iron::status;
use router::*;
use logger::*;
use iron::mime::Mime;
use git_appraise::{ Oid, Repository, Review, Status };
use persistent::{ Read };
use typemap::Key;
use maud_pulldown_cmark::markdown;

fn style() -> String {
  format!("
    html * {{
      color-profile: sRGB;
      rendering-intent: auto;
    }}

    body {{
      background-color: {base03};
      color: {base0};
    }}

    h1, h2, h3, h4, h5, h6 {{
      color: {base1};
      border-color: {base0};
    }}

    body {{
      font-family: \"Raleway\", \"HelveticaNeue\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;
      margin: 20px auto;
      max-width: 650px;
      line-height: 1.4;
      font-size: 18px;
      padding: 0 10px;
    }}

    h1,h2,h3 {{
      font-family: \"Lucida Console\", Monaco, monospace;
      line-height: 1.2;
    }}

    a {{
      color: {blue};
      text-decoration: none;
      cursor: pointer;
    }}

    a:hover {{
      color: {lightblue}
    }}
  ",
    base03 = "#002b36",
    // base02 = "#073642",
    // base01 = "#586e75",
    // base00 = "#657b83",
    base0 = "#839496",
    base1 = "#93a1a1",
    // base2 = "#eee8d5",
    // base3 = "#fdf6e3",
    // yellow = "#b58900",
    // orange = "#cb4b16",
    // red = "#dc322f",
    // magenta = "#d33682",
    // violet = "#6c71c4",
    blue = "#268bd2",
    // cyan = "#2aa198",
    // green = "#859900",
    lightblue = "#3797db"
  )
}

fn get_reviews(repo: &Repository) -> Vec<Review> {
  repo.all_reviews().unwrap().collect()
}

fn get_review(repo: &Repository, id: Oid) -> Review {
  repo.review_for(id).unwrap()
}

fn render_reviews(reviews: Vec<Review>) -> String {
  let mut buffer = String::new();
  html!(buffer, {
    head {
      style type="text/css" {
        $PreEscaped(style())
      }
    }
    body {
      ol {
        #for review in &reviews {
          li {
            a href={ "/" $review.id() } $review.id()
            " -> "
            $review.request().description().unwrap()
          }
        }
      }
    }
  }).unwrap();
  buffer
}

fn render_review(review: Review) -> String {
  let mut buffer = String::new();
  html!(buffer, {
    head {
      style type="text/css" {
        $PreEscaped(style())
      }
    }
    body {
      ul {
        #if let Some(requester) = review.request().requester() {
          li { "Requester: " $requester }
        }
        #if let Some(timestamp) = review.request().timestamp() {
          li { "Timestamp: " $(chrono::naive::datetime::NaiveDateTime::from_timestamp(timestamp.seconds(), 0)) }
        }
        #if let (Some(review_ref), Some(target_ref)) = (review.request().review_ref(), review.request().target_ref()) {
          li { "Proposed merge: " $review_ref " -> " $target_ref }
        }
        #if let Some(reviewers) = review.request().reviewers() {
          li { "Reviewers:"
            ul {
              #for reviewer in reviewers {
                li $reviewer
              }
            }
          }
        }
        #if let Some(ref description) = review.request().description() {
          li {
            "Description: "
            $(markdown::from_string(description))
          }
        }
        li {
          "CI Statuses: "
          ol {
            #for status in review.ci_statuses() {
              li {
                #if let Some(url) = status.url() {
                  a href={ $url } $status.agent().unwrap_or("<Unknown agent>")
                }
                #if status.url().is_none() {
                  $status.agent().unwrap_or("<Unknown agent>")
                }
                ": "
                $status.status().map(|s| match s { Status::Success => "success", Status::Failure => "failure" }).unwrap_or("null")
              }
            }
          }
        }
        li {
          "Analyses: "
          ol {
            #for analysis in review.analyses() {
              #if let Some(url) = analysis.url() {
                li {
                  a href={ $url } $url
                }
              }
            }
          }
        }
        li {
          "Comments: "
          ol {
            #for comment in review.comments() {
              li {
                ul {
                  #if let Some(author) = comment.author() {
                    li { "Comment from " $author }
                  }
                  li { "Comment Status: " $comment.resolved().map(|r| if r { "lgtm" } else { "nmw" }).unwrap_or("fyi") }
                  #if let Some(location) = comment.location() {
                    li { "Referencing " $(format!("{:?}", location)) }
                  }
                  #if let Some(description) = comment.description() {
                    li { $(markdown::from_string(description)) }
                  }
                }
              }
            }
          }
        }
      }
    }
  }).unwrap();
  buffer
}

pub fn result(buffer: String) -> IronResult<Response> {
  Ok(Response::with(("text/html".parse::<Mime>().unwrap(), status::Ok, buffer)))
}

fn reviews_handler(req: &mut iron::request::Request) -> IronResult<Response> {
  let path = req.get::<Read<RepositoryPath>>().unwrap();
  let repo = Repository::open(&*path).unwrap();
  let reviews = get_reviews(&repo);
  let buffer = render_reviews(reviews);
  result(buffer)
}

fn review_handler(req: &mut iron::request::Request) -> IronResult<Response> {
  let path = req.get::<Read<RepositoryPath>>().unwrap();
  let repo = Repository::open(&*path).unwrap();
  let id = Oid::from_str(req.extensions.get::<Router>().unwrap().find("query").unwrap()).unwrap();
  let review = get_review(&repo, id);
  let buffer = render_review(review);
  result(buffer)
}

#[derive(Copy, Clone)]
struct RepositoryPath;
impl Key for RepositoryPath { type Value = String; }

fn main() {
  let path = env::args().nth(1).unwrap();

  let mut router = Router::new();
  router.get("/", reviews_handler);
  router.get("/:query", review_handler);

  let (logger_before, logger_after) = Logger::new(None);

  let mut chain = Chain::new(router);

  chain.link(Read::<RepositoryPath>::both(path));
  chain.link_before(logger_before);
  chain.link_after(logger_after);

  Iron::new(chain).http("localhost:3000").unwrap();
}
<commit_msg>Pull out some rendering logic to separate functions<commit_after>#![feature(plugin)]
#![plugin(maud_macros)]

extern crate maud;
extern crate iron;
extern crate router;
extern crate logger;
extern crate pulldown_cmark;
extern crate git_appraise;
extern crate persistent;
extern crate typemap;
extern crate chrono;
extern crate maud_pulldown_cmark;

use maud::{ PreEscaped, Render };
use std::env;
use std::fmt;
use iron::prelude::*;
use iron::status;
use router::*;
use logger::*;
use iron::mime::Mime;
use git_appraise::{ Oid, Repository, Review, Status, Comment };
use persistent::{ Read };
use typemap::Key;
use maud_pulldown_cmark::markdown;

fn style() -> String {
  format!("
    html * {{
      color-profile: sRGB;
      rendering-intent: auto;
    }}

    body {{
      background-color: {base03};
      color: {base0};
    }}

    h1, h2, h3, h4, h5, h6 {{
      color: {base1};
      border-color: {base0};
    }}

    body {{
      font-family: \"Raleway\", \"HelveticaNeue\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;
      margin: 20px auto;
      max-width: 650px;
      line-height: 1.4;
      font-size: 18px;
      padding: 0 10px;
    }}

    h1,h2,h3 {{
      font-family: \"Lucida Console\", Monaco, monospace;
      line-height: 1.2;
    }}

    a {{
      color: {blue};
      text-decoration: none;
      cursor: pointer;
    }}

    a:hover {{
      color: {lightblue}
    }}
  ",
    base03 = "#002b36",
    // base02 = "#073642",
    // base01 = "#586e75",
    // base00 = "#657b83",
    base0 = "#839496",
    base1 = "#93a1a1",
    // base2 = "#eee8d5",
    // base3 = "#fdf6e3",
    // yellow = "#b58900",
    // orange = "#cb4b16",
    // red = "#dc322f",
    // magenta = "#d33682",
    // violet = "#6c71c4",
    blue = "#268bd2",
    // cyan = "#2aa198",
    // green = "#859900",
    lightblue = "#3797db"
  )
}

fn get_reviews(repo: &Repository) -> Vec<Review> {
  repo.all_reviews().unwrap().collect()
}

fn get_review(repo: &Repository, id: Oid) -> Review {
  repo.review_for(id).unwrap()
}

fn render_reviews(reviews: Vec<Review>) -> String {
  let mut buffer = String::new();
  html!(buffer, {
    head {
      style type="text/css" {
        $PreEscaped(style())
      }
    }
    body {
      ol {
        #for review in &reviews {
          li {
            a href={ "/" $review.id() } $review.id()
            " -> "
            $review.request().description().unwrap()
          }
        }
      }
    }
  }).unwrap();
  buffer
}

struct RequestRenderer<'a>(&'a git_appraise::Request);

impl<'a> Render for RequestRenderer<'a> {
  fn render(&self, mut w: &mut fmt::Write) -> fmt::Result {
    let request = self.0;
    html!(w, {
      div {
        #if let Some(requester) = request.requester() {
          div { "Requester: " $requester }
        }
        #if let Some(timestamp) = request.timestamp() {
          div { "Timestamp: " $(chrono::naive::datetime::NaiveDateTime::from_timestamp(timestamp.seconds(), 0)) }
        }
        #if let (Some(review_ref), Some(target_ref)) = (request.review_ref(), request.target_ref()) {
          div { "Proposed merge: " $review_ref " -> " $target_ref }
        }
        #if let Some(reviewers) = request.reviewers() {
          div { "Reviewers:"
            ul {
              #for reviewer in reviewers {
                li $reviewer
              }
            }
          }
        }
        #if let Some(ref description) = request.description() {
          div {
            "Description: "
            div { $(markdown::from_string(description)) }
          }
        }
      }
    })
  }
}

struct CommentRenderer<'a>(&'a git_appraise::Comment);

impl<'a> Render for CommentRenderer<'a> {
  fn render(&self, mut w: &mut fmt::Write) -> fmt::Result {
    let comment = self.0;
    html!(w, {
      div {
        #if let Some(author) = comment.author() {
          div { "Comment from " $author }
        }
        div { "Comment Status: " $comment.resolved().map(|r| if r { "lgtm" } else { "nmw" }).unwrap_or("fyi") }
        #if let Some(location) = comment.location() {
          div { "Referencing " $(format!("{:?}", location)) }
        }
        #if let Some(description) = comment.description() {
          div { $(markdown::from_string(description)) }
        }
      }
    })
  }
}

fn render_review(review: Review) -> String {
  let mut buffer = String::new();
  html!(buffer, {
    head {
      style type="text/css" {
        $PreEscaped(style())
      }
    }
    body {
      $(RequestRenderer(review.request()))
      div {
        "CI Statuses: "
        ul {
          #for status in review.ci_statuses() {
            li {
              #if let Some(url) = status.url() {
                a href={ $url } $status.agent().unwrap_or("<Unknown agent>")
              }
              #if status.url().is_none() {
                $status.agent().unwrap_or("<Unknown agent>")
              }
              ": "
              $status.status().map(|s| match s { Status::Success => "success", Status::Failure => "failure" }).unwrap_or("null")
            }
          }
        }
      }
      div {
        "Analyses: "
        ul {
          #for analysis in review.analyses() {
            #if let Some(url) = analysis.url() {
              li {
                a href={ $url } $url
              }
            }
          }
        }
      }
      div {
        "Comments: "
        ul {
          #for comment in review.comments() {
            li {
              $(CommentRenderer(&comment))
            }
          }
        }
      }
    }
  }).unwrap();
  buffer
}

pub fn result(buffer: String) -> IronResult<Response> {
  Ok(Response::with(("text/html".parse::<Mime>().unwrap(), status::Ok, buffer)))
}

fn reviews_handler(req: &mut iron::request::Request) -> IronResult<Response> {
  let path = req.get::<Read<RepositoryPath>>().unwrap();
  let repo = Repository::open(&*path).unwrap();
  let reviews = get_reviews(&repo);
  let buffer = render_reviews(reviews);
  result(buffer)
}

fn review_handler(req: &mut iron::request::Request) -> IronResult<Response> {
  let path = req.get::<Read<RepositoryPath>>().unwrap();
  let repo = Repository::open(&*path).unwrap();
  let id = Oid::from_str(req.extensions.get::<Router>().unwrap().find("query").unwrap()).unwrap();
  let review = get_review(&repo, id);
  let buffer = render_review(review);
  result(buffer)
}

#[derive(Copy, Clone)]
struct RepositoryPath;
impl Key for RepositoryPath { type Value = String; }

fn main() {
  let path = env::args().nth(1).unwrap();

  let mut router = Router::new();
  router.get("/", reviews_handler);
  router.get("/:query", review_handler);

  let (logger_before, logger_after) = Logger::new(None);

  let mut chain = Chain::new(router);

  chain.link(Read::<RepositoryPath>::both(path));
  chain.link_before(logger_before);
  chain.link_after(logger_after);

  Iron::new(chain).http("localhost:3000").unwrap();
}
<|endoftext|>


<commit_before>use crate::prelude::*;

/// Create the `main` function which will initialize the rust runtime and call
/// users main function.
pub fn maybe_create_entry_wrapper<'a, 'tcx: 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<impl Backend + 'static>,
) {
    use rustc::middle::lang_items::StartFnLangItem;
    use rustc::session::config::EntryFnType;

    let (main_def_id, use_start_lang_item) = match *tcx.sess.entry_fn.borrow() {
        Some((id, _, entry_ty)) => (
            tcx.hir.local_def_id(id),
            match entry_ty {
                EntryFnType::Main => true,
                EntryFnType::Start => false,
            },
        ),
        None => return,
    };

    create_entry_fn(tcx, module, main_def_id, use_start_lang_item);;

    fn create_entry_fn<'a, 'tcx: 'a>(
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        m: &mut Module<impl Backend + 'static>,
        rust_main_def_id: DefId,
        use_start_lang_item: bool,
    ) {
        let main_ret_ty = tcx.fn_sig(rust_main_def_id).output();
        // Given that `main()` has no arguments,
        // then its return type cannot have
        // late-bound regions, since late-bound
        // regions must appear in the argument
        // listing.
        let main_ret_ty = tcx.erase_regions(&main_ret_ty.no_bound_vars().unwrap());

        let cmain_sig = Signature {
            params: vec![
                AbiParam::new(m.target_config().pointer_type()),
                AbiParam::new(m.target_config().pointer_type()),
            ],
            returns: vec![AbiParam::new(
                m.target_config().pointer_type(), /*isize*/
            )],
            call_conv: CallConv::SystemV,
        };

        let cmain_func_id = m
            .declare_function("main", Linkage::Export, &cmain_sig)
            .unwrap();

        let instance = Instance::mono(tcx, rust_main_def_id);

        let (main_name, main_sig) = get_function_name_and_sig(tcx, instance);

        let main_func_id = m
            .declare_function(&main_name, Linkage::Import, &main_sig)
            .unwrap();

        let mut ctx = Context::new();
        ctx.func = Function::with_name_signature(ExternalName::user(0, 0), cmain_sig.clone());
        {
            let mut func_ctx = FunctionBuilderContext::new();
            let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);

            let ebb = bcx.create_ebb();
            bcx.switch_to_block(ebb);
            let arg_argc = bcx.append_ebb_param(ebb, m.target_config().pointer_type());
            let arg_argv = bcx.append_ebb_param(ebb, m.target_config().pointer_type());

            let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func);

            let call_inst = if use_start_lang_item {
                let start_def_id = tcx.require_lang_item(StartFnLangItem);
                let start_instance = Instance::resolve(
                    tcx,
                    ParamEnv::reveal_all(),
                    start_def_id,
                    tcx.intern_substs(&[main_ret_ty.into()]),
                )
                .unwrap();

                let (start_name, start_sig) = get_function_name_and_sig(tcx, start_instance);
                let start_func_id = m
                    .declare_function(&start_name, Linkage::Import, &start_sig)
                    .unwrap();

                let main_val = bcx
                    .ins()
                    .func_addr(m.target_config().pointer_type(), main_func_ref);

                let func_ref = m.declare_func_in_func(start_func_id, &mut bcx.func);
                bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv])
            } else {
                // using user-defined start fn
                bcx.ins().call(main_func_ref, &[arg_argc, arg_argv])
            };

            let result = bcx.inst_results(call_inst)[0];
            bcx.ins().return_(&[result]);
            bcx.seal_all_blocks();
            bcx.finalize();
        }
        m.define_function(cmain_func_id, &mut ctx).unwrap();
    }
}
<commit_msg>Rustup to rustc 1.32.0-nightly (4a45578bc 2018-12-07)<commit_after>use crate::prelude::*;

/// Create the `main` function which will initialize the rust runtime and call
/// users main function.
pub fn maybe_create_entry_wrapper<'a, 'tcx: 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<impl Backend + 'static>,
) {
    use rustc::middle::lang_items::StartFnLangItem;
    use rustc::session::config::EntryFnType;

    let (main_def_id, use_start_lang_item) = match *tcx.sess.entry_fn.borrow() {
        Some((id, _, entry_ty)) => (
            tcx.hir().local_def_id(id),
            match entry_ty {
                EntryFnType::Main => true,
                EntryFnType::Start => false,
            },
        ),
        None => return,
    };

    create_entry_fn(tcx, module, main_def_id, use_start_lang_item);;

    fn create_entry_fn<'a, 'tcx: 'a>(
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        m: &mut Module<impl Backend + 'static>,
        rust_main_def_id: DefId,
        use_start_lang_item: bool,
    ) {
        let main_ret_ty = tcx.fn_sig(rust_main_def_id).output();
        // Given that `main()` has no arguments,
        // then its return type cannot have
        // late-bound regions, since late-bound
        // regions must appear in the argument
        // listing.
        let main_ret_ty = tcx.erase_regions(&main_ret_ty.no_bound_vars().unwrap());

        let cmain_sig = Signature {
            params: vec![
                AbiParam::new(m.target_config().pointer_type()),
                AbiParam::new(m.target_config().pointer_type()),
            ],
            returns: vec![AbiParam::new(
                m.target_config().pointer_type(), /*isize*/
            )],
            call_conv: CallConv::SystemV,
        };

        let cmain_func_id = m
            .declare_function("main", Linkage::Export, &cmain_sig)
            .unwrap();

        let instance = Instance::mono(tcx, rust_main_def_id);

        let (main_name, main_sig) = get_function_name_and_sig(tcx, instance);

        let main_func_id = m
            .declare_function(&main_name, Linkage::Import, &main_sig)
            .unwrap();

        let mut ctx = Context::new();
        ctx.func = Function::with_name_signature(ExternalName::user(0, 0), cmain_sig.clone());
        {
            let mut func_ctx = FunctionBuilderContext::new();
            let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);

            let ebb = bcx.create_ebb();
            bcx.switch_to_block(ebb);
            let arg_argc = bcx.append_ebb_param(ebb, m.target_config().pointer_type());
            let arg_argv = bcx.append_ebb_param(ebb, m.target_config().pointer_type());

            let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func);

            let call_inst = if use_start_lang_item {
                let start_def_id = tcx.require_lang_item(StartFnLangItem);
                let start_instance = Instance::resolve(
                    tcx,
                    ParamEnv::reveal_all(),
                    start_def_id,
                    tcx.intern_substs(&[main_ret_ty.into()]),
                )
                .unwrap();

                let (start_name, start_sig) = get_function_name_and_sig(tcx, start_instance);
                let start_func_id = m
                    .declare_function(&start_name, Linkage::Import, &start_sig)
                    .unwrap();

                let main_val = bcx
                    .ins()
                    .func_addr(m.target_config().pointer_type(), main_func_ref);

                let func_ref = m.declare_func_in_func(start_func_id, &mut bcx.func);
                bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv])
            } else {
                // using user-defined start fn
                bcx.ins().call(main_func_ref, &[arg_argc, arg_argv])
            };

            let result = bcx.inst_results(call_inst)[0];
            bcx.ins().return_(&[result]);
            bcx.seal_all_blocks();
            bcx.finalize();
        }
        m.define_function(cmain_func_id, &mut ctx).unwrap();
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2015, Alberto Corona <alberto@0x1a.us>
// All rights reserved. This file is part of rpf, distributed under the
// BSD 3-Clause license. For full terms please see the LICENSE file.

extern crate ansi_term;

use self::ansi_term::Style;
use self::ansi_term::{Colour,ANSIString};
use self::ansi_term::Colour::{Red};

/// Wrapper for `ansi_term::Colour`
pub enum Color {
    Black,
    Red,
    Green,
    Yellow,
    Blue,
    Purple,
    Cyan,
    White,
}

/// Trait for creating stylized console printing using `ansi_term`
pub trait Styled {
    /// Creates a bold `ANSIString`
    ///
    /// # Example
    /// ```
    /// use rpf::Styled;
    ///
    /// let styled = "Styled string test".bold();
    /// ```
    fn bold(&self) -> ansi_term::ANSIString;

    /// Creates an underlined `ANSIString`
    ///
    /// # Example
    /// ```
    /// use rpf::Styled;
    ///
    /// let styled = "Styled string test".bold();
    /// ```
    fn underline(&self) -> ansi_term::ANSIString;

    /// Paints a given string with the color given
    ///
    /// # Example
    /// ```
    /// use rpf::Styled;
    /// use rpf::Color;
    ///
    /// let painted = "Styled string test".paint(Color::Yellow);
    /// ```
    fn paint(&self, color: Color) -> ansi_term::ANSIString;
}

impl Styled for String {
    fn bold(&self) -> ansi_term::ANSIString {
        Style::default().bold().paint(&self)
    }

    fn underline(&self) -> ansi_term::ANSIString {
        Style::default().underline().paint(&self)
    }

    fn paint(&self, color: Color) -> ansi_term::ANSIString {
        match color {
            Color::Black   => { Colour::Black.paint(&self) },
            Color::Red     => { Colour::Red.paint(&self) },
            Color::Green   => { Colour::Green.paint(&self) },
            Color::Yellow  => { Colour::Yellow.paint(&self) },
            Color::Blue    => { Colour::Blue.paint(&self) },
            Color::Purple  => { Colour::Purple.paint(&self) },
            Color::Cyan    => { Colour::Cyan.paint(&self) },
            Color::White   => { Colour::White.paint(&self) },
        }
    }
}

impl Styled for str {
    fn bold(&self) -> ansi_term::ANSIString {
        Style::default().bold().paint(&self)
    }

    fn underline(&self) -> ansi_term::ANSIString {
        Style::default().underline().paint(&self)
    }

    fn paint(&self, color: Color) -> ansi_term::ANSIString {
        match color {
            Color::Black   => { Colour::Black.paint(&self) },
            Color::Red     => { Colour::Red.paint(&self) },
            Color::Green   => { Colour::Green.paint(&self) },
            Color::Yellow  => { Colour::Yellow.paint(&self) },
            Color::Blue    => { Colour::Blue.paint(&self) },
            Color::Purple  => { Colour::Purple.paint(&self) },
            Color::Cyan    => { Colour::Cyan.paint(&self) },
            Color::White   => { Colour::White.paint(&self) },
        }
    }
}

#[test]
#[should_panic]
fn test_styled_bold() {
    let styled = String::from("Styled string test");
    assert_eq!(styled.bold().to_string(),
        Style::default().paint("Styled string test").to_string());
}

#[test]
fn test_styled_underline() {
    let styled = String::from("Styled string test");
    assert_eq!(styled.underline().to_string(),
        Style::default().underline().paint("Styled string test").to_string());
}

#[test]
fn test_styled_paint() {
    let styled = String::from("Styled string test");
    assert_eq!(styled.paint(Color::Yellow).to_string(),
        Colour::Yellow.paint("Styled string test").to_string());
}
<commit_msg>styled: fix bold test, should not panic<commit_after>// Copyright (C) 2015, Alberto Corona <alberto@0x1a.us>
// All rights reserved. This file is part of rpf, distributed under the
// BSD 3-Clause license. For full terms please see the LICENSE file.

extern crate ansi_term;

use self::ansi_term::Style;
use self::ansi_term::{Colour,ANSIString};
use self::ansi_term::Colour::{Red};

/// Wrapper for `ansi_term::Colour`
pub enum Color {
    Black,
    Red,
    Green,
    Yellow,
    Blue,
    Purple,
    Cyan,
    White,
}

/// Trait for creating stylized console printing using `ansi_term`
pub trait Styled {
    /// Creates a bold `ANSIString`
    ///
    /// # Example
    /// ```
    /// use rpf::Styled;
    ///
    /// let styled = "Styled string test".bold();
    /// println!("{}", styled);
    /// ```
    fn bold(&self) -> ansi_term::ANSIString;

    /// Creates an underlined `ANSIString`
    ///
    /// # Example
    /// ```
    /// use rpf::Styled;
    ///
    /// let styled = "Styled string test".underline();
    /// println!("{}", styled);
    /// ```
    fn underline(&self) -> ansi_term::ANSIString;

    /// Paints a given string with the color given
    ///
    /// # Example
    /// ```
    /// use rpf::Styled;
    /// use rpf::Color;
    ///
    /// let painted = "Styled string test".paint(Color::Yellow);
    /// println!("{}", painted);
    /// ```
    fn paint(&self, color: Color) -> ansi_term::ANSIString;
}

impl Styled for String {
    fn bold(&self) -> ansi_term::ANSIString {
        Style::default().bold().paint(&self)
    }

    fn underline(&self) -> ansi_term::ANSIString {
        Style::default().underline().paint(&self)
    }

    fn paint(&self, color: Color) -> ansi_term::ANSIString {
        match color {
            Color::Black   => { Colour::Black.paint(&self) },
            Color::Red     => { Colour::Red.paint(&self) },
            Color::Green   => { Colour::Green.paint(&self) },
            Color::Yellow  => { Colour::Yellow.paint(&self) },
            Color::Blue    => { Colour::Blue.paint(&self) },
            Color::Purple  => { Colour::Purple.paint(&self) },
            Color::Cyan    => { Colour::Cyan.paint(&self) },
            Color::White   => { Colour::White.paint(&self) },
        }
    }
}

impl Styled for str {
    fn bold(&self) -> ansi_term::ANSIString {
        Style::default().bold().paint(&self)
    }

    fn underline(&self) -> ansi_term::ANSIString {
        Style::default().underline().paint(&self)
    }

    fn paint(&self, color: Color) -> ansi_term::ANSIString {
        match color {
            Color::Black   => { Colour::Black.paint(&self) },
            Color::Red     => { Colour::Red.paint(&self) },
            Color::Green   => { Colour::Green.paint(&self) },
            Color::Yellow  => { Colour::Yellow.paint(&self) },
            Color::Blue    => { Colour::Blue.paint(&self) },
            Color::Purple  => { Colour::Purple.paint(&self) },
            Color::Cyan    => { Colour::Cyan.paint(&self) },
            Color::White   => { Colour::White.paint(&self) },
        }
    }
}

#[test]
fn test_styled_bold() {
    let styled = String::from("Styled string test");
    assert_eq!(styled.bold().to_string(),
        Style::default().bold().paint("Styled string test").to_string());
}

#[test]
fn test_styled_underline() {
    let styled = String::from("Styled string test");
    assert_eq!(styled.underline().to_string(),
        Style::default().underline().paint("Styled string test").to_string());
}

#[test]
fn test_styled_paint() {
    let styled = String::from("Styled string test");
    assert_eq!(styled.paint(Color::Yellow).to_string(),
        Colour::Yellow.paint("Styled string test").to_string());
}
<|endoftext|>


<commit_before>//! Definitions of types and traits related to packet filtering
//!
//! Two different parameters class are going to be mentioned in this module:
//!
//! - Generic parameter: ether type, protocol id, ...
//! - Specific parameter: hardware address, ip address, ...

use sync::Arc;

use net::Packet;

use net::defs::Rule;

use net::conn::MultiConn;

/// Extract generic/specific parameters of type T from a packet or a rule.
///
/// This is used by filters to extract the generic/specific parameter and use
/// it to route the packet to the appropriate connexion (if such connexion
/// exists).
pub trait Extractor<T> {
    /// Extract the parameter from a rule.
    ///
    /// This will return `None` if the method fails to extract the parameter.
    fn from_rule(rule: &Rule) -> Option<T>;

    /// Extract the parameter from a Packet.
    ///
    /// This will return `None` if the method fails to extract the parameter.
    fn from_packet(pkt: &Packet) -> Option<T>;
}

/// Sanitize an incoming packet.
///
/// Packets that arrive from the network need to be checked by every used
/// protocols for correctness (i.e. checksum, ...).
///
/// Some properties or extra information might need to be added to the packet
/// as well.
///
/// This trait let protocols do this.
pub trait PacketSanitizer {
    /// This method is called when a filter needs to sanitize a packet.
    ///
    /// If this method returns an `Err` the packet will be dropped.
    fn sanitize(pkt: &mut Packet) -> Result<(), ()>;
}

/// Trait implemented by generic filters (i.e. filters based on generic
/// parameters)
///
/// Generic filters allow protocols to route packets to the appropriate
/// connexion based on a generic parameter.
///
/// It may drop the packet if no matching connexion exists or if the packet is
/// invalid (failed checksum, ...).
pub trait GenericFilterTrait {
    /// Insert a new multi connexion to the filter based on a rule.
    fn insert_multi(&mut self, conn: Arc<MultiConn>,
                    rule: &Rule) -> Result<(), ()>;

    /// Filter and route an incoming packet to a connexion (uni or multi).
    fn rx(&self, pkt: Packet);

    /// Filter and route an incoming packet to a multi connexion
    fn rx_multi(&self, pkt: Packet, rule: Rule);
}
<commit_msg>conn/filter: Add definition of trait SpecificFilterTrait<commit_after>//! Definitions of types and traits related to packet filtering
//!
//! Two different parameters class are going to be mentioned in this module:
//!
//! - Generic parameter: ether type, protocol id, ...
//! - Specific parameter: hardware address, ip address, ...

use sync::Arc;

use net::Packet;

use net::defs::Rule;

use net::conn::MultiConn;

/// Extract generic/specific parameters of type T from a packet or a rule.
///
/// This is used by filters to extract the generic/specific parameter and use
/// it to route the packet to the appropriate connexion (if such connexion
/// exists).
pub trait Extractor<T> {
    /// Extract the parameter from a rule.
    ///
    /// This will return `None` if the method fails to extract the parameter.
    fn from_rule(rule: &Rule) -> Option<T>;

    /// Extract the parameter from a Packet.
    ///
    /// This will return `None` if the method fails to extract the parameter.
    fn from_packet(pkt: &Packet) -> Option<T>;
}

/// Sanitize an incoming packet.
///
/// Packets that arrive from the network need to be checked by every used
/// protocols for correctness (i.e. checksum, ...).
///
/// Some properties or extra information might need to be added to the packet
/// as well.
///
/// This trait let protocols do this.
pub trait PacketSanitizer {
    /// This method is called when a filter needs to sanitize a packet.
    ///
    /// If this method returns an `Err` the packet will be dropped.
    fn sanitize(pkt: &mut Packet) -> Result<(), ()>;
}

/// Trait implemented by generic filters (i.e. filters based on generic
/// parameters)
///
/// Generic filters allow protocols to route packets to the appropriate
/// connexion based on a generic parameter.
///
/// It may drop the packet if no matching connexion exists or if the packet is
/// invalid (failed checksum, ...).
pub trait GenericFilterTrait {
    /// Insert a new multi connexion to the filter based on a rule.
    fn insert_multi(&mut self, conn: Arc<MultiConn>,
                    rule: &Rule) -> Result<(), ()>;

    /// Filter and route an incoming packet to a connexion (uni or multi).
    fn rx(&self, pkt: Packet);

    /// Filter and route an incoming packet to a multi connexion
    fn rx_multi(&self, pkt: Packet, rule: Rule);
}

/// Trait implemented by specific filters (i.e. filters based on specific
/// parameters)
///
/// Specific filters allow protocols to route packets to the appropriate
/// connexion based on a specific parameter
///
/// It may drop the packet if no matching connexion exists.
pub trait SpecificFilterTrait<T> {
    /// Create a new specific filter.
    ///
    /// The generic parameter taken as parameter is used to associate a
    /// specific filter with a generic one.
    fn new(generic_param: T) -> Self;

    /// Insert a new multi connexion to the filter based on a rule.
    fn insert_multi(&mut self, conn: Arc<MultiConn>,
                    rule: &Rule) -> Result<(), ()>;

    /// Filter and route an incoming packet to a connexion (uni or multi).
    fn rx(&self, pkt: Packet);

    /// Filter and route an incoming packet to a multi connexion
    fn rx_multi(&self, pkt: Packet, rule: Rule);
}
<|endoftext|>


<commit_before>// Disable this lint to avoid it wanting to change `0xABCDEF` to `0xAB_CDEF`.
#![allow(clippy::unreadable_literal)]

macro_rules! colour {
    ($(#[$attr:meta] $constname:ident, $name:ident, $val:expr;)*) => {
        impl Colour {
            $(
                #[$attr]
                pub const $constname: Colour = Colour($val);
            )*
        }
    }
}

/// A utility struct to help with working with the basic representation of a
/// colour. This is particularly useful when working with a [`Role`]'s colour,
/// as the API works with an integer value instead of an RGB value.
///
/// Instances can be created by using the struct's associated functions. These
/// produce presets equivalent to those found in the official client's colour
/// picker.
///
/// # Examples
///
/// Passing in a role's colour, and then retrieving its green component
/// via [`g`]:
///
/// ```rust
/// # use serenity::model::guild::Role;
/// # use serenity::model::id::RoleId;
/// # use serenity::model::permissions;
/// #
/// # let role = Role {
/// #     colour: Colour::BLURPLE,
/// #     hoist: false,
/// #     id: RoleId(1),
/// #     managed: false,
/// #     mentionable: false,
/// #     name: "test".to_string(),
/// #     permissions: permissions::PRESET_GENERAL,
/// #     position: 7,
/// # };
/// #
/// use serenity::utils::Colour;
///
/// // assuming a `role` has already been bound
///
/// let green = role.colour.g();
///
/// println!("The green component is: {}", green);
/// ```
///
/// Creating an instance with the [`DARK_TEAL`] preset:
///
/// ```rust
/// use serenity::utils::Colour;
///
/// let colour = Colour::DARK_TEAL;
///
/// assert_eq!(colour.tuple(), (17, 128, 106));
/// ```
///
/// Colours can also be directly compared for equivalence:
///
/// ```rust
/// use serenity::utils::Colour;
///
/// let blitz_blue = Colour::BLITZ_BLUE;
/// let fooyoo = Colour::FOOYOO;
/// let fooyoo2 = Colour::FOOYOO;
/// assert!(blitz_blue != fooyoo);
/// assert_eq!(fooyoo, fooyoo2);
/// assert!(blitz_blue > fooyoo);
/// ```
///
/// [`Role`]: ../model/guild/struct.Role.html
/// [`DARK_TEAL`]: #associatedconstant.DARK_TEAL
/// [`g`]: #method.g
#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Colour(pub u32);

impl Colour {
    /// Generates a new Colour with the given integer value set.
    ///
    /// # Examples
    ///
    /// Create a new Colour, and then ensure that its inner value is equivalent
    /// to a specific RGB value, retrieved via [`tuple`]:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// let colour = Colour::new(6573123);
    ///
    /// assert_eq!(colour.tuple(), (100, 76, 67));
    /// ```
    ///
    /// [`tuple`]: #method.tuple
    #[inline]
    pub fn new(value: u32) -> Colour { Colour(value) }

    /// Generates a new Colour from an RGB value, creating an inner u32
    /// representation.
    ///
    /// # Examples
    ///
    /// Creating a `Colour` via its RGB values will set its inner u32 correctly:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert!(Colour::from_rgb(255, 0, 0).0 == 0xFF0000);
    /// assert!(Colour::from_rgb(217, 23, 211).0 == 0xD917D3);
    /// ```
    ///
    /// And you can then retrieve those same RGB values via its methods:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// let colour = Colour::from_rgb(217, 45, 215);
    ///
    /// assert_eq!(colour.r(), 217);
    /// assert_eq!(colour.g(), 45);
    /// assert_eq!(colour.b(), 215);
    /// assert_eq!(colour.tuple(), (217, 45, 215));
    /// ```
    pub fn from_rgb(red: u8, green: u8, blue: u8) -> Colour {
        let mut uint = u32::from(red);
        uint = (uint << 8) | (u32::from(green));
        uint = (uint << 8) | (u32::from(blue));

        Colour(uint)
    }

    /// Returns the red RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).r(), 100);
    /// ```
    pub fn r(self) -> u8 { ((self.0 >> 16) & 255) as u8 }

    /// Returns the green RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).g(), 76);
    /// ```
    pub fn g(self) -> u8 { ((self.0 >> 8) & 255) as u8 }

    /// Returns the blue RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).b(), 67);
    pub fn b(self) -> u8 { (self.0 & 255) as u8 }

    /// Returns a tuple of the red, green, and blue components of this Colour.
    ///
    /// This is equivalent to creating a tuple with the return values of
    /// [`r`], [`g`], and [`b`].
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).tuple(), (100, 76, 67));
    /// ```
    ///
    /// [`r`]: #method.r
    /// [`g`]: #method.g
    /// [`b`]: #method.b
    pub fn tuple(self) -> (u8, u8, u8) { (self.r(), self.g(), self.b()) }

    /// Returns a hexadecimal string of this Colour.
    ///
    /// This is equivalent to passing the integer value through
    /// `std::fmt::UpperHex` with 0 padding and 6 width
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).hex(), "644C43");
    /// ```
    pub fn hex(self) -> String {
        format!("{:06X}", self.0)
    }
}

impl From<i32> for Colour {
    /// Constructs a Colour from a i32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// This is useful when providing hex values.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(0xDEA584).tuple(), (222, 165, 132));
    /// ```
    fn from(value: i32) -> Colour { Colour(value as u32) }
}

impl From<u32> for Colour {
    /// Constructs a Colour from a u32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(6573123u32).r(), 100);
    /// ```
    fn from(value: u32) -> Colour { Colour(value) }
}

impl From<u64> for Colour {
    /// Constructs a Colour from a u32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(6573123u64).r(), 100);
    /// ```
    fn from(value: u64) -> Colour { Colour(value as u32) }
}

impl From<(u8, u8, u8)> for Colour {
    /// Constructs a Colour from rgb.
    fn from((red, green, blue): (u8, u8, u8)) -> Self {
        Colour::from_rgb(red, green, blue)
    }
}

colour! {
    /// Creates a new `Colour`, setting its RGB value to `(111, 198, 226)`.
    BLITZ_BLUE, blitz_blue, 0x6FC6E2;
    /// Creates a new `Colour`, setting its RGB value to `(52, 152, 219)`.
    BLUE, blue, 0x3498DB;
    /// Creates a new `Colour`, setting its RGB value to `(114, 137, 218)`.
    BLURPLE, blurple, 0x7289DA;
    /// Creates a new `Colour`, setting its RGB value to `(32, 102, 148)`.
    DARK_BLUE, dark_blue, 0x206694;
    /// Creates a new `Colour`, setting its RGB value to `(194, 124, 14)`.
    DARK_GOLD, dark_gold, 0xC27C0E;
    /// Creates a new `Colour`, setting its RGB value to `(31, 139, 76)`.
    DARK_GREEN, dark_green, 0x1F8B4C;
    /// Creates a new `Colour`, setting its RGB value to `(96, 125, 139)`.
    DARK_GREY, dark_grey, 0x607D8B;
    /// Creates a new `Colour`, setting its RGB value to `(173, 20, 87)`.
    DARK_MAGENTA, dark_magenta, 0xAD1457;
    /// Creates a new `Colour`, setting its RGB value to `(168, 67, 0)`.
    DARK_ORANGE, dark_orange, 0xA84300;
    /// Creates a new `Colour`, setting its RGB value to `(113, 54, 138)`.
    DARK_PURPLE, dark_purple, 0x71368A;
    /// Creates a new `Colour`, setting its RGB value to `(153, 45, 34)`.
    DARK_RED, dark_red, 0x992D22;
    /// Creates a new `Colour`, setting its RGB value to `(17, 128, 106)`.
    DARK_TEAL, dark_teal, 0x11806A;
    /// Creates a new `Colour`, setting its RGB value to `(84, 110, 122)`.
    DARKER_GREY, darker_grey, 0x546E7A;
    /// Creates a new `Colour`, setting its RGB value to `(250, 177, 237)`.
    FABLED_PINK, fabled_pink, 0xFAB1ED;
    /// Creates a new `Colour`, setting its RGB value to `(136, 130, 196)`.`
    FADED_PURPLE, faded_purple, 0x8882C4;
    /// Creates a new `Colour`, setting its RGB value to `(17, 202, 128)`.
    FOOYOO, fooyoo, 0x11CA80;
    /// Creates a new `Colour`, setting its RGB value to `(241, 196, 15)`.
    GOLD, gold, 0xF1C40F;
    /// Creates a new `Colour`, setting its RGB value to `(186, 218, 85)`.
    KERBAL, kerbal, 0xBADA55;
    /// Creates a new `Colour`, setting its RGB value to `(151, 156, 159)`.
    LIGHT_GREY, light_grey, 0x979C9F;
    /// Creates a new `Colour`, setting its RGB value to `(149, 165, 166)`.
    LIGHTER_GREY, lighter_grey, 0x95A5A6;
    /// Creates a new `Colour`, setting its RGB value to `(233, 30, 99)`.
    MAGENTA, magenta, 0xE91E63;
    /// Creates a new `Colour`, setting its RGB value to `(230, 131, 151)`.
    MEIBE_PINK, meibe_pink, 0xE68397;
    /// Creates a new `Colour`, setting its RGB value to `(230, 126, 34)`.
    ORANGE, orange, 0xE67E22;
    /// Creates a new `Colour`, setting its RGB value to `(155, 89, 182)`.
    PURPLE, purple, 0x9B59B6;
    /// Creates a new `Colour`, setting its RGB value to `(231, 76, 60)`.
    RED, red, 0xE74C3C;
    /// Creates a new `Colour`, setting its RGB value to `(117, 150, 255)`.
    ROHRKATZE_BLUE, rohrkatze_blue, 0x7596FF;
    /// Creates a new `Colour`, setting its RGB value to `(246, 219, 216)`.
    ROSEWATER, rosewater, 0xF6DBD8;
    /// Creates a new `Colour`, setting its RGB value to `(26, 188, 156)`.
    TEAL, teal, 0x1ABC9C;
}

impl Default for Colour {
    /// Creates a default value for a `Colour`, setting the inner value to `0`.
    fn default() -> Colour { Colour(0) }
}

#[cfg(test)]
mod test {
    use super::Colour;
    use std::u32;

    #[test]
    fn new() {
        assert_eq!(Colour::new(1).0, 1);
        assert_eq!(Colour::new(u32::MIN).0, u32::MIN);
        assert_eq!(Colour::new(u32::MAX).0, u32::MAX);
    }

    #[test]
    fn from_rgb() {
        assert_eq!(Colour::from_rgb(255, 0, 0).0, 0xFF0000);
        assert_eq!(Colour::from_rgb(0, 255, 0).0, 0x00FF00);
        assert_eq!(Colour::from_rgb(0, 0, 255).0, 0x0000FF);
    }

    #[test]
    fn r() {
        assert_eq!(Colour::new(0x336123).r(), 0x33);
    }

    #[test]
    fn g() {
        assert_eq!(Colour::new(0x336123).g(), 0x61);
    }

    #[test]
    fn b() {
        assert_eq!(Colour::new(0x336123).b(), 0x23);
    }

    #[test]
    fn tuple() {
        assert_eq!(Colour::new(0x336123).tuple(), (0x33, 0x61, 0x23));
    }

    #[test]
    fn default() {
        assert_eq!(Colour::default().0, 0);
    }

    #[test]
    fn from() {
        assert_eq!(Colour::from(7i32).0, 7);
        assert_eq!(Colour::from(7u32).0, 7);
        assert_eq!(Colour::from(7u64).0, 7);
    }
}
<commit_msg>Update colour.rs<commit_after>// Disable this lint to avoid it wanting to change `0xABCDEF` to `0xAB_CDEF`.
#![allow(clippy::unreadable_literal)]

macro_rules! colour {
    ($(#[$attr:meta] $constname:ident, $name:ident, $val:expr;)*) => {
        impl Colour {
            $(
                #[$attr]
                pub const $constname: Colour = Colour($val);
            )*
        }
    }
}

/// A utility struct to help with working with the basic representation of a
/// colour. This is particularly useful when working with a [`Role`]'s colour,
/// as the API works with an integer value instead of an RGB value.
///
/// Instances can be created by using the struct's associated functions. These
/// produce presets equivalent to those found in the official client's colour
/// picker.
///
/// # Examples
///
/// Passing in a role's colour, and then retrieving its green component
/// via [`g`]:
///
/// ```rust
/// # use serenity::model::guild::Role;
/// # use serenity::model::id::RoleId;
/// # use serenity::model::permissions;
/// #
/// # let role = Role {
/// #     colour: Colour::BLURPLE,
/// #     hoist: false,
/// #     id: RoleId(1),
/// #     managed: false,
/// #     mentionable: false,
/// #     name: "test".to_string(),
/// #     permissions: permissions::PRESET_GENERAL,
/// #     position: 7,
/// # };
/// #
/// use serenity::utils::Colour;
///
/// // assuming a `role` has already been bound
///
/// let green = role.colour.g();
///
/// println!("The green component is: {}", green);
/// ```
///
/// Creating an instance with the [`DARK_TEAL`] preset:
///
/// ```rust
/// use serenity::utils::Colour;
///
/// let colour = Colour::DARK_TEAL;
///
/// assert_eq!(colour.tuple(), (17, 128, 106));
/// ```
///
/// Colours can also be directly compared for equivalence:
///
/// ```rust
/// use serenity::utils::Colour;
///
/// let blitz_blue = Colour::BLITZ_BLUE;
/// let fooyoo = Colour::FOOYOO;
/// let fooyoo2 = Colour::FOOYOO;
/// assert!(blitz_blue != fooyoo);
/// assert_eq!(fooyoo, fooyoo2);
/// assert!(blitz_blue > fooyoo);
/// ```
///
/// [`Role`]: ../model/guild/struct.Role.html
/// [`DARK_TEAL`]: #associatedconstant.DARK_TEAL
/// [`g`]: #method.g
#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Colour(pub u32);

impl Colour {
    /// Generates a new Colour with the given integer value set.
    ///
    /// # Examples
    ///
    /// Create a new Colour, and then ensure that its inner value is equivalent
    /// to a specific RGB value, retrieved via [`tuple`]:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// let colour = Colour::new(6573123);
    ///
    /// assert_eq!(colour.tuple(), (100, 76, 67));
    /// ```
    ///
    /// [`tuple`]: #method.tuple
    #[inline]
    pub const fn new(value: u32) -> Colour { Colour(value) }

    /// Generates a new Colour from an RGB value, creating an inner u32
    /// representation.
    ///
    /// # Examples
    ///
    /// Creating a `Colour` via its RGB values will set its inner u32 correctly:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert!(Colour::from_rgb(255, 0, 0).0 == 0xFF0000);
    /// assert!(Colour::from_rgb(217, 23, 211).0 == 0xD917D3);
    /// ```
    ///
    /// And you can then retrieve those same RGB values via its methods:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// let colour = Colour::from_rgb(217, 45, 215);
    ///
    /// assert_eq!(colour.r(), 217);
    /// assert_eq!(colour.g(), 45);
    /// assert_eq!(colour.b(), 215);
    /// assert_eq!(colour.tuple(), (217, 45, 215));
    /// ```
    pub const fn from_rgb(red: u8, green: u8, blue: u8) -> Colour {
        Colour((red as u32) << 16 | (green as u32) << 8 | blue as u32)
    }

    /// Returns the red RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).r(), 100);
    /// ```
    pub const fn r(self) -> u8 { ((self.0 >> 16) & 255) as u8 }

    /// Returns the green RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).g(), 76);
    /// ```
    pub const fn g(self) -> u8 { ((self.0 >> 8) & 255) as u8 }

    /// Returns the blue RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).b(), 67);
    pub const fn b(self) -> u8 { (self.0 & 255) as u8 }

    /// Returns a tuple of the red, green, and blue components of this Colour.
    ///
    /// This is equivalent to creating a tuple with the return values of
    /// [`r`], [`g`], and [`b`].
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).tuple(), (100, 76, 67));
    /// ```
    ///
    /// [`r`]: #method.r
    /// [`g`]: #method.g
    /// [`b`]: #method.b
    pub const fn tuple(self) -> (u8, u8, u8) { (self.r(), self.g(), self.b()) }

    /// Returns a hexadecimal string of this Colour.
    ///
    /// This is equivalent to passing the integer value through
    /// `std::fmt::UpperHex` with 0 padding and 6 width.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).hex(), "644C43");
    /// ```
    pub fn hex(self) -> String {
        format!("{:06X}", self.0)
    }
}

impl From<i32> for Colour {
    /// Constructs a Colour from a i32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// This is useful when providing hex values.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(0xDEA584).tuple(), (222, 165, 132));
    /// ```
    fn from(value: i32) -> Colour { Colour(value as u32) }
}

impl From<u32> for Colour {
    /// Constructs a Colour from a u32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(6573123u32).r(), 100);
    /// ```
    fn from(value: u32) -> Colour { Colour(value) }
}

impl From<u64> for Colour {
    /// Constructs a Colour from a u32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(6573123u64).r(), 100);
    /// ```
    fn from(value: u64) -> Colour { Colour(value as u32) }
}

impl From<(u8, u8, u8)> for Colour {
    /// Constructs a Colour from RGB.
    fn from((red, green, blue): (u8, u8, u8)) -> Self {
        Colour::from_rgb(red, green, blue)
    }
}

colour! {
    /// Creates a new `Colour`, setting its RGB value to `(111, 198, 226)`.
    BLITZ_BLUE, blitz_blue, 0x6FC6E2;
    /// Creates a new `Colour`, setting its RGB value to `(52, 152, 219)`.
    BLUE, blue, 0x3498DB;
    /// Creates a new `Colour`, setting its RGB value to `(114, 137, 218)`.
    BLURPLE, blurple, 0x7289DA;
    /// Creates a new `Colour`, setting its RGB value to `(32, 102, 148)`.
    DARK_BLUE, dark_blue, 0x206694;
    /// Creates a new `Colour`, setting its RGB value to `(194, 124, 14)`.
    DARK_GOLD, dark_gold, 0xC27C0E;
    /// Creates a new `Colour`, setting its RGB value to `(31, 139, 76)`.
    DARK_GREEN, dark_green, 0x1F8B4C;
    /// Creates a new `Colour`, setting its RGB value to `(96, 125, 139)`.
    DARK_GREY, dark_grey, 0x607D8B;
    /// Creates a new `Colour`, setting its RGB value to `(173, 20, 87)`.
    DARK_MAGENTA, dark_magenta, 0xAD1457;
    /// Creates a new `Colour`, setting its RGB value to `(168, 67, 0)`.
    DARK_ORANGE, dark_orange, 0xA84300;
    /// Creates a new `Colour`, setting its RGB value to `(113, 54, 138)`.
    DARK_PURPLE, dark_purple, 0x71368A;
    /// Creates a new `Colour`, setting its RGB value to `(153, 45, 34)`.
    DARK_RED, dark_red, 0x992D22;
    /// Creates a new `Colour`, setting its RGB value to `(17, 128, 106)`.
    DARK_TEAL, dark_teal, 0x11806A;
    /// Creates a new `Colour`, setting its RGB value to `(84, 110, 122)`.
    DARKER_GREY, darker_grey, 0x546E7A;
    /// Creates a new `Colour`, setting its RGB value to `(250, 177, 237)`.
    FABLED_PINK, fabled_pink, 0xFAB1ED;
    /// Creates a new `Colour`, setting its RGB value to `(136, 130, 196)`.
    FADED_PURPLE, faded_purple, 0x8882C4;
    /// Creates a new `Colour`, setting its RGB value to `(17, 202, 128)`.
    FOOYOO, fooyoo, 0x11CA80;
    /// Creates a new `Colour`, setting its RGB value to `(241, 196, 15)`.
    GOLD, gold, 0xF1C40F;
    /// Creates a new `Colour`, setting its RGB value to `(186, 218, 85)`.
    KERBAL, kerbal, 0xBADA55;
    /// Creates a new `Colour`, setting its RGB value to `(151, 156, 159)`.
    LIGHT_GREY, light_grey, 0x979C9F;
    /// Creates a new `Colour`, setting its RGB value to `(149, 165, 166)`.
    LIGHTER_GREY, lighter_grey, 0x95A5A6;
    /// Creates a new `Colour`, setting its RGB value to `(233, 30, 99)`.
    MAGENTA, magenta, 0xE91E63;
    /// Creates a new `Colour`, setting its RGB value to `(230, 131, 151)`.
    MEIBE_PINK, meibe_pink, 0xE68397;
    /// Creates a new `Colour`, setting its RGB value to `(230, 126, 34)`.
    ORANGE, orange, 0xE67E22;
    /// Creates a new `Colour`, setting its RGB value to `(155, 89, 182)`.
    PURPLE, purple, 0x9B59B6;
    /// Creates a new `Colour`, setting its RGB value to `(231, 76, 60)`.
    RED, red, 0xE74C3C;
    /// Creates a new `Colour`, setting its RGB value to `(117, 150, 255)`.
    ROHRKATZE_BLUE, rohrkatze_blue, 0x7596FF;
    /// Creates a new `Colour`, setting its RGB value to `(246, 219, 216)`.
    ROSEWATER, rosewater, 0xF6DBD8;
    /// Creates a new `Colour`, setting its RGB value to `(26, 188, 156)`.
    TEAL, teal, 0x1ABC9C;
}

impl Default for Colour {
    /// Creates a default value for a `Colour`, setting the inner value to `0`.
    fn default() -> Colour { Colour(0) }
}

#[cfg(test)]
mod test {
    use super::Colour;
    use std::u32;

    #[test]
    fn new() {
        assert_eq!(Colour::new(1).0, 1);
        assert_eq!(Colour::new(u32::MIN).0, u32::MIN);
        assert_eq!(Colour::new(u32::MAX).0, u32::MAX);
    }

    #[test]
    fn from_rgb() {
        assert_eq!(Colour::from_rgb(255, 0, 0).0, 0xFF0000);
        assert_eq!(Colour::from_rgb(0, 255, 0).0, 0x00FF00);
        assert_eq!(Colour::from_rgb(0, 0, 255).0, 0x0000FF);
    }

    #[test]
    fn r() {
        assert_eq!(Colour::new(0x336123).r(), 0x33);
    }

    #[test]
    fn g() {
        assert_eq!(Colour::new(0x336123).g(), 0x61);
    }

    #[test]
    fn b() {
        assert_eq!(Colour::new(0x336123).b(), 0x23);
    }

    #[test]
    fn tuple() {
        assert_eq!(Colour::new(0x336123).tuple(), (0x33, 0x61, 0x23));
    }

    #[test]
    fn default() {
        assert_eq!(Colour::default().0, 0);
    }

    #[test]
    fn from() {
        assert_eq!(Colour::from(7i32).0, 7);
        assert_eq!(Colour::from(7u32).0, 7);
        assert_eq!(Colour::from(7u64).0, 7);
    }
}
<|endoftext|>


<commit_before>//! Simple daemon
//!
//! This daemon will start web server, track new packages and build them

use std::{env, thread};
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::process::exit;
use std::fs::File;
use std::io::Write;
use std::time::Duration;
use std::path::PathBuf;
use libc::fork;
use time;
use DocBuilderOptions;
use DocBuilder;
use utils::{update_sources, update_release_activity, github_updater, pubsubhubbub};
use db::{connect_db, update_search_index};

pub fn start_daemon() {
    // first check required environment variables
    for v in ["CRATESFYI_PREFIX",
              "CRATESFYI_PREFIX",
              "CRATESFYI_GITHUB_USERNAME",
              "CRATESFYI_GITHUB_ACCESSTOKEN"]
        .iter() {
        env::var(v).expect("Environment variable not found");
    }

    let dbopts = opts();

    // check paths once
    dbopts.check_paths().unwrap();

    // fork the process
    let pid = unsafe { fork() };
    if pid > 0 {
        let mut file = File::create(dbopts.prefix.join("cratesfyi.pid"))
            .expect("Failed to create pid file");
        writeln!(&mut file, "{}", pid).expect("Failed to write pid");

        info!("cratesfyi {} daemon started on: {}", ::BUILD_VERSION, pid);
        exit(0);
    }

    // check new crates every minute
    thread::spawn(move || {
        // space this out to prevent it from clashing against the queue-builder thread on launch
        thread::sleep(Duration::from_secs(30));
        loop {
            let opts = opts();
            let mut doc_builder = DocBuilder::new(opts);

            debug!("Checking new crates");
            match doc_builder.get_new_crates() {
                Ok(n) => debug!("{} crates added to queue", n),
                Err(e) => error!("Failed to get new crates: {}", e),
            }

            thread::sleep(Duration::from_secs(60));
        }
    });

    // build new crates every minute
    thread::spawn(move || {
        let opts = opts();
        let mut doc_builder = DocBuilder::new(opts);

        /// Represents the current state of the builder thread.
        enum BuilderState {
            /// The builder thread has just started, and hasn't built any crates yet.
            Fresh,
            /// The builder has just seen an empty build queue.
            EmptyQueue,
            /// The builder has just seen the lock file.
            Locked,
            /// The builder has just finished building a crate. The enclosed count is the number of
            /// crates built since the caches have been refreshed.
            QueueInProgress(usize),
        }

        let mut status = BuilderState::Fresh;

        loop {
            if !status.is_in_progress() {
                thread::sleep(Duration::from_secs(60));
            }

            // check lock file
            if doc_builder.is_locked() {
                warn!("Lock file exits, skipping building new crates");
                status = BuilderState::Locked;
                continue;
            }

            if status.count() >= 10 {
                // periodically, we need to flush our caches and ping the hubs
                debug!("10 builds in a row; flushing caches");
                status = BuilderState::QueueInProgress(0);

                match pubsubhubbub::ping_hubs() {
                    Err(e) => error!("Failed to ping hub: {}", e),
                    Ok(n) => debug!("Succesfully pinged {} hubs", n)
                }

                if let Err(e) = doc_builder.load_cache() {
                    error!("Failed to load cache: {}", e);
                }

                if let Err(e) = doc_builder.save_cache() {
                    error!("Failed to save cache: {}", e);
                }

                if let Err(e) = update_sources() {
                    error!("Failed to update sources: {}", e);
                    continue;
                }
            }

            // Only build crates if there are any to build
            debug!("Checking build queue");
            match doc_builder.get_queue_count() {
                Err(e) => {
                    error!("Failed to read the number of crates in the queue: {}", e);
                    continue;
                }
                Ok(0) => {
                    if status.count() > 0 {
                        // ping the hubs before continuing
                        match pubsubhubbub::ping_hubs() {
                            Err(e) => error!("Failed to ping hub: {}", e),
                            Ok(n) => debug!("Succesfully pinged {} hubs", n)
                        }

                        if let Err(e) = doc_builder.save_cache() {
                            error!("Failed to save cache: {}", e);
                        }
                    }
                    debug!("Queue is empty, going back to sleep");
                    status = BuilderState::EmptyQueue;
                    continue;
                }
                Ok(queue_count) => {
                    info!("Starting build with {} crates in queue (currently on a {} crate streak)",
                          queue_count, status.count());
                }
            }

            // if we're starting a new batch, reload our caches and sources
            if !status.is_in_progress() {
                if let Err(e) = doc_builder.load_cache() {
                    error!("Failed to load cache: {}", e);
                    continue;
                }

                if let Err(e) = update_sources() {
                    error!("Failed to update sources: {}", e);
                    continue;
                }
            }

            // Run build_packages_queue under `catch_unwind` to catch panics
            // This only panicked twice in the last 6 months but its just a better
            // idea to do this.
            let res = catch_unwind(AssertUnwindSafe(|| {
                match doc_builder.build_next_queue_package() {
                    Err(e) => error!("Failed to build crate from queue: {}", e),
                    Ok(crate_built) => if crate_built {
                        status.increment();
                    }

                }
            }));

            if let Err(e) = res {
                error!("GRAVE ERROR Building new crates panicked: {:?}", e);
            }
        }

        impl BuilderState {
            fn count(&self) -> usize {
                match *self {
                    BuilderState::QueueInProgress(n) => n,
                    _ => 0,
                }
            }

            fn is_in_progress(&self) -> bool {
                match *self {
                    BuilderState::QueueInProgress(_) => true,
                    _ => false,
                }
            }

            fn increment(&mut self) {
                *self = BuilderState::QueueInProgress(self.count() + 1);
            }
        }
    });

    // update release activity everyday at 23:55
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60));
            let now = time::now();
            if now.tm_hour == 23 && now.tm_min == 55 {
                info!("Updating release activity");
                if let Err(e) = update_release_activity() {
                    error!("Failed to update release activity: {}", e);
                }
            }
        }
    });

    // update search index every 3 hours
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60 * 60 * 3));
            let conn = connect_db().expect("Failed to connect database");
            if let Err(e) = update_search_index(&conn) {
                error!("Failed to update search index: {}", e);
            }
        }
    });

    // update github stats every 6 hours
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60 * 60 * 6));
            if let Err(e) = github_updater() {
                error!("Failed to update github fields: {}", e);
            }
        }
    });

    // TODO: update ssl certificate every 3 months

    // at least start web server
    info!("Starting web server");
    ::start_web_server(None);
}

fn opts() -> DocBuilderOptions {
    let prefix = PathBuf::from(env::var("CRATESFYI_PREFIX")
        .expect("CRATESFYI_PREFIX environment variable not found"));
    DocBuilderOptions::from_prefix(prefix)
}
<commit_msg>use thread builders to give the daemon threads names<commit_after>//! Simple daemon
//!
//! This daemon will start web server, track new packages and build them

use std::{env, thread};
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::process::exit;
use std::fs::File;
use std::io::Write;
use std::time::Duration;
use std::path::PathBuf;
use libc::fork;
use time;
use DocBuilderOptions;
use DocBuilder;
use utils::{update_sources, update_release_activity, github_updater, pubsubhubbub};
use db::{connect_db, update_search_index};

pub fn start_daemon() {
    // first check required environment variables
    for v in ["CRATESFYI_PREFIX",
              "CRATESFYI_PREFIX",
              "CRATESFYI_GITHUB_USERNAME",
              "CRATESFYI_GITHUB_ACCESSTOKEN"]
        .iter() {
        env::var(v).expect("Environment variable not found");
    }

    let dbopts = opts();

    // check paths once
    dbopts.check_paths().unwrap();

    // fork the process
    let pid = unsafe { fork() };
    if pid > 0 {
        let mut file = File::create(dbopts.prefix.join("cratesfyi.pid"))
            .expect("Failed to create pid file");
        writeln!(&mut file, "{}", pid).expect("Failed to write pid");

        info!("cratesfyi {} daemon started on: {}", ::BUILD_VERSION, pid);
        exit(0);
    }

    // check new crates every minute
    thread::Builder::new().name("crates.io reader".to_string()).spawn(move || {
        // space this out to prevent it from clashing against the queue-builder thread on launch
        thread::sleep(Duration::from_secs(30));
        loop {
            let opts = opts();
            let mut doc_builder = DocBuilder::new(opts);

            debug!("Checking new crates");
            match doc_builder.get_new_crates() {
                Ok(n) => debug!("{} crates added to queue", n),
                Err(e) => error!("Failed to get new crates: {}", e),
            }

            thread::sleep(Duration::from_secs(60));
        }
    }).unwrap();

    // build new crates every minute
    thread::Builder::new().name("build queue reader".to_string()).spawn(move || {
        let opts = opts();
        let mut doc_builder = DocBuilder::new(opts);

        /// Represents the current state of the builder thread.
        enum BuilderState {
            /// The builder thread has just started, and hasn't built any crates yet.
            Fresh,
            /// The builder has just seen an empty build queue.
            EmptyQueue,
            /// The builder has just seen the lock file.
            Locked,
            /// The builder has just finished building a crate. The enclosed count is the number of
            /// crates built since the caches have been refreshed.
            QueueInProgress(usize),
        }

        let mut status = BuilderState::Fresh;

        loop {
            if !status.is_in_progress() {
                thread::sleep(Duration::from_secs(60));
            }

            // check lock file
            if doc_builder.is_locked() {
                warn!("Lock file exits, skipping building new crates");
                status = BuilderState::Locked;
                continue;
            }

            if status.count() >= 10 {
                // periodically, we need to flush our caches and ping the hubs
                debug!("10 builds in a row; flushing caches");
                status = BuilderState::QueueInProgress(0);

                match pubsubhubbub::ping_hubs() {
                    Err(e) => error!("Failed to ping hub: {}", e),
                    Ok(n) => debug!("Succesfully pinged {} hubs", n)
                }

                if let Err(e) = doc_builder.load_cache() {
                    error!("Failed to load cache: {}", e);
                }

                if let Err(e) = doc_builder.save_cache() {
                    error!("Failed to save cache: {}", e);
                }

                if let Err(e) = update_sources() {
                    error!("Failed to update sources: {}", e);
                    continue;
                }
            }

            // Only build crates if there are any to build
            debug!("Checking build queue");
            match doc_builder.get_queue_count() {
                Err(e) => {
                    error!("Failed to read the number of crates in the queue: {}", e);
                    continue;
                }
                Ok(0) => {
                    if status.count() > 0 {
                        // ping the hubs before continuing
                        match pubsubhubbub::ping_hubs() {
                            Err(e) => error!("Failed to ping hub: {}", e),
                            Ok(n) => debug!("Succesfully pinged {} hubs", n)
                        }

                        if let Err(e) = doc_builder.save_cache() {
                            error!("Failed to save cache: {}", e);
                        }
                    }
                    debug!("Queue is empty, going back to sleep");
                    status = BuilderState::EmptyQueue;
                    continue;
                }
                Ok(queue_count) => {
                    info!("Starting build with {} crates in queue (currently on a {} crate streak)",
                          queue_count, status.count());
                }
            }

            // if we're starting a new batch, reload our caches and sources
            if !status.is_in_progress() {
                if let Err(e) = doc_builder.load_cache() {
                    error!("Failed to load cache: {}", e);
                    continue;
                }

                if let Err(e) = update_sources() {
                    error!("Failed to update sources: {}", e);
                    continue;
                }
            }

            // Run build_packages_queue under `catch_unwind` to catch panics
            // This only panicked twice in the last 6 months but its just a better
            // idea to do this.
            let res = catch_unwind(AssertUnwindSafe(|| {
                match doc_builder.build_next_queue_package() {
                    Err(e) => error!("Failed to build crate from queue: {}", e),
                    Ok(crate_built) => if crate_built {
                        status.increment();
                    }

                }
            }));

            if let Err(e) = res {
                error!("GRAVE ERROR Building new crates panicked: {:?}", e);
            }
        }

        impl BuilderState {
            fn count(&self) -> usize {
                match *self {
                    BuilderState::QueueInProgress(n) => n,
                    _ => 0,
                }
            }

            fn is_in_progress(&self) -> bool {
                match *self {
                    BuilderState::QueueInProgress(_) => true,
                    _ => false,
                }
            }

            fn increment(&mut self) {
                *self = BuilderState::QueueInProgress(self.count() + 1);
            }
        }
    }).unwrap();

    // update release activity everyday at 23:55
    thread::Builder::new().name("release activity updater".to_string()).spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60));
            let now = time::now();
            if now.tm_hour == 23 && now.tm_min == 55 {
                info!("Updating release activity");
                if let Err(e) = update_release_activity() {
                    error!("Failed to update release activity: {}", e);
                }
            }
        }
    }).unwrap();

    // update search index every 3 hours
    thread::Builder::new().name("search index updater".to_string()).spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60 * 60 * 3));
            let conn = connect_db().expect("Failed to connect database");
            if let Err(e) = update_search_index(&conn) {
                error!("Failed to update search index: {}", e);
            }
        }
    }).unwrap();

    // update github stats every 6 hours
    thread::Builder::new().name("github stat updater".to_string()).spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60 * 60 * 6));
            if let Err(e) = github_updater() {
                error!("Failed to update github fields: {}", e);
            }
        }
    }).unwrap();

    // TODO: update ssl certificate every 3 months

    // at least start web server
    info!("Starting web server");
    ::start_web_server(None);
}

fn opts() -> DocBuilderOptions {
    let prefix = PathBuf::from(env::var("CRATESFYI_PREFIX")
        .expect("CRATESFYI_PREFIX environment variable not found"));
    DocBuilderOptions::from_prefix(prefix)
}
<|endoftext|>