<commit_before>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use std::cmp;

use model::constants::*;
use model::{BitBoard, Color, ColorMap, FieldCoord, HexCoord, Move};

#[derive(Clone, Copy)]
pub struct Board {
    /*
    Board layout:
    The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
    up and to the right, and the y-axis goes up and down.
    See http://www.redblobgames.com/grids/hexagons/#coordinates-axial for more info.
                                             ____
                                            /    \
                                       ____/  +y  \____
                                      /    \      /    \
                                     /      \____/  +x  \
                                     \      /    \      /
                                      \____/      \____/
                                      /    \      /    \
                                     /  -x  \____/      \
                                     \      /    \      /
                                      \____/  -y  \____/
                                           \      /
                                            \____/

    Field layout:
    Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
                                          _________
                                         / \     / \
                                        /   \ 0 /   \
                                       /  5  \ /  1  \
                                      (-------*-------)
                                       \  4  / \  2  /
                                        \   / 3 \   /
                                         \_/_____\_/
    u64 Bitboard layout:

     MSB                                                                              LSB

     7 bits                            57 bits (19 groups of 3)
     +-----+  +-------------------------------------------------------------------------+
    [0000000][000 111 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 010 000]
     Unused   -+- -+-                 ||+-- Field 0           ||+-- Field 1       |+-- Piece on field
               |   +-- Extant hex     |+--- Field 2           |+--- Field 3       +--- No piece on field
               +------ Removed hex    +---- Field 4           +---- Field 5            (Field bitboards)
                      (Hex bitboard)  (Black field bitboard)  (White field bitboard)
    */
    fields: ColorMap<BitBoard>,
    hexes: BitBoard,
    extant_hex_count: u8,
    turn: Color,
    vitals: ColorMap<PlayerVitals>,
    outcome: Outcome,
}

/// A struct tracking a player's piece and captured hex count. So named because these two numbers are
/// essential to a player's survival (i.e. vital signs).
#[derive(Clone, Copy)]
struct PlayerVitals {
    pieces: u8,
    hexes: u8,
}

impl PlayerVitals {
    fn new() -> Self {
        Self {
            pieces: 18,
            hexes: 0,
        }
    }
}

/// The outcome of a game. Wins or draws caused by a resignation or an offered and accepted draw are
/// not differentiated from wins and draws by capturing all of an opponent's pieces, running out of
/// moves, being unable to capture any of the opponent's pieces, or reaching threefold repetition.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Outcome {
    InProgress,
    Win(Color),
    Draw,
}

lazy_static! {
    static ref EDGE_NEIGHBORS: NeighborLookup = NeighborLookup::new_edge();
    static ref VERTEX_NEIGHBORS: NeighborLookup = NeighborLookup::new_vertex();
    static ref HEX_FIELD_NEIGHBORS: NeighborLookup = NeighborLookup::new_hex_field();
    static ref HEX_MASK: [BitBoard; 19] = generate_hex_mask();
    static ref REMOVABLE_HEX_COMBS: [BitBoard; 342] = generate_removable_hex_combs();
}

