<commit_before>#[cfg(feature = "serde-serialize")]
use serde::{Deserialize, Serialize};

use alga::general::ComplexField;
use crate::allocator::Allocator;
use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixN};
use crate::constraint::{SameNumberOfRows, ShapeConstraint};
use crate::dimension::{Dim, DimMin, DimMinimum};
use crate::storage::{Storage, StorageMut};

use crate::linalg::lu;
use crate::linalg::PermutationSequence;

/// LU decomposition with full row and column pivoting.
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[cfg_attr(
    feature = "serde-serialize",
    serde(bound(
        serialize = "DefaultAllocator: Allocator<N, R, C> +
                           Allocator<(usize, usize), DimMinimum<R, C>>,
         MatrixMN<N, R, C>: Serialize,
         PermutationSequence<DimMinimum<R, C>>: Serialize"
    ))
)]
#[cfg_attr(
    feature = "serde-serialize",
    serde(bound(
        deserialize = "DefaultAllocator: Allocator<N, R, C> +
                           Allocator<(usize, usize), DimMinimum<R, C>>,
         MatrixMN<N, R, C>: Deserialize<'de>,
         PermutationSequence<DimMinimum<R, C>>: Deserialize<'de>"
    ))
)]
#[derive(Clone, Debug)]
pub struct FullPivLU<N: ComplexField, R: DimMin<C>, C: Dim>
where DefaultAllocator: Allocator<N, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>
{
    lu: MatrixMN<N, R, C>,
    p: PermutationSequence<DimMinimum<R, C>>,
    q: PermutationSequence<DimMinimum<R, C>>,
}

impl<N: ComplexField, R: DimMin<C>, C: Dim> Copy for FullPivLU<N, R, C>
where
    DefaultAllocator: Allocator<N, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
    MatrixMN<N, R, C>: Copy,
    PermutationSequence<DimMinimum<R, C>>: Copy,
{}

impl<N: ComplexField, R: DimMin<C>, C: Dim> FullPivLU<N, R, C>
where DefaultAllocator: Allocator<N, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>
{
    /// Computes the LU decomposition with full pivoting of `matrix`.
    ///
    /// This effectively computes `P, L, U, Q` such that `P * matrix * Q = LU`.
    pub fn new(mut matrix: MatrixMN<N, R, C>) -> Self {
        let (nrows, ncols) = matrix.data.shape();
        let min_nrows_ncols = nrows.min(ncols);

        let mut p = PermutationSequence::identity_generic(min_nrows_ncols);
        let mut q = PermutationSequence::identity_generic(min_nrows_ncols);

        if min_nrows_ncols.value() == 0 {
            return Self {
                lu: matrix,
                p: p,
                q: q,
            };
        }

        for i in 0..min_nrows_ncols.value() {
            let piv = matrix.slice_range(i.., i..).icamax_full();
            let row_piv = piv.0 + i;
            let col_piv = piv.1 + i;
            let diag = matrix[(row_piv, col_piv)];

            if diag.is_zero() {
                // The remaining of the matrix is zero.
                break;
            }

            matrix.swap_columns(i, col_piv);
            q.append_permutation(i, col_piv);

            if row_piv != i {
                p.append_permutation(i, row_piv);
                matrix.columns_range_mut(..i).swap_rows(i, row_piv);
                lu::gauss_step_swap(&mut matrix, diag, i, row_piv);
            } else {
                lu::gauss_step(&mut matrix, diag, i);
            }
        }

        Self {
            lu: matrix,
            p: p,
            q: q,
        }
    }

    #[doc(hidden)]
    pub fn lu_internal(&self) -> &MatrixMN<N, R, C> {
        &self.lu
    }

    /// The lower triangular matrix of this decomposition.
    #[inline]
    pub fn l(&self) -> MatrixMN<N, R, DimMinimum<R, C>>
    where DefaultAllocator: Allocator<N, R, DimMinimum<R, C>> {
        let (nrows, ncols) = self.lu.data.shape();
        let mut m = self.lu.columns_generic(0, nrows.min(ncols)).into_owned();
        m.fill_upper_triangle(N::zero(), 1);
        m.fill_diagonal(N::one());
        m
    }

    /// The upper triangular matrix of this decomposition.
    #[inline]
    pub fn u(&self) -> MatrixMN<N, DimMinimum<R, C>, C>
    where DefaultAllocator: Allocator<N, DimMinimum<R, C>, C> {
        let (nrows, ncols) = self.lu.data.shape();
        self.lu.rows_generic(0, nrows.min(ncols)).upper_triangle()
    }

    /// The row permutations of this decomposition.
    #[inline]
    pub fn p(&self) -> &PermutationSequence<DimMinimum<R, C>> {
        &self.p
    }

    /// The column permutations of this decomposition.
    #[inline]
    pub fn q(&self) -> &PermutationSequence<DimMinimum<R, C>> {
        &self.q
    }

    /// The two matrices of this decomposition and the row and column permutations: `(P, L, U, Q)`.
    #[inline]
    pub fn unpack(
        self,
    ) -> (
        PermutationSequence<DimMinimum<R, C>>,
        MatrixMN<N, R, DimMinimum<R, C>>,
        MatrixMN<N, DimMinimum<R, C>, C>,
        PermutationSequence<DimMinimum<R, C>>,
    )
    where DefaultAllocator: Allocator<N, R, DimMinimum<R, C>> + Allocator<N, DimMinimum<R, C>, C>
    {
        // Use reallocation for either l or u.
        let l = self.l();
        let u = self.u();
        let p = self.p;
        let q = self.q;

        (p, l, u, q)
    }
}

impl<N: ComplexField, D: DimMin<D, Output = D>> FullPivLU<N, D, D>
where DefaultAllocator: Allocator<N, D, D> + Allocator<(usize, usize), D>
{
    /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined.
    ///
    /// Returns `None` if the decomposed matrix is not invertible.
    pub fn solve<R2: Dim, C2: Dim, S2>(
        &self,
        b: &Matrix<N, R2, C2, S2>,
    ) -> Option<MatrixMN<N, R2, C2>>
    where
        S2: StorageMut<N, R2, C2>,
        ShapeConstraint: SameNumberOfRows<R2, D>,
        DefaultAllocator: Allocator<N, R2, C2>,
    {
        let mut res = b.clone_owned();
        if self.solve_mut(&mut res) {
            Some(res)
        } else {
            None
        }
    }

    /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined.
    ///
    /// If the decomposed matrix is not invertible, this returns `false` and its input `b` may
    /// be overwritten with garbage.
    pub fn solve_mut<R2: Dim, C2: Dim, S2>(&self, b: &mut Matrix<N, R2, C2, S2>) -> bool
    where
        S2: StorageMut<N, R2, C2>,
        ShapeConstraint: SameNumberOfRows<R2, D>,
    {
        assert_eq!(
            self.lu.nrows(),
            b.nrows(),
            "FullPivLU solve matrix dimension mismatch."
        );
        assert!(
            self.lu.is_square(),
            "FullPivLU solve: unable to solve a non-square system."
        );

        if self.is_invertible() {
            self.p.permute_rows(b);
            let _ = self.lu.solve_lower_triangular_with_diag_mut(b, N::one());
            let _ = self.lu.solve_upper_triangular_mut(b);
            self.q.inv_permute_rows(b);

            true
        } else {
            false
        }
    }

    /// Computes the inverse of the decomposed matrix.
    ///
    /// Returns `None` if the decomposed matrix is not invertible.
    pub fn try_inverse(&self) -> Option<MatrixN<N, D>> {
        assert!(
            self.lu.is_square(),
            "FullPivLU inverse: unable to compute the inverse of a non-square matrix."
        );

        let (nrows, ncols) = self.lu.data.shape();

        let mut res = MatrixN::identity_generic(nrows, ncols);
        if self.solve_mut(&mut res) {
            Some(res)
        } else {
            None
        }
    }

    /// Indicates if the decomposed matrix is invertible.
    pub fn is_invertible(&self) -> bool {
        assert!(
            self.lu.is_square(),
            "FullPivLU: unable to test the invertibility of a non-square matrix."
        );

        let dim = self.lu.nrows();
        !self.lu[(dim - 1, dim - 1)].is_zero()
    }

    /// Computes the determinant of the decomposed matrix.
    pub fn determinant(&self) -> N {
        assert!(
            self.lu.is_square(),
            "FullPivLU determinant: unable to compute the determinant of a non-square matrix."
        );

        let dim = self.lu.nrows();
        let mut res = self.lu[(dim - 1, dim - 1)];
        if !res.is_zero() {
            for i in 0..dim - 1 {
                res *= unsafe { *self.lu.get_unchecked((i, i)) };
            }

            res * self.p.determinant() * self.q.determinant()
        } else {
            N::zero()
        }
    }
}

impl<N: ComplexField, R: DimMin<C>, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S>
where DefaultAllocator: Allocator<N, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>
{
    /// Computes the LU decomposition with full pivoting of `matrix`.
    ///
    /// This effectively computes `P, L, U, Q` such that `P * matrix * Q = LU`.
    pub fn full_piv_lu(self) -> FullPivLU<N, R, C> {
        FullPivLU::new(self.into_owned())
    }
}
<commit_msg>Used Storage trait for solve method<commit_after>#[cfg(feature = "serde-serialize")]
use serde::{Deserialize, Serialize};

use alga::general::ComplexField;
use crate::allocator::Allocator;
use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixN};
use crate::constraint::{SameNumberOfRows, ShapeConstraint};
use crate::dimension::{Dim, DimMin, DimMinimum};
use crate::storage::{Storage, StorageMut};

use crate::linalg::lu;
use crate::linalg::PermutationSequence;

/// LU decomposition with full row and column pivoting.
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[cfg_attr(
    feature = "serde-serialize",
    serde(bound(
        serialize = "DefaultAllocator: Allocator<N, R, C> +
                           Allocator<(usize, usize), DimMinimum<R, C>>,
         MatrixMN<N, R, C>: Serialize,
         PermutationSequence<DimMinimum<R, C>>: Serialize"
    ))
)]
#[cfg_attr(
    feature = "serde-serialize",
    serde(bound(
        deserialize = "DefaultAllocator: Allocator<N, R, C> +
                           Allocator<(usize, usize), DimMinimum<R, C>>,
         MatrixMN<N, R, C>: Deserialize<'de>,
         PermutationSequence<DimMinimum<R, C>>: Deserialize<'de>"
    ))
)]
#[derive(Clone, Debug)]
pub struct FullPivLU<N: ComplexField, R: DimMin<C>, C: Dim>
where DefaultAllocator: Allocator<N, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>
{
    lu: MatrixMN<N, R, C>,
    p: PermutationSequence<DimMinimum<R, C>>,
    q: PermutationSequence<DimMinimum<R, C>>,
}

impl<N: ComplexField, R: DimMin<C>, C: Dim> Copy for FullPivLU<N, R, C>
where
    DefaultAllocator: Allocator<N, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
    MatrixMN<N, R, C>: Copy,
    PermutationSequence<DimMinimum<R, C>>: Copy,
{}