// Public methods
impl Board {
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Self {
        Self {
            fields: generate_laurentius(),
            hexes: HEX_STARTING_POSITION,
            extant_hex_count: 19,
            turn: Color::White,
            vitals: ColorMap::new(PlayerVitals::new(), PlayerVitals::new()),
            outcome: Outcome::InProgress,
        }
    }
    pub fn apply_move(&mut self, mv: &Move) {
        assert!(self.can_apply_move(mv), "Cannot apply {:?}", mv);
        match *mv {
            Move::Move(from, to, color) => {
                self.toggle_field(from, color);
                self.toggle_field(to, color);

                let (capture_count, mut fields_to_check) =
                    self.check_hexes(from.trailing_zeros() as usize / 3);
                fields_to_check |= EDGE_NEIGHBORS.bb_get(to, color);
                self.check_captures(fields_to_check);

                self.vitals.get_mut(self.turn).hexes += capture_count;
            }
            Move::Exchange(bb, color) => {
                self.remove_piece(bb, color);
                self.vitals.get_mut(self.turn).hexes -= 2;

                // Players don't collect hexes removed due to an exchange
                let (_, fields_to_check) = self.check_hexes(bb.trailing_zeros() as usize / 3);
                self.check_captures(fields_to_check);
            }
        }
        self.turn = self.turn.switch();
        self.update_outcome();
    }
    pub fn can_apply_move(&self, mv: &Move) -> bool {
        match *mv {
            Move::Move(from, to, color) => {
                let vertex_neighbors = VERTEX_NEIGHBORS.bb_get(from, color);
                color == self.turn && (to & vertex_neighbors != 0)
                    && self.is_piece_on_bitboard(from, color)
                    && !self.is_piece_on_bitboard(to, color)
            }
            Move::Exchange(bb, color) => {
                self.can_exchange() && color != self.turn && self.is_piece_on_bitboard(bb, color)
            }
        }
    }
    pub fn generate_moves(&self) -> Vec<Move> {
        let turn = self.turn;
        // A player with no pieces cannot make any moves, including exchange moves
        if self.pieces(turn) == 0 {
            return vec![];
        }

        let can_exchange = self.can_exchange();
        let mut moves = Vec::with_capacity(
            // 3 moves per piece is an untested guess
            self.pieces(turn) as usize * 3 + if can_exchange {
                self.pieces(turn.switch()) as usize
            } else {
                0
            },
        );

        let fields = *self.fields.get_ref(turn);
        for origin in BitBoardIter::new(fields) {
            let mut vertex_neighbors = VERTEX_NEIGHBORS.bb_get(origin, turn);
            vertex_neighbors &= !fields & self.hexes;

            for dest in BitBoardIter::new(vertex_neighbors) {
                moves.push(Move::Move(origin, dest, turn));
            }
        }

        if can_exchange {
            let opp_color = turn.switch();
            for exchanged in BitBoardIter::new(*self.fields.get_ref(opp_color)) {
                moves.push(Move::Exchange(exchanged, opp_color));
            }
        }
        moves
    }
    pub fn available_moves_for_piece(&self, field: &FieldCoord) -> Vec<FieldCoord> {
        if self.is_piece_on_field(field) {
            let color = field.color();
            let vertex_neighbors = self.hexes & VERTEX_NEIGHBORS.bb_get(field.to_bitboard(), color);
            let mut moves = Vec::with_capacity(3);

            for dest in BitBoardIter::new(vertex_neighbors) {
                moves.push(FieldCoord::from_bitboard(dest, color));
            }
            moves
        } else {
            vec![]
        }
    }
    pub fn can_exchange(&self) -> bool {
        self.vitals.get_ref(self.turn).hexes >= 2
    }
    pub fn is_piece_on_field(&self, coord: &FieldCoord) -> bool {
        self.is_piece_on_bitboard(coord.to_bitboard(), coord.color())
    }
    pub fn is_piece_on_bitboard(&self, bb: BitBoard, color: Color) -> bool {
        assert!(
            bb & self.hexes != 0,
            "Cannot cannot check if piece is on {:?}. Hex was removed.",
            FieldCoord::from_bitboard(bb, color),
        );

        bb & self.fields.get_ref(color) != 0
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Return the coordinates of the hexes that have not been removed yet.
    pub fn extant_hexes(&self) -> Vec<HexCoord> {
        let mut coords = Vec::with_capacity(19);
        let try_coord = |coords: &mut Vec<HexCoord>, x, y| {
            if let Some(hex) = self.try_hex((x, y)) {
                coords.push(hex);
            }
        };
        try_coord(&mut coords, 1, 1);
        try_coord(&mut coords, -1, -1);

        for x in 0..3 {
            for y in -2..1 {
                try_coord(&mut coords, x, y);
                if x != y {
                    try_coord(&mut coords, -x, -y);
                }
            }
        }
        coords
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Returns true if a hex has not been removed yet.
    pub fn is_hex_extant(&self, index: usize) -> bool {
        self.hexes & HEX_MASK[index] != 0
    }
    pub fn resign(&mut self) {
        assert_eq!(self.outcome, Outcome::InProgress);
        self.outcome = Outcome::Win(self.turn.switch());
    }
    pub fn turn(&self) -> Color {
        self.turn
    }
    pub fn pieces(&self, color: Color) -> u8 {
        self.vitals.get_ref(color).pieces
    }
    pub fn hexes(&self, color: Color) -> u8 {
        self.vitals.get_ref(color).hexes
    }
    pub fn outcome(&self) -> Outcome {
        self.outcome
    }
}

impl Board {
    // TODO: check for threefold repetition
    fn update_outcome(&mut self) {
        if self.pieces(self.turn) == 0 {
            self.outcome = Outcome::Win(self.turn.switch());
        } else if !self.can_move() {
            self.outcome = Outcome::Draw;
        } else {
            use model::Color::*;

            let wp = self.pieces(White);
            let bp = self.pieces(Black);
            let wh = self.hexes(White);
            let bh = self.hexes(Black);

            // If neither side can capture the other's pieces, the game is drawn
            if wp == 1 && bp == 1 && (self.extant_hex_count + cmp::max(wh, bh) - 1 < 2) {
                self.outcome = Outcome::Draw;
            }
        }
    }
    fn can_move(&self) -> bool {
        if self.can_exchange() {
            return true;
        }

        for bb in BitBoardIter::new(*self.fields.get_ref(self.turn)) {
            let vertex_neighbors = VERTEX_NEIGHBORS.bb_get(bb, self.turn);
            if vertex_neighbors & self.fields.get_ref(self.turn) != vertex_neighbors {
                return true;
            }
        }
        false
    }
}

// Field and piece methods
impl Board {
    fn toggle_field(&mut self, bb: BitBoard, color: Color) {
        assert!(
            bb & self.hexes != 0,
            "Cannot set field {:?}. Hex was removed.",
            FieldCoord::from_bitboard(bb, color),
        );

        *self.fields.get_mut(color) ^= bb;
    }
    fn remove_piece(&mut self, bb: BitBoard, color: Color) {
        assert!(
            self.is_piece_on_bitboard(bb, color),
            "There is no piece at {:?} to remove",
            FieldCoord::from_bitboard(bb, color)
        );
        self.toggle_field(bb, color);
        self.vitals.get_mut(color).pieces -= 1;
    }
    fn check_captures(&mut self, mut fields_to_check: BitBoard) {
        // fields_to_check must be a BitBoard for the opponent player (i.e. opposite of current turn)
        let us = self.turn;
        let them = us.switch();
        fields_to_check &= self.hexes & self.fields.get_ref(them);
        for bb in BitBoardIter::new(fields_to_check) {
            let neighbors = self.hexes & EDGE_NEIGHBORS.bb_get(bb, them);
            if !self.fields.get_ref(us) & neighbors == 0 {
                self.remove_piece(bb, them);
            }
        }
    }
}

// Hex methods
impl Board {
    /// A hex is removable (and must be removed) if it is empty and is "attached to the board by 3
    /// or less adjacent sides."
    fn is_hex_removable(&self, index: usize) -> bool {
        let is_hex_empty = (self.fields.white | self.fields.black) & HEX_MASK[index] == 0;
        if !self.is_hex_extant(index) || !is_hex_empty {
            return false;
        }

        // Combining colors here is okay because there won't be overlaps
        let hex = self.hexes
            & (HEX_FIELD_NEIGHBORS.index_get(index, Color::White)
                | HEX_FIELD_NEIGHBORS.index_get(index, Color::Black));
        // There are 18 combinations to check for each hex
        REMOVABLE_HEX_COMBS
            .iter()
            .skip(index * 18)
            .take(18)
            .any(|&comb| hex == comb)
    }
    fn remove_hex(&mut self, index: usize) -> bool {
        let removable = self.is_hex_removable(index);

        if removable {
            self.hexes &= !HEX_MASK[index];
            self.extant_hex_count -= 1;
        }
        removable
    }
    fn try_hex(&self, coord: (i8, i8)) -> Option<HexCoord> {
        if let Some(coord) = HexCoord::try_new(coord.0, coord.1) {
            if self.is_hex_extant(coord.to_index()) {
                return Some(coord);
            }
        }
        None
    }
    fn check_hexes(&mut self, index: usize) -> (u8, BitBoard) {
        let mut remove_count = 0;
        let mut fields = 0;

        if self.remove_hex(index) {
            remove_count += 1;

            let our_neighbors = self.hexes & HEX_FIELD_NEIGHBORS.index_get(index, self.turn);
            let their_neighbors =
                self.hexes & HEX_FIELD_NEIGHBORS.index_get(index, self.turn.switch());

            for neighbor in BitBoardIter::new(our_neighbors | their_neighbors) {
                let check_result = self.check_hexes(neighbor.trailing_zeros() as usize / 3);
                remove_count += check_result.0;
                fields |= check_result.1;
            }

            // Add in the opponent's neighbors, excluding those on hexes that have been removed
            fields |= their_neighbors;
            fields &= self.hexes;
        }
        (remove_count, fields)
    }
}
<commit_msg>Toggle both fields of a Move at once<commit_after>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use std::cmp;

use model::constants::*;
use model::{BitBoard, Color, ColorMap, FieldCoord, HexCoord, Move};

#[derive(Clone, Copy)]
pub struct Board {
    /*
    Board layout:
    The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
    up and to the right, and the y-axis goes up and down.
    See http://www.redblobgames.com/grids/hexagons/#coordinates-axial for more info.
                                             ____
                                            /    \
                                       ____/  +y  \____
                                      /    \      /    \
                                     /      \____/  +x  \
                                     \      /    \      /
                                      \____/      \____/
                                      /    \      /    \
                                     /  -x  \____/      \
                                     \      /    \      /
                                      \____/  -y  \____/
                                           \      /
                                            \____/

    Field layout:
    Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
                                          _________
                                         / \     / \
                                        /   \ 0 /   \
                                       /  5  \ /  1  \
                                      (-------*-------)
                                       \  4  / \  2  /
                                        \   / 3 \   /
                                         \_/_____\_/
    u64 Bitboard layout:

     MSB                                                                              LSB

     7 bits                            57 bits (19 groups of 3)
     +-----+  +-------------------------------------------------------------------------+
    [0000000][000 111 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 010 000]
     Unused   -+- -+-                 ||+-- Field 0           ||+-- Field 1       |+-- Piece on field
               |   +-- Extant hex     |+--- Field 2           |+--- Field 3       +--- No piece on field
               +------ Removed hex    +---- Field 4           +---- Field 5            (Field bitboards)
                      (Hex bitboard)  (Black field bitboard)  (White field bitboard)
    */
    fields: ColorMap<BitBoard>,
    hexes: BitBoard,
    extant_hex_count: u8,
    turn: Color,
    vitals: ColorMap<PlayerVitals>,
    outcome: Outcome,
}

/// A struct tracking a player's piece and captured hex count. So named because these two numbers are
/// essential to a player's survival (i.e. vital signs).
#[derive(Clone, Copy)]
struct PlayerVitals {
    pieces: u8,
    hexes: u8,
}

impl PlayerVitals {
    fn new() -> Self {
        Self {
            pieces: 18,
            hexes: 0,
        }
    }
}

/// The outcome of a game. Wins or draws caused by a resignation or an offered and accepted draw are
/// not differentiated from wins and draws by capturing all of an opponent's pieces, running out of
/// moves, being unable to capture any of the opponent's pieces, or reaching threefold repetition.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Outcome {
    InProgress,
    Win(Color),
    Draw,
}

lazy_static! {
    static ref EDGE_NEIGHBORS: NeighborLookup = NeighborLookup::new_edge();
    static ref VERTEX_NEIGHBORS: NeighborLookup = NeighborLookup::new_vertex();
    static ref HEX_FIELD_NEIGHBORS: NeighborLookup = NeighborLookup::new_hex_field();
    static ref HEX_MASK: [BitBoard; 19] = generate_hex_mask();
    static ref REMOVABLE_HEX_COMBS: [BitBoard; 342] = generate_removable_hex_combs();
}

// Public methods
impl Board {
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Self {
        Self {
            fields: generate_laurentius(),
            hexes: HEX_STARTING_POSITION,
            extant_hex_count: 19,
            turn: Color::White,
            vitals: ColorMap::new(PlayerVitals::new(), PlayerVitals::new()),
            outcome: Outcome::InProgress,
        }
    }
    pub fn apply_move(&mut self, mv: &Move) {
        assert!(self.can_apply_move(mv), "Cannot apply {:?}", mv);
        match *mv {
            Move::Move(from, to, color) => {
                self.toggle_field(from | to, color);

                let (capture_count, mut fields_to_check) =
                    self.check_hexes(from.trailing_zeros() as usize / 3);
                fields_to_check |= EDGE_NEIGHBORS.bb_get(to, color);
                self.check_captures(fields_to_check);

                self.vitals.get_mut(self.turn).hexes += capture_count;
            }
            Move::Exchange(bb, color) => {
                self.remove_piece(bb, color);
                self.vitals.get_mut(self.turn).hexes -= 2;

                // Players don't collect hexes removed due to an exchange
                let (_, fields_to_check) = self.check_hexes(bb.trailing_zeros() as usize / 3);
                self.check_captures(fields_to_check);
            }
        }
        self.turn = self.turn.switch();
        self.update_outcome();
    }
    pub fn can_apply_move(&self, mv: &Move) -> bool {
        match *mv {
            Move::Move(from, to, color) => {
                let vertex_neighbors = VERTEX_NEIGHBORS.bb_get(from, color);
                color == self.turn && (to & vertex_neighbors != 0)
                    && self.is_piece_on_bitboard(from, color)
                    && !self.is_piece_on_bitboard(to, color)
            }
            Move::Exchange(bb, color) => {
                self.can_exchange() && color != self.turn && self.is_piece_on_bitboard(bb, color)
            }
        }
    }
    pub fn generate_moves(&self) -> Vec<Move> {
        let turn = self.turn;
        // A player with no pieces cannot make any moves, including exchange moves
        if self.pieces(turn) == 0 {
            return vec![];
        }

        let can_exchange = self.can_exchange();
        let mut moves = Vec::with_capacity(
            // 3 moves per piece is an untested guess
            self.pieces(turn) as usize * 3 + if can_exchange {
                self.pieces(turn.switch()) as usize
            } else {
                0
            },
        );

        let fields = *self.fields.get_ref(turn);
        for origin in BitBoardIter::new(fields) {
            let mut vertex_neighbors = VERTEX_NEIGHBORS.bb_get(origin, turn);
            vertex_neighbors &= !fields & self.hexes;

            for dest in BitBoardIter::new(vertex_neighbors) {
                moves.push(Move::Move(origin, dest, turn));
            }
        }

        if can_exchange {
            let opp_color = turn.switch();
            for exchanged in BitBoardIter::new(*self.fields.get_ref(opp_color)) {
                moves.push(Move::Exchange(exchanged, opp_color));
            }
        }
        moves
    }
    pub fn available_moves_for_piece(&self, field: &FieldCoord) -> Vec<FieldCoord> {
        if self.is_piece_on_field(field) {
            let color = field.color();
            let vertex_neighbors = self.hexes & VERTEX_NEIGHBORS.bb_get(field.to_bitboard(), color);
            let mut moves = Vec::with_capacity(3);

            for dest in BitBoardIter::new(vertex_neighbors) {
                moves.push(FieldCoord::from_bitboard(dest, color));
            }
            moves
        } else {
            vec![]
        }
    }
    pub fn can_exchange(&self) -> bool {
        self.vitals.get_ref(self.turn).hexes >= 2
    }
    pub fn is_piece_on_field(&self, coord: &FieldCoord) -> bool {
        self.is_piece_on_bitboard(coord.to_bitboard(), coord.color())
    }
    pub fn is_piece_on_bitboard(&self, bb: BitBoard, color: Color) -> bool {
        assert!(
            bb & self.hexes != 0,
            "Cannot cannot check if piece is on {:?}. Hex was removed.",
            FieldCoord::from_bitboard(bb, color),
        );

        bb & self.fields.get_ref(color) != 0
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Return the coordinates of the hexes that have not been removed yet.
    pub fn extant_hexes(&self) -> Vec<HexCoord> {
        let mut coords = Vec::with_capacity(19);
        let try_coord = |coords: &mut Vec<HexCoord>, x, y| {
            if let Some(hex) = self.try_hex((x, y)) {
                coords.push(hex);
            }
        };
        try_coord(&mut coords, 1, 1);
        try_coord(&mut coords, -1, -1);

        for x in 0..3 {
            for y in -2..1 {
                try_coord(&mut coords, x, y);
                if x != y {
                    try_coord(&mut coords, -x, -y);
                }
            }
        }
        coords
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Returns true if a hex has not been removed yet.
    pub fn is_hex_extant(&self, index: usize) -> bool {
        self.hexes & HEX_MASK[index] != 0
    }
    pub fn resign(&mut self) {
        assert_eq!(self.outcome, Outcome::InProgress);
        self.outcome = Outcome::Win(self.turn.switch());
    }
    pub fn turn(&self) -> Color {
        self.turn
    }
    pub fn pieces(&self, color: Color) -> u8 {
        self.vitals.get_ref(color).pieces
    }
    pub fn hexes(&self, color: Color) -> u8 {
        self.vitals.get_ref(color).hexes
    }
    pub fn outcome(&self) -> Outcome {
        self.outcome
    }
}

impl Board {
    // TODO: check for threefold repetition
    fn update_outcome(&mut self) {
        if self.pieces(self.turn) == 0 {
            self.outcome = Outcome::Win(self.turn.switch());
        } else if !self.can_move() {
            self.outcome = Outcome::Draw;
        } else {
            use model::Color::*;

            let wp = self.pieces(White);
            let bp = self.pieces(Black);
            let wh = self.hexes(White);
            let bh = self.hexes(Black);

            // If neither side can capture the other's pieces, the game is drawn
            if wp == 1 && bp == 1 && (self.extant_hex_count + cmp::max(wh, bh) - 1 < 2) {
                self.outcome = Outcome::Draw;
            }
        }
    }
    fn can_move(&self) -> bool {
        if self.can_exchange() {
            return true;
        }

        for bb in BitBoardIter::new(*self.fields.get_ref(self.turn)) {
            let vertex_neighbors = VERTEX_NEIGHBORS.bb_get(bb, self.turn);
            if vertex_neighbors & self.fields.get_ref(self.turn) != vertex_neighbors {
                return true;
            }
        }
        false
    }
}

// Field and piece methods
impl Board {
    fn toggle_field(&mut self, bb: BitBoard, color: Color) {
        assert_ne!(
            bb & self.hexes,
            0,
            "Trying to toggle field(s) on removed hex(es)"
        );

        *self.fields.get_mut(color) ^= bb;
    }
    fn remove_piece(&mut self, bb: BitBoard, color: Color) {
        assert!(
            self.is_piece_on_bitboard(bb, color),
            "There is no piece at {:?} to remove",
            FieldCoord::from_bitboard(bb, color)
        );
        self.toggle_field(bb, color);
        self.vitals.get_mut(color).pieces -= 1;
    }
    fn check_captures(&mut self, mut fields_to_check: BitBoard) {
        // fields_to_check must be a BitBoard for the opponent player (i.e. opposite of current turn)
        let us = self.turn;
        let them = us.switch();
        fields_to_check &= self.hexes & self.fields.get_ref(them);
        for bb in BitBoardIter::new(fields_to_check) {
            let neighbors = self.hexes & EDGE_NEIGHBORS.bb_get(bb, them);
            if !self.fields.get_ref(us) & neighbors == 0 {
                self.remove_piece(bb, them);
            }
        }
    }
}

// Hex methods
impl Board {
    /// A hex is removable (and must be removed) if it is empty and is "attached to the board by 3
    /// or less adjacent sides."
    fn is_hex_removable(&self, index: usize) -> bool {
        let is_hex_empty = (self.fields.white | self.fields.black) & HEX_MASK[index] == 0;
        if !self.is_hex_extant(index) || !is_hex_empty {
            return false;
        }

        // Combining colors here is okay because there won't be overlaps
        let hex = self.hexes
            & (HEX_FIELD_NEIGHBORS.index_get(index, Color::White)
                | HEX_FIELD_NEIGHBORS.index_get(index, Color::Black));
        // There are 18 combinations to check for each hex
        REMOVABLE_HEX_COMBS
            .iter()
            .skip(index * 18)
            .take(18)
            .any(|&comb| hex == comb)
    }
    fn remove_hex(&mut self, index: usize) -> bool {
        let removable = self.is_hex_removable(index);

        if removable {
            self.hexes &= !HEX_MASK[index];
            self.extant_hex_count -= 1;
        }
        removable
    }
    fn try_hex(&self, coord: (i8, i8)) -> Option<HexCoord> {
        if let Some(coord) = HexCoord::try_new(coord.0, coord.1) {
            if self.is_hex_extant(coord.to_index()) {
                return Some(coord);
            }
        }
        None
    }
    fn check_hexes(&mut self, index: usize) -> (u8, BitBoard) {
        let mut remove_count = 0;
        let mut fields = 0;

        if self.remove_hex(index) {
            remove_count += 1;

            let our_neighbors = self.hexes & HEX_FIELD_NEIGHBORS.index_get(index, self.turn);
            let their_neighbors =
                self.hexes & HEX_FIELD_NEIGHBORS.index_get(index, self.turn.switch());

            for neighbor in BitBoardIter::new(our_neighbors | their_neighbors) {
                let check_result = self.check_hexes(neighbor.trailing_zeros() as usize / 3);
                remove_count += check_result.0;
                fields |= check_result.1;
            }

            // Add in the opponent's neighbors, excluding those on hexes that have been removed
            fields |= their_neighbors;
            fields &= self.hexes;
        }
        (remove_count, fields)
    }
}
<|endoftext|>


<commit_before>use llvm_sys::object::{LLVMDisposeObjectFile, LLVMObjectFileRef};

// TODO: Iterator for LLVMSectionIteratorRef

pub struct ObjectFile {
    object_file: LLVMObjectFileRef
}

impl ObjectFile {
    pub(crate) fn new(object_file: LLVMObjectFileRef) -> Self {
        assert!(!object_file.is_null());

        ObjectFile {
            object_file
        }
    }
}

impl Drop for ObjectFile {
    fn drop(&mut self) {
        unsafe {
            LLVMDisposeObjectFile(self.object_file)
        }
    }
}
<commit_msg>Initial versions of ObjectFile, SectionIterator, RelocationIterator & SymbolIterator<commit_after>use llvm_sys::object::{LLVMDisposeObjectFile, LLVMObjectFileRef, LLVMSectionIteratorRef, LLVMGetSections, LLVMDisposeSectionIterator, LLVMSymbolIteratorRef, LLVMIsSectionIteratorAtEnd, LLVMGetSectionName, LLVMDisposeRelocationIterator, LLVMRelocationIteratorRef, LLVMDisposeSymbolIterator, LLVMGetSectionContents, LLVMGetSectionSize, LLVMMoveToNextSection, LLVMGetSectionAddress, LLVMGetSymbolName, LLVMGetSymbolSize, LLVMGetRelocations, LLVMGetSymbolAddress, LLVMGetRelocationOffset, LLVMGetRelocationSymbol, LLVMGetRelocationType, LLVMGetRelocationTypeName, LLVMGetRelocationValueString, LLVMMoveToNextSymbol, LLVMMoveToNextRelocation, LLVMIsSymbolIteratorAtEnd, LLVMIsRelocationIteratorAtEnd};

use std::ffi::CStr;

// REVIEW: Make sure SectionIterator's object_file ptr doesn't outlive ObjectFile
// REVIEW: This module is very untested
// TODO: More references to account for lifetimes

pub struct ObjectFile {
    object_file: LLVMObjectFileRef
}

impl ObjectFile {
    pub(crate) fn new(object_file: LLVMObjectFileRef) -> Self {
        assert!(!object_file.is_null());

        ObjectFile {
            object_file
        }
    }

    pub fn get_sections(&self) -> SectionIterator {
        let section_iterator = unsafe {
            LLVMGetSections(self.object_file)
        };

        SectionIterator::new(section_iterator, self.object_file)
    }
}

impl Drop for ObjectFile {
    fn drop(&mut self) {
        unsafe {
            LLVMDisposeObjectFile(self.object_file)
        }
    }
}

pub struct SectionIterator {
    section_iterator: LLVMSectionIteratorRef,
    object_file: LLVMObjectFileRef,
}

impl SectionIterator {
    fn new(section_iterator: LLVMSectionIteratorRef, object_file: LLVMObjectFileRef) -> Self {
        assert!(!section_iterator.is_null());

        SectionIterator {
            section_iterator,
            object_file
        }
    }
}

impl Iterator for SectionIterator {
    type Item = Section;

    fn next(&mut self) -> Option<Self::Item> {
        // REVIEW: Should it compare against 1? End checking order might also be off
        let at_end = unsafe {
            LLVMIsSectionIteratorAtEnd(self.object_file, self.section_iterator) == 1
        };

        if at_end {
            return None;
        }

        let section = Section::new(self.section_iterator, self.object_file);

        unsafe {
            LLVMMoveToNextSection(self.section_iterator)
        }

        Some(section)
    }
}

impl Drop for SectionIterator {
    fn drop(&mut self) {
        unsafe {
            LLVMDisposeSectionIterator(self.section_iterator)
        }
    }
}

pub struct Section {
    section: LLVMSectionIteratorRef,
    object_file: LLVMObjectFileRef,
}

impl Section {
    fn new(section: LLVMSectionIteratorRef, object_file: LLVMObjectFileRef) -> Self {
        assert!(!section.is_null());

        Section {
            section,
            object_file,
        }
    }

    pub fn get_name(&self) -> &CStr {
        unsafe {
            CStr::from_ptr(LLVMGetSectionName(self.section))
        }
    }

    pub fn size(&self) -> u64 {
        unsafe {
            LLVMGetSectionSize(self.section)
        }
    }

    pub fn get_contents(&self) -> &CStr {
        unsafe {
            CStr::from_ptr(LLVMGetSectionContents(self.section))
        }
    }

    pub fn get_address(&self) -> u64 {
        unsafe {
            LLVMGetSectionAddress(self.section)
        }
    }

    pub fn get_relocations(&self) -> RelocationIterator {
        let relocation_iterator = unsafe {
            LLVMGetRelocations(self.section)
        };

        RelocationIterator::new(relocation_iterator, self.section, self.object_file)
    }
}

pub struct RelocationIterator {
    relocation_iterator: LLVMRelocationIteratorRef,
    section_iterator: LLVMSectionIteratorRef,
    object_file: LLVMObjectFileRef,
}

impl RelocationIterator {
    fn new(relocation_iterator: LLVMRelocationIteratorRef, section_iterator: LLVMSectionIteratorRef, object_file: LLVMObjectFileRef) -> Self {
        assert!(!relocation_iterator.is_null());

        RelocationIterator {
            relocation_iterator,
            section_iterator,
            object_file,
        }
    }
}

impl Iterator for RelocationIterator {
    type Item = Relocation;

    fn next(&mut self) -> Option<Self::Item> {
        // REVIEW: Should it compare against 1? End checking order might also be off
        let at_end = unsafe {
            LLVMIsRelocationIteratorAtEnd(self.section_iterator, self.relocation_iterator) == 1
        };

        if at_end {
            return None;
        }

        let relocation = Relocation::new(self.relocation_iterator, self.object_file);

        unsafe {
            LLVMMoveToNextRelocation(self.relocation_iterator)
        }

        Some(relocation)
    }
}

impl Drop for RelocationIterator {
    fn drop(&mut self) {
        unsafe {
            LLVMDisposeRelocationIterator(self.relocation_iterator)
        }
    }
}

pub struct Relocation {
    relocation: LLVMRelocationIteratorRef,
    object_file: LLVMObjectFileRef,
}

impl Relocation {
    fn new(relocation: LLVMRelocationIteratorRef, object_file: LLVMObjectFileRef) -> Self {
        assert!(!relocation.is_null());

        Relocation {
            relocation,
            object_file,
        }
    }

    pub fn get_offset(&self) -> u64 {
        unsafe {
            LLVMGetRelocationOffset(self.relocation)
        }
    }

    pub fn get_symbols(&self) -> SymbolIterator {
        let symbol_iterator = unsafe {
            LLVMGetRelocationSymbol(self.relocation)
        };

        SymbolIterator::new(symbol_iterator, self.object_file)
    }

    pub fn get_type(&self) -> (u64, &CStr) {
        let type_int = unsafe {
            LLVMGetRelocationType(self.relocation)
        };
        let type_name = unsafe {
            CStr::from_ptr(LLVMGetRelocationTypeName(self.relocation))
        };

        (type_int, type_name)
    }

    pub fn get_value(&self) -> &CStr {
        unsafe {
            CStr::from_ptr(LLVMGetRelocationValueString(self.relocation))
        }
    }
}

pub struct SymbolIterator {
    symbol_iterator: LLVMSymbolIteratorRef,
    object_file: LLVMObjectFileRef,
}

impl SymbolIterator {
    fn new(symbol_iterator: LLVMSymbolIteratorRef, object_file: LLVMObjectFileRef) -> Self {
        assert!(!symbol_iterator.is_null());

        SymbolIterator {
            symbol_iterator,
            object_file,
        }
    }
}

impl Iterator for SymbolIterator {
    type Item = Symbol;

    fn next(&mut self) -> Option<Self::Item> {
        // REVIEW: Should it compare against 1? End checking order might also be off
        let at_end = unsafe {
            LLVMIsSymbolIteratorAtEnd(self.object_file, self.symbol_iterator) == 1
        };

        if at_end {
            return None;
        }

        let symbol = Symbol::new(self.symbol_iterator);

        unsafe {
            LLVMMoveToNextSymbol(self.symbol_iterator)
        }

        Some(symbol)
    }
}

impl Drop for SymbolIterator {
    fn drop(&mut self) {
        unsafe {
            LLVMDisposeSymbolIterator(self.symbol_iterator)
        }
    }
}

pub struct Symbol {
    symbol: LLVMSymbolIteratorRef,
}

impl Symbol {
    fn new(symbol: LLVMSymbolIteratorRef) -> Self {
        assert!(!symbol.is_null());

        Symbol {
            symbol,
        }
    }

    pub fn get_name(&self) -> &CStr {
        unsafe {
            CStr::from_ptr(LLVMGetSymbolName(self.symbol))
        }
    }

    pub fn size(&self) -> u64 {
        unsafe {
            LLVMGetSymbolSize(self.symbol)
        }
    }

    pub fn get_address(&self) -> u64 {
        unsafe {
            LLVMGetSymbolAddress(self.symbol)
        }
    }
}
<|endoftext|>


<commit_before>use {osc_types as ot,
    errors as oe};

use std::{io, string, mem, error};
use std::io::{Read, BufRead};

use byteorder;
use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8], size: usize) -> ot::OscResult<ot::OscPacket> {
    match msg[0] as char {
        '/' => {
            decode_message(msg, size)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(oe::OscError::BadOscPacket("Unknown message format.".to_string())),
    }
}

fn decode_message(msg: &[u8], size: usize) -> ot::OscResult<ot::OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    match read_osc_string(&mut cursor) {
        Ok(s) => {
            let addr: String = s;
            match read_osc_string(&mut cursor) {
                Ok(type_tags) => {
                    if type_tags.len() > 1 {
                        match read_osc_args(&mut cursor, type_tags) {
                            Ok(args) => {
                                Ok(ot::OscPacket::Message(ot::OscMessage{
                                    addr: addr,
                                    args: Some(args),
                                }))
                            },
                            Err(e) => Err(e),
                        }
                    } else {
                        Ok(ot::OscPacket::Message(ot::OscMessage{
                            addr: addr,
                            args: None
                        }))
                    }
                },
                Err(e) => Err(e),
            }
        }
        Err(e) => Err(e),
    }

    Ok(ot::OscPacket::Message(ot::OscMessage))
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> ot::OscResult<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    match cursor.read_until(0, &mut str_buf) {
        Ok(_) => {
            pad_cursor(cursor);
            String::from_utf8(str_buf)
                .map_err(|e| oe::OscError::StringError(e))
                .map(|s| s.trim_matches(0u8 as char).to_string())
        },
        Err(e) => Err(oe::OscError::ReadError(e)),
    }
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> ot::OscResult<Vec<ot::OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
        .skip(1)
        .map(|c| c as char)
        .collect();
    let mut args: Vec<ot::OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        match read_osc_arg(cursor, tag) {
            Ok(arg) => {
                args.push(arg);
            },
            Err(e) => return Err(e)
        }
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> ot::OscResult<ot::OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
            .map(|f| ot::OscType::OscFloat(f))
            .map_err(|e| oe::OscError::ByteOrderError(e))
        },
        'd' => {
            cursor.read_f64::<BigEndian>()
            .map(|d| ot::OscType::OscDouble(d))
            .map_err(|e| oe::OscError::ByteOrderError(e))
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
            .map(|i| ot::OscType::OscInt(i))
            .map_err(|e| oe::OscError::ByteOrderError(e))
        },
        'h' => {
            cursor.read_i64::<BigEndian>()
            .map(|l| ot::OscType::OscLong(l))
            .map_err(|e| oe::OscError::ByteOrderError(e))
        },
        's' => {
            read_osc_string(cursor)
            .map(|s| ot::OscType::OscString(s))
        },
        't' => {
            // http://opensoundcontrol.org/node/3/#timetags
            read_time_tag(cursor)
        }
        'b' => {
            match cursor.read_u32::<BigEndian>() {
                Ok(size) => {
                    let mut buf: Vec<u8> = Vec::with_capacity(size as usize);
                    match cursor.take(size as u64).read(&mut buf) {
                        Ok(blob_size) => Ok(ot::OscType::OscBlob(buf)),
                        Err(e) => Err(oe::OscError::ReadError(e))
                    }
                },
                Err(e) => return Err(oe::OscError::BadOscBundle)
            }
        },
        _ => Err(oe::OscError::BadOscArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> ot::OscResult<ot::OscType> {
    match cursor.read_u32::<BigEndian>() {
        Ok(date) => {
            match cursor.read_u32::<BigEndian>() {
                Ok(frac) => Ok(ot::OscType::OscTime(date, frac)),
                Err(e) => Err(oe::OscError::ByteOrderError(e))
            }
        },
        Err(e) => Err(oe::OscError::ByteOrderError(e))
    }
}

fn decode_bundle(msg: &[u8]) -> ot::OscResult<ot::OscPacket> {
    Err(oe::OscError::BadOscBundle)
}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    match pos % 4 {
        0 => (),
        d => cursor.set_position(pos + (4 - d)),
    }
}<commit_msg>Rustfmt<commit_after>use {osc_types as ot, errors as oe};

use std::{io, string, mem, error};
use std::io::{Read, BufRead};

use byteorder;
use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8], size: usize) -> ot::OscResult<ot::OscPacket> {
    match msg[0] as char {
        '/' => {
            decode_message(msg, size)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(oe::OscError::BadOscPacket("Unknown message format.".to_string())),
    }
}

fn decode_message(msg: &[u8], size: usize) -> ot::OscResult<ot::OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    match read_osc_string(&mut cursor) {
        Ok(s) => {
            let addr: String = s;
            match read_osc_string(&mut cursor) {
                Ok(type_tags) => {
                    if type_tags.len() > 1 {
                        match read_osc_args(&mut cursor, type_tags) {
                            Ok(args) => {
                                Ok(ot::OscPacket::Message(ot::OscMessage {
                                    addr: addr,
                                    args: Some(args),
                                }))
                            }
                            Err(e) => Err(e),
                        }
                    } else {
                        Ok(ot::OscPacket::Message(ot::OscMessage {
                            addr: addr,
                            args: None,
                        }))
                    }
                }
                Err(e) => Err(e),
            }
        }
        Err(e) => Err(e),
    }

    Ok(ot::OscPacket::Message(ot::OscMessage))
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> ot::OscResult<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    match cursor.read_until(0, &mut str_buf) {
        Ok(_) => {
            pad_cursor(cursor);
            String::from_utf8(str_buf)
                .map_err(|e| oe::OscError::StringError(e))
                .map(|s| s.trim_matches(0u8 as char).to_string())
        }
        Err(e) => Err(oe::OscError::ReadError(e)),
    }
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>,
                 raw_type_tags: String)
                 -> ot::OscResult<Vec<ot::OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
                                            .skip(1)
                                            .map(|c| c as char)
                                            .collect();
    let mut args: Vec<ot::OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        match read_osc_arg(cursor, tag) {
            Ok(arg) => {
                args.push(arg);
            }
            Err(e) => return Err(e),
        }
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> ot::OscResult<ot::OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
                  .map(|f| ot::OscType::OscFloat(f))
                  .map_err(|e| oe::OscError::ByteOrderError(e))
        }
        'd' => {
            cursor.read_f64::<BigEndian>()
                  .map(|d| ot::OscType::OscDouble(d))
                  .map_err(|e| oe::OscError::ByteOrderError(e))
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
                  .map(|i| ot::OscType::OscInt(i))
                  .map_err(|e| oe::OscError::ByteOrderError(e))
        }
        'h' => {
            cursor.read_i64::<BigEndian>()
                  .map(|l| ot::OscType::OscLong(l))
                  .map_err(|e| oe::OscError::ByteOrderError(e))
        }
        's' => {
            read_osc_string(cursor).map(|s| ot::OscType::OscString(s))
        }
        't' => {
            // http://opensoundcontrol.org/node/3/#timetags
            read_time_tag(cursor)
        }
        'b' => {
            match cursor.read_u32::<BigEndian>() {
                Ok(size) => {
                    let mut buf: Vec<u8> = Vec::with_capacity(size as usize);
                    match cursor.take(size as u64).read(&mut buf) {
                        Ok(blob_size) => Ok(ot::OscType::OscBlob(buf)),
                        Err(e) => Err(oe::OscError::ReadError(e)),
                    }
                }
                // TODO: use correct error type
                Err(e) => return Err(oe::OscError::BadOscBundle),
            }
        }
        _ => Err(oe::OscError::BadOscArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> ot::OscResult<ot::OscType> {
    match cursor.read_u32::<BigEndian>() {
        Ok(date) => {
            match cursor.read_u32::<BigEndian>() {
                Ok(frac) => Ok(ot::OscType::OscTime(date, frac)),
                Err(e) => Err(oe::OscError::ByteOrderError(e)),
            }
        }
        Err(e) => Err(oe::OscError::ByteOrderError(e)),
    }
}

fn decode_bundle(msg: &[u8]) -> ot::OscResult<ot::OscPacket> {
    Err(oe::OscError::BadOscBundle)
}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    match pos % 4 {
        0 => (),
        d => cursor.set_position(pos + (4 - d)),
    }
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::io::BufReader;

use color::{ColorType};
use image::{DecodingResult, ImageDecoder, ImageResult, ImageError};
extern crate byteorder;
use self::byteorder::{BigEndian, ByteOrder};

/// PPM decoder
pub struct PPMDecoder<R> {
    reader: BufReader<R>,
    width: u32,
    height: u32,
    maxwhite: u32,
}

impl<R: Read> PPMDecoder<R> {
    /// Create a new decoder that decodes from the stream ```r```
    pub fn new(r: R) -> ImageResult<PPMDecoder<R>> {
        let mut buf = BufReader::new(r);
        let mut magic: [u8; 2] = [0, 0];
        try!(buf.read_exact(&mut magic[..])); // Skip magic constant
        if magic[0] != b'P' || (magic[1] != b'3' && magic[1] != b'6') {
            return Err(ImageError::FormatError("Expected magic constant for ppm, P3 or P6".to_string()));
        }
        let width = try!(PPMDecoder::read_next_u32(&mut buf));
        let height = try!(PPMDecoder::read_next_u32(&mut buf));
        let maxwhite = try!(PPMDecoder::read_next_u32(&mut buf));
        Ok(PPMDecoder {
            reader: buf,
            width: width,
            height: height,
            maxwhite: maxwhite,
        })
    }

    /// Reads a string as well as a single whitespace after it, ignoring comments
    fn read_next_string(reader: &mut BufReader<R>) -> ImageResult<String> {
        let mut bytes = Vec::new();
        let mut comment = false;

        for byte in reader.bytes() {
            match byte {
                Ok(b'\n') | Ok(b'\r') if comment => {
                    // End of comment, this does not end tokens (http://netpbm.sourceforge.net/doc/ppm.html)
                    comment = false;
                },
                Ok(_) if comment => {
                    // Ignore all other bytes in comments
                },
                Ok(b'\n') | Ok(b' ') | Ok(b'\r') | Ok(b'\t') => {
                    if !bytes.is_empty() {
                        break // We're done as we already have some content
                    }
                },
                Ok(b'#') => {
                    comment = true;
                },
                Ok(byte) => {
                    bytes.push(byte);
                },
                Err(_) => break,
            }
        }

        if comment && bytes.is_empty() {
            return Err(ImageError::FormatError("Unexpected eof".to_string()))
        }

        String::from_utf8(bytes).map_err(|_| ImageError::FormatError("Couldn't read preamble".to_string()))
    }

    fn read_next_u32(reader: &mut BufReader<R>) -> ImageResult<u32> {
        let s = try!(PPMDecoder::read_next_string(reader));
        s.parse::<u32>().map_err(|_| ImageError::FormatError("Couldn't read preamble".to_string()))
    }
}

impl<R: Read> ImageDecoder for PPMDecoder<R> {
    fn dimensions(&mut self) -> ImageResult<(u32, u32)> {
        Ok((self.width, self.height))
    }

    fn colortype(&mut self) -> ImageResult<ColorType> {
        match self.bytewidth() {
            1 => Ok(ColorType::RGB(8)),
            2 => Ok(ColorType::RGB(16)),
            _ => Err(ImageError::FormatError("Don't know how to decode PPM with more than 16 bits".to_string())),
        }
    }

    fn row_len(&mut self) -> ImageResult<usize> {
        Ok((self.width*3*self.bytewidth()) as usize)
    }

    fn read_scanline(&mut self, _buf: &mut [u8]) -> ImageResult<u32> {
        unimplemented!();
    }

    fn read_image(&mut self) -> ImageResult<DecodingResult> {
        let opt_size = self.width.checked_mul(self.height)
            .map_or(None, |v| v.checked_mul(3))
            .map_or(None, |v| v.checked_mul(self.bytewidth()));

        let size = match opt_size {
            Some(v) => v,
            None => return Err(ImageError::DimensionError),
        };

        let mut data = vec![0 as u8; size as usize];

        match self.reader.read_exact(&mut data) {
            Ok(_) => {},
            Err(e) => return Err(ImageError::IoError(e)),
        };

        if self.bytewidth() == 1 {
            Ok(DecodingResult::U8(data))
        } else {
            let mut out = vec![0 as u16; (self.width*self.height*3) as usize];
            for (o, i) in out.chunks_mut(1).zip(data.chunks(2)) {
                o[0] = BigEndian::read_u16(i);
            }
            Ok(DecodingResult::U16(out))
        }
    }
}

impl<R: Read> PPMDecoder<R> {
    fn bytewidth(&self) -> u32 {
        if self.maxwhite < 256 { 1 } else { 2 }
    }
}

/// Tests parsing binary buffers were written based on and validated against `identify` from
/// ImageMagick (https://www.imagemagick.org/script/identify.php).
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn minimal_form() {
        // Violates current specification (October 2016 ) but accepted by both netpbm and ImageMagick
        decode_minimal_image(&b"P61 1 255 123"[..]);
        decode_minimal_image(&b"P6 1 1 255 123"[..]);
        decode_minimal_image(&b"P6 1 1 255 123\xFF"[..]); // Too long should not be an issue
    }

    #[test]
    fn comment_in_token() {
        decode_minimal_image(&b"P6 1 1 2#comment\n55 123"[..]); // Terminating LF
        decode_minimal_image(&b"P6 1 1 2#comment\r55 123"[..]); // Terminating CR
        decode_minimal_image(&b"P6 1 1 255#comment\n 123"[..]); // Comment after token
        decode_minimal_image(&b"P6 1 1 #comment\n255 123"[..]); // Comment before token
        decode_minimal_image(&b"P6#comment\n 1 1 255 123"[..]); // Begin of header
        decode_minimal_image(&b"P6 1 1 255#comment\n 123"[..]); // End of header
    }

    #[test]
    fn whitespace() {
        decode_minimal_image(&b"P6\x091\x091\x09255\x09123"[..]); // TAB
        decode_minimal_image(&b"P6\x0a1\x0a1\x0a255\x0a123"[..]); // LF
        decode_minimal_image(&b"P6\x0b1\x0b1\x0b255\x0b123"[..]); // VT
        decode_minimal_image(&b"P6\x0c1\x0c1\x0c255\x0c123"[..]); // FF
        decode_minimal_image(&b"P6\x0d1\x0d1\x0d255\x0d123"[..]); // CR
        // Spaces tested before
        decode_minimal_image(&b"P61\x09\x0a\x0b\x0c\x0d1 255 123"[..]); // All whitespace, combined
    }

    /// Tests for decoding error, assuming `encoded` is ppm encoding for the very simplistic image
    /// containing a single pixel with one byte values (1, 2, 3).
    fn decode_minimal_image(encoded: &[u8]) {
        let content = vec![49 as u8, 50, 51];
        let mut decoder = super::PPMDecoder::new(encoded).unwrap();

        assert_eq!(decoder.dimensions().unwrap(), (1, 1));
        assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(8));
        assert_eq!(decoder.row_len().unwrap(), 3);
        assert_eq!(decoder.bytewidth(), 1);

        match decoder.read_image().unwrap() {
            DecodingResult::U8(image) => assert_eq!(image, content),
            _ => assert!(false),
        }
    }
}
<commit_msg>Implement alternative spec conform comments<commit_after>use std::io::Read;
use std::io::BufReader;
use std::io::Error as IoError;