impl<N: ComplexField, R: DimMin<C>, C: Dim> FullPivLU<N, R, C>
where DefaultAllocator: Allocator<N, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>
{
    /// Computes the LU decomposition with full pivoting of `matrix`.
    ///
    /// This effectively computes `P, L, U, Q` such that `P * matrix * Q = LU`.
    pub fn new(mut matrix: MatrixMN<N, R, C>) -> Self {
        let (nrows, ncols) = matrix.data.shape();
        let min_nrows_ncols = nrows.min(ncols);

        let mut p = PermutationSequence::identity_generic(min_nrows_ncols);
        let mut q = PermutationSequence::identity_generic(min_nrows_ncols);

        if min_nrows_ncols.value() == 0 {
            return Self {
                lu: matrix,
                p: p,
                q: q,
            };
        }

        for i in 0..min_nrows_ncols.value() {
            let piv = matrix.slice_range(i.., i..).icamax_full();
            let row_piv = piv.0 + i;
            let col_piv = piv.1 + i;
            let diag = matrix[(row_piv, col_piv)];

            if diag.is_zero() {
                // The remaining of the matrix is zero.
                break;
            }

            matrix.swap_columns(i, col_piv);
            q.append_permutation(i, col_piv);

            if row_piv != i {
                p.append_permutation(i, row_piv);
                matrix.columns_range_mut(..i).swap_rows(i, row_piv);
                lu::gauss_step_swap(&mut matrix, diag, i, row_piv);
            } else {
                lu::gauss_step(&mut matrix, diag, i);
            }
        }

        Self {
            lu: matrix,
            p: p,
            q: q,
        }
    }

    #[doc(hidden)]
    pub fn lu_internal(&self) -> &MatrixMN<N, R, C> {
        &self.lu
    }

    /// The lower triangular matrix of this decomposition.
    #[inline]
    pub fn l(&self) -> MatrixMN<N, R, DimMinimum<R, C>>
    where DefaultAllocator: Allocator<N, R, DimMinimum<R, C>> {
        let (nrows, ncols) = self.lu.data.shape();
        let mut m = self.lu.columns_generic(0, nrows.min(ncols)).into_owned();
        m.fill_upper_triangle(N::zero(), 1);
        m.fill_diagonal(N::one());
        m
    }

    /// The upper triangular matrix of this decomposition.
    #[inline]
    pub fn u(&self) -> MatrixMN<N, DimMinimum<R, C>, C>
    where DefaultAllocator: Allocator<N, DimMinimum<R, C>, C> {
        let (nrows, ncols) = self.lu.data.shape();
        self.lu.rows_generic(0, nrows.min(ncols)).upper_triangle()
    }

    /// The row permutations of this decomposition.
    #[inline]
    pub fn p(&self) -> &PermutationSequence<DimMinimum<R, C>> {
        &self.p
    }

    /// The column permutations of this decomposition.
    #[inline]
    pub fn q(&self) -> &PermutationSequence<DimMinimum<R, C>> {
        &self.q
    }

    /// The two matrices of this decomposition and the row and column permutations: `(P, L, U, Q)`.
    #[inline]
    pub fn unpack(
        self,
    ) -> (
        PermutationSequence<DimMinimum<R, C>>,
        MatrixMN<N, R, DimMinimum<R, C>>,
        MatrixMN<N, DimMinimum<R, C>, C>,
        PermutationSequence<DimMinimum<R, C>>,
    )
    where DefaultAllocator: Allocator<N, R, DimMinimum<R, C>> + Allocator<N, DimMinimum<R, C>, C>
    {
        // Use reallocation for either l or u.
        let l = self.l();
        let u = self.u();
        let p = self.p;
        let q = self.q;

        (p, l, u, q)
    }
}

impl<N: ComplexField, D: DimMin<D, Output = D>> FullPivLU<N, D, D>
where DefaultAllocator: Allocator<N, D, D> + Allocator<(usize, usize), D>
{
    /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined.
    ///
    /// Returns `None` if the decomposed matrix is not invertible.
    pub fn solve<R2: Dim, C2: Dim, S2>(
        &self,
        b: &Matrix<N, R2, C2, S2>,
    ) -> Option<MatrixMN<N, R2, C2>>
    where
        S2: Storage<N, R2, C2>,
        ShapeConstraint: SameNumberOfRows<R2, D>,
        DefaultAllocator: Allocator<N, R2, C2>,
    {
        let mut res = b.clone_owned();
        if self.solve_mut(&mut res) {
            Some(res)
        } else {
            None
        }
    }

    /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined.
    ///
    /// If the decomposed matrix is not invertible, this returns `false` and its input `b` may
    /// be overwritten with garbage.
    pub fn solve_mut<R2: Dim, C2: Dim, S2>(&self, b: &mut Matrix<N, R2, C2, S2>) -> bool
    where
        S2: StorageMut<N, R2, C2>,
        ShapeConstraint: SameNumberOfRows<R2, D>,
    {
        assert_eq!(
            self.lu.nrows(),
            b.nrows(),
            "FullPivLU solve matrix dimension mismatch."
        );
        assert!(
            self.lu.is_square(),
            "FullPivLU solve: unable to solve a non-square system."
        );

        if self.is_invertible() {
            self.p.permute_rows(b);
            let _ = self.lu.solve_lower_triangular_with_diag_mut(b, N::one());
            let _ = self.lu.solve_upper_triangular_mut(b);
            self.q.inv_permute_rows(b);

            true
        } else {
            false
        }
    }

    /// Computes the inverse of the decomposed matrix.
    ///
    /// Returns `None` if the decomposed matrix is not invertible.
    pub fn try_inverse(&self) -> Option<MatrixN<N, D>> {
        assert!(
            self.lu.is_square(),
            "FullPivLU inverse: unable to compute the inverse of a non-square matrix."
        );

        let (nrows, ncols) = self.lu.data.shape();

        let mut res = MatrixN::identity_generic(nrows, ncols);
        if self.solve_mut(&mut res) {
            Some(res)
        } else {
            None
        }
    }

    /// Indicates if the decomposed matrix is invertible.
    pub fn is_invertible(&self) -> bool {
        assert!(
            self.lu.is_square(),
            "FullPivLU: unable to test the invertibility of a non-square matrix."
        );

        let dim = self.lu.nrows();
        !self.lu[(dim - 1, dim - 1)].is_zero()
    }

    /// Computes the determinant of the decomposed matrix.
    pub fn determinant(&self) -> N {
        assert!(
            self.lu.is_square(),
            "FullPivLU determinant: unable to compute the determinant of a non-square matrix."
        );

        let dim = self.lu.nrows();
        let mut res = self.lu[(dim - 1, dim - 1)];
        if !res.is_zero() {
            for i in 0..dim - 1 {
                res *= unsafe { *self.lu.get_unchecked((i, i)) };
            }

            res * self.p.determinant() * self.q.determinant()
        } else {
            N::zero()
        }
    }
}

impl<N: ComplexField, R: DimMin<C>, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S>
where DefaultAllocator: Allocator<N, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>
{
    /// Computes the LU decomposition with full pivoting of `matrix`.
    ///
    /// This effectively computes `P, L, U, Q` such that `P * matrix * Q = LU`.
    pub fn full_piv_lu(self) -> FullPivLU<N, R, C> {
        FullPivLU::new(self.into_owned())
    }
}
<|endoftext|>


<commit_before>use color::Color;
use game::Piece;
use clear_strategy::ClearStrategy;

#[derive(Debug, PartialEq, Eq)]
pub struct Board {
    color_matrix: Vec<Vec<Option<Color>>>,
}

impl Board {
    pub fn new(width: usize, height: usize) -> Board {
        Board {
            color_matrix: vec![vec![None; width]; height],
        }
    }

    fn height(&self) -> usize {
        self.color_matrix.len()
    }

    fn width(&self) -> usize {
        self.color_matrix.get(0).unwrap_or(&vec![]).len()
    }

    pub fn set(&mut self, row: usize, col: usize, color: Color) {
        self.color_matrix.get_mut(row).unwrap()[col] = Some(color);
    }

    pub fn get(&self, row: usize, col:usize) -> Option<Color> {
        self.color_matrix.get(row)
            .unwrap_or(&vec![])
            .get(col)
            .unwrap_or(&None)
            .clone()
    }

    pub fn get_pieces(&self) -> Vec<Piece> {
        self.color_matrix.iter()
            .enumerate()
            .flat_map(|(row_num, col)| {
                let pieces: Vec<Piece> = col.iter()
                    .enumerate()
                    .filter_map(|(col_num, color)| {
                        if let Some(c) = color.clone() {
                            Some(Piece { row: row_num, col: col_num, color: c })
                        } else {
                            None
                        }
                    }).collect();
                pieces
            })
            .collect()
    }

    fn get_sequential_pieces(&self, coordinates: Vec<(usize, usize)>) -> Vec<Piece> {
        let mut sequence_coordinates: Vec<&(usize, usize)> = coordinates.windows(4)
            .filter(|sequence| {
                sequence.get(0).map_or(false, |&(row_0, col_0)| {
                    self.get(row_0, col_0).map_or(false, |first_color| {
                        sequence.iter().all(|&(row, col)| {
                            self.get(row, col) == Some(first_color.clone())
                        })
                    })
                })
            })
            .flat_map(|s| s)
            .collect();

            sequence_coordinates.sort();
            sequence_coordinates.dedup();

            sequence_coordinates.iter().map(|&&(row, col)| {
                Piece { row: row, col: col, color: self.get(row, col).unwrap() }
            }).collect()
    }

    pub fn get_pieces_to_clear(&self) -> Vec<Piece> {
        let height = self.height();
        let width = self.width();

        let strategies = vec![
            ClearStrategy::Vertical,
            ClearStrategy::Horizontal,
            ClearStrategy::DiagonalUp,
            ClearStrategy::DiagonalDown,
        ];

        let mut pieces: Vec<Piece> = vec![];

        for strategy in strategies {
            let starting_points = strategy.get_starting_points(height, width);

            for (mut row, mut col) in starting_points {
                let mut coordinates = vec![];

                coordinates.push((row, col));

                while let Some(point) = strategy.get_next_point(
                    row, col, height, width
                ) {

                    row = point.0;
                    col = point.1;

                    coordinates.push((row, col));
                }

                let new_pieces = self.get_sequential_pieces(coordinates);
                for s in new_pieces {
                    pieces.push(s);
                }
            }
        }

        pieces
    }

    pub fn clear_all(&mut self, pieces: Vec<Piece>) {
    }

    pub fn get_lowest_free_row_in_col(&self, col: usize) -> usize {
        self.color_matrix.iter()
            .rposition(|row| row.get(col).unwrap_or(&None).is_none())
            .unwrap()
    }
}

#[cfg(test)]
mod tests {
    use board::Board;
    use color::Color::*;
    use game::Piece;