use color::{ColorType};
use image::{DecodingResult, ImageDecoder, ImageResult, ImageError};
extern crate byteorder;
use self::byteorder::{BigEndian, ByteOrder};

/// PPM decoder
pub struct PPMDecoder<R> {
    reader: BufReader<R>,
    width: u32,
    height: u32,
    maxwhite: u32,
}

impl<R: Read> PPMDecoder<R> {
    /// Create a new decoder that decodes from the stream ```r```
    pub fn new(read: R) -> ImageResult<PPMDecoder<R>> {
        let mut buf = BufReader::new(read);
        let mut magic: [u8; 2] = [0, 0];
        try!(buf.read_exact(&mut magic[..])); // Skip magic constant
        if magic[0] != b'P' || (magic[1] != b'3' && magic[1] != b'6') {
            return Err(ImageError::FormatError("Expected magic constant for ppm, P3 or P6".to_string()));
        }

        let width = try!(PPMDecoder::read_next_u32(&mut buf));
        let height = try!(PPMDecoder::read_next_u32(&mut buf));
        let maxwhite = try!(PPMDecoder::read_next_u32(&mut buf));

        Ok(PPMDecoder {
            reader: buf,
            width: width,
            height: height,
            maxwhite: maxwhite,
        })
    }

    /// Reads a string as well as a single whitespace after it, ignoring comments
    fn read_next_string(reader: &mut BufReader<R>) -> ImageResult<String> {
        let mut bytes = Vec::new();

        let mark_comments = reader
            .bytes()
            .scan(true, |partof, read| {
                let byte = match read {
                    Err(err) => return Some((*partof, Err(err))),
                    Ok(byte) => byte,
                };
                if *partof && byte == b'#' {
                    *partof = false;
                    return Some((false, Ok(byte)));
                } else if !*partof && (byte == b'\r' || byte == b'\n') {
                    *partof = true;
                    return Some((false, Ok(byte)));
                }
                return Some((*partof, Ok(byte)));
            });

        for (_, byte) in mark_comments.filter(|ref e| e.0) {
            match byte {
                Ok(b'\n') | Ok(b' ') | Ok(b'\r') | Ok(b'\t') => {
                    if !bytes.is_empty() {
                        break // We're done as we already have some content
                    }
                },
                Ok(byte) => {
                    bytes.push(byte);
                },
                Err(_) => break,
            }
        }

        if bytes.is_empty() {
            return Err(ImageError::FormatError("Unexpected eof".to_string()))
        }

        String::from_utf8(bytes).map_err(|_| ImageError::FormatError("Couldn't read preamble".to_string()))
    }