    #[test]
    fn get_pieces_to_clear_diagonal_down() {
        let board = Board {
            color_matrix: vec![
                vec![ Some(Red), None, None, None ],
                vec![ None, Some(Red), None, None ],
                vec![ None, None, Some(Red), None ],
                vec![ None, None, None, Some(Red) ],
            ],
        };

        let mut expected_pieces_to_clear = vec![
            Piece { row: 0, col: 0, color: Red },
            Piece { row: 1, col: 1, color: Red },
            Piece { row: 2, col: 2, color: Red },
            Piece { row: 3, col: 3, color: Red },
        ];

        let mut pieces_to_clear = board.get_pieces_to_clear();

        expected_pieces_to_clear.sort();
        pieces_to_clear.sort();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_diagonal_down_off_center_down() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, None, None],
                vec![ Some(Red), None, None, None ],
                vec![ None, Some(Red), None, None ],
                vec![ None, None, Some(Red), None ],
                vec![ None, None, None, Some(Red) ],
            ],
        };

        let mut expected_pieces_to_clear = vec![
            Piece { row: 1, col: 0, color: Red },
            Piece { row: 2, col: 1, color: Red },
            Piece { row: 3, col: 2, color: Red },
            Piece { row: 4, col: 3, color: Red },
        ];

        let mut pieces_to_clear = board.get_pieces_to_clear();

        expected_pieces_to_clear.sort();
        pieces_to_clear.sort();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_diagonal_down_off_center_right() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, None, None ],
                vec![ None, Some(Red), None, None, None ],
                vec![ None, None, Some(Red), None, None ],
                vec![ None, None, None, Some(Red), None ],
                vec![ None, None, None, None, Some(Red) ],
            ],
        };

        let mut expected_pieces_to_clear = vec![
            Piece { row: 1, col: 1, color: Red },
            Piece { row: 2, col: 2, color: Red },
            Piece { row: 3, col: 3, color: Red },
            Piece { row: 4, col: 4, color: Red },
        ];

        let mut pieces_to_clear = board.get_pieces_to_clear();

        expected_pieces_to_clear.sort();
        pieces_to_clear.sort();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_diagonal_up() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, Some(Red) ],
                vec![ None, None, Some(Red), None ],
                vec![ None, Some(Red), None, None ],
                vec![ Some(Red), None, None, None ],
            ],
        };

        let mut expected_pieces_to_clear = vec![
            Piece { row: 3, col: 0, color: Red },
            Piece { row: 2, col: 1, color: Red },
            Piece { row: 1, col: 2, color: Red },
            Piece { row: 0, col: 3, color: Red },
        ];

        let mut pieces_to_clear = board.get_pieces_to_clear();

        expected_pieces_to_clear.sort();
        pieces_to_clear.sort();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_diagonal_up_off_center_up() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, Some(Red), None ],
                vec![ None, None, Some(Red), None, None ],
                vec![ None, Some(Red), None, None, None ],
                vec![ Some(Red), None, None, None, None ],
                vec![ None, None, None, None, None ],
            ],
        };

        let mut expected_pieces_to_clear = vec![
            Piece { row: 3, col: 0, color: Red },
            Piece { row: 2, col: 1, color: Red },
            Piece { row: 1, col: 2, color: Red },
            Piece { row: 0, col: 3, color: Red },
        ];

        let mut pieces_to_clear = board.get_pieces_to_clear();

        expected_pieces_to_clear.sort();
        pieces_to_clear.sort();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_diagonal_up_off_center_down() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, None, None ],
                vec![ None, None, None, None, Some(Red) ],
                vec![ None, None, None, Some(Red), None ],
                vec![ None, None, Some(Red), None, None ],
                vec![ None, Some(Red), None, None, None ],
            ],
        };

        let mut expected_pieces_to_clear = vec![
            Piece { row: 4, col: 1, color: Red },
            Piece { row: 3, col: 2, color: Red },
            Piece { row: 2, col: 3, color: Red },
            Piece { row: 1, col: 4, color: Red },
        ];

        let mut pieces_to_clear = board.get_pieces_to_clear();

        expected_pieces_to_clear.sort();
        pieces_to_clear.sort();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_horizontal() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, None ],
                vec![ None, None, None, None ],
                vec![ Some(Red), Some(Red), Some(Red), Some(Red) ],
                vec![ None, None, None, None ],
            ],
        };

        let expected_pieces_to_clear = vec![
            Piece { row: 2, col: 0, color: Red },
            Piece { row: 2, col: 1, color: Red },
            Piece { row: 2, col: 2, color: Red },
            Piece { row: 2, col: 3, color: Red },
        ];

        let pieces_to_clear = board.get_pieces_to_clear();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_vertical() {
        let board = Board {
            color_matrix: vec![
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
                vec![ Some(Yellow), None ],
            ],
        };

        let expected_pieces_to_clear = vec![
            Piece { row: 0, col: 0, color: Red },
            Piece { row: 1, col: 0, color: Red },
            Piece { row: 2, col: 0, color: Red },
            Piece { row: 3, col: 0, color: Red },
        ];

        let pieces_to_clear = board.get_pieces_to_clear();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_vertical_none_eligible() {
        let board = Board {
            color_matrix: vec![
                vec![ Some(Red), None ],
                vec![ Some(Blue), None ],
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
            ],
        };

        let expected_pieces_to_clear: Vec<Piece> = vec![];

        let pieces_to_clear = board.get_pieces_to_clear();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn set_a_color() {
        let mut board = Board {
            color_matrix: vec![
                vec![ Some(Red), Some(Red) ],
                vec![ Some(Red), Some(Red) ],
            ],
        };

        board.set(1, 1, Yellow);

        let expected_board = Board {
            color_matrix: vec![
                vec![ Some(Red), Some(Red) ],
                vec![ Some(Red), Some(Yellow) ],
            ],
        };

        assert_eq!(expected_board, board);
    }

    #[test]
    fn get_a_color() {
        let board = Board {
            color_matrix: vec![
                vec![ Some(Red), Some(Blue) ],
                vec![ Some(Red), Some(Yellow) ],
            ],
        };

        let color = board.get(0, 1);

        let expected_color = Some(Blue);

        assert_eq!(expected_color, color);
    }

    #[test]
    fn get_lowest_free_row_in_col() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None ],
                vec![ None, None ],
            ],
        };

        let row = board.get_lowest_free_row_in_col(0);
        let expected_row = 1;

        assert_eq!(expected_row, row);
    }

    #[test]
    fn get_lowest_free_row_in_col_with_another_existing_piece() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None ],
                vec![ Some(Red), None ],
            ],
        };

        let row = board.get_lowest_free_row_in_col(0);
        let expected_row = 0;

        assert_eq!(expected_row, row);
    }
}
<commit_msg>clear pieces<commit_after>use color::Color;
use game::Piece;
use clear_strategy::ClearStrategy;

#[derive(Debug, PartialEq, Eq)]
pub struct Board {
    color_matrix: Vec<Vec<Option<Color>>>,
}

impl Board {
    pub fn new(width: usize, height: usize) -> Board {
        Board {
            color_matrix: vec![vec![None; width]; height],
        }
    }

    fn height(&self) -> usize {
        self.color_matrix.len()
    }

    fn width(&self) -> usize {
        self.color_matrix.get(0).unwrap_or(&vec![]).len()
    }

    pub fn set(&mut self, row: usize, col: usize, color: Color) {
        self.color_matrix.get_mut(row).unwrap()[col] = Some(color);
    }

    fn unset(&mut self, row: usize, col: usize) {
        self.color_matrix.get_mut(row).unwrap()[col] = None;
    }

    fn remove_and_shift_column(&mut self, starting_row: usize, col: usize) {
        for row in (starting_row..self.height()).rev() {
            let piece_above = if row > 0 {
                self.get(row - 1, col)
            } else {
                None
            };

            self.color_matrix.get_mut(row).unwrap()[col] = piece_above;
        }
    }

    pub fn get(&self, row: usize, col:usize) -> Option<Color> {
        self.color_matrix.get(row)
            .unwrap_or(&vec![])
            .get(col)
            .unwrap_or(&None)
            .clone()
    }

    pub fn get_pieces(&self) -> Vec<Piece> {
        self.color_matrix.iter()
            .enumerate()
            .flat_map(|(row_num, col)| {
                let pieces: Vec<Piece> = col.iter()
                    .enumerate()
                    .filter_map(|(col_num, color)| {
                        if let Some(c) = color.clone() {
                            Some(Piece { row: row_num, col: col_num, color: c })
                        } else {
                            None
                        }
                    }).collect();
                pieces
            })
            .collect()
    }

    fn get_sequential_pieces(&self, coordinates: Vec<(usize, usize)>) -> Vec<Piece> {
        let mut sequence_coordinates: Vec<&(usize, usize)> = coordinates.windows(4)
            .filter(|sequence| {
                sequence.get(0).map_or(false, |&(row_0, col_0)| {
                    self.get(row_0, col_0).map_or(false, |first_color| {
                        sequence.iter().all(|&(row, col)| {
                            self.get(row, col) == Some(first_color.clone())
                        })
                    })
                })
            })
            .flat_map(|s| s)
            .collect();

            sequence_coordinates.sort();
            sequence_coordinates.dedup();

            sequence_coordinates.iter().map(|&&(row, col)| {
                Piece { row: row, col: col, color: self.get(row, col).unwrap() }
            }).collect()
    }

    pub fn get_pieces_to_clear(&self) -> Vec<Piece> {
        let height = self.height();
        let width = self.width();

        let strategies = vec![
            ClearStrategy::Vertical,
            ClearStrategy::Horizontal,
            ClearStrategy::DiagonalUp,
            ClearStrategy::DiagonalDown,
        ];

        let mut pieces: Vec<Piece> = vec![];

        for strategy in strategies {
            let starting_points = strategy.get_starting_points(height, width);

            for (mut row, mut col) in starting_points {
                let mut coordinates = vec![];

                coordinates.push((row, col));

                while let Some(point) = strategy.get_next_point(
                    row, col, height, width
                ) {

                    row = point.0;
                    col = point.1;

                    coordinates.push((row, col));
                }

                let new_pieces = self.get_sequential_pieces(coordinates);
                for p in new_pieces {
                    pieces.push(p);
                }
            }
        }

        pieces
    }

    pub fn clear_all(&mut self, pieces: Vec<Piece>) {
        for piece in pieces {
            self.unset(piece.row(), piece.col());
        }

        for col in 0..self.width() {
            for row in (0..self.height()).rev() {
                let color = self.get(row, col);
                let color_above = self.get(row + 1, col);

                if let (None, Some(_)) = (color, color_above) {
                    self.remove_and_shift_column(row, col);
                }
            }
        }
    }

    pub fn get_lowest_free_row_in_col(&self, col: usize) -> usize {
        self.color_matrix.iter()
            .rposition(|row| row.get(col).unwrap_or(&None).is_none())
            .unwrap()
    }
}

#[cfg(test)]
mod tests {
    use board::Board;
    use color::Color::*;
    use game::Piece;

    #[test]
    fn delete_all_horizontal_row() {
        let mut board = Board {
            color_matrix: vec![
                vec![ None, None, None, None ],
                vec![ None, None, None, None ],
                vec![ None, Some(Red), None, None ],
                vec![ Some(Red), Some(Red), Some(Red), Some(Red) ],
            ],
        };

        let pieces_to_clear = vec![
            Piece { row: 3, col: 0, color: Red },
            Piece { row: 3, col: 1, color: Red },
            Piece { row: 3, col: 2, color: Red },
            Piece { row: 3, col: 3, color: Red },
        ];

        let expected_board = Board {
            color_matrix: vec![
                vec![ None, None, None, None ],
                vec![ None, None, None, None ],
                vec![ None, None, None, None ],
                vec![ None, Some(Red), None, None ],
            ],
        };

        board.clear_all(pieces_to_clear);

        assert_eq!(expected_board, board);
    }