    fn read_next_u32(reader: &mut BufReader<R>) -> ImageResult<u32> {
        let s = try!(PPMDecoder::read_next_string(reader));
        s.parse::<u32>().map_err(|_| ImageError::FormatError("Couldn't read preamble".to_string()))
    }
}

impl<R: Read> ImageDecoder for PPMDecoder<R> {
    fn dimensions(&mut self) -> ImageResult<(u32, u32)> {
        Ok((self.width, self.height))
    }

    fn colortype(&mut self) -> ImageResult<ColorType> {
        match self.bytewidth() {
            1 => Ok(ColorType::RGB(8)),
            2 => Ok(ColorType::RGB(16)),
            _ => Err(ImageError::FormatError("Don't know how to decode PPM with more than 16 bits".to_string())),
        }
    }

    fn row_len(&mut self) -> ImageResult<usize> {
        Ok((self.width*3*self.bytewidth()) as usize)
    }

    fn read_scanline(&mut self, _buf: &mut [u8]) -> ImageResult<u32> {
        unimplemented!();
    }

    fn read_image(&mut self) -> ImageResult<DecodingResult> {
        let opt_size = self.width.checked_mul(self.height)
            .map_or(None, |v| v.checked_mul(3))
            .map_or(None, |v| v.checked_mul(self.bytewidth()));

        let size = match opt_size {
            Some(v) => v,
            None => return Err(ImageError::DimensionError),
        };

        let mut data = vec![0 as u8; size as usize];

        match self.reader.read_exact(&mut data) {
            Ok(_) => {},
            Err(e) => return Err(ImageError::IoError(e)),
        };

        if self.bytewidth() == 1 {
            Ok(DecodingResult::U8(data))
        } else {
            let mut out = vec![0 as u16; (self.width*self.height*3) as usize];
            for (o, i) in out.chunks_mut(1).zip(data.chunks(2)) {
                o[0] = BigEndian::read_u16(i);
            }
            Ok(DecodingResult::U16(out))
        }
    }
}