    #[test]
    fn get_pieces_to_clear_diagonal_down() {
        let board = Board {
            color_matrix: vec![
                vec![ Some(Red), None, None, None ],
                vec![ None, Some(Red), None, None ],
                vec![ None, None, Some(Red), None ],
                vec![ None, None, None, Some(Red) ],
            ],
        };

        let mut expected_pieces_to_clear = vec![
            Piece { row: 0, col: 0, color: Red },
            Piece { row: 1, col: 1, color: Red },
            Piece { row: 2, col: 2, color: Red },
            Piece { row: 3, col: 3, color: Red },
        ];

        let mut pieces_to_clear = board.get_pieces_to_clear();

        expected_pieces_to_clear.sort();
        pieces_to_clear.sort();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_diagonal_down_off_center_down() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, None, None],
                vec![ Some(Red), None, None, None ],
                vec![ None, Some(Red), None, None ],
                vec![ None, None, Some(Red), None ],
                vec![ None, None, None, Some(Red) ],
            ],
        };

        let mut expected_pieces_to_clear = vec![
            Piece { row: 1, col: 0, color: Red },
            Piece { row: 2, col: 1, color: Red },
            Piece { row: 3, col: 2, color: Red },
            Piece { row: 4, col: 3, color: Red },
        ];

        let mut pieces_to_clear = board.get_pieces_to_clear();

        expected_pieces_to_clear.sort();
        pieces_to_clear.sort();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_diagonal_down_off_center_right() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, None, None ],
                vec![ None, Some(Red), None, None, None ],
                vec![ None, None, Some(Red), None, None ],
                vec![ None, None, None, Some(Red), None ],
                vec![ None, None, None, None, Some(Red) ],
            ],
        };

        let mut expected_pieces_to_clear = vec![
            Piece { row: 1, col: 1, color: Red },
            Piece { row: 2, col: 2, color: Red },
            Piece { row: 3, col: 3, color: Red },
            Piece { row: 4, col: 4, color: Red },
        ];

        let mut pieces_to_clear = board.get_pieces_to_clear();

        expected_pieces_to_clear.sort();
        pieces_to_clear.sort();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_diagonal_up() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, Some(Red) ],
                vec![ None, None, Some(Red), None ],
                vec![ None, Some(Red), None, None ],
                vec![ Some(Red), None, None, None ],
            ],
        };

        let mut expected_pieces_to_clear = vec![
            Piece { row: 3, col: 0, color: Red },
            Piece { row: 2, col: 1, color: Red },
            Piece { row: 1, col: 2, color: Red },
            Piece { row: 0, col: 3, color: Red },
        ];

        let mut pieces_to_clear = board.get_pieces_to_clear();

        expected_pieces_to_clear.sort();
        pieces_to_clear.sort();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_diagonal_up_off_center_up() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, Some(Red), None ],
                vec![ None, None, Some(Red), None, None ],
                vec![ None, Some(Red), None, None, None ],
                vec![ Some(Red), None, None, None, None ],
                vec![ None, None, None, None, None ],
            ],
        };

        let mut expected_pieces_to_clear = vec![
            Piece { row: 3, col: 0, color: Red },
            Piece { row: 2, col: 1, color: Red },
            Piece { row: 1, col: 2, color: Red },
            Piece { row: 0, col: 3, color: Red },
        ];

        let mut pieces_to_clear = board.get_pieces_to_clear();

        expected_pieces_to_clear.sort();
        pieces_to_clear.sort();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_diagonal_up_off_center_down() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, None, None ],
                vec![ None, None, None, None, Some(Red) ],
                vec![ None, None, None, Some(Red), None ],
                vec![ None, None, Some(Red), None, None ],
                vec![ None, Some(Red), None, None, None ],
            ],
        };

        let mut expected_pieces_to_clear = vec![
            Piece { row: 4, col: 1, color: Red },
            Piece { row: 3, col: 2, color: Red },
            Piece { row: 2, col: 3, color: Red },
            Piece { row: 1, col: 4, color: Red },
        ];

        let mut pieces_to_clear = board.get_pieces_to_clear();

        expected_pieces_to_clear.sort();
        pieces_to_clear.sort();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_horizontal() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, None ],
                vec![ None, None, None, None ],
                vec![ Some(Red), Some(Red), Some(Red), Some(Red) ],
                vec![ None, None, None, None ],
            ],
        };

        let expected_pieces_to_clear = vec![
            Piece { row: 2, col: 0, color: Red },
            Piece { row: 2, col: 1, color: Red },
            Piece { row: 2, col: 2, color: Red },
            Piece { row: 2, col: 3, color: Red },
        ];

        let pieces_to_clear = board.get_pieces_to_clear();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_vertical() {
        let board = Board {
            color_matrix: vec![
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
                vec![ Some(Yellow), None ],
            ],
        };

        let expected_pieces_to_clear = vec![
            Piece { row: 0, col: 0, color: Red },
            Piece { row: 1, col: 0, color: Red },
            Piece { row: 2, col: 0, color: Red },
            Piece { row: 3, col: 0, color: Red },
        ];

        let pieces_to_clear = board.get_pieces_to_clear();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_vertical_none_eligible() {
        let board = Board {
            color_matrix: vec![
                vec![ Some(Red), None ],
                vec![ Some(Blue), None ],
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
            ],
        };

        let expected_pieces_to_clear: Vec<Piece> = vec![];

        let pieces_to_clear = board.get_pieces_to_clear();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn set_a_color() {
        let mut board = Board {
            color_matrix: vec![
                vec![ Some(Red), Some(Red) ],
                vec![ Some(Red), Some(Red) ],
            ],
        };

        board.set(1, 1, Yellow);

        let expected_board = Board {
            color_matrix: vec![
                vec![ Some(Red), Some(Red) ],
                vec![ Some(Red), Some(Yellow) ],
            ],
        };

        assert_eq!(expected_board, board);
    }

    #[test]
    fn get_a_color() {
        let board = Board {
            color_matrix: vec![
                vec![ Some(Red), Some(Blue) ],
                vec![ Some(Red), Some(Yellow) ],
            ],
        };

        let color = board.get(0, 1);

        let expected_color = Some(Blue);

        assert_eq!(expected_color, color);
    }

    #[test]
    fn get_lowest_free_row_in_col() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None ],
                vec![ None, None ],
            ],
        };

        let row = board.get_lowest_free_row_in_col(0);
        let expected_row = 1;

        assert_eq!(expected_row, row);
    }

    #[test]
    fn get_lowest_free_row_in_col_with_another_existing_piece() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None ],
                vec![ Some(Red), None ],
            ],
        };

        let row = board.get_lowest_free_row_in_col(0);
        let expected_row = 0;

        assert_eq!(expected_row, row);
    }
}
<|endoftext|>


<commit_before>use codegen::generate_single_version_file;
use env::Env;

mod build;
mod cargo_toml;
pub mod ffi_type;
mod fields;
mod functions;
mod lib_;
mod statics;
mod tests;

pub fn generate(env: &Env) {
    generate_single_version_file(env);
    lib_::generate(env);
    build::generate(env);
    let crate_name = cargo_toml::generate(env);
    tests::generate(env, &crate_name);
}
<commit_msg>Fix invalid crate name generation<commit_after>use codegen::generate_single_version_file;
use env::Env;

mod build;
mod cargo_toml;
pub mod ffi_type;
mod fields;
mod functions;
mod lib_;
mod statics;
mod tests;

pub fn generate(env: &Env) {
    generate_single_version_file(env);
    lib_::generate(env);
    build::generate(env);
    let crate_name = cargo_toml::generate(env);
    tests::generate(env, &crate_name.replace("-", "_"));
}
<|endoftext|>


<commit_before>use super::socket_addr;
use crate::net::{SocketAddr, UnixStream};
use crate::sys::unix::net::new_socket;
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::os::unix::net;
use std::path::Path;
use std::{io, mem};

pub(crate) fn bind(path: &Path) -> io::Result<net::UnixListener> {
    let socket = new_socket(libc::AF_UNIX, libc::SOCK_STREAM)?;
    let (sockaddr, socklen) = socket_addr(path)?;
    let sockaddr = &sockaddr as *const libc::sockaddr_un as *const libc::sockaddr;

    syscall!(bind(socket, sockaddr, socklen))
        .and_then(|_| syscall!(listen(socket, 1024)))
        .map_err(|err| {
            // Close the socket if we hit an error, ignoring the error from
            // closing since we can't pass back two errors.
            let _ = unsafe { libc::close(socket) };
            err
        })
        .map(|_| unsafe { net::UnixListener::from_raw_fd(socket) })
}

pub(crate) fn accept(listener: &net::UnixListener) -> io::Result<(UnixStream, SocketAddr)> {
    let sockaddr = mem::MaybeUninit::<libc::sockaddr_un>::zeroed();

    // This is safe to assume because a `libc::sockaddr_un` filled with `0`
    // bytes is properly initialized.
    //
    // `0` is a valid value for `sockaddr_un::sun_family`; it is
    // `libc::AF_UNSPEC`.
    //
    // `[0; 108]` is a valid value for `sockaddr_un::sun_path`; it begins an
    // abstract path.
    let mut sockaddr = unsafe { sockaddr.assume_init() };

    sockaddr.sun_family = libc::AF_UNIX as libc::sa_family_t;
    let mut socklen = mem::size_of_val(&sockaddr) as libc::socklen_t;

    #[cfg(not(any(
        target_os = "ios",
        target_os = "macos",
        target_os = "netbsd",
        target_os = "solaris"
    )))]
    let socket = {
        let flags = libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC;
        syscall!(accept4(
            listener.as_raw_fd(),
            &mut sockaddr as *mut libc::sockaddr_un as *mut libc::sockaddr,
            &mut socklen,
            flags
        ))
        .map(|socket| unsafe { net::UnixStream::from_raw_fd(socket) })
    };

    #[cfg(any(
        target_os = "ios",
        target_os = "macos",
        target_os = "netbsd",
        target_os = "solaris"
    ))]
    let socket = syscall!(accept(
        listener.as_raw_fd(),
        &mut sockaddr as *mut libc::sockaddr_un as *mut libc::sockaddr,
        &mut socklen,
    ))
    .and_then(|socket| {
        // Ensure the socket is closed if either of the `fcntl` calls
        // error below.
        let s = unsafe { net::UnixStream::from_raw_fd(socket) };
        syscall!(fcntl(socket, libc::F_SETFL, libc::O_NONBLOCK))
            .and_then(|_| syscall!(fcntl(socket, libc::F_SETFD, libc::FD_CLOEXEC)).map(|_| s))
    });

    socket
        .map(UnixStream::from_std)
        .map(|stream| (stream, SocketAddr::from_parts(sockaddr, socklen)))
}

pub(crate) fn local_addr(listener: &net::UnixListener) -> io::Result<SocketAddr> {
    super::local_addr(listener.as_raw_fd())
}
<commit_msg>Remove unneeded setting of O_NONBLOCK<commit_after>use super::socket_addr;
use crate::net::{SocketAddr, UnixStream};
use crate::sys::unix::net::new_socket;
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::os::unix::net;
use std::path::Path;
use std::{io, mem};

pub(crate) fn bind(path: &Path) -> io::Result<net::UnixListener> {
    let socket = new_socket(libc::AF_UNIX, libc::SOCK_STREAM)?;
    let (sockaddr, socklen) = socket_addr(path)?;
    let sockaddr = &sockaddr as *const libc::sockaddr_un as *const libc::sockaddr;

    syscall!(bind(socket, sockaddr, socklen))
        .and_then(|_| syscall!(listen(socket, 1024)))
        .map_err(|err| {
            // Close the socket if we hit an error, ignoring the error from
            // closing since we can't pass back two errors.
            let _ = unsafe { libc::close(socket) };
            err
        })
        .map(|_| unsafe { net::UnixListener::from_raw_fd(socket) })
}