impl<R: Read> PPMDecoder<R> {
    fn bytewidth(&self) -> u32 {
        if self.maxwhite < 256 { 1 } else { 2 }
    }
}

/// Tests parsing binary buffers were written based on and validated against `identify` from
/// ImageMagick (https://www.imagemagick.org/script/identify.php).
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn minimal_form() {
        // Violates current specification (October 2016 ) but accepted by both netpbm and ImageMagick
        decode_minimal_image(&b"P61 1 255 123"[..]);
        decode_minimal_image(&b"P6 1 1 255 123"[..]);
        decode_minimal_image(&b"P6 1 1 255 123\xFF"[..]); // Too long should not be an issue
    }

    #[test]
    fn comment_in_token() {
        decode_minimal_image(&b"P6 1 1 2#comment\n55 123"[..]); // Terminating LF
        decode_minimal_image(&b"P6 1 1 2#comment\r55 123"[..]); // Terminating CR
        decode_minimal_image(&b"P6 1 1#comment\n 255 123"[..]); // Comment after token
        decode_minimal_image(&b"P6 1 1 #comment\n255 123"[..]); // Comment before token
        decode_minimal_image(&b"P6#comment\n 1 1 255 123"[..]); // Begin of header
        decode_minimal_image(&b"P6 1 1 255#comment\n 123"[..]); // End of header
    }

    #[test]
    fn whitespace() {
        decode_minimal_image(&b"P6\x091\x091\x09255\x09123"[..]); // TAB
        decode_minimal_image(&b"P6\x0a1\x0a1\x0a255\x0a123"[..]); // LF
        decode_minimal_image(&b"P6\x0b1\x0b1\x0b255\x0b123"[..]); // VT
        decode_minimal_image(&b"P6\x0c1\x0c1\x0c255\x0c123"[..]); // FF
        decode_minimal_image(&b"P6\x0d1\x0d1\x0d255\x0d123"[..]); // CR
        // Spaces tested before
        decode_minimal_image(&b"P61\x09\x0a\x0b\x0c\x0d1 255 123"[..]); // All whitespace, combined
    }

    /// Tests for decoding error, assuming `encoded` is ppm encoding for the very simplistic image
    /// containing a single pixel with one byte values (1, 2, 3).
    fn decode_minimal_image(encoded: &[u8]) {
        let content = vec![49 as u8, 50, 51];
        let mut decoder = super::PPMDecoder::new(encoded).unwrap();

        assert_eq!(decoder.dimensions().unwrap(), (1, 1));
        assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(8));
        assert_eq!(decoder.row_len().unwrap(), 3);
        assert_eq!(decoder.bytewidth(), 1);

        match decoder.read_image().unwrap() {
            DecodingResult::U8(image) => assert_eq!(image, content),
            _ => assert!(false),
        }
    }
}
<|endoftext|>