pub(crate) fn accept(listener: &net::UnixListener) -> io::Result<(UnixStream, SocketAddr)> {
    let sockaddr = mem::MaybeUninit::<libc::sockaddr_un>::zeroed();

    // This is safe to assume because a `libc::sockaddr_un` filled with `0`
    // bytes is properly initialized.
    //
    // `0` is a valid value for `sockaddr_un::sun_family`; it is
    // `libc::AF_UNSPEC`.
    //
    // `[0; 108]` is a valid value for `sockaddr_un::sun_path`; it begins an
    // abstract path.
    let mut sockaddr = unsafe { sockaddr.assume_init() };

    sockaddr.sun_family = libc::AF_UNIX as libc::sa_family_t;
    let mut socklen = mem::size_of_val(&sockaddr) as libc::socklen_t;

    #[cfg(not(any(
        target_os = "ios",
        target_os = "macos",
        target_os = "netbsd",
        target_os = "solaris"
    )))]
    let socket = {
        let flags = libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC;
        syscall!(accept4(
            listener.as_raw_fd(),
            &mut sockaddr as *mut libc::sockaddr_un as *mut libc::sockaddr,
            &mut socklen,
            flags
        ))
        .map(|socket| unsafe { net::UnixStream::from_raw_fd(socket) })
    };

    #[cfg(any(
        target_os = "ios",
        target_os = "macos",
        target_os = "netbsd",
        target_os = "solaris"
    ))]
    let socket = syscall!(accept(
        listener.as_raw_fd(),
        &mut sockaddr as *mut libc::sockaddr_un as *mut libc::sockaddr,
        &mut socklen,
    ))
    .and_then(|socket| {
        // Ensure the socket is closed if either of the `fcntl` calls
        // error below.
        let s = unsafe { net::UnixStream::from_raw_fd(socket) };
        syscall!(fcntl(socket, libc::F_SETFD, libc::FD_CLOEXEC)).map(|_| s)
    });

    socket
        .map(UnixStream::from_std)
        .map(|stream| (stream, SocketAddr::from_parts(sockaddr, socklen)))
}

pub(crate) fn local_addr(listener: &net::UnixListener) -> io::Result<SocketAddr> {
    super::local_addr(listener.as_raw_fd())
}
<|endoftext|>


<commit_before>import std::option;
import std::generic_os::getenv;
import std::io;
import std::str;

import common::config;

fn make_new_path(path: str) -> str {

    // Windows just uses PATH as the library search path, so we have to
    // maintain the current value while adding our own
    alt getenv(lib_path_env_var()) {
      option::some(curr) { #fmt["%s:%s", path, curr] }
      option::none. { path }
    }
}

#[cfg(target_os = "linux")]
fn lib_path_env_var() -> str { "LD_LIBRARY_PATH" }

#[cfg(target_os = "macos")]
fn lib_path_env_var() -> str { "DYLD_LIBRARY_PATH" }

#[cfg(target_os = "win32")]
fn lib_path_env_var() -> str { "PATH" }

fn logv(config: config, s: str) {
    log s;
    if config.verbose { io::stdout().write_line(s); }
}
<commit_msg>Teach compiletest to construct the PATH variable correctly on win32<commit_after>import std::option;
import std::generic_os::getenv;
import std::io;
import std::str;

import common::config;

fn make_new_path(path: str) -> str {

    // Windows just uses PATH as the library search path, so we have to
    // maintain the current value while adding our own
    alt getenv(lib_path_env_var()) {
      option::some(curr) {
        #fmt["%s%s%s", path, path_div(), curr]
      }
      option::none. { path }
    }
}

#[cfg(target_os = "linux")]
fn lib_path_env_var() -> str { "LD_LIBRARY_PATH" }

#[cfg(target_os = "macos")]
fn lib_path_env_var() -> str { "DYLD_LIBRARY_PATH" }

#[cfg(target_os = "win32")]
fn lib_path_env_var() -> str { "PATH" }

#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
fn path_div() -> str { ":" }

#[cfg(target_os = "win32")]
fn path_div() -> str { ";" }

fn logv(config: config, s: str) {
    log s;
    if config.verbose { io::stdout().write_line(s); }
}
<|endoftext|>


<commit_before>use bot::BotEnv;
use filters::Filter;

use lalafell::commands::prelude::*;

use serenity::prelude::Mentionable;
use serenity::model::guild::Role;

use chrono::Utc;

const USAGE: &str = "!search <filters>";

pub struct SearchCommand;

impl SearchCommand {
  pub fn new(_: Arc<BotEnv>) -> Self {
    SearchCommand
  }
}

#[derive(Debug, Deserialize)]
pub struct Params {
  filter_strings: Vec<String>
}

impl HasParams for SearchCommand {
  type Params = Params;
}

impl<'a> PublicChannelCommand<'a> for SearchCommand {
  fn run(&self, _: &Context, _: &Message, guild: GuildId, _: Arc<RwLock<GuildChannel>>, params: &[&str]) -> CommandResult<'a> {
    let params = self.params(USAGE, params)?;

    let filters = match Filter::all_filters(&params.filter_strings.join(" ")) {
      Some(f) => f,
      None => return Err("Invalid filters.".into())
    };
    let guild = some_or!(guild.find(), bail!("could not find guild"));
    let roles: Vec<Role> = guild.read().roles.values().cloned().collect();
    let now = Utc::now();
    let matches: Vec<String> = guild.read().members.values()
      .filter(|m| filters.iter().all(|f| f.matches(m, &roles)))
      .map(|m| format!("{} - {}",
        m.mention(),
        m.joined_at
          .map(|d| now.signed_duration_since(d))
          .map(|d| {
            let mut res = String::new();
            let seconds = d.num_seconds() % 60;
            let minutes = d.num_minutes() % 60;
            let hours = d.num_hours() % 24;
            let days = d.num_days();
            if days > 0 {
              res.push_str(&format!("{} day{}, ", days, if days == 1 { "" } else { "s" }));
            }
            if hours > 0 {
              res.push_str(&format!("{} hour{}, ", hours, if hours == 1 { "" } else { "s" }));
            }
            if minutes > 0 {
              res.push_str(&format!("{} minute{}, ", minutes, if minutes == 1 { "" } else { "s" }));
            }
            if seconds > 0 {
              res.push_str(&format!("{} second{}", seconds, if seconds == 1 { "" } else { "s" }));
            }
            res
          })
          .unwrap_or_else(|| String::from("unknown"))))
      .collect();
    Ok(matches.join("\n").into())
  }
}
<commit_msg>fix: don't silently error if message too large<commit_after>use bot::BotEnv;
use filters::Filter;

use lalafell::commands::prelude::*;

use serenity::prelude::Mentionable;
use serenity::model::guild::Role;

use chrono::Utc;

const USAGE: &str = "!search <filters>";

pub struct SearchCommand;

impl SearchCommand {
  pub fn new(_: Arc<BotEnv>) -> Self {
    SearchCommand
  }
}

#[derive(Debug, Deserialize)]
pub struct Params {
  filter_strings: Vec<String>
}

impl HasParams for SearchCommand {
  type Params = Params;
}

impl<'a> PublicChannelCommand<'a> for SearchCommand {
  fn run(&self, _: &Context, _: &Message, guild: GuildId, _: Arc<RwLock<GuildChannel>>, params: &[&str]) -> CommandResult<'a> {
    let params = self.params(USAGE, params)?;

    let filters = match Filter::all_filters(&params.filter_strings.join(" ")) {
      Some(f) => f,
      None => return Err("Invalid filters.".into())
    };
    let guild = some_or!(guild.find(), bail!("could not find guild"));
    let roles: Vec<Role> = guild.read().roles.values().cloned().collect();
    let now = Utc::now();
    let matches: Vec<String> = guild.read().members.values()
      .filter(|m| filters.iter().all(|f| f.matches(m, &roles)))
      .map(|m| format!("{} - {}",
        m.mention(),
        m.joined_at
          .map(|d| now.signed_duration_since(d))
          .map(|d| {
            let mut res = String::new();
            let seconds = d.num_seconds() % 60;
            let minutes = d.num_minutes() % 60;
            let hours = d.num_hours() % 24;
            let days = d.num_days();
            if days > 0 {
              res.push_str(&format!("{} day{}, ", days, if days == 1 { "" } else { "s" }));
            }
            if hours > 0 {
              res.push_str(&format!("{} hour{}, ", hours, if hours == 1 { "" } else { "s" }));
            }
            if minutes > 0 {
              res.push_str(&format!("{} minute{}, ", minutes, if minutes == 1 { "" } else { "s" }));
            }
            if seconds > 0 {
              res.push_str(&format!("{} second{}", seconds, if seconds == 1 { "" } else { "s" }));
            }
            res
          })
          .unwrap_or_else(|| String::from("unknown"))))
      .collect();
    let to_send = matches.join("\n");
    if to_send.len() > 2000 {
      return Err("Result was too large. Try a smaller filter.".into());
    }
    Ok(to_send.into())
  }
}
<|endoftext|>


<commit_before>// xfail-stage0

use std;
import std::run;

// Regression test for memory leaks
fn test_leaks() {
  run::run_program("echo", []);
  run::start_program("echo", []);
  run::program_output("echo", []);
}

fn main() {
  test_leaks();
}<commit_msg>Revert "Enable run-pass/lib-run on win32. Closes #714"<commit_after>// xfail-stage0

use std;
import std::run;

// Regression test for memory leaks
// FIXME (714) Why does this fail on win32?

#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
fn test_leaks() {
  run::run_program("echo", []);
  run::start_program("echo", []);
  run::program_output("echo", []);
}

#[cfg(target_os = "win32")]
fn test_leaks() {}

fn main() {
  test_leaks();
}<|endoftext|>


<commit_before>use serde::{Deserialize, Serialize};
use super::super::rosxmlrpc::{self, Response as Result};
use xml_rpc;

pub struct Master {
    client: rosxmlrpc::Client,
    client_id: String,
    caller_api: String,
}

macro_rules! request {
    ($s:expr; $name:ident; $($item:expr),*)=> ({
        $s.client.request(stringify!($name),&(&$s.client_id,
            $(
                $item,
            )*
            ))
    })
}

macro_rules! request_tree {
    ($s:expr; $name:ident; $($item:expr),*)=> ({
        $s.client.request_tree(stringify!($name),&(&$s.client_id,
            $(
                $item,
            )*
            ))
    })
}

impl Master {
    pub fn new(master_uri: &str, client_id: &str, caller_api: &str) -> Master {
        Master {
            client: rosxmlrpc::Client::new(master_uri).unwrap(),
            client_id: client_id.to_owned(),
            caller_api: caller_api.to_owned(),
        }
    }

    pub fn register_service(&self, service: &str, service_api: &str) -> Result<i32> {
        request!(self; registerService; service, service_api, &self.caller_api)
    }

    pub fn unregister_service(&self, service: &str, service_api: &str) -> Result<i32> {
        request!(self; unregisterService; service, service_api)
    }

    pub fn register_subscriber(&self, topic: &str, topic_type: &str) -> Result<Vec<String>> {
        request!(self; registerSubscriber; topic, topic_type, &self.caller_api)
    }

    pub fn unregister_subscriber(&self, topic: &str) -> Result<i32> {
        request!(self; registerSubscriber; topic, &self.caller_api)
    }

    pub fn register_publisher(&self, topic: &str, topic_type: &str) -> Result<Vec<String>> {
        request!(self; registerPublisher; topic, topic_type, &self.caller_api)
    }