<commit_before>// run-pass
#![allow(non_camel_case_types)]

// ignore-emscripten

// Test that the simd_select intrinsics produces correct results.

#![feature(repr_simd, platform_intrinsics)]
#[allow(non_camel_case_types)]

#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
struct i32x4(pub i32, pub i32, pub i32, pub i32);

#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
struct u32x4(pub u32, pub u32, pub u32, pub u32);

#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
struct u32x8(u32, u32, u32, u32, u32, u32, u32, u32);

#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
struct f32x4(pub f32, pub f32, pub f32, pub f32);

#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
struct b8x4(pub i8, pub i8, pub i8, pub i8);

extern "platform-intrinsic" {
    fn simd_select<T, U>(x: T, a: U, b: U) -> U;
    fn simd_select_bitmask<T, U>(x: T, a: U, b: U) -> U;
}

fn main() {
    let m0 = b8x4(!0, !0, !0, !0);
    let m1 = b8x4(0, 0, 0, 0);
    let m2 = b8x4(!0, !0, 0, 0);
    let m3 = b8x4(0, 0, !0, !0);
    let m4 = b8x4(!0, 0, !0, 0);

    unsafe {
        let a = i32x4(1, -2, 3, 4);
        let b = i32x4(5, 6, -7, 8);

        let r: i32x4 = simd_select(m0, a, b);
        let e = a;
        assert_eq!(r, e);

        let r: i32x4 = simd_select(m1, a, b);
        let e = b;
        assert_eq!(r, e);

        let r: i32x4 = simd_select(m2, a, b);
        let e = i32x4(1, -2, -7, 8);
        assert_eq!(r, e);

        let r: i32x4 = simd_select(m3, a, b);
        let e = i32x4(5, 6, 3, 4);
        assert_eq!(r, e);

        let r: i32x4 = simd_select(m4, a, b);
        let e = i32x4(1, 6, 3, 8);
        assert_eq!(r, e);
    }

    unsafe {
        let a = u32x4(1, 2, 3, 4);
        let b = u32x4(5, 6, 7, 8);

        let r: u32x4 = simd_select(m0, a, b);
        let e = a;
        assert_eq!(r, e);

        let r: u32x4 = simd_select(m1, a, b);
        let e = b;
        assert_eq!(r, e);

        let r: u32x4 = simd_select(m2, a, b);
        let e = u32x4(1, 2, 7, 8);
        assert_eq!(r, e);

        let r: u32x4 = simd_select(m3, a, b);
        let e = u32x4(5, 6, 3, 4);
        assert_eq!(r, e);

        let r: u32x4 = simd_select(m4, a, b);
        let e = u32x4(1, 6, 3, 8);
        assert_eq!(r, e);
    }

    unsafe {
        let a = f32x4(1., 2., 3., 4.);
        let b = f32x4(5., 6., 7., 8.);

        let r: f32x4 = simd_select(m0, a, b);
        let e = a;
        assert_eq!(r, e);

        let r: f32x4 = simd_select(m1, a, b);
        let e = b;
        assert_eq!(r, e);

        let r: f32x4 = simd_select(m2, a, b);
        let e = f32x4(1., 2., 7., 8.);
        assert_eq!(r, e);

        let r: f32x4 = simd_select(m3, a, b);
        let e = f32x4(5., 6., 3., 4.);
        assert_eq!(r, e);

        let r: f32x4 = simd_select(m4, a, b);
        let e = f32x4(1., 6., 3., 8.);
        assert_eq!(r, e);
    }

    unsafe {
        let t = !0 as i8;
        let f = 0 as i8;
        let a = b8x4(t, f, t, f);
        let b = b8x4(f, f, f, t);

        let r: b8x4 = simd_select(m0, a, b);
        let e = a;
        assert_eq!(r, e);

        let r: b8x4 = simd_select(m1, a, b);
        let e = b;
        assert_eq!(r, e);

        let r: b8x4 = simd_select(m2, a, b);
        let e = b8x4(t, f, f, t);
        assert_eq!(r, e);

        let r: b8x4 = simd_select(m3, a, b);
        let e = b8x4(f, f, t, f);
        assert_eq!(r, e);

        let r: b8x4 = simd_select(m4, a, b);
        let e = b8x4(t, f, t, t);
        assert_eq!(r, e);
    }

    unsafe {
        let a = u32x8(0, 1, 2, 3, 4, 5, 6, 7);
        let b = u32x8(8, 9, 10, 11, 12, 13, 14, 15);

        let r: u32x8 = simd_select_bitmask(0u8, a, b);
        let e = b;
        assert_eq!(r, e);

        let r: u32x8 = simd_select_bitmask(0xffu8, a, b);
        let e = a;
        assert_eq!(r, e);

        let r: u32x8 = simd_select_bitmask(0b01010101u8, a, b);
        let e = u32x8(0, 9, 2, 11, 4, 13, 6, 15);
        assert_eq!(r, e);

        let r: u32x8 = simd_select_bitmask(0b10101010u8, a, b);
        let e = u32x8(8, 1, 10, 3, 12, 5, 14, 7);
        assert_eq!(r, e);

        let r: u32x8 = simd_select_bitmask(0b11110000u8, a, b);
        let e = u32x8(8, 9, 10, 11, 4, 5, 6, 7);
        assert_eq!(r, e);
    }
}
<commit_msg>Disable simd_select_bitmask test on big endian<commit_after>// run-pass
#![allow(non_camel_case_types)]

// ignore-emscripten
// ignore-mips       behavior of simd_select_bitmask is endian-specific
// ignore-mips64     behavior of simd_select_bitmask is endian-specific
// ignore-powerpc    behavior of simd_select_bitmask is endian-specific
// ignore-powerpc64  behavior of simd_select_bitmask is endian-specific

// Test that the simd_select intrinsics produces correct results.

#![feature(repr_simd, platform_intrinsics)]
#[allow(non_camel_case_types)]

#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
struct i32x4(pub i32, pub i32, pub i32, pub i32);

#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
struct u32x4(pub u32, pub u32, pub u32, pub u32);

#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
struct u32x8(u32, u32, u32, u32, u32, u32, u32, u32);

#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
struct f32x4(pub f32, pub f32, pub f32, pub f32);

#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
struct b8x4(pub i8, pub i8, pub i8, pub i8);

extern "platform-intrinsic" {
    fn simd_select<T, U>(x: T, a: U, b: U) -> U;
    fn simd_select_bitmask<T, U>(x: T, a: U, b: U) -> U;
}

fn main() {
    let m0 = b8x4(!0, !0, !0, !0);
    let m1 = b8x4(0, 0, 0, 0);
    let m2 = b8x4(!0, !0, 0, 0);
    let m3 = b8x4(0, 0, !0, !0);
    let m4 = b8x4(!0, 0, !0, 0);

    unsafe {
        let a = i32x4(1, -2, 3, 4);
        let b = i32x4(5, 6, -7, 8);

        let r: i32x4 = simd_select(m0, a, b);
        let e = a;
        assert_eq!(r, e);

        let r: i32x4 = simd_select(m1, a, b);
        let e = b;
        assert_eq!(r, e);

        let r: i32x4 = simd_select(m2, a, b);
        let e = i32x4(1, -2, -7, 8);
        assert_eq!(r, e);

        let r: i32x4 = simd_select(m3, a, b);
        let e = i32x4(5, 6, 3, 4);
        assert_eq!(r, e);

        let r: i32x4 = simd_select(m4, a, b);
        let e = i32x4(1, 6, 3, 8);
        assert_eq!(r, e);
    }

    unsafe {
        let a = u32x4(1, 2, 3, 4);
        let b = u32x4(5, 6, 7, 8);

        let r: u32x4 = simd_select(m0, a, b);
        let e = a;
        assert_eq!(r, e);

        let r: u32x4 = simd_select(m1, a, b);
        let e = b;
        assert_eq!(r, e);

        let r: u32x4 = simd_select(m2, a, b);
        let e = u32x4(1, 2, 7, 8);
        assert_eq!(r, e);

        let r: u32x4 = simd_select(m3, a, b);
        let e = u32x4(5, 6, 3, 4);
        assert_eq!(r, e);

        let r: u32x4 = simd_select(m4, a, b);
        let e = u32x4(1, 6, 3, 8);
        assert_eq!(r, e);
    }

    unsafe {
        let a = f32x4(1., 2., 3., 4.);
        let b = f32x4(5., 6., 7., 8.);

        let r: f32x4 = simd_select(m0, a, b);
        let e = a;
        assert_eq!(r, e);

        let r: f32x4 = simd_select(m1, a, b);
        let e = b;
        assert_eq!(r, e);

        let r: f32x4 = simd_select(m2, a, b);
        let e = f32x4(1., 2., 7., 8.);
        assert_eq!(r, e);

        let r: f32x4 = simd_select(m3, a, b);
        let e = f32x4(5., 6., 3., 4.);
        assert_eq!(r, e);

        let r: f32x4 = simd_select(m4, a, b);
        let e = f32x4(1., 6., 3., 8.);
        assert_eq!(r, e);
    }

    unsafe {
        let t = !0 as i8;
        let f = 0 as i8;
        let a = b8x4(t, f, t, f);
        let b = b8x4(f, f, f, t);

        let r: b8x4 = simd_select(m0, a, b);
        let e = a;
        assert_eq!(r, e);

        let r: b8x4 = simd_select(m1, a, b);
        let e = b;
        assert_eq!(r, e);

        let r: b8x4 = simd_select(m2, a, b);
        let e = b8x4(t, f, f, t);
        assert_eq!(r, e);

        let r: b8x4 = simd_select(m3, a, b);
        let e = b8x4(f, f, t, f);
        assert_eq!(r, e);

        let r: b8x4 = simd_select(m4, a, b);
        let e = b8x4(t, f, t, t);
        assert_eq!(r, e);
    }

    unsafe {
        let a = u32x8(0, 1, 2, 3, 4, 5, 6, 7);
        let b = u32x8(8, 9, 10, 11, 12, 13, 14, 15);

        let r: u32x8 = simd_select_bitmask(0u8, a, b);
        let e = b;
        assert_eq!(r, e);

        let r: u32x8 = simd_select_bitmask(0xffu8, a, b);
        let e = a;
        assert_eq!(r, e);

        let r: u32x8 = simd_select_bitmask(0b01010101u8, a, b);
        let e = u32x8(0, 9, 2, 11, 4, 13, 6, 15);
        assert_eq!(r, e);

        let r: u32x8 = simd_select_bitmask(0b10101010u8, a, b);
        let e = u32x8(8, 1, 10, 3, 12, 5, 14, 7);
        assert_eq!(r, e);

        let r: u32x8 = simd_select_bitmask(0b11110000u8, a, b);
        let e = u32x8(8, 9, 10, 11, 4, 5, 6, 7);
        assert_eq!(r, e);
    }
}
<|endoftext|>


<commit_before>use crate::utils::{differing_macro_contexts, in_macro, snippet_opt, span_note_and_lint};
use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintPass};
use rustc::{declare_tool_lint, lint_array};
use syntax::ast;
use syntax::ptr::P;