    pub fn unregister_publisher(&self, topic: &str) -> Result<i32> {
        request!(self; unregisterPublisher; topic, &self.caller_api)
    }

    #[allow(dead_code)]
    pub fn lookup_node(&self, node_name: &str) -> Result<String> {
        request!(self; lookupNode; node_name)
    }

    #[allow(dead_code)]
    pub fn get_published_topics(&self, subgraph: &str) -> Result<Vec<(String, String)>> {
        request!(self; getPublishedTopics; subgraph)
    }

    pub fn get_topic_types(&self) -> Result<Vec<TopicTuple>> {
        request!(self; getTopicTypes;)
    }

    pub fn get_system_state(&self) -> Result<SystemStateTuple> {
        request!(self; getSystemState;)
    }

    #[allow(dead_code)]
    pub fn get_uri(&self) -> Result<String> {
        request!(self; getUri;)
    }

    pub fn lookup_service(&self, service: &str) -> Result<String> {
        request!(self; lookupService; service)
    }

    pub fn delete_param(&self, key: &str) -> Result<i32> {
        request!(self; deleteParam; key)
    }

    pub fn set_param<T: Serialize>(&self, key: &str, value: &T) -> Result<i32> {
        request!(self; setParam; key, value)
    }

    pub fn set_param_any(&self, key: &str, value: xml_rpc::Value) -> Result<()> {
        self.client
            .request_tree_with_tree(
                "setParam",
                vec![
                    xml_rpc::Value::String(self.client_id.clone()),
                    xml_rpc::Value::String(key.into()),
                    value,
                ],
            )
            .and(Ok(()))
    }

    pub fn get_param<'a, T: Deserialize<'a>>(&self, key: &str) -> Result<T> {
        request!(self; getParam; key)
    }

    pub fn get_param_any(&self, key: &str) -> Result<xml_rpc::Value> {
        request_tree!(self; getParam; key)
    }

    pub fn search_param(&self, key: &str) -> Result<String> {
        request!(self; searchParam; key)
    }

    #[allow(dead_code)]
    pub fn subscribe_param<'a, T: Deserialize<'a>>(&self, key: &str) -> Result<T> {
        request!(self; subscribeParam; &self.caller_api, key)
    }

    #[allow(dead_code)]
    pub fn subscribe_param_any(&self, key: &str) -> Result<xml_rpc::Value> {
        request_tree!(self; subscribeParam; &self.caller_api, key)
    }

    #[allow(dead_code)]
    pub fn unsubscribe_param(&self, key: &str) -> Result<i32> {
        request!(self; unsubscribeParam; &self.caller_api, key)
    }

    pub fn has_param(&self, key: &str) -> Result<bool> {
        request!(self; hasParam; key)
    }

    pub fn get_param_names(&self) -> Result<Vec<String>> {
        request!(self; getParamNames;)
    }
}

#[derive(Debug)]
pub struct TopicData {
    pub name: String,
    pub connections: Vec<String>,
}

#[derive(Debug)]
pub struct SystemState {
    pub publishers: Vec<TopicData>,
    pub subscribers: Vec<TopicData>,
    pub services: Vec<TopicData>,
}

#[derive(Debug, Deserialize)]
pub struct TopicDataTuple(String, Vec<String>);
#[derive(Debug, Deserialize)]
pub struct SystemStateTuple(
    Vec<TopicDataTuple>,
    Vec<TopicDataTuple>,
    Vec<TopicDataTuple>,
);

impl Into<SystemState> for SystemStateTuple {
    fn into(self) -> SystemState {
        SystemState {
            publishers: self.0.into_iter().map(Into::into).collect(),
            subscribers: self.1.into_iter().map(Into::into).collect(),
            services: self.2.into_iter().map(Into::into).collect(),
        }
    }
}

impl Into<TopicData> for TopicDataTuple {
    fn into(self) -> TopicData {
        TopicData {
            name: self.0,
            connections: self.1,
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct TopicTuple(String, String);

impl Into<Topic> for TopicTuple {
    fn into(self) -> Topic {
        Topic {
            name: self.0,
            datatype: self.1,
        }
    }
}

pub struct Topic {
    pub name: String,
    pub datatype: String,
}
<commit_msg>Fix typo for unregistering subscriber<commit_after>use serde::{Deserialize, Serialize};
use super::super::rosxmlrpc::{self, Response as Result};
use xml_rpc;

pub struct Master {
    client: rosxmlrpc::Client,
    client_id: String,
    caller_api: String,
}

macro_rules! request {
    ($s:expr; $name:ident; $($item:expr),*)=> ({
        $s.client.request(stringify!($name),&(&$s.client_id,
            $(
                $item,
            )*
            ))
    })
}

macro_rules! request_tree {
    ($s:expr; $name:ident; $($item:expr),*)=> ({
        $s.client.request_tree(stringify!($name),&(&$s.client_id,
            $(
                $item,
            )*
            ))
    })
}

impl Master {
    pub fn new(master_uri: &str, client_id: &str, caller_api: &str) -> Master {
        Master {
            client: rosxmlrpc::Client::new(master_uri).unwrap(),
            client_id: client_id.to_owned(),
            caller_api: caller_api.to_owned(),
        }
    }

    pub fn register_service(&self, service: &str, service_api: &str) -> Result<i32> {
        request!(self; registerService; service, service_api, &self.caller_api)
    }

    pub fn unregister_service(&self, service: &str, service_api: &str) -> Result<i32> {
        request!(self; unregisterService; service, service_api)
    }

    pub fn register_subscriber(&self, topic: &str, topic_type: &str) -> Result<Vec<String>> {
        request!(self; registerSubscriber; topic, topic_type, &self.caller_api)
    }

    pub fn unregister_subscriber(&self, topic: &str) -> Result<i32> {
        request!(self; unregisterSubscriber; topic, &self.caller_api)
    }

    pub fn register_publisher(&self, topic: &str, topic_type: &str) -> Result<Vec<String>> {
        request!(self; registerPublisher; topic, topic_type, &self.caller_api)
    }

    pub fn unregister_publisher(&self, topic: &str) -> Result<i32> {
        request!(self; unregisterPublisher; topic, &self.caller_api)
    }

    #[allow(dead_code)]
    pub fn lookup_node(&self, node_name: &str) -> Result<String> {
        request!(self; lookupNode; node_name)
    }

    #[allow(dead_code)]
    pub fn get_published_topics(&self, subgraph: &str) -> Result<Vec<(String, String)>> {
        request!(self; getPublishedTopics; subgraph)
    }

    pub fn get_topic_types(&self) -> Result<Vec<TopicTuple>> {
        request!(self; getTopicTypes;)
    }

    pub fn get_system_state(&self) -> Result<SystemStateTuple> {
        request!(self; getSystemState;)
    }

    #[allow(dead_code)]
    pub fn get_uri(&self) -> Result<String> {
        request!(self; getUri;)
    }

    pub fn lookup_service(&self, service: &str) -> Result<String> {
        request!(self; lookupService; service)
    }

    pub fn delete_param(&self, key: &str) -> Result<i32> {
        request!(self; deleteParam; key)
    }

    pub fn set_param<T: Serialize>(&self, key: &str, value: &T) -> Result<i32> {
        request!(self; setParam; key, value)
    }

    pub fn set_param_any(&self, key: &str, value: xml_rpc::Value) -> Result<()> {
        self.client
            .request_tree_with_tree(
                "setParam",
                vec![
                    xml_rpc::Value::String(self.client_id.clone()),
                    xml_rpc::Value::String(key.into()),
                    value,
                ],
            )
            .and(Ok(()))
    }

    pub fn get_param<'a, T: Deserialize<'a>>(&self, key: &str) -> Result<T> {
        request!(self; getParam; key)
    }

    pub fn get_param_any(&self, key: &str) -> Result<xml_rpc::Value> {
        request_tree!(self; getParam; key)
    }

    pub fn search_param(&self, key: &str) -> Result<String> {
        request!(self; searchParam; key)
    }

    #[allow(dead_code)]
    pub fn subscribe_param<'a, T: Deserialize<'a>>(&self, key: &str) -> Result<T> {
        request!(self; subscribeParam; &self.caller_api, key)
    }

    #[allow(dead_code)]
    pub fn subscribe_param_any(&self, key: &str) -> Result<xml_rpc::Value> {
        request_tree!(self; subscribeParam; &self.caller_api, key)
    }

    #[allow(dead_code)]
    pub fn unsubscribe_param(&self, key: &str) -> Result<i32> {
        request!(self; unsubscribeParam; &self.caller_api, key)
    }

    pub fn has_param(&self, key: &str) -> Result<bool> {
        request!(self; hasParam; key)
    }

    pub fn get_param_names(&self) -> Result<Vec<String>> {
        request!(self; getParamNames;)
    }
}

#[derive(Debug)]
pub struct TopicData {
    pub name: String,
    pub connections: Vec<String>,
}

#[derive(Debug)]
pub struct SystemState {
    pub publishers: Vec<TopicData>,
    pub subscribers: Vec<TopicData>,
    pub services: Vec<TopicData>,
}

#[derive(Debug, Deserialize)]
pub struct TopicDataTuple(String, Vec<String>);
#[derive(Debug, Deserialize)]
pub struct SystemStateTuple(
    Vec<TopicDataTuple>,
    Vec<TopicDataTuple>,
    Vec<TopicDataTuple>,
);

impl Into<SystemState> for SystemStateTuple {
    fn into(self) -> SystemState {
        SystemState {
            publishers: self.0.into_iter().map(Into::into).collect(),
            subscribers: self.1.into_iter().map(Into::into).collect(),
            services: self.2.into_iter().map(Into::into).collect(),
        }
    }
}

impl Into<TopicData> for TopicDataTuple {
    fn into(self) -> TopicData {
        TopicData {
            name: self.0,
            connections: self.1,
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct TopicTuple(String, String);

impl Into<Topic> for TopicTuple {
    fn into(self) -> Topic {
        Topic {
            name: self.0,
            datatype: self.1,
        }
    }
}

pub struct Topic {
    pub name: String,
    pub datatype: String,
}
<|endoftext|>


<commit_before>use rustc::hir::*;
use rustc::hir::map::Node::NodeItem;
use rustc::lint::*;
use rustc::ty::TypeVariants;
use syntax::ast::LitKind;
use utils::paths;
use utils::{is_expn_of, match_def_path, match_path, match_type, resolve_node, span_lint, walk_ptrs_ty};

/// **What it does:** Checks for the use of `format!("string literal with no
/// argument")` and `format!("{}", foo)` where `foo` is a string.
///
/// **Why is this bad?** There is no point of doing that. `format!("too")` can
/// be replaced by `"foo".to_owned()` if you really need a `String`. The even
/// worse `&format!("foo")` is often encountered in the wild. `format!("{}",
/// foo)` can be replaced by `foo.clone()` if `foo: String` or `foo.to_owned()`
/// is `foo: &str`.
///
/// **Known problems:** None.
///
/// **Examples:**
/// ```rust
/// format!("foo")
/// format!("{}", foo)
/// ```
declare_lint! {
    pub USELESS_FORMAT,
    Warn,
    "useless use of `format!`"
}

#[derive(Copy, Clone, Debug)]
pub struct Pass;

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array![USELESS_FORMAT]
    }
}

impl LateLintPass for Pass {
    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
        if let Some(span) = is_expn_of(cx, expr.span, "format") {
            match expr.node {
                // `format!("{}", foo)` expansion
                ExprCall(ref fun, ref args) => {
                    if_let_chain!{[
                        let ExprPath(..) = fun.node,
                        args.len() == 2,
                        let Some(fun) = resolve_node(cx, fun.id),
                        match_def_path(cx, fun.def_id(), &paths::FMT_ARGUMENTS_NEWV1),
                        // ensure the format string is `"{..}"` with only one argument and no text
                        check_static_str(cx, &args[0]),
                        // ensure the format argument is `{}` ie. Display with no fancy option
                        check_arg_is_display(cx, &args[1])
                    ], {
                        span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`");
                    }}
                }
                // `format!("foo")` expansion contains `match () { () => [], }`
                ExprMatch(ref matchee, _, _) => {
                    if let ExprTup(ref tup) = matchee.node {
                        if tup.is_empty() {
                            span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`");
                        }
                    }
                }
                _ => (),
            }
        }
    }
}

/// Returns the slice of format string parts in an `Arguments::new_v1` call.
/// Public because it's shared with a lint in print.rs.
pub fn get_argument_fmtstr_parts<'a, 'b>(cx: &LateContext<'a, 'b>, expr: &'a Expr)
                                         -> Option<Vec<&'a str>> {
    if_let_chain! {[
        let ExprBlock(ref block) = expr.node,
        block.stmts.len() == 1,
        let StmtDecl(ref decl, _) = block.stmts[0].node,
        let DeclItem(ref decl) = decl.node,
        let Some(NodeItem(decl)) = cx.tcx.map.find(decl.id),
        decl.name.as_str() == "__STATIC_FMTSTR",
        let ItemStatic(_, _, ref expr) = decl.node,
        let ExprAddrOf(_, ref expr) = expr.node, // &["…", "…", …]
        let ExprArray(ref exprs) = expr.node,
    ], {
        let mut result = Vec::new();
        for expr in exprs {
            if let ExprLit(ref lit) = expr.node {
                if let LitKind::Str(ref lit, _) = lit.node {
                    result.push(&**lit);
                }
            }
        }
        return Some(result);
    }}
    None
}

/// Checks if the expressions matches
/// ```rust
/// { static __STATIC_FMTSTR: … = &["…", "…", …]; __STATIC_FMTSTR }
/// ```
fn check_static_str(cx: &LateContext, expr: &Expr) -> bool {
    if let Some(expr) = get_argument_fmtstr_parts(cx, expr) {
        expr.len() == 1 && expr[0].is_empty()
    } else {
        false
    }
}

/// Checks if the expressions matches
/// ```rust
/// &match (&42,) {
///     (__arg0,) => [::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Display::fmt)],
/// })
/// ```
fn check_arg_is_display(cx: &LateContext, expr: &Expr) -> bool {
    if_let_chain! {[
        let ExprAddrOf(_, ref expr) = expr.node,
        let ExprMatch(_, ref arms, _) = expr.node,
        arms.len() == 1,
        arms[0].pats.len() == 1,
        let PatKind::Tuple(ref pat, None) = arms[0].pats[0].node,
        pat.len() == 1,
        let ExprArray(ref exprs) = arms[0].body.node,
        exprs.len() == 1,
        let ExprCall(_, ref args) = exprs[0].node,
        args.len() == 2,
        let ExprPath(None, _) = args[1].node,
        let Some(fun) = resolve_node(cx, args[1].id),
        match_def_path(cx, fun.def_id(), &paths::DISPLAY_FMT_METHOD),
    ], {
        let ty = walk_ptrs_ty(cx.tcx.pat_ty(&pat[0]));

        return ty.sty == TypeVariants::TyStr || match_type(cx, ty, &paths::STRING);
    }}

    false
}
<commit_msg>Fix unused import warning<commit_after>use rustc::hir::*;
use rustc::hir::map::Node::NodeItem;
use rustc::lint::*;
use rustc::ty::TypeVariants;
use syntax::ast::LitKind;
use utils::paths;
use utils::{is_expn_of, match_def_path, match_type, resolve_node, span_lint, walk_ptrs_ty};

/// **What it does:** Checks for the use of `format!("string literal with no
/// argument")` and `format!("{}", foo)` where `foo` is a string.
///
/// **Why is this bad?** There is no point of doing that. `format!("too")` can
/// be replaced by `"foo".to_owned()` if you really need a `String`. The even
/// worse `&format!("foo")` is often encountered in the wild. `format!("{}",
/// foo)` can be replaced by `foo.clone()` if `foo: String` or `foo.to_owned()`
/// is `foo: &str`.
///
/// **Known problems:** None.
///
/// **Examples:**
/// ```rust
/// format!("foo")
/// format!("{}", foo)
/// ```
declare_lint! {
    pub USELESS_FORMAT,
    Warn,
    "useless use of `format!`"
}

#[derive(Copy, Clone, Debug)]
pub struct Pass;

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array![USELESS_FORMAT]
    }
}

impl LateLintPass for Pass {
    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
        if let Some(span) = is_expn_of(cx, expr.span, "format") {
            match expr.node {
                // `format!("{}", foo)` expansion
                ExprCall(ref fun, ref args) => {
                    if_let_chain!{[
                        let ExprPath(..) = fun.node,
                        args.len() == 2,
                        let Some(fun) = resolve_node(cx, fun.id),
                        match_def_path(cx, fun.def_id(), &paths::FMT_ARGUMENTS_NEWV1),
                        // ensure the format string is `"{..}"` with only one argument and no text
                        check_static_str(cx, &args[0]),
                        // ensure the format argument is `{}` ie. Display with no fancy option
                        check_arg_is_display(cx, &args[1])
                    ], {
                        span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`");
                    }}
                }
                // `format!("foo")` expansion contains `match () { () => [], }`
                ExprMatch(ref matchee, _, _) => {
                    if let ExprTup(ref tup) = matchee.node {
                        if tup.is_empty() {
                            span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`");
                        }
                    }
                }
                _ => (),
            }
        }
    }
}