declare_clippy_lint! {
    /// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-`
    /// operators.
    ///
    /// **Why is this bad?** This is either a typo of `*=`, `!=` or `-=` or
    /// confusing.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// a =- 42; // confusing, should it be `a -= 42` or `a = -42`?
    /// ```
    pub SUSPICIOUS_ASSIGNMENT_FORMATTING,
    style,
    "suspicious formatting of `*=`, `-=` or `!=`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for formatting of `else`. It lints if the `else`
    /// is followed immediately by a newline or the `else` seems to be missing.
    ///
    /// **Why is this bad?** This is probably some refactoring remnant, even if the
    /// code is correct, it might look confusing.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// if foo {
    /// } { // looks like an `else` is missing here
    /// }
    ///
    /// if foo {
    /// } if bar { // looks like an `else` is missing here
    /// }
    ///
    /// if foo {
    /// } else
    ///
    /// { // this is the `else` block of the previous `if`, but should it be?
    /// }
    ///
    /// if foo {
    /// } else
    ///
    /// if bar { // this is the `else` block of the previous `if`, but should it be?
    /// }
    /// ```
    pub SUSPICIOUS_ELSE_FORMATTING,
    style,
    "suspicious formatting of `else`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for possible missing comma in an array. It lints if
    /// an array element is a binary operator expression and it lies on two lines.
    ///
    /// **Why is this bad?** This could lead to unexpected results.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// let a = &[
    ///     -1, -2, -3 // <= no comma here
    ///     -4, -5, -6
    /// ];
    /// ```
    pub POSSIBLE_MISSING_COMMA,
    correctness,
    "possible missing comma in array"
}

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

impl LintPass for Formatting {
    fn get_lints(&self) -> LintArray {
        lint_array!(
            SUSPICIOUS_ASSIGNMENT_FORMATTING,
            SUSPICIOUS_ELSE_FORMATTING,
            POSSIBLE_MISSING_COMMA
        )
    }

    fn name(&self) -> &'static str {
        "Formatting"
    }
}

impl EarlyLintPass for Formatting {
    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
        for w in block.stmts.windows(2) {
            match (&w[0].node, &w[1].node) {
                (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second))
                | (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref second)) => {
                    check_missing_else(cx, first, second);
                },
                _ => (),
            }
        }
    }

    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
        check_assign(cx, expr);
        check_else(cx, expr);
        check_array(cx, expr);
    }
}

/// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint.
fn check_assign(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let ast::ExprKind::Assign(ref lhs, ref rhs) = expr.node {
        if !differing_macro_contexts(lhs.span, rhs.span) && !in_macro(lhs.span) {
            let eq_span = lhs.span.between(rhs.span);
            if let ast::ExprKind::Unary(op, ref sub_rhs) = rhs.node {
                if let Some(eq_snippet) = snippet_opt(cx, eq_span) {
                    let op = ast::UnOp::to_string(op);
                    let eqop_span = lhs.span.between(sub_rhs.span);
                    if eq_snippet.ends_with('=') {
                        span_note_and_lint(
                            cx,
                            SUSPICIOUS_ASSIGNMENT_FORMATTING,
                            eqop_span,
                            &format!(
                                "this looks like you are trying to use `.. {op}= ..`, but you \
                                 really are doing `.. = ({op} ..)`",
                                op = op
                            ),
                            eqop_span,
                            &format!("to remove this lint, use either `{op}=` or `= {op}`", op = op),
                        );
                    }
                }
            }
        }
    }
}

/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else`.
fn check_else(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let Some((then, &Some(ref else_))) = unsugar_if(expr) {
        if (is_block(else_) || unsugar_if(else_).is_some())
            && !differing_macro_contexts(then.span, else_.span)
            && !in_macro(then.span)
            && !in_external_macro(cx.sess, expr.span)
        {
            // workaround for rust-lang/rust#43081
            if expr.span.lo().0 == 0 && expr.span.hi().0 == 0 {
                return;
            }

            // this will be a span from the closing ‘}’ of the “then” block (excluding) to
            // the
            // “if” of the “else if” block (excluding)
            let else_span = then.span.between(else_.span);

            // the snippet should look like " else \n    " with maybe comments anywhere
            // it’s bad when there is a ‘\n’ after the “else”
            if let Some(else_snippet) = snippet_opt(cx, else_span) {
                let else_pos = else_snippet.find("else").expect("there must be a `else` here");

                if else_snippet[else_pos..].contains('\n') {
                    let else_desc = if unsugar_if(else_).is_some() { "if" } else { "{..}" };

                    span_note_and_lint(
                        cx,
                        SUSPICIOUS_ELSE_FORMATTING,
                        else_span,
                        &format!("this is an `else {}` but the formatting might hide it", else_desc),
                        else_span,
                        &format!(
                            "to remove this lint, remove the `else` or remove the new line between \
                             `else` and `{}`",
                            else_desc,
                        ),
                    );
                }
            }
        }
    }
}

fn has_unary_equivalent(bin_op: ast::BinOpKind) -> bool {
    // &, *, -
    bin_op == ast::BinOpKind::And || bin_op == ast::BinOpKind::Mul || bin_op == ast::BinOpKind::Sub
}

/// Implementation of the `POSSIBLE_MISSING_COMMA` lint for array
fn check_array(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let ast::ExprKind::Array(ref array) = expr.node {
        for element in array {
            if let ast::ExprKind::Binary(ref op, ref lhs, _) = element.node {
                if has_unary_equivalent(op.node) && !differing_macro_contexts(lhs.span, op.span) {
                    let space_span = lhs.span.between(op.span);
                    if let Some(space_snippet) = snippet_opt(cx, space_span) {
                        let lint_span = lhs.span.with_lo(lhs.span.hi());
                        if space_snippet.contains('\n') {
                            span_note_and_lint(
                                cx,
                                POSSIBLE_MISSING_COMMA,
                                lint_span,
                                "possibly missing a comma here",
                                lint_span,
                                "to remove this lint, add a comma or write the expr in a single line",
                            );
                        }
                    }
                }
            }
        }
    }
}

fn check_missing_else(cx: &EarlyContext<'_>, first: &ast::Expr, second: &ast::Expr) {
    if !differing_macro_contexts(first.span, second.span)
        && !in_macro(first.span)
        && unsugar_if(first).is_some()
        && (is_block(second) || unsugar_if(second).is_some())
    {
        // where the else would be
        let else_span = first.span.between(second.span);

        if let Some(else_snippet) = snippet_opt(cx, else_span) {
            if !else_snippet.contains('\n') {
                let (looks_like, next_thing) = if unsugar_if(second).is_some() {
                    ("an `else if`", "the second `if`")
                } else {
                    ("an `else {..}`", "the next block")
                };

                span_note_and_lint(
                    cx,
                    SUSPICIOUS_ELSE_FORMATTING,
                    else_span,
                    &format!("this looks like {} but the `else` is missing", looks_like),
                    else_span,
                    &format!(
                        "to remove this lint, add the missing `else` or add a new line before {}",
                        next_thing,
                    ),
                );
            }
        }
    }
}

fn is_block(expr: &ast::Expr) -> bool {
    if let ast::ExprKind::Block(..) = expr.node {
        true
    } else {
        false
    }
}

/// Match `if` or `if let` expressions and return the `then` and `else` block.
fn unsugar_if(expr: &ast::Expr) -> Option<(&P<ast::Block>, &Option<P<ast::Expr>>)> {
    match expr.node {
        ast::ExprKind::If(_, ref then, ref else_) | ast::ExprKind::IfLet(_, _, ref then, ref else_) => {
            Some((then, else_))
        },
        _ => None,
    }
}
<commit_msg>Remove `except` in suspicious_else_formatting<commit_after>use crate::utils::{differing_macro_contexts, in_macro, snippet_opt, span_note_and_lint};
use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintPass};
use rustc::{declare_tool_lint, lint_array};
use syntax::ast;
use syntax::ptr::P;

declare_clippy_lint! {
    /// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-`
    /// operators.
    ///
    /// **Why is this bad?** This is either a typo of `*=`, `!=` or `-=` or
    /// confusing.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// a =- 42; // confusing, should it be `a -= 42` or `a = -42`?
    /// ```
    pub SUSPICIOUS_ASSIGNMENT_FORMATTING,
    style,
    "suspicious formatting of `*=`, `-=` or `!=`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for formatting of `else`. It lints if the `else`
    /// is followed immediately by a newline or the `else` seems to be missing.
    ///
    /// **Why is this bad?** This is probably some refactoring remnant, even if the
    /// code is correct, it might look confusing.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// if foo {
    /// } { // looks like an `else` is missing here
    /// }
    ///
    /// if foo {
    /// } if bar { // looks like an `else` is missing here
    /// }
    ///
    /// if foo {
    /// } else
    ///
    /// { // this is the `else` block of the previous `if`, but should it be?
    /// }
    ///
    /// if foo {
    /// } else
    ///
    /// if bar { // this is the `else` block of the previous `if`, but should it be?
    /// }
    /// ```
    pub SUSPICIOUS_ELSE_FORMATTING,
    style,
    "suspicious formatting of `else`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for possible missing comma in an array. It lints if
    /// an array element is a binary operator expression and it lies on two lines.
    ///
    /// **Why is this bad?** This could lead to unexpected results.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// let a = &[
    ///     -1, -2, -3 // <= no comma here
    ///     -4, -5, -6
    /// ];
    /// ```
    pub POSSIBLE_MISSING_COMMA,
    correctness,
    "possible missing comma in array"
}

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

impl LintPass for Formatting {
    fn get_lints(&self) -> LintArray {
        lint_array!(
            SUSPICIOUS_ASSIGNMENT_FORMATTING,
            SUSPICIOUS_ELSE_FORMATTING,
            POSSIBLE_MISSING_COMMA
        )
    }

    fn name(&self) -> &'static str {
        "Formatting"
    }
}

impl EarlyLintPass for Formatting {
    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
        for w in block.stmts.windows(2) {
            match (&w[0].node, &w[1].node) {
                (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second))
                | (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref second)) => {
                    check_missing_else(cx, first, second);
                },
                _ => (),
            }
        }
    }

    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
        check_assign(cx, expr);
        check_else(cx, expr);
        check_array(cx, expr);
    }
}

/// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint.
fn check_assign(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let ast::ExprKind::Assign(ref lhs, ref rhs) = expr.node {
        if !differing_macro_contexts(lhs.span, rhs.span) && !in_macro(lhs.span) {
            let eq_span = lhs.span.between(rhs.span);
            if let ast::ExprKind::Unary(op, ref sub_rhs) = rhs.node {
                if let Some(eq_snippet) = snippet_opt(cx, eq_span) {
                    let op = ast::UnOp::to_string(op);
                    let eqop_span = lhs.span.between(sub_rhs.span);
                    if eq_snippet.ends_with('=') {
                        span_note_and_lint(
                            cx,
                            SUSPICIOUS_ASSIGNMENT_FORMATTING,
                            eqop_span,
                            &format!(
                                "this looks like you are trying to use `.. {op}= ..`, but you \
                                 really are doing `.. = ({op} ..)`",
                                op = op
                            ),
                            eqop_span,
                            &format!("to remove this lint, use either `{op}=` or `= {op}`", op = op),
                        );
                    }
                }
            }
        }
    }
}

/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else`.
fn check_else(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let Some((then, &Some(ref else_))) = unsugar_if(expr) {
        if (is_block(else_) || unsugar_if(else_).is_some())
            && !differing_macro_contexts(then.span, else_.span)
            && !in_macro(then.span)
            && !in_external_macro(cx.sess, expr.span)
        {
            // workaround for rust-lang/rust#43081
            if expr.span.lo().0 == 0 && expr.span.hi().0 == 0 {
                return;
            }

            // this will be a span from the closing ‘}’ of the “then” block (excluding) to
            // the
            // “if” of the “else if” block (excluding)
            let else_span = then.span.between(else_.span);

            // the snippet should look like " else \n    " with maybe comments anywhere
            // it’s bad when there is a ‘\n’ after the “else”
            if let Some(else_snippet) = snippet_opt(cx, else_span) {
                if let Some(else_pos) = else_snippet.find("else") {
                    if else_snippet[else_pos..].contains('\n') {
                        let else_desc = if unsugar_if(else_).is_some() { "if" } else { "{..}" };

                        span_note_and_lint(
                            cx,
                            SUSPICIOUS_ELSE_FORMATTING,
                            else_span,
                            &format!("this is an `else {}` but the formatting might hide it", else_desc),
                            else_span,
                            &format!(
                                "to remove this lint, remove the `else` or remove the new line between \
                                 `else` and `{}`",
                                else_desc,
                            ),
                        );
                    }
                }
            }
        }
    }
}

fn has_unary_equivalent(bin_op: ast::BinOpKind) -> bool {
    // &, *, -
    bin_op == ast::BinOpKind::And || bin_op == ast::BinOpKind::Mul || bin_op == ast::BinOpKind::Sub
}

/// Implementation of the `POSSIBLE_MISSING_COMMA` lint for array
fn check_array(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let ast::ExprKind::Array(ref array) = expr.node {
        for element in array {
            if let ast::ExprKind::Binary(ref op, ref lhs, _) = element.node {
                if has_unary_equivalent(op.node) && !differing_macro_contexts(lhs.span, op.span) {
                    let space_span = lhs.span.between(op.span);
                    if let Some(space_snippet) = snippet_opt(cx, space_span) {
                        let lint_span = lhs.span.with_lo(lhs.span.hi());
                        if space_snippet.contains('\n') {
                            span_note_and_lint(
                                cx,
                                POSSIBLE_MISSING_COMMA,
                                lint_span,
                                "possibly missing a comma here",
                                lint_span,
                                "to remove this lint, add a comma or write the expr in a single line",
                            );
                        }
                    }
                }
            }
        }
    }
}

fn check_missing_else(cx: &EarlyContext<'_>, first: &ast::Expr, second: &ast::Expr) {
    if !differing_macro_contexts(first.span, second.span)
        && !in_macro(first.span)
        && unsugar_if(first).is_some()
        && (is_block(second) || unsugar_if(second).is_some())
    {
        // where the else would be
        let else_span = first.span.between(second.span);

        if let Some(else_snippet) = snippet_opt(cx, else_span) {
            if !else_snippet.contains('\n') {
                let (looks_like, next_thing) = if unsugar_if(second).is_some() {
                    ("an `else if`", "the second `if`")
                } else {
                    ("an `else {..}`", "the next block")
                };

                span_note_and_lint(
                    cx,
                    SUSPICIOUS_ELSE_FORMATTING,
                    else_span,
                    &format!("this looks like {} but the `else` is missing", looks_like),
                    else_span,
                    &format!(
                        "to remove this lint, add the missing `else` or add a new line before {}",
                        next_thing,
                    ),
                );
            }
        }
    }
}

fn is_block(expr: &ast::Expr) -> bool {
    if let ast::ExprKind::Block(..) = expr.node {
        true
    } else {
        false
    }
}

/// Match `if` or `if let` expressions and return the `then` and `else` block.
fn unsugar_if(expr: &ast::Expr) -> Option<(&P<ast::Block>, &Option<P<ast::Expr>>)> {
    match expr.node {
        ast::ExprKind::If(_, ref then, ref else_) | ast::ExprKind::IfLet(_, _, ref then, ref else_) => {
            Some((then, else_))
        },
        _ => None,
    }
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(asm)]
#![feature(macro_rules)]
#![feature(simd)]

extern crate serialize;
extern crate test;

pub mod aes;
pub mod aessafe;
pub mod bcrypt;
pub mod bcrypt_pbkdf;
pub mod blockmodes;
pub mod blowfish;
pub mod buffer;
pub mod chacha20;
mod cryptoutil;
pub mod digest;
pub mod hmac;
pub mod mac;
pub mod md5;
pub mod pbkdf2;
pub mod poly1305;
pub mod rc4;
pub mod salsa20;
pub mod scrypt;
pub mod sha1;
pub mod sha2;
pub mod symmetriccipher;
pub mod util;

#[cfg(target_arch = "x86")]
#[cfg(target_arch = "x86_64")]
pub mod aesni;
<commit_msg>Add ripemd160.rs to the test.rs module<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(asm)]
#![feature(macro_rules)]
#![feature(simd)]

extern crate serialize;
extern crate test;

pub mod aes;
pub mod aessafe;
pub mod bcrypt;
pub mod bcrypt_pbkdf;
pub mod blockmodes;
pub mod blowfish;
pub mod buffer;
pub mod chacha20;
mod cryptoutil;
pub mod digest;
pub mod hmac;
pub mod mac;
pub mod md5;
pub mod pbkdf2;
pub mod poly1305;
pub mod ripemd160;
pub mod rc4;
pub mod salsa20;
pub mod scrypt;
pub mod sha1;
pub mod sha2;
pub mod symmetriccipher;
pub mod util;

#[cfg(target_arch = "x86")]
#[cfg(target_arch = "x86_64")]
pub mod aesni;
<|endoftext|>


<commit_before>use rules::Rule;

pub struct OwnLineBrace {

}

impl OwnLineBrace {
	pub fn new() -> OwnLineBrace {
		OwnLineBrace {  }
	}
}

impl Rule for OwnLineBrace {
	fn verify(&self, filename: &str, content: &str) -> Vec<String> {
		let mut errors = Vec::new();
		let mut line_number: usize = 1;

		for line in content.lines() {
			if line.contains("{") && line.chars().filter(|c| !c.is_whitespace() && *c != '{').count() > 0 {
				errors.push(format!("[{}:{}]Opening brace must be on their own line.", filename, line_number));
			}
			else if line.contains("}") && line.chars().filter(|c| !c.is_whitespace() && *c != '}' && *c != ';').count() > 0 {
				errors.push(format!("[{}:{}]Closing brace must be on their own line.", filename, line_number));
			}

			line_number += 1;
		}

		return errors;
	}
}

pub struct IndentationLevel {
	nb_spaces: usize
}

impl IndentationLevel {
	pub fn new(nb_spaces_per_indentation_level: usize) -> IndentationLevel {
		IndentationLevel { nb_spaces: nb_spaces_per_indentation_level }
	}
}

impl Rule for IndentationLevel {
	fn verify(&self, filename: &str, content: &str) -> Vec<String> {
		let mut errors = Vec::new();
		let mut line_number: usize = 1;
		let mut indentation_level: usize = 0;

		for line in content.lines() {
			if line.contains("}") {
				if indentation_level > 0 {
					indentation_level -= 1;
				}
				else {
					errors.push(format!("[{}:{}]Unexpected closing brace.", filename, line_number));
				}
			}

			//Test of indentation
			if line.trim().len() > 0 {
				let current_indentation = line.len() - line.trim_left().len();
				if current_indentation != indentation_level * self.nb_spaces {
					errors.push(format!("[{}:{}]Wrong indentation level. Expected {} got {}",
						filename, line_number, indentation_level * self.nb_spaces, current_indentation));
				}
			}

			if line.contains("{") {
				indentation_level += 1;
			}

			line_number += 1;
		}

		if indentation_level > 0 {
			errors.push(format!("[{}:{}]Expected closing brace.", filename, line_number));
		}

		return errors;
	}
}
<commit_msg>OwnLineBrace pass all test<commit_after>use rules::Rule;

pub struct OwnLineBrace {

}

impl OwnLineBrace {
	pub fn new() -> OwnLineBrace {
		OwnLineBrace {  }
	}
}

impl Rule for OwnLineBrace {
	fn verify(&self, filename: &str, content: &str) -> Vec<String> {
		let mut errors = Vec::new();
		let mut line_number: usize = 1;

		for line in content.lines() {
			if line.contains("{") && line.chars().filter(|c| !c.is_whitespace()).count() > 1 {
				errors.push(format!("[{}:{}]Opening brace must be on their own line.", filename, line_number));
			}
			else if line.contains("}") {
				let nb_non_white_char =  line.chars().filter(|c| !c.is_whitespace()).count();
				if !(nb_non_white_char == 1 || (nb_non_white_char == 2 && line.contains("};"))) {
					errors.push(format!("[{}:{}]Closing brace must be on their own line.", filename, line_number));
				}
			}

			line_number += 1;
		}

		return errors;
	}
}

pub struct IndentationLevel {
	nb_spaces: usize
}

impl IndentationLevel {
	pub fn new(nb_spaces_per_indentation_level: usize) -> IndentationLevel {
		IndentationLevel { nb_spaces: nb_spaces_per_indentation_level }
	}
}

impl Rule for IndentationLevel {
	fn verify(&self, filename: &str, content: &str) -> Vec<String> {
		let mut errors = Vec::new();
		let mut line_number: usize = 1;
		let mut indentation_level: usize = 0;

		for line in content.lines() {
			if line.contains("}") {
				if indentation_level > 0 {
					indentation_level -= 1;
				}
				else {
					errors.push(format!("[{}:{}]Unexpected closing brace.", filename, line_number));
				}
			}

			//Test of indentation
			if line.trim().len() > 0 {
				let current_indentation = line.len() - line.trim_left().len();
				if current_indentation != indentation_level * self.nb_spaces {
					errors.push(format!("[{}:{}]Wrong indentation level. Expected {} got {}",
						filename, line_number, indentation_level * self.nb_spaces, current_indentation));
				}
			}

			if line.contains("{") {
				indentation_level += 1;
			}

			line_number += 1;
		}

		if indentation_level > 0 {
			errors.push(format!("[{}:{}]Expected closing brace.", filename, line_number));
		}

		return errors;
	}
}

#[cfg(test)]
mod test {
	use super::*;
	#[test]
	fn own_line_brace() {
		let own_line_brace = OwnLineBrace::new();

		assert_eq!(own_line_brace.verify("", "{\nsome text\n}\n").len(), 0);
		assert_eq!(own_line_brace.verify("", "  {  ").len(), 0);
		assert_eq!(own_line_brace.verify("", "};").len(), 0);

		assert_ne!(own_line_brace.verify("", "{}\n").len(), 0);
		assert_ne!(own_line_brace.verify("", "}}").len(), 0);
		assert_ne!(own_line_brace.verify("", "{{").len(), 0);

		assert_eq!(own_line_brace.verify("", "{some").len(), 1);
		assert_eq!(own_line_brace.verify("", ";}").len(), 1);
		assert_eq!(own_line_brace.verify("", "} ;").len(), 1);

	}

	#[test]
	fn indentation_level() {
		let indentation_level = IndentationLevel::new(4);

		assert_eq!(indentation_level.verify("", "             ").len(), 0);
		assert_eq!(indentation_level.verify("", "{\n    \n}   ").len(), 0);
		assert_eq!(indentation_level.verify("", "{\n    {\n    }\n}   ").len(), 0);

		//Missing closing and opening brace
		assert_eq!(indentation_level.verify("", "{").len(), 1);
		assert_eq!(indentation_level.verify("", "}").len(), 1);

		//Wrong indentation
		assert_eq!(indentation_level.verify("", "{\n 56\n}").len(), 1);
		assert_eq!(indentation_level.verify("", "{\n     56\n}").len(), 1);
		assert_eq!(indentation_level.verify("", "{\n    {\n  }\n}   ").len(), 1);
		assert_eq!(indentation_level.verify("", "{\n    {\n    test\n    }\n}   ").len(), 1);
	}
}
<|endoftext|>