/// Returns the slice of format string parts in an `Arguments::new_v1` call.
/// Public because it's shared with a lint in print.rs.
pub fn get_argument_fmtstr_parts<'a, 'b>(cx: &LateContext<'a, 'b>, expr: &'a Expr)
                                         -> Option<Vec<&'a str>> {
    if_let_chain! {[
        let ExprBlock(ref block) = expr.node,
        block.stmts.len() == 1,
        let StmtDecl(ref decl, _) = block.stmts[0].node,
        let DeclItem(ref decl) = decl.node,
        let Some(NodeItem(decl)) = cx.tcx.map.find(decl.id),
        decl.name.as_str() == "__STATIC_FMTSTR",
        let ItemStatic(_, _, ref expr) = decl.node,
        let ExprAddrOf(_, ref expr) = expr.node, // &["…", "…", …]
        let ExprArray(ref exprs) = expr.node,
    ], {
        let mut result = Vec::new();
        for expr in exprs {
            if let ExprLit(ref lit) = expr.node {
                if let LitKind::Str(ref lit, _) = lit.node {
                    result.push(&**lit);
                }
            }
        }
        return Some(result);
    }}
    None
}

/// Checks if the expressions matches
/// ```rust
/// { static __STATIC_FMTSTR: … = &["…", "…", …]; __STATIC_FMTSTR }
/// ```
fn check_static_str(cx: &LateContext, expr: &Expr) -> bool {
    if let Some(expr) = get_argument_fmtstr_parts(cx, expr) {
        expr.len() == 1 && expr[0].is_empty()
    } else {
        false
    }
}

/// Checks if the expressions matches
/// ```rust
/// &match (&42,) {
///     (__arg0,) => [::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Display::fmt)],
/// })
/// ```
fn check_arg_is_display(cx: &LateContext, expr: &Expr) -> bool {
    if_let_chain! {[
        let ExprAddrOf(_, ref expr) = expr.node,
        let ExprMatch(_, ref arms, _) = expr.node,
        arms.len() == 1,
        arms[0].pats.len() == 1,
        let PatKind::Tuple(ref pat, None) = arms[0].pats[0].node,
        pat.len() == 1,
        let ExprArray(ref exprs) = arms[0].body.node,
        exprs.len() == 1,
        let ExprCall(_, ref args) = exprs[0].node,
        args.len() == 2,
        let ExprPath(None, _) = args[1].node,
        let Some(fun) = resolve_node(cx, args[1].id),
        match_def_path(cx, fun.def_id(), &paths::DISPLAY_FMT_METHOD),
    ], {
        let ty = walk_ptrs_ty(cx.tcx.pat_ty(&pat[0]));

        return ty.sty == TypeVariants::TyStr || match_type(cx, ty, &paths::STRING);
    }}

    false
}
<|endoftext|>


<commit_before>//! Context management

use alloc::arc::Arc;
use collections::{BTreeMap, Vec};
use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};

/// File operations
pub mod file;

/// Maximum context files
pub const CONTEXT_MAX_FILES: usize = 65536;

/// Context ID
pub type ContextId = u16;

/// Context list type
pub type ContextList = BTreeMap<ContextId, Arc<RwLock<Context>>>;

/// Contexts list
static CONTEXTS: Once<RwLock<ContextList>> = Once::new();

/// Initialize contexts, called if needed
fn init_contexts() -> RwLock<ContextList> {
    let mut map: ContextList = BTreeMap::new();
    map.insert(0, Arc::new(RwLock::new(Context::new())));
    RwLock::new(map)
}

/// Get the global schemes list, const
pub fn contexts() -> RwLockReadGuard<'static, ContextList> {
    CONTEXTS.call_once(init_contexts).read()
}

/// Get the global schemes list, mutable
pub fn contexts_mut() -> RwLockWriteGuard<'static, ContextList> {
    CONTEXTS.call_once(init_contexts).write()
}

/// A context, which identifies either a process or a thread
#[derive(Clone, Debug)]
pub struct Context {
    /// The open files in the scheme
    pub files: Vec<Option<file::File>>
}

impl Context {
    pub fn new() -> Context {
        Context {
            files: Vec::new()
        }
    }

    /// Add a file to the lowest available slot.
    /// Return the file descriptor number or None if no slot was found
    pub fn add_file(&mut self, file: file::File) -> Option<usize> {
        for (i, mut file_option) in self.files.iter_mut().enumerate() {
            if file_option.is_none() {
                *file_option = Some(file);
                return Some(i);
            }
        }
        let len = self.files.len();
        if len < CONTEXT_MAX_FILES {
            self.files.push(Some(file));
            Some(len)
        } else {
            None
        }
    }
}
<commit_msg>Remove clone from context<commit_after>//! Context management

use alloc::arc::Arc;
use collections::{BTreeMap, Vec};
use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};

/// File operations
pub mod file;

/// Maximum context files
pub const CONTEXT_MAX_FILES: usize = 65536;

/// Context ID
pub type ContextId = u16;

/// Context list type
pub type ContextList = BTreeMap<ContextId, Arc<RwLock<Context>>>;

/// Contexts list
static CONTEXTS: Once<RwLock<ContextList>> = Once::new();

/// Initialize contexts, called if needed
fn init_contexts() -> RwLock<ContextList> {
    let mut map: ContextList = BTreeMap::new();
    map.insert(0, Arc::new(RwLock::new(Context::new())));
    RwLock::new(map)
}

/// Get the global schemes list, const
pub fn contexts() -> RwLockReadGuard<'static, ContextList> {
    CONTEXTS.call_once(init_contexts).read()
}

/// Get the global schemes list, mutable
pub fn contexts_mut() -> RwLockWriteGuard<'static, ContextList> {
    CONTEXTS.call_once(init_contexts).write()
}

/// A context, which identifies either a process or a thread
#[derive(Debug)]
pub struct Context {
    /// The open files in the scheme
    pub files: Vec<Option<file::File>>
}

impl Context {
    pub fn new() -> Context {
        Context {
            files: Vec::new()
        }
    }

    /// Add a file to the lowest available slot.
    /// Return the file descriptor number or None if no slot was found
    pub fn add_file(&mut self, file: file::File) -> Option<usize> {
        for (i, mut file_option) in self.files.iter_mut().enumerate() {
            if file_option.is_none() {
                *file_option = Some(file);
                return Some(i);
            }
        }
        let len = self.files.len();
        if len < CONTEXT_MAX_FILES {
            self.files.push(Some(file));
            Some(len)
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>// 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 https://mozilla.org/MPL/2.0/.

use common::is_whitespace;

use regex::Regex;
use std::borrow::Cow;

/// Removes unnecessary whitespaces from a String.
///
/// # Example
///
/// ```
/// use crowbook_text_processing::clean::remove_whitespaces;
/// let s = remove_whitespaces("  A  string   with   more   whitespaces  than  needed   ");
/// assert_eq!(&s, " A string with more whitespaces than needed ");
/// ```
pub fn remove_whitespaces<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    lazy_static! {
        static ref REGEX: Regex = Regex::new(r"[  \x{202F}\x{2002}]{2,}?").unwrap();
    }
    let input = input.into();
    let first = REGEX.find(&input);
    if let Some((first, _)) = first {
        let mut new_s = String::with_capacity(input.len());
        new_s.push_str(&input[0..first]);
        let mut previous_space = false;
        for c in input[first..].chars() {
            if is_whitespace(c) {
                if previous_space {
                    // previous char already a space, don't copy it
                } else {
                    new_s.push(c);
                    previous_space = true;
                }
            } else {
                previous_space = false;
                new_s.push(c);
            }
        }
        Cow::Owned(new_s)
    } else {
        input
    }
}

/// Replace quotes with more typographic variants
///
/// # Example
///
/// ```
/// use crowbook_text_processing::typographic_quotes;
/// let s = typographic_quotes("\"foo\"");
/// assert_eq!(&s, "“foo”");
/// let s = typographic_quotes("'foo'");
/// assert_eq!(&s, "‘foo’");
/// ```
pub fn typographic_quotes<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    lazy_static! {
        static ref REGEX: Regex = Regex::new("[\"\']").unwrap();
    }
    let input = input.into();
    let first = REGEX.find(&input);
    if let Some((mut first, _)) = first {
        let mut new_s = String::with_capacity(input.len());
        if first > 0 {
            // Move one step backward since we might need to know if previous char was
            // a letter or not
            first -= 1;
        }
        new_s.push_str(&input[0..first]);
        let chars = input[first..].chars().collect::<Vec<_>>();
        for i in 0..chars.len() {
            let c = chars[i];
            match c {
                '"' => {
                    if i > 0 && chars[i - 1].is_alphabetic() {
                        new_s.push('”');
                    } else if i < chars.len() - 1 && chars[i + 1].is_alphabetic() {
                        new_s.push('“');
                    } else {
                        new_s.push('"');
                    }
                },
                '\'' => {
                    if i > 0 && chars[i - 1].is_alphabetic() {
                        new_s.push('’');
                    } else if i < chars.len() - 1 && chars[i + 1].is_alphabetic() {
                        new_s.push('‘');
                    } else {
                        new_s.push('\'');
                    }
                },
                _ => new_s.push(c)
            }
        }
        Cow::Owned(new_s)
    } else {
        input
    }
}

#[test]
fn remove_whitespaces_1() {
    let s = "   Remove    supplementary   spaces    but    don't    trim     either   ";
    let res = remove_whitespaces(s);
    assert_eq!(&res, " Remove supplementary spaces but don't trim either ");
}

#[test]
fn typographic_quotes_1() {
    let s = "Some string without ' typographic ' quotes";
    let res = typographic_quotes(s);
    assert_eq!(&res, s);
}

#[test]
fn typographic_quotes_2() {
    let s = typographic_quotes("\"foo\"");
    assert_eq!(&s, "“foo”");
    let s = typographic_quotes("'foo'");
    assert_eq!(&s, "‘foo’");
}

#[test]
fn typographic_quotes_3() {
    let s = typographic_quotes("\'mam, how are you?");
    assert_eq!(&s, "’mam, how are you?");
}

#[test]
fn typographic_quotes_4() {
    let s = typographic_quotes("some char: 'c', '4', '&'");
    assert_eq!(&s, "some char: ‘c’, ‘4’, ‘&’");
}
<commit_msg>Update typographic_quotes algorithm<commit_after>// 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 https://mozilla.org/MPL/2.0/.

use common::is_whitespace;

use regex::Regex;
use std::borrow::Cow;

/// Removes unnecessary whitespaces from a String.
///
/// # Example
///
/// ```
/// use crowbook_text_processing::clean::remove_whitespaces;
/// let s = remove_whitespaces("  A  string   with   more   whitespaces  than  needed   ");
/// assert_eq!(&s, " A string with more whitespaces than needed ");
/// ```
pub fn remove_whitespaces<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    lazy_static! {
        static ref REGEX: Regex = Regex::new(r"[  \x{202F}\x{2002}]{2,}?").unwrap();
    }
    let input = input.into();
    let first = REGEX.find(&input);
    if let Some((first, _)) = first {
        let mut new_s = String::with_capacity(input.len());
        new_s.push_str(&input[0..first]);
        let mut previous_space = false;
        for c in input[first..].chars() {
            if is_whitespace(c) {
                if previous_space {
                    // previous char already a space, don't copy it
                } else {
                    new_s.push(c);
                    previous_space = true;
                }
            } else {
                previous_space = false;
                new_s.push(c);
            }
        }
        Cow::Owned(new_s)
    } else {
        input
    }
}

/// Replace quotes with more typographic variants
///
/// While it should work pretty well for double quotes (`"`), the rules for single
/// quote (`'`) are more ambiguous, as it can be a quote, or an apostrophe and it's not
/// that easy to get right.
///
/// # Example
///
/// ```
/// use crowbook_text_processing::typographic_quotes;
/// let s = typographic_quotes("\"foo\"");
/// assert_eq!(&s, "“foo”");
/// let s = typographic_quotes("'foo'");
/// assert_eq!(&s, "‘foo’");
/// ```
pub fn typographic_quotes<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    /// Custom whitespace-detection function, including `,`, `;`, `.`, `!`, `?`, and `:`
    fn is_whitespace(c: char) -> bool {
        match c {
            ',' | '.' | ';' | '!' | '?' | ':' => true,
            _ => c.is_whitespace()
        }
    }

    lazy_static! {
        static ref REGEX: Regex = Regex::new("[\"\']").unwrap();
    }
    let input = input.into();
    let first = REGEX.find(&input);
    if let Some((mut first, _)) = first {
        let mut new_s = String::with_capacity(input.len());
        if first > 0 {
            // Move one step backward since we might need to know if previous char was
            // a letter or not
            first -= 1;
        }
        new_s.push_str(&input[0..first]);
        let chars = input[first..].chars().collect::<Vec<_>>();
        let mut has_opened_quote = false;
        for i in 0..chars.len() {
            let c = chars[i];
            match c {
                '"' => {
                    if i > 0 && !is_whitespace(chars[i - 1]) {
                        new_s.push('”');
                    } else if i < chars.len() - 1 && !is_whitespace(chars[i + 1]) {
                        new_s.push('“');
                    } else {
                        new_s.push('"');
                    }
                },
                '\'' => {
                    let prev = if i > 0 {
                        Some(!is_whitespace(chars[i - 1]))
                    } else {
                        None
                    };
                    let next = if i < chars.len() - 1 {
                        Some(!is_whitespace(chars[i + 1]))
                    } else {
                        None
                    };
                    let replacement = match (prev, next) {
                        // Elision, it's closing
                        (Some(true), Some(true)) => '’',

                        // Beginning of word, it's opening (not always though)
                        (Some(false), Some(true))
                            | (None, Some(true))
                            => {
                                let mut is_next_closing = false;
                                for j in (i + 1)..chars.len() {
                                    if chars[j] == '\'' {
                                        println!("match at {}", j);
                                        if chars[j-1].is_whitespace() {
                                            println!("prev is whitespace, not closing quote");
                                            continue;
                                        } else {
                                            if j >= chars.len() - 1
                                                || is_whitespace(chars[j+1])
                                                || chars[j+1] == '"' {
                                                    is_next_closing = true;
                                                    break;
                                                }
                                            else {
                                                println!("j: {}, len: {}", j, chars.len());
                                            }
                                        }
                                    }
                                }
                                println!("is_next_closing: {}", is_next_closing);
                                if is_next_closing && !has_opened_quote {
                                    has_opened_quote = true;
                                    '‘'
                                } else {
                                    '’'
                                }
                            }

                        // Apostrophe at end of word, it's closing
                        (Some(true), Some(false))
                            | (Some(true), None)
                            => {
                                has_opened_quote = false;
                                '’'
                            },

                        _ => '\'',
                    };
                    new_s.push(replacement);
                    // if i > 0 && !chars[i - 1].is_whitespace() {
                    //     new_s.push('’');
                    // } else if i < chars.len() - 1 && !chars[i + 1].is_whitespace() {
                    //     new_s.push('‘');
                    // } else {
                    //     new_s.push('\'');
                    // }
                },
                _ => new_s.push(c)
            }
        }
        Cow::Owned(new_s)
    } else {
        input
    }
}

#[test]
fn remove_whitespaces_1() {
    let s = "   Remove    supplementary   spaces    but    don't    trim     either   ";
    let res = remove_whitespaces(s);
    assert_eq!(&res, " Remove supplementary spaces but don't trim either ");
}

#[test]
fn typographic_quotes_1() {
    let s = "Some string without ' typographic ' quotes";
    let res = typographic_quotes(s);
    assert_eq!(&res, s);
}

#[test]
fn typographic_quotes_2() {
    let s = typographic_quotes("\"foo\"");
    assert_eq!(&s, "“foo”");
    let s = typographic_quotes("'foo'");
    assert_eq!(&s, "‘foo’");
}

#[test]
fn typographic_quotes_3() {
    let s = typographic_quotes("\'mam, how are you?");
    assert_eq!(&s, "’mam, how are you?");
}

#[test]
fn typographic_quotes_4() {
    let s = typographic_quotes("some char: 'c', '4', '&'");
    assert_eq!(&s, "some char: ‘c’, ‘4’, ‘&’");
}

#[test]
fn typographic_quotes_5() {
    let s = typographic_quotes("It's a good day to say 'hi'");
    assert_eq!(&s, "It’s a good day to say ‘hi’");
}

#[test]
fn typographic_quotes_6() {
    let s = typographic_quotes("The '60s were nice, weren't they?");
    assert_eq!(&s, "The ’60s were nice, weren’t they?");
}

#[test]
fn typographic_quotes_7() {
    let s = typographic_quotes("Plurals' possessive");
    assert_eq!(&s, "Plurals’ possessive");
}

#[test]
fn typographic_quotes_8() {
    let s = typographic_quotes("\"I like 'That '70s show'\", she said");
    assert_eq!(&s, "“I like ‘That ’70s show’”, she said");
}
<|endoftext|>