<commit_before>//! Implements single-threaded game tree search.

use basetypes::*;
use bitsets::*;
use chess_move::*;
use tt::*;
use position::Position;

/// Represents a terminated search condition.
pub struct TerminatedSearch;

/// Represents a game tree search.
pub struct Search<'a> {
    tt: &'a TranspositionTable,
    position: Position,
    moves: &'a mut MoveStack,
    moves_starting_ply: usize,
    state_stack: Vec<NodeState>,
    reported_nodes: NodeCount,
    unreported_nodes: NodeCount,
    report_function: &'a mut FnMut(NodeCount) -> bool,
}

impl<'a> Search<'a> {
    /// Creates a new instance.
    ///
    /// `report_function` should be a function that registers the
    /// search progress. It will be called with the number of searched
    /// positions from the beginning of the search to this moment. The
    /// function should return `true` if the search should be
    /// terminated, otherwise it should return `false`.
    pub fn new(root: Position,
               tt: &'a TranspositionTable,
               move_stack: &'a mut MoveStack,
               report_function: &'a mut FnMut(NodeCount) -> bool)
               -> Search<'a> {
        let moves_starting_ply = move_stack.ply();
        Search {
            tt: tt,
            position: root,
            moves: move_stack,
            moves_starting_ply: moves_starting_ply,
            state_stack: Vec::with_capacity(32),
            reported_nodes: 0,
            unreported_nodes: 0,
            report_function: report_function,
        }
    }

    /// Performs a principal variation search (PVS) and returns a
    /// result.
    ///
    /// The alpha-beta algorithm is a significant enhancement to the
    /// minimax search algorithm that eliminates the need to search
    /// large portions of the game tree applying a branch-and-bound
    /// technique. Remarkably, it does this without any potential of
    /// overlooking a better move. If one already has found a quite
    /// good move and search for alternatives, one refutation is
    /// enough to avoid it. No need to look for even stronger
    /// refutations. The algorithm maintains two values, alpha and
    /// beta. They represent the minimum score that the maximizing
    /// player is assured of and the maximum score that the minimizing
    /// player is assured of respectively. PVS is an enhancement to
    /// the alpha-beta search, based on zero (null) window searches of
    /// none PV-nodes, to prove a move is worse or not than an already
    /// safe score from the principal variation. (The principal
    /// variation (PV) is a sequence of moves that the program
    /// considers best and therefore expects to be played.)
    ///
    /// **Important note**: This method may leave un-restored move
    /// lists in the move stack. Call `reset` if you want the move
    /// stack to be restored to the state it had when the search
    /// instance was created.
    pub fn run(&mut self,
               mut alpha: Value, // lower bound
               beta: Value, // upper bound
               depth: u8)
               -> Result<Value, TerminatedSearch> {
        assert!(alpha < beta);

        if let Some(value) = self.node_begin(alpha, beta, depth) {
            // We already have the final result.
            alpha = value;

        } else {
            // Initial guests.
            let mut bound = BOUND_UPPER;
            let mut best_move = Move::invalid();

            // Try moves.
            let mut no_moves_yet = true;
            while let Some(m) = self.do_move() {
                try!(self.report_progress(1));

                // Make a recursive call.
                let value = if no_moves_yet {
                    // The first move we analyze with a fully open window
                    // (alpha, beta). If this happens to be a good move,
                    // it will probably raise `alpha`.
                    no_moves_yet = false;
                    -try!(self.run(-beta, -alpha, depth - 1))
                } else {
                    // For the next moves we first try to prove that they
                    // are not better than our current best move. For this
                    // purpose we analyze them with a null window (alpha,
                    // alpha + 1). This is faster than a full window
                    // search. Only if we are certain that the move is
                    // better than our current best move, we do a
                    // full-window search.
                    match -try!(self.run(-alpha - 1, -alpha, depth - 1)) {
                        x if x <= alpha => x,
                        _ => -try!(self.run(-beta, -alpha, depth - 1)),
                    }
                };
                self.undo_move();

                // See how good this move was.
                if value >= beta {
                    // This move is so good, that the opponent will
                    // probably not allow this line of play to
                    // happen. Therefore we should not lose any more time
                    // on this position.
                    alpha = beta;
                    bound = BOUND_LOWER;
                    best_move = m;
                    break;
                }
                if value > alpha {
                    // We found a new best move.
                    alpha = value;
                    bound = BOUND_EXACT;
                    best_move = m;
                }
            }

            // Check if we are in a final position (no legal moves).
            if no_moves_yet {
                let value = self.position.evaluate_final();
                if value >= beta {
                    alpha = beta;
                    bound = BOUND_LOWER;
                }
                if value > alpha {
                    alpha = value;
                    bound = BOUND_EXACT;
                }
            }

            // Store the result to the TT.
            self.store(alpha, bound, depth, best_move);
        }

        self.node_end();
        Ok(alpha)
    }

    /// Returns the number of searched positions.
    #[inline(always)]
    pub fn node_count(&self) -> NodeCount {
        self.reported_nodes + self.unreported_nodes
    }

    /// Resets the instance to the state it had when it was created.
    #[inline]
    pub fn reset(&mut self) {
        while self.moves.ply() > self.moves_starting_ply {
            self.moves.restore();
        }
        self.state_stack.clear();
        self.reported_nodes = 0;
        self.unreported_nodes = 0;
    }

    // Declares that we are starting to process a new node.
    //
    // Each recursive call to `run` begins with a call to
    // `node_begin`. The returned value (if not `None`) is the value
    // assigned to the node (taken from the TT or, on leaf nodes --
    // calculated by performing quiescence search).
    #[inline]
    fn node_begin(&mut self, alpha: Value, beta: Value, depth: u8) -> Option<Value> {
        // Consult the transposition table.
        let entry = if let Some(e) = self.tt.probe(self.position.hash()) {
            e
        } else {
            EntryData::new(0, BOUND_NONE, 0, 0, self.position.evaluate_static())
        };
        self.state_stack.push(NodeState {
            phase: NodePhase::Pristine,
            entry: entry,
            checkers: BB_UNIVERSAL_SET,
        });

        // Check if the TT entry gives the result.
        if entry.depth() >= depth {
            let value = entry.value();
            let bound = entry.bound();
            if value >= beta && bound & BOUND_LOWER != 0 {
                return Some(beta);
            }
            if value <= alpha && bound & BOUND_UPPER != 0 {
                return Some(alpha);
            }
            if bound == BOUND_EXACT {
                return Some(value);
            };
        };

        // On leaf nodes, do quiescence search.
        if depth == 0 {
            let eval_value = entry.eval_value();
            let (mut value, nodes) = self.position
                                         .evaluate_quiescence(alpha, beta, Some(eval_value));
            self.report_progress(nodes).ok();
            let bound = if value >= beta {
                value = beta;
                BOUND_LOWER
            } else if value <= alpha {
                value = alpha;
                BOUND_UPPER
            } else {
                BOUND_EXACT
            };
            self.tt.store(self.position.hash(),
                          EntryData::new(value, bound, 0, 0, eval_value));
            return Some(value);
        }

        None
    }

    // Declares that we are done processing the current node.
    //
    // Each recursive call to `run` ends with a call to `node_end`.
    #[inline]
    fn node_end(&mut self) {
        if let NodePhase::Pristine = self.state_stack.last().unwrap().phase {
            // For pristine nodes we have not saved the move list
            // yet, so we should not restore it.
        } else {
            self.moves.restore();
        }
        self.state_stack.pop();
    }

    // TODO: Implement do_null_move() method?

    // Plays the next legal move in the current position and returns
    // it.
    //
    // Each call to `do_move` for the same position will play and
    // return a different move. When all legal moves has been played,
    // `None` will be returned. `do_move` will do whatever it can to
    // play the best moves first, and the worst last. It will also try
    // to be efficient, for example it will generate the list of all
    // pseudo-legal moves at the last possible moment.
    #[inline]
    fn do_move(&mut self) -> Option<Move> {
        let state = self.state_stack.last_mut().unwrap();

        // Try the hash move first.
        if let NodePhase::Pristine = state.phase {
            // We save the move list at the last possible moment,
            // because most of the nodes are leafs.
            self.moves.save();

            // We save the checkers bitboard also, because we will
            // need this information later many times, and we do not
            // want to recalculate it needlessly.
            //
            // TODO: Verify if this is the best place to calculate
            // checkers, especially in relation to trying null moves.
            state.checkers = self.position.board().checkers();

            state.phase = NodePhase::TriedHashMove;
            if state.entry.move16() != 0 {
                if let Some(mut m) = self.position.try_move_digest(state.entry.move16()) {
                    if self.position.do_move(m) {
                        m.set_score(MAX_MOVE_SCORE);
                        return Some(m);
                    }
                }
            }
        }

        // After the hash move, we generate all pseudo-legal
        // moves. But we should not forget to remove the already tried
        // hash move from the list.
        if let NodePhase::TriedHashMove = state.phase {
            // TODO: `generate_moves` needs `_checkers` and `_pinned`
            // to do its work. At this time we already have generated
            // them, so we should use them.
            self.position.board()._checkers.set(state.checkers);

            self.position.generate_moves(self.moves);
            if state.entry.move16() != 0 {
                self.moves.remove_move(state.entry.move16());
            }
            state.phase = NodePhase::GeneratedMoves;
        }

        // Spit out the generated moves.
        while let Some(mut m) = self.moves.remove_best_move() {

            // First, the good captures.
            if let NodePhase::GeneratedMoves = state.phase {
                if m.score() == MAX_MOVE_SCORE {
                    if self.position.evaluate_move(m) >= 0 {
                        if self.position.do_move(m) {
                            return Some(m);
                        }
                        continue;
                    }
                    // This is a bad capture -- push it back to the
                    // move stack.
                    m.set_score(MAX_MOVE_SCORE - 1);
                    self.moves.push(m);
                    continue;
                }
                state.phase = NodePhase::TriedGoodCaptures;
            }

            // Second, the bad captures.
            if let NodePhase::TriedGoodCaptures = state.phase {
                if m.score() == MAX_MOVE_SCORE - 1 {
                    if self.position.do_move(m) {
                        return Some(m);
                    }
                    continue;
                }
                state.phase = NodePhase::TriedBadCaptures;
            }

            // Before trying the quiet moves, we should assign proper
            // move scores to them.
            if let NodePhase::TriedBadCaptures = state.phase {
                // TODO: Assign the moves scores here using the killer
                // move heuristics and the history heuristics.

                // We use the score field (2 bits) to properly order
                // quiet movies. Moves which destination square is
                // more advanced into enemy's territory are tried
                // first. The logic is that those moves are riskier,
                // so if such a move loses material this will be
                // detected early and the search tree will be pruned,
                // but if the move does not lose material, chances are
                // that it is a very good move.
                const SCORE_LOOKUP: [[u32; 8]; 2] = [// white
                                                     [0, 1, 2, 3, 4, 5, 6, 7],
                                                     // black
                                                     [7, 6, 5, 4, 3, 2, 1, 0]];
                for m in self.moves.iter_mut() {
                    let rank = rank(m.dest_square());
                    m.set_score(unsafe {
                        *SCORE_LOOKUP.get_unchecked(self.position.board().to_move())
                                     .get_unchecked(rank)
                    });
                }

                state.phase = NodePhase::SortedQuietMoves;
            }

            // Last, quiet moves.
            if self.position.do_move(m) {
                if state.checkers != 0 {
                    // When in check, we set a high move score to all
                    // moves to avoid search depth reductions.
                    m.set_score(MAX_MOVE_SCORE - 1);
                }
                return Some(m);
            }
        }
        None
    }

    // Takes the last played move back.
    #[inline]
    fn undo_move(&mut self) {
        self.position.undo_move();
    }

    // Stores updated node information in the transposition table.
    #[inline]
    fn store(&mut self, value: Value, bound: BoundType, depth: u8, best_move: Move) {
        let entry = &self.state_stack.last().unwrap().entry;
        self.tt.store(self.position.hash(),
                      EntryData::new(value, bound, depth, best_move.digest(), entry.eval_value()));
    }

    // Reports search progress.
    //
    // From time to time, we should report how many nodes had been
    // searched since the beginning of the search. This also gives an
    // opportunity for the search to be terminated.
    #[inline]
    fn report_progress(&mut self, new_nodes: NodeCount) -> Result<(), TerminatedSearch> {
        self.unreported_nodes += new_nodes;
        if self.unreported_nodes >= super::NODE_COUNT_REPORT_INTERVAL {
            self.reported_nodes += self.unreported_nodes;
            self.unreported_nodes = 0;
            if (*self.report_function)(self.reported_nodes) {
                return Err(TerminatedSearch);
            }
        }
        Ok(())
    }
}

enum NodePhase {
    Pristine,
    TriedHashMove,
    GeneratedMoves,
    TriedGoodCaptures,
    TriedBadCaptures,
    SortedQuietMoves,
}

struct NodeState {
    phase: NodePhase,
    entry: EntryData,
    checkers: u64,
}

#[cfg(test)]
mod tests {
    use super::Search;
    use chess_move::*;
    use tt::*;
    use position::Position;

    #[test]
    fn test_search() {
        let p = Position::from_fen("8/8/8/8/3q3k/7n/6PP/2Q2R1K b - - 0 1").ok().unwrap();
        let tt = TranspositionTable::new();
        let mut moves = MoveStack::new();
        let mut report = |_| false;
        let mut search = Search::new(p, &tt, &mut moves, &mut report);
        let value = search.run(-30000, 30000, 2)
                          .ok()
                          .unwrap();
        assert!(value < -300);
        search.reset();
        let value = search.run(-30000, 30000, 4)
                          .ok()
                          .unwrap();
        assert!(value >= 20000);
    }
}
<commit_msg>added TriedNullMove phase<commit_after>//! Implements single-threaded game tree search.

use basetypes::*;
use bitsets::*;
use chess_move::*;
use tt::*;
use position::Position;

/// Represents a terminated search condition.
pub struct TerminatedSearch;

/// Represents a game tree search.
pub struct Search<'a> {
    tt: &'a TranspositionTable,
    position: Position,
    moves: &'a mut MoveStack,
    moves_starting_ply: usize,
    state_stack: Vec<NodeState>,
    reported_nodes: NodeCount,
    unreported_nodes: NodeCount,
    report_function: &'a mut FnMut(NodeCount) -> bool,
}

impl<'a> Search<'a> {
    /// Creates a new instance.
    ///
    /// `report_function` should be a function that registers the
    /// search progress. It will be called with the number of searched
    /// positions from the beginning of the search to this moment. The
    /// function should return `true` if the search should be
    /// terminated, otherwise it should return `false`.
    pub fn new(root: Position,
               tt: &'a TranspositionTable,
               move_stack: &'a mut MoveStack,
               report_function: &'a mut FnMut(NodeCount) -> bool)
               -> Search<'a> {
        let moves_starting_ply = move_stack.ply();
        Search {
            tt: tt,
            position: root,
            moves: move_stack,
            moves_starting_ply: moves_starting_ply,
            state_stack: Vec::with_capacity(32),
            reported_nodes: 0,
            unreported_nodes: 0,
            report_function: report_function,
        }
    }

    /// Performs a principal variation search (PVS) and returns a
    /// result.
    ///
    /// The alpha-beta algorithm is a significant enhancement to the
    /// minimax search algorithm that eliminates the need to search
    /// large portions of the game tree applying a branch-and-bound
    /// technique. Remarkably, it does this without any potential of
    /// overlooking a better move. If one already has found a quite
    /// good move and search for alternatives, one refutation is
    /// enough to avoid it. No need to look for even stronger
    /// refutations. The algorithm maintains two values, alpha and
    /// beta. They represent the minimum score that the maximizing
    /// player is assured of and the maximum score that the minimizing
    /// player is assured of respectively. PVS is an enhancement to
    /// the alpha-beta search, based on zero (null) window searches of
    /// none PV-nodes, to prove a move is worse or not than an already
    /// safe score from the principal variation. (The principal
    /// variation (PV) is a sequence of moves that the program
    /// considers best and therefore expects to be played.)
    ///
    /// **Important note**: This method may leave un-restored move
    /// lists in the move stack. Call `reset` if you want the move
    /// stack to be restored to the state it had when the search
    /// instance was created.
    pub fn run(&mut self,
               mut alpha: Value, // lower bound
               beta: Value, // upper bound
               depth: u8)
               -> Result<Value, TerminatedSearch> {
        assert!(alpha < beta);

        if let Some(value) = self.node_begin(alpha, beta, depth) {
            // We already have the final result.
            alpha = value;

        } else {
            // Initial guests.
            let mut bound = BOUND_UPPER;
            let mut best_move = Move::invalid();

            // Try moves.
            let mut no_moves_yet = true;
            while let Some(m) = self.do_move() {
                try!(self.report_progress(1));

                // Make a recursive call.
                let value = if no_moves_yet {
                    // The first move we analyze with a fully open window
                    // (alpha, beta). If this happens to be a good move,
                    // it will probably raise `alpha`.
                    no_moves_yet = false;
                    -try!(self.run(-beta, -alpha, depth - 1))
                } else {
                    // For the next moves we first try to prove that they
                    // are not better than our current best move. For this
                    // purpose we analyze them with a null window (alpha,
                    // alpha + 1). This is faster than a full window
                    // search. Only if we are certain that the move is
                    // better than our current best move, we do a
                    // full-window search.
                    match -try!(self.run(-alpha - 1, -alpha, depth - 1)) {
                        x if x <= alpha => x,
                        _ => -try!(self.run(-beta, -alpha, depth - 1)),
                    }
                };
                self.undo_move();

                // See how good this move was.
                if value >= beta {
                    // This move is so good, that the opponent will
                    // probably not allow this line of play to
                    // happen. Therefore we should not lose any more time
                    // on this position.
                    alpha = beta;
                    bound = BOUND_LOWER;
                    best_move = m;
                    break;
                }
                if value > alpha {
                    // We found a new best move.
                    alpha = value;
                    bound = BOUND_EXACT;
                    best_move = m;
                }
            }

            // Check if we are in a final position (no legal moves).
            if no_moves_yet {
                let value = self.position.evaluate_final();
                if value >= beta {
                    alpha = beta;
                    bound = BOUND_LOWER;
                }
                if value > alpha {
                    alpha = value;
                    bound = BOUND_EXACT;
                }
            }

            // Store the result to the TT.
            self.store(alpha, bound, depth, best_move);
        }

        self.node_end();
        Ok(alpha)
    }

    /// Returns the number of searched positions.
    #[inline(always)]
    pub fn node_count(&self) -> NodeCount {
        self.reported_nodes + self.unreported_nodes
    }

    /// Resets the instance to the state it had when it was created.
    #[inline]
    pub fn reset(&mut self) {
        while self.moves.ply() > self.moves_starting_ply {
            self.moves.restore();
        }
        self.state_stack.clear();
        self.reported_nodes = 0;
        self.unreported_nodes = 0;
    }

    // Declares that we are starting to process a new node.
    //
    // Each recursive call to `run` begins with a call to
    // `node_begin`. The returned value (if not `None`) is the value
    // assigned to the node (taken from the TT or, on leaf nodes --
    // calculated by performing quiescence search).
    #[inline]
    fn node_begin(&mut self, alpha: Value, beta: Value, depth: u8) -> Option<Value> {
        // Consult the transposition table.
        let entry = if let Some(e) = self.tt.probe(self.position.hash()) {
            e
        } else {
            EntryData::new(0, BOUND_NONE, 0, 0, self.position.evaluate_static())
        };
        self.state_stack.push(NodeState {
            phase: NodePhase::Pristine,
            entry: entry,
            checkers: BB_UNIVERSAL_SET,
            pinned: BB_UNIVERSAL_SET,
        });

        // Check if the TT entry gives the result.
        if entry.depth() >= depth {
            let value = entry.value();
            let bound = entry.bound();
            if value >= beta && bound & BOUND_LOWER != 0 {
                return Some(beta);
            }
            if value <= alpha && bound & BOUND_UPPER != 0 {
                return Some(alpha);
            }
            if bound == BOUND_EXACT {
                return Some(value);
            };
        };

        // On leaf nodes, do quiescence search.
        if depth == 0 {
            let eval_value = entry.eval_value();
            let (mut value, nodes) = self.position
                                         .evaluate_quiescence(alpha, beta, Some(eval_value));
            self.report_progress(nodes).ok();
            let bound = if value >= beta {
                value = beta;
                BOUND_LOWER
            } else if value <= alpha {
                value = alpha;
                BOUND_UPPER
            } else {
                BOUND_EXACT
            };
            self.tt.store(self.position.hash(),
                          EntryData::new(value, bound, 0, 0, eval_value));
            return Some(value);
        }

        // We save checkers and pinned bitboards, because we will need
        // this information later many times, and we do not want to
        // recalculate it needlessly.
        let state = self.state_stack.last_mut().unwrap();
        state.checkers = self.position.board().checkers();
        state.pinned = self.position.board().pinned();

        // Before trying the null move, we should not forget the save
        // the current move list.
        self.moves.save();

        // TODO: Try the null move here.
        state.phase = NodePhase::TriedNullMove;

        None
    }

    // Declares that we are done processing the current node.
    //
    // Each recursive call to `run` ends with a call to `node_end`.
    #[inline]
    fn node_end(&mut self) {
        if let NodePhase::Pristine = self.state_stack.last().unwrap().phase {
            // For pristine nodes we have not saved the move list
            // yet, so we should not restore it.
        } else {
            self.moves.restore();
        }
        self.state_stack.pop();
    }

    // TODO: Implement do_null_move() method?

    // Plays the next legal move in the current position and returns
    // it.
    //
    // Each call to `do_move` for the same position will play and
    // return a different move. When all legal moves has been played,
    // `None` will be returned. `do_move` will do whatever it can to
    // play the best moves first, and the worst last. It will also try
    // to be efficient, for example it will generate the list of all
    // pseudo-legal moves at the last possible moment.
    #[inline]
    fn do_move(&mut self) -> Option<Move> {
        let state = self.state_stack.last_mut().unwrap();

        if let NodePhase::Pristine = state.phase {
            panic!("wrong node state");
        }

        // Try the hash move first.
        if let NodePhase::TriedNullMove = state.phase {
            state.phase = NodePhase::TriedHashMove;
            if state.entry.move16() != 0 {
                if let Some(mut m) = self.position.try_move_digest(state.entry.move16()) {
                    if self.position.do_move(m) {
                        m.set_score(MAX_MOVE_SCORE);
                        return Some(m);
                    }
                }
            }
        }

        // After the hash move, we generate all pseudo-legal
        // moves. But we should not forget to remove the already tried
        // hash move from the list.
        if let NodePhase::TriedHashMove = state.phase {
            // TODO: `generate_moves` needs `_checkers` and `_pinned`
            // to do its work. At this time we already have generated
            // them, so we should use them.
            self.position.board()._checkers.set(state.checkers);

            self.position.generate_moves(self.moves);
            if state.entry.move16() != 0 {
                self.moves.remove_move(state.entry.move16());
            }
            state.phase = NodePhase::GeneratedMoves;
        }

        // Spit out the generated moves.
        while let Some(mut m) = self.moves.remove_best_move() {

            // First, the good captures.
            if let NodePhase::GeneratedMoves = state.phase {
                if m.score() == MAX_MOVE_SCORE {
                    if self.position.evaluate_move(m) >= 0 {
                        if self.position.do_move(m) {
                            return Some(m);
                        }
                        continue;
                    }
                    // This is a bad capture -- push it back to the
                    // move stack.
                    m.set_score(MAX_MOVE_SCORE - 1);
                    self.moves.push(m);
                    continue;
                }
                state.phase = NodePhase::TriedGoodCaptures;
            }

            // Second, the bad captures.
            if let NodePhase::TriedGoodCaptures = state.phase {
                if m.score() == MAX_MOVE_SCORE - 1 {
                    if self.position.do_move(m) {
                        return Some(m);
                    }
                    continue;
                }
                state.phase = NodePhase::TriedBadCaptures;
            }

            // Before trying the quiet moves, we should assign proper
            // move scores to them.
            if let NodePhase::TriedBadCaptures = state.phase {
                // TODO: Assign the moves scores here using the killer
                // move heuristics and the history heuristics.

                // We use the score field (2 bits) to properly order
                // quiet movies. Moves which destination square is
                // more advanced into enemy's territory are tried
                // first. The logic is that those moves are riskier,
                // so if such a move loses material this will be
                // detected early and the search tree will be pruned,
                // but if the move does not lose material, chances are
                // that it is a very good move.
                const SCORE_LOOKUP: [[u32; 8]; 2] = [// white
                                                     [0, 1, 2, 3, 4, 5, 6, 7],
                                                     // black
                                                     [7, 6, 5, 4, 3, 2, 1, 0]];
                for m in self.moves.iter_mut() {
                    let rank = rank(m.dest_square());
                    m.set_score(unsafe {
                        *SCORE_LOOKUP.get_unchecked(self.position.board().to_move())
                                     .get_unchecked(rank)
                    });
                }

                state.phase = NodePhase::SortedQuietMoves;
            }

            // Last, quiet moves.
            if self.position.do_move(m) {
                if state.checkers != 0 {
                    // When in check, we set a high move score to all
                    // moves to avoid search depth reductions.
                    m.set_score(MAX_MOVE_SCORE - 1);
                }
                return Some(m);
            }
        }
        None
    }

    // Takes the last played move back.
    #[inline]
    fn undo_move(&mut self) {
        self.position.undo_move();
    }

    // Stores updated node information in the transposition table.
    #[inline]
    fn store(&mut self, value: Value, bound: BoundType, depth: u8, best_move: Move) {
        let entry = &self.state_stack.last().unwrap().entry;
        self.tt.store(self.position.hash(),
                      EntryData::new(value, bound, depth, best_move.digest(), entry.eval_value()));
    }

    // Reports search progress.
    //
    // From time to time, we should report how many nodes had been
    // searched since the beginning of the search. This also gives an
    // opportunity for the search to be terminated.
    #[inline]
    fn report_progress(&mut self, new_nodes: NodeCount) -> Result<(), TerminatedSearch> {
        self.unreported_nodes += new_nodes;
        if self.unreported_nodes >= super::NODE_COUNT_REPORT_INTERVAL {
            self.reported_nodes += self.unreported_nodes;
            self.unreported_nodes = 0;
            if (*self.report_function)(self.reported_nodes) {
                return Err(TerminatedSearch);
            }
        }
        Ok(())
    }
}

enum NodePhase {
    Pristine,
    TriedNullMove,
    TriedHashMove,
    GeneratedMoves,
    TriedGoodCaptures,
    TriedBadCaptures,
    SortedQuietMoves,
}

struct NodeState {
    phase: NodePhase,
    entry: EntryData,
    checkers: u64,
    pinned: u64,
}

#[cfg(test)]
mod tests {
    use super::Search;
    use chess_move::*;
    use tt::*;
    use position::Position;

    #[test]
    fn test_search() {
        let p = Position::from_fen("8/8/8/8/3q3k/7n/6PP/2Q2R1K b - - 0 1").ok().unwrap();
        let tt = TranspositionTable::new();
        let mut moves = MoveStack::new();
        let mut report = |_| false;
        let mut search = Search::new(p, &tt, &mut moves, &mut report);
        let value = search.run(-30000, 30000, 2)
                          .ok()
                          .unwrap();
        assert!(value < -300);
        search.reset();
        let value = search.run(-30000, 30000, 4)
                          .ok()
                          .unwrap();
        assert!(value >= 20000);
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use num::rational::Rational32;
use data::frame::MediaKind;

enum CodecID {
    //
}

pub struct CodecParams {
    kind: MediaKind,
    codec_id: CodecID,
    extradata: Vec<u8>,
    tag: u32,
    bit_rate: usize,
    bits_per_coded_sample: usize,
    profile: usize,
    level: usize,
}

pub struct Stream {
    id: usize,
    index: usize,
    params : CodecParams,
    start: Option<u64>,
    duration: Option<u64>,
    timebase : Rational32,
//  seek_index : SeekIndex
}

pub struct StreamGroup<'a> {
    id: usize,
    start: u64,
    end: u64,
    streams: &'a [Stream],
}
<commit_msg>stream: Add reference to VP9 and Opus<commit_after>#![allow(dead_code)]

use num::rational::Rational32;
use data::frame::MediaKind;

enum CodecID {
    VP9,
    Opus
}

pub struct CodecParams {
    kind: MediaKind,
    codec_id: CodecID,
    extradata: Vec<u8>,
    tag: u32,
    bit_rate: usize,
    bits_per_coded_sample: usize,
    profile: usize,
    level: usize,
}

pub struct Stream {
    id: usize,
    index: usize,
    params : CodecParams,
    start: Option<u64>,
    duration: Option<u64>,
    timebase : Rational32,
//  seek_index : SeekIndex
}

pub struct StreamGroup<'a> {
    id: usize,
    start: u64,
    end: u64,
    streams: &'a [Stream],
}
<|endoftext|>


<commit_before>use std::env;
use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::path::Path;

// Lookup table
// We can generate this but it's small enough to hardcode
const TABLE : [u32; 256] = [
        0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
        0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
        0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
        0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
        0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
        0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
        0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
        0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
        0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
        0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
        0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
        0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
        0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
        0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
        0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
        0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
        0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
        0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
        0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
        0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
        0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
        0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
        0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
        0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
        0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
        0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
        0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
        0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
        0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
        0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
        0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
        0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
        0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
        0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
        0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
        0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
        0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
        0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
        0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
        0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
        0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
        0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
        0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
    ];

fn main() {

	let args : Vec<_> = env::args().collect();

	if args.len() < 2 {
		print_usage();
		return;
	}

	// Get the file name from the commandline
	// arguments
	let filename = &args[1];

	// Open the file
	let mut file = match File::open(filename) {
	    Ok(file) => file,
	    Err(why) => panic!("Couldn't open {}: {}", filename,
                     Error::description(&why)),
	};

 	// Read the contents of the file into a byte vector
	let mut contents : Vec<u8> = Vec::new();
	file.read_to_end(&mut contents).unwrap();

	// Compute the check sum
	let crc = compute_checksum(&contents);

	// Print it
	println!("{0:x}", crc);
}

fn compute_checksum(input : &[u8]) -> u32 {

	// Start an initial value of 0xFFFFFFFF - all bits are set
    input.iter().fold(0xFFFFFFFFu32,
    	| acc, &item | {
    		// Generate an index based on the low bits of our current
    		// CRC XOR'd with current item in our array
			let index = (acc & 0xFF) ^ (item as u32);

			// Right shift the crc by 8 bits and XOR it with the value
			// in the look up table
			(acc >> 8) ^ (TABLE[index as usize] as u32)
	}) ^ 0xFFFFFFFFu32 // XOR the final CRC with -1

}

fn print_usage() {
	let app_path = env::args().next().unwrap().clone();

	let path = Path::new(&app_path);
	println!("usage: {} <filename>",
		// Display the file name only, not the full path
		path.file_name().unwrap().to_str().unwrap());
}<commit_msg>Update crc32.rs<commit_after>use std::env;
use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::path::Path;

// Lookup table
// We can generate this but it's small enough to hardcode
const TABLE : [u32; 256] = [
        0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
        0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
        0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
        0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
        0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
        0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
        0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
        0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
        0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
        0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
        0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
        0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
        0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
        0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
        0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
        0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
        0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
        0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
        0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
        0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
        0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
        0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
        0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
        0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
        0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
        0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
        0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
        0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
        0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
        0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
        0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
        0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
        0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
        0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
        0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
        0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
        0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
        0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
        0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
        0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
        0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
        0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
        0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
    ];

fn main() {

	let args : Vec<_> = env::args().collect();

	if args.len() < 2 {
		print_usage();
		return;
	}

	// Get the file name from the commandline arguments
	let filename = &args[1];

	// Open the file
	let mut file = match File::open(filename) {
	    Ok(file) => file,
	    Err(why) => panic!("Couldn't open {}: {}", filename,
                     Error::description(&why)),
	};

 	// Read the contents of the file into a byte vector
	let mut contents : Vec<u8> = Vec::new();
	file.read_to_end(&mut contents).unwrap();

	// Compute the check sum
	let crc = compute_checksum(&contents);

	// Print it
	println!("{0:x}", crc);
}

fn compute_checksum(input : &[u8]) -> u32 {

	// Start an initial value of 0xFFFFFFFF - all bits are set
    input.iter().fold(0xFFFFFFFFu32,
    	| acc, &item | {
    		// Generate an index based on the low bits of our current
    		// CRC XOR'd with current item in our array
		let index = (acc & 0xFF) ^ (item as u32);

		// Right shift the crc by 8 bits and XOR it with the value
		// in the look up table
		(acc >> 8) ^ (TABLE[index as usize] as u32)
	}) ^ 0xFFFFFFFFu32 // XOR the final CRC with -1

}

fn print_usage() {
	let app_path = env::args().next().unwrap().clone();

	let path = Path::new(&app_path);
	println!("usage: {} <filename>",
		// Display the file name only, not the full path
		path.file_name().unwrap().to_str().unwrap());
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;

fn run_app() -> Result<(), std::io::Error> {
	let path = "Cargo.toml";
	let file = File::open(path);
	let file = match file {
		Ok(file) => file,
		Err(err) => return Err(err), // Put nicer error message with path that was not found
	};
	let mut reader = BufReader::new(file);
	let mut contents = String::new();
	reader.read_to_string(&mut contents)?;
	println!("File content: {}", contents);

    Ok(())
}

fn main() {
    ::std::process::exit(match run_app() {
       Ok(_) => 0,
       Err(err) => {
           writeln!(std::io::stderr(), "error: {:?}", err).unwrap();
           1
       }
    });
}
<commit_msg>read file line by line.<commit_after>use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;

fn run_app() -> Result<(), std::io::Error> {
	let path = "Cargo.toml";
	let file = File::open(path);
	let file = match file {
		Ok(file) => file,
		Err(err) => return Err(err), // Put nicer error message with path that was not found
	};
	let reader = BufReader::new(file);
	for line in reader.lines() {
		match line {
			Ok(line) => println!("Line: {}", line),
			Err(err) => return Err(err),
		};

	}
    Ok(())
}

fn main() {
    ::std::process::exit(match run_app() {
       Ok(_) => 0,
       Err(err) => {
           writeln!(std::io::stderr(), "error: {:?}", err).unwrap();
           1
       }
    });
}
<|endoftext|>


<commit_before>use crate::clippy_project_root;
use shell_escape::escape;
use std::ffi::OsStr;
use std::path::Path;
use std::process::{self, Command};
use std::{fs, io};
use walkdir::WalkDir;

#[derive(Debug)]
pub enum CliError {
    CommandFailed(String, String),
    IoError(io::Error),
    RustfmtNotInstalled,
    WalkDirError(walkdir::Error),
    RaSetupActive,
}

impl From<io::Error> for CliError {
    fn from(error: io::Error) -> Self {
        Self::IoError(error)
    }
}

impl From<walkdir::Error> for CliError {
    fn from(error: walkdir::Error) -> Self {
        Self::WalkDirError(error)
    }
}

struct FmtContext {
    check: bool,
    verbose: bool,
}

// the "main" function of cargo dev fmt
pub fn run(check: bool, verbose: bool) {
    fn try_run(context: &FmtContext) -> Result<bool, CliError> {
        let mut success = true;

        let project_root = clippy_project_root();

        // if we added a local rustc repo as path dependency to clippy for rust analyzer, we do NOT want to
        // format because rustfmt would also format the entire rustc repo as it is a local
        // dependency
        if fs::read_to_string(project_root.join("Cargo.toml"))
            .expect("Failed to read clippy Cargo.toml")
            .contains(&"[target.'cfg(NOT_A_PLATFORM)'.dependencies]")
        {
            return Err(CliError::RaSetupActive);
        }

        rustfmt_test(context)?;

        success &= cargo_fmt(context, project_root.as_path())?;
        success &= cargo_fmt(context, &project_root.join("clippy_dev"))?;
        success &= cargo_fmt(context, &project_root.join("rustc_tools_util"))?;
        success &= cargo_fmt(context, &project_root.join("lintcheck"))?;

        for entry in WalkDir::new(project_root.join("tests")) {
            let entry = entry?;
            let path = entry.path();

            if path.extension() != Some("rs".as_ref())
                || entry.file_name() == "ice-3891.rs"
                // Avoid rustfmt bug rust-lang/rustfmt#1873
                || cfg!(windows) && entry.file_name() == "implicit_hasher.rs"
            {
                continue;
            }

            success &= rustfmt(context, path)?;
        }

        Ok(success)
    }

    fn output_err(err: CliError) {
        match err {
            CliError::CommandFailed(command, stderr) => {
                eprintln!("error: A command failed! `{}`\nstderr: {}", command, stderr);
            },
            CliError::IoError(err) => {
                eprintln!("error: {}", err);
            },
            CliError::RustfmtNotInstalled => {
                eprintln!("error: rustfmt nightly is not installed.");
            },
            CliError::WalkDirError(err) => {
                eprintln!("error: {}", err);
            },
            CliError::RaSetupActive => {
                eprintln!(
                    "error: a local rustc repo is enabled as path dependency via `cargo dev ide_setup`.
Not formatting because that would format the local repo as well!
Please revert the changes to Cargo.tomls first."
                );
            },
        }
    }

    let context = FmtContext { check, verbose };
    let result = try_run(&context);
    let code = match result {
        Ok(true) => 0,
        Ok(false) => {
            eprintln!();
            eprintln!("Formatting check failed.");
            eprintln!("Run `cargo dev fmt` to update formatting.");
            1
        },
        Err(err) => {
            output_err(err);
            1
        },
    };
    process::exit(code);
}

fn format_command(program: impl AsRef<OsStr>, dir: impl AsRef<Path>, args: &[impl AsRef<OsStr>]) -> String {
    let arg_display: Vec<_> = args.iter().map(|a| escape(a.as_ref().to_string_lossy())).collect();

    format!(
        "cd {} && {} {}",
        escape(dir.as_ref().to_string_lossy()),
        escape(program.as_ref().to_string_lossy()),
        arg_display.join(" ")
    )
}

fn exec(
    context: &FmtContext,
    program: impl AsRef<OsStr>,
    dir: impl AsRef<Path>,
    args: &[impl AsRef<OsStr>],
) -> Result<bool, CliError> {
    if context.verbose {
        println!("{}", format_command(&program, &dir, args));
    }

    let child = Command::new(&program).current_dir(&dir).args(args.iter()).spawn()?;
    let output = child.wait_with_output()?;
    let success = output.status.success();

    if !context.check && !success {
        let stderr = std::str::from_utf8(&output.stderr).unwrap_or("");
        return Err(CliError::CommandFailed(
            format_command(&program, &dir, args),
            String::from(stderr),
        ));
    }

    Ok(success)
}

fn cargo_fmt(context: &FmtContext, path: &Path) -> Result<bool, CliError> {
    let mut args = vec!["+nightly", "fmt", "--all"];
    if context.check {
        args.push("--");
        args.push("--check");
    }
    let success = exec(context, "cargo", path, &args)?;

    Ok(success)
}

fn rustfmt_test(context: &FmtContext) -> Result<(), CliError> {
    let program = "rustfmt";
    let dir = std::env::current_dir()?;
    let args = &["+nightly", "--version"];

    if context.verbose {
        println!("{}", format_command(&program, &dir, args));
    }

    let output = Command::new(&program).current_dir(&dir).args(args.iter()).output()?;

    if output.status.success() {
        Ok(())
    } else if std::str::from_utf8(&output.stderr)
        .unwrap_or("")
        .starts_with("error: 'rustfmt' is not installed")
    {
        Err(CliError::RustfmtNotInstalled)
    } else {
        Err(CliError::CommandFailed(
            format_command(&program, &dir, args),
            std::str::from_utf8(&output.stderr).unwrap_or("").to_string(),
        ))
    }
}

fn rustfmt(context: &FmtContext, path: &Path) -> Result<bool, CliError> {
    let mut args = vec!["+nightly".as_ref(), path.as_os_str()];
    if context.check {
        args.push("--check".as_ref());
    }
    let success = exec(context, "rustfmt", std::env::current_dir()?, &args)?;
    if !success {
        eprintln!("rustfmt failed on {}", path.display());
    }
    Ok(success)
}
<commit_msg>Remove rustfmt workaround<commit_after>use crate::clippy_project_root;
use shell_escape::escape;
use std::ffi::OsStr;
use std::path::Path;
use std::process::{self, Command};
use std::{fs, io};
use walkdir::WalkDir;

#[derive(Debug)]
pub enum CliError {
    CommandFailed(String, String),
    IoError(io::Error),
    RustfmtNotInstalled,
    WalkDirError(walkdir::Error),
    RaSetupActive,
}

impl From<io::Error> for CliError {
    fn from(error: io::Error) -> Self {
        Self::IoError(error)
    }
}

impl From<walkdir::Error> for CliError {
    fn from(error: walkdir::Error) -> Self {
        Self::WalkDirError(error)
    }
}

struct FmtContext {
    check: bool,
    verbose: bool,
}

// the "main" function of cargo dev fmt
pub fn run(check: bool, verbose: bool) {
    fn try_run(context: &FmtContext) -> Result<bool, CliError> {
        let mut success = true;

        let project_root = clippy_project_root();

        // if we added a local rustc repo as path dependency to clippy for rust analyzer, we do NOT want to
        // format because rustfmt would also format the entire rustc repo as it is a local
        // dependency
        if fs::read_to_string(project_root.join("Cargo.toml"))
            .expect("Failed to read clippy Cargo.toml")
            .contains(&"[target.'cfg(NOT_A_PLATFORM)'.dependencies]")
        {
            return Err(CliError::RaSetupActive);
        }

        rustfmt_test(context)?;

        success &= cargo_fmt(context, project_root.as_path())?;
        success &= cargo_fmt(context, &project_root.join("clippy_dev"))?;
        success &= cargo_fmt(context, &project_root.join("rustc_tools_util"))?;
        success &= cargo_fmt(context, &project_root.join("lintcheck"))?;

        for entry in WalkDir::new(project_root.join("tests")) {
            let entry = entry?;
            let path = entry.path();

            if path.extension() != Some("rs".as_ref()) || entry.file_name() == "ice-3891.rs" {
                continue;
            }

            success &= rustfmt(context, path)?;
        }

        Ok(success)
    }

    fn output_err(err: CliError) {
        match err {
            CliError::CommandFailed(command, stderr) => {
                eprintln!("error: A command failed! `{}`\nstderr: {}", command, stderr);
            },
            CliError::IoError(err) => {
                eprintln!("error: {}", err);
            },
            CliError::RustfmtNotInstalled => {
                eprintln!("error: rustfmt nightly is not installed.");
            },
            CliError::WalkDirError(err) => {
                eprintln!("error: {}", err);
            },
            CliError::RaSetupActive => {
                eprintln!(
                    "error: a local rustc repo is enabled as path dependency via `cargo dev ide_setup`.
Not formatting because that would format the local repo as well!
Please revert the changes to Cargo.tomls first."
                );
            },
        }
    }

    let context = FmtContext { check, verbose };
    let result = try_run(&context);
    let code = match result {
        Ok(true) => 0,
        Ok(false) => {
            eprintln!();
            eprintln!("Formatting check failed.");
            eprintln!("Run `cargo dev fmt` to update formatting.");
            1
        },
        Err(err) => {
            output_err(err);
            1
        },
    };
    process::exit(code);
}

fn format_command(program: impl AsRef<OsStr>, dir: impl AsRef<Path>, args: &[impl AsRef<OsStr>]) -> String {
    let arg_display: Vec<_> = args.iter().map(|a| escape(a.as_ref().to_string_lossy())).collect();

    format!(
        "cd {} && {} {}",
        escape(dir.as_ref().to_string_lossy()),
        escape(program.as_ref().to_string_lossy()),
        arg_display.join(" ")
    )
}

fn exec(
    context: &FmtContext,
    program: impl AsRef<OsStr>,
    dir: impl AsRef<Path>,
    args: &[impl AsRef<OsStr>],
) -> Result<bool, CliError> {
    if context.verbose {
        println!("{}", format_command(&program, &dir, args));
    }

    let child = Command::new(&program).current_dir(&dir).args(args.iter()).spawn()?;
    let output = child.wait_with_output()?;
    let success = output.status.success();

    if !context.check && !success {
        let stderr = std::str::from_utf8(&output.stderr).unwrap_or("");
        return Err(CliError::CommandFailed(
            format_command(&program, &dir, args),
            String::from(stderr),
        ));
    }

    Ok(success)
}

fn cargo_fmt(context: &FmtContext, path: &Path) -> Result<bool, CliError> {
    let mut args = vec!["+nightly", "fmt", "--all"];
    if context.check {
        args.push("--");
        args.push("--check");
    }
    let success = exec(context, "cargo", path, &args)?;

    Ok(success)
}

fn rustfmt_test(context: &FmtContext) -> Result<(), CliError> {
    let program = "rustfmt";
    let dir = std::env::current_dir()?;
    let args = &["+nightly", "--version"];

    if context.verbose {
        println!("{}", format_command(&program, &dir, args));
    }

    let output = Command::new(&program).current_dir(&dir).args(args.iter()).output()?;

    if output.status.success() {
        Ok(())
    } else if std::str::from_utf8(&output.stderr)
        .unwrap_or("")
        .starts_with("error: 'rustfmt' is not installed")
    {
        Err(CliError::RustfmtNotInstalled)
    } else {
        Err(CliError::CommandFailed(
            format_command(&program, &dir, args),
            std::str::from_utf8(&output.stderr).unwrap_or("").to_string(),
        ))
    }
}

fn rustfmt(context: &FmtContext, path: &Path) -> Result<bool, CliError> {
    let mut args = vec!["+nightly".as_ref(), path.as_os_str()];
    if context.check {
        args.push("--check".as_ref());
    }
    let success = exec(context, "rustfmt", std::env::current_dir()?, &args)?;
    if !success {
        eprintln!("rustfmt failed on {}", path.display());
    }
    Ok(success)
}
<|endoftext|>


<commit_before>use event::Event;
use sass::selector::SassSelector;

use std::fmt;

#[derive(Clone)]
pub struct SassRule<'a> {
    pub selectors: Vec<SassSelector<'a>>,
    pub children: Vec<Event<'a>>,
}

impl<'a> SassRule<'a> {
    pub fn new() -> SassRule<'a> {
        SassRule {
            selectors: Vec::new(),
            children: Vec::new(),
        }
    }

    fn selector_distribution(&self, parents: &str, separator: &str) -> String {
        match parents.len() {
            0 => self.selectors.iter().map(|s| (*s.name).to_string()).collect::<Vec<_>>().connect(separator),
            _ => parents.split(",").map(|p| {
                self.selectors.iter().map(|s| {
                    format!("{} {}", p.trim(), s.name)
                }).collect::<Vec<_>>().connect(separator)
            }).collect::<Vec<_>>().connect(separator),
        }
    }

    pub fn expanded(&self) -> String {
        self.expanded_with_parent("")
    }

    pub fn expanded_with_parent(&self, parents: &str) -> String {
        let mut output = String::new();

        let selector_string = self.selector_distribution(parents, ", ");

        let properties_string = self.children.iter().filter(|c| !c.is_child_rule() ).map(|c| {
            c.expanded()
        }).collect::<Vec<_>>().connect("\n");

        let child_rules_string = self.children.iter().filter(|c| c.is_child_rule() ).map(|c| {
            match c {
                &Event::ChildRule(ref rule) => rule.expanded_with_parent(&selector_string),
                _ => unreachable!(),
            }
        }).collect::<Vec<_>>().connect("\n");

        if properties_string.len() > 0 {
            output.push_str(&selector_string);
            output.push_str(" ");
            output.push_str(&format!("{{\n{}\n}}", properties_string));
        }

        if properties_string.len() > 0 && child_rules_string.len() > 0 {
            output.push_str("\n");
        }

        if child_rules_string.len() > 0 {
            output.push_str(&child_rules_string);
        }

        output
    }

    pub fn nested(&self) -> String {
        self.nested_with_parent("")
    }

    pub fn nested_with_parent(&self, parents: &str) -> String {
        let mut output = String::new();

        let selector_string = self.selector_distribution(parents, ", ");

        let properties_string = self.children.iter().filter(|c| !c.is_child_rule() ).map(|c| {
            c.nested()
        }).collect::<Vec<_>>().connect("\n");

        let child_rules_string = self.children.iter().filter(|c| c.is_child_rule() ).map(|c| {
            match c {
                &Event::ChildRule(ref rule) => rule.nested_with_parent(&selector_string),
                _ => unreachable!(),
            }
        }).collect::<Vec<_>>().connect("\n");

        if properties_string.len() > 0 {
            output.push_str(&selector_string);
            output.push_str(" ");
            output.push_str(&format!("{{\n{} }}", properties_string));
            if child_rules_string.len() > 0 {
                output.push_str("\n  ");
                output.push_str(&child_rules_string.split('\n').collect::<Vec<_>>().connect("\n  "));
            }
        } else {
            output.push_str(&child_rules_string);
        }

        output
    }

    pub fn compact(&self) -> String {
        self.compact_with_parent("")
    }

    pub fn compact_with_parent(&self, parents: &str) -> String {
        let mut output = String::new();

        let selector_string = self.selector_distribution(parents, ", ");

        let properties_string = self.children.iter().filter(|c| !c.is_child_rule() ).map(|c| {
            c.compact()
        }).collect::<Vec<_>>().connect(" ");

        let child_rules_string = self.children.iter().filter(|c| c.is_child_rule() ).map(|c| {
            match c {
                &Event::ChildRule(ref rule) => rule.compact_with_parent(&selector_string),
                _ => unreachable!(),
            }
        }).collect::<Vec<_>>().connect("\n");

        if properties_string.len() > 0 {
            output.push_str(&selector_string);
            output.push_str(" ");
            output.push_str(&format!("{{ {} }}", properties_string));
            if child_rules_string.len() > 0 {
                output.push_str("\n");
                output.push_str(&child_rules_string);
            }
        } else {
            output.push_str(&child_rules_string);
        }

        output
    }

    pub fn compressed(&self) -> String {
        self.compressed_with_parent("")
    }

    pub fn compressed_with_parent(&self, parents: &str) -> String {
        let mut output = String::new();

        let selector_string = self.selector_distribution(parents, ",");

        let properties_string = self.children.iter().filter(|c| !c.is_child_rule() && !c.is_comment() ).map(|c| {
            c.compressed()
        }).collect::<Vec<_>>().connect(";");

        let child_rules_string = self.children.iter().filter(|c| c.is_child_rule() ).map(|c| {
            match c {
                &Event::ChildRule(ref rule) => rule.compressed_with_parent(&selector_string),
                _ => unreachable!(),
            }
        }).collect::<Vec<_>>().connect("");

        if properties_string.len() > 0 {
            output.push_str(&selector_string);
            output.push_str(&format!("{{{}}}", properties_string));
            if child_rules_string.len() > 0 {
                output.push_str(&child_rules_string);
            }
        } else {
            output.push_str(&child_rules_string);
        }

        output
    }
}

impl<'a> fmt::Debug for SassRule<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let children = self.children.iter().map(|c| format!("{:?}", c)).collect::<Vec<_>>().connect("\n");
        let indented_children = children.split("\n").collect::<Vec<_>>().connect("\n  ");
        write!(f, "{:?} {{\n  {}\n}}", self.selectors, indented_children)
    }
}
<commit_msg>Make smallest needed replacement fn for selectors in compressed output<commit_after>use event::Event;
use sass::selector::SassSelector;

use std::fmt;

#[derive(Clone)]
pub struct SassRule<'a> {
    pub selectors: Vec<SassSelector<'a>>,
    pub children: Vec<Event<'a>>,
}

impl<'a> SassRule<'a> {
    pub fn new() -> SassRule<'a> {
        SassRule {
            selectors: Vec::new(),
            children: Vec::new(),
        }
    }

    fn selector_distribution(&self, parents: &str, separator: &str) -> String {
        match parents.len() {
            0 => self.selectors.iter().map(|s| (*s.name).to_string()).collect::<Vec<_>>().connect(separator),
            _ => parents.split(",").map(|p| {
                self.selectors.iter().map(|s| {
                    format!("{} {}", p.trim(), s.name)
                }).collect::<Vec<_>>().connect(separator)
            }).collect::<Vec<_>>().connect(separator),
        }
    }

    pub fn expanded(&self) -> String {
        self.expanded_with_parent("")
    }

    pub fn expanded_with_parent(&self, parents: &str) -> String {
        let mut output = String::new();

        let selector_string = self.selector_distribution(parents, ", ");

        let properties_string = self.children.iter().filter(|c| !c.is_child_rule() ).map(|c| {
            c.expanded()
        }).collect::<Vec<_>>().connect("\n");

        let child_rules_string = self.children.iter().filter(|c| c.is_child_rule() ).map(|c| {
            match c {
                &Event::ChildRule(ref rule) => rule.expanded_with_parent(&selector_string),
                _ => unreachable!(),
            }
        }).collect::<Vec<_>>().connect("\n");

        if properties_string.len() > 0 {
            output.push_str(&selector_string);
            output.push_str(" ");
            output.push_str(&format!("{{\n{}\n}}", properties_string));
        }

        if properties_string.len() > 0 && child_rules_string.len() > 0 {
            output.push_str("\n");
        }

        if child_rules_string.len() > 0 {
            output.push_str(&child_rules_string);
        }

        output
    }

    pub fn nested(&self) -> String {
        self.nested_with_parent("")
    }

    pub fn nested_with_parent(&self, parents: &str) -> String {
        let mut output = String::new();

        let selector_string = self.selector_distribution(parents, ", ");

        let properties_string = self.children.iter().filter(|c| !c.is_child_rule() ).map(|c| {
            c.nested()
        }).collect::<Vec<_>>().connect("\n");

        let child_rules_string = self.children.iter().filter(|c| c.is_child_rule() ).map(|c| {
            match c {
                &Event::ChildRule(ref rule) => rule.nested_with_parent(&selector_string),
                _ => unreachable!(),
            }
        }).collect::<Vec<_>>().connect("\n");

        if properties_string.len() > 0 {
            output.push_str(&selector_string);
            output.push_str(" ");
            output.push_str(&format!("{{\n{} }}", properties_string));
            if child_rules_string.len() > 0 {
                output.push_str("\n  ");
                output.push_str(&child_rules_string.split('\n').collect::<Vec<_>>().connect("\n  "));
            }
        } else {
            output.push_str(&child_rules_string);
        }

        output
    }

    pub fn compact(&self) -> String {
        self.compact_with_parent("")
    }

    pub fn compact_with_parent(&self, parents: &str) -> String {
        let mut output = String::new();

        let selector_string = self.selector_distribution(parents, ", ");

        let properties_string = self.children.iter().filter(|c| !c.is_child_rule() ).map(|c| {
            c.compact()
        }).collect::<Vec<_>>().connect(" ");

        let child_rules_string = self.children.iter().filter(|c| c.is_child_rule() ).map(|c| {
            match c {
                &Event::ChildRule(ref rule) => rule.compact_with_parent(&selector_string),
                _ => unreachable!(),
            }
        }).collect::<Vec<_>>().connect("\n");

        if properties_string.len() > 0 {
            output.push_str(&selector_string);
            output.push_str(" ");
            output.push_str(&format!("{{ {} }}", properties_string));
            if child_rules_string.len() > 0 {
                output.push_str("\n");
                output.push_str(&child_rules_string);
            }
        } else {
            output.push_str(&child_rules_string);
        }

        output
    }

    pub fn compressed(&self) -> String {
        self.compressed_with_parent("")
    }

    pub fn compressed_with_parent(&self, parents: &str) -> String {
        let mut output = String::new();

        let selector_string = compress_selectors(self.selector_distribution(parents, ","));

        let properties_string = self.children.iter().filter(|c| !c.is_child_rule() && !c.is_comment() ).map(|c| {
            c.compressed()
        }).collect::<Vec<_>>().connect(";");

        let child_rules_string = self.children.iter().filter(|c| c.is_child_rule() ).map(|c| {
            match c {
                &Event::ChildRule(ref rule) => rule.compressed_with_parent(&selector_string),
                _ => unreachable!(),
            }
        }).collect::<Vec<_>>().connect("");

        if properties_string.len() > 0 {
            output.push_str(&selector_string);
            output.push_str(&format!("{{{}}}", properties_string));
            if child_rules_string.len() > 0 {
                output.push_str(&child_rules_string);
            }
        } else {
            output.push_str(&child_rules_string);
        }

        output
    }
}

fn compress_selectors(selector_string: String) -> String {
    selector_string.replace(" > ", ">").replace(" + ", "+")
}

impl<'a> fmt::Debug for SassRule<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let children = self.children.iter().map(|c| format!("{:?}", c)).collect::<Vec<_>>().connect("\n");
        let indented_children = children.split("\n").collect::<Vec<_>>().connect("\n  ");
        write!(f, "{:?} {{\n  {}\n}}", self.selectors, indented_children)
    }
}
<|endoftext|>


<commit_before>// (c) 2016 Joost Yervante Damad <joost@productize.be>

use std::fmt;

// get from parent
use ERes;
use err;
use read_file;

#[derive(Debug)]
pub struct Schematic {
    libraries:Vec<String>,
    description:Description,
    components:Vec<Component>,
}

impl Schematic {
    fn new() -> Schematic {
        Schematic {
            libraries:vec![],
            description:Description::new(),
            components:vec![],
        }
    }

    fn add_library(&mut self, s:&str) {
        self.libraries.push(String::from(s))
    }

    fn set_description(&mut self, d:&Description) {
        self.description.clone_from(d)
    }

    fn append_component(&mut self, c:Component) {
        self.components.push(c)
    }
}

impl fmt::Display for Schematic {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "EESchema Schematic File Version 2"));
        for v in &self.libraries[..] {
            try!(writeln!(f, "LIBS:{}", v))
        }
        try!(write!(f, "{}", self.description));
        for v in &self.components[..] {
            try!(write!(f, "{}", v))
        }
        Ok(())
    }
}

macro_rules! assume_line {
    ($s:expr, $exp:expr) => (
        if $s.eof() {
            return err("end of file reached")
        }
        if $s.here() != $exp {
            return Err(format!("expected '{}', got '{}'", $exp, $s.here()))
        }
        $s.i += 1;
    )
}

#[derive(Debug)]
struct ParseState {
    i:usize,
    v:Vec<String>,
}

impl ParseState {
    fn new(v2:Vec<&str>) -> ParseState {
        ParseState {
            i:0,
            v:v2.iter().map(|x| String::from(*x)).collect(),
        }
    }

    fn here(&self) -> &String {
        return &self.v[self.i]
    }

    fn next(&mut self) {
        self.i += 1;
    }

    fn eof(&self) -> bool {
        self.i >= self.v.len()
    }
}

#[derive(Debug,Clone)]
pub struct Description {
    size:String
}

impl Description {
    fn new() -> Description {
        Description { size:String::from("A4") }
    }
}

impl fmt::Display for Description {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "$Descr {}", self.size));
        writeln!(f, "$EndDescr")
    }
}

#[derive(Debug)]
struct Component {
    name:String,
    reference:String,
}

impl Component {
    fn new() -> Component {
        Component {
            name:String::from("EFM32HG310"),
            reference:String::from("U1"),
        }
    }
}

impl fmt::Display for Component {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "$Comp"));
        try!(writeln!(f, "L {} {}", self.name, self.reference));
        writeln!(f, "$EndComp")
    }
}

fn parse_description(p:&mut ParseState) -> ERes<Description> {
    Ok(Description::new())
}

fn parse_component(p:&mut ParseState) -> ERes<Component> {
    Ok(Component::new())
}

fn parse(s: &str) -> ERes<Schematic> {
    let mut sch = Schematic::new();
    let v:Vec<&str> = s.lines().collect();
    let p = &mut ParseState::new(v);
    assume_line!(p, "EESchema Schematic File Version 2");
    while !p.eof() {
        {
          let s = p.here();
          if !s.starts_with("LIBS:") {
              break
          }
            sch.add_library(&s[5..]);
        }
        p.next();
    }
    assume_line!(p, "EELAYER 25 0");
    assume_line!(p, "EELAYER END");
    while !p.eof() {
        {
            match &p.here()[..] {
                "$Descr" => {
                    let d = try!(parse_description(p));
                    sch.set_description(&d)
                },
                "$Comp" => {
                    let d = try!(parse_component(p));
                    sch.append_component(d)
                },
                _ => {
                    println!("TODO other parts");
                }
            }
        }
        p.next()
    }
    Ok(sch)
}

pub fn parse_str(s: &str) -> Schematic {
    parse(s).unwrap()
}

pub fn parse_file(name: &str) -> Schematic {
    let s = read_file(name).unwrap();
    parse(&s[..]).unwrap()
}

<commit_msg>description parsing<commit_after>// (c) 2016 Joost Yervante Damad <joost@productize.be>

use std::fmt;
use std::str::FromStr;

// get from parent
use ERes;
use err;
use read_file;

#[derive(Debug)]
pub struct Schematic {
    libraries:Vec<String>,
    description:Description,
    components:Vec<Component>,
}

impl Schematic {
    fn new() -> Schematic {
        Schematic {
            libraries:vec![],
            description:Description::new(),
            components:vec![],
        }
    }

    fn add_library(&mut self, s:&str) {
        self.libraries.push(String::from(s))
    }

    fn set_description(&mut self, d:&Description) {
        self.description.clone_from(d)
    }

    fn append_component(&mut self, c:Component) {
        self.components.push(c)
    }
}

impl fmt::Display for Schematic {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "EESchema Schematic File Version 2"));
        for v in &self.libraries[..] {
            try!(writeln!(f, "LIBS:{}", v))
        }
        try!(write!(f, "{}", self.description));
        for v in &self.components[..] {
            try!(write!(f, "{}", v))
        }
        Ok(())
    }
}

macro_rules! assume_line {
    ($s:expr, $exp:expr) => (
        if $s.eof() {
            return err("end of file reached")
        }
        if $s.here() != $exp {
            return Err(format!("expected '{}', got '{}'", $exp, $s.here()))
        }
        $s.i += 1;
    )
}

#[derive(Debug)]
struct ParseState {
    i:usize,
    v:Vec<String>,
}

impl ParseState {
    fn new(v2:Vec<&str>) -> ParseState {
        ParseState {
            i:0,
            v:v2.iter().map(|x| String::from(*x)).collect(),
        }
    }

    fn here(&self) -> String {
        return (self.v[self.i]).clone()
    }

    fn next(&mut self) {
        self.i += 1;
    }

    fn eof(&self) -> bool {
        self.i >= self.v.len()
    }
}
/*
$Descr A4 11693 8268
encoding utf-8
Sheet 1 1
Title "Normal"
Date "Tue 19 May 2015"
Rev ""
Comp ""
Comment1 ""
Comment2 ""
Comment3 ""
Comment4 ""
$EndDesc
*/
#[derive(Debug,Clone)]
pub struct Description {
    size:String,
    dimx:i64,
    dimy:i64,
    title:String,
    date:String,
    rev:String,
    comp:String,
    comment1:String,
    comment2:String,
    comment3:String,
    comment4:String,
}

impl Description {
    fn new() -> Description {
        Description {
            size:String::from(""),
            dimx:0,
            dimy:0,
            title:String::from("Normal"),
            date:String::from("Tue 19 May 2015"),
            rev:String::from(""),
            comp:String::from(""),
            comment1:String::from(""),
            comment2:String::from(""),
            comment3:String::from(""),
            comment4:String::from(""),
        }
    }
    fn set_size(&mut self, s:&String) {
        self.size.clone_from(s)
    }
    fn set_dimx(&mut self, i:i64) {
        self.dimx = i;
    }
    fn set_dimy(&mut self, i:i64) {
        self.dimy = i;
    }
    fn set_title(&mut self, s:&String) {
        self.title.clone_from(s)
    }
    fn set_date(&mut self, s:&String) {
        self.date.clone_from(s)
    }
    fn set_rev(&mut self, s:&String) {
        self.rev.clone_from(s)
    }
    fn set_comp(&mut self, s:&String) {
        self.comp.clone_from(s)
    }
    fn set_comment1(&mut self, s:&String) {
        self.comment1.clone_from(s)
    }
    fn set_comment2(&mut self, s:&String) {
        self.comment2.clone_from(s)
    }
    fn set_comment3(&mut self, s:&String) {
        self.comment3.clone_from(s)
    }
    fn set_comment4(&mut self, s:&String) {
        self.comment4.clone_from(s)
    }
}

impl fmt::Display for Description {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "$Descr {} {} {}", self.size, self.dimx, self.dimy));
        try!(writeln!(f, "encoding utf-8"));
        try!(writeln!(f, "Sheet 1 1")); // TODO: handle sheet
        try!(writeln!(f, "Title \"{}\"", self.title));
        try!(writeln!(f, "Date \"{}\"", self.date));
        try!(writeln!(f, "Rev \"{}\"", self.rev));
        try!(writeln!(f, "Comp \"{}\"", self.comp));
        try!(writeln!(f, "Comment1 \"{}\"", self.comment1));
        try!(writeln!(f, "Comment2 \"{}\"", self.comment2));
        try!(writeln!(f, "Comment3 \"{}\"", self.comment3));
        try!(writeln!(f, "Comment4 \"{}\"", self.comment4));
        writeln!(f, "$EndDescr")
    }
}

#[derive(Debug)]
struct Component {
    name:String,
    reference:String,
}

impl Component {
    fn new() -> Component {
        Component {
            name:String::from("EFM32HG310"),
            reference:String::from("U1"),
        }
    }
}

impl fmt::Display for Component {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "$Comp"));
        try!(writeln!(f, "L {} {}", self.name, self.reference));
        writeln!(f, "$EndComp")
    }
}

fn assume_string(e:&'static str, s:&String) -> ERes<()> {
    if String::from(e) != *s {
        return Err(format!("expecting: {}, actually: {}", e, s))
    }
    return Ok(())
}

fn parse_split_n(n:usize, s:&String) -> ERes<Vec<String>> {
    let sp:Vec<&str> = s.splitn(n, ' ').collect();
    if sp.len() < n {
        return Err(format!("expecting {} elements in {}", n, s))
    }
    return Ok(sp.iter().map(|x| String::from(*x)).collect())
}

fn i64_from_string(s:&String) -> ERes<i64> {
    match i64::from_str(&s[..]) {
        Ok(i) => Ok(i),
        _ => Err(format!("int parse error in {}", s))
    }
}

// this is not perfect
fn unquote_string(s:&String) -> ERes<String> {
    let l = s.len();
    if s.starts_with("\"") && s.ends_with("\"") {
        let mut s = s.clone();
        s.remove(l-1);
        s.remove(0);
        return Ok(s)
    }
    Err(format!("expecting quoted string: {}", s))
}

fn word_and_qstring<F>(d:&mut Description, name:&'static str, s:&String, setter:F) -> ERes<()>
    where F:Fn(&mut Description, &String) -> ()
{
    let v = try!(parse_split_n(2, s));
    try!(assume_string(name, &v[0]));
    setter(d, &try!(unquote_string(&v[1])));
    Ok(())
}

fn parse_description(p:&mut ParseState) -> ERes<Description> {
    let mut d = Description::new();
    let v = try!(parse_split_n(4, &p.here()));
    d.set_size(&v[1]);
    d.set_dimx(try!(i64_from_string(&v[2])));
    d.set_dimy(try!(i64_from_string(&v[3])));
    p.next(); // $Descr
    p.next(); // encoding
    try!(assume_string("Sheet 1 1", &p.here()));
    p.next(); // Sheet
    try!(word_and_qstring(&mut d, "Title", &p.here(), |d, x| d.set_title(x)));
    p.next();
    try!(word_and_qstring(&mut d, "Date", &p.here(), |d, x| d.set_date(x)));
    p.next();
    try!(word_and_qstring(&mut d, "Rev", &p.here(), |d, x| d.set_rev(x)));
    p.next();
    try!(word_and_qstring(&mut d, "Comp", &p.here(), |d, x| d.set_comp(x)));
    p.next();
    try!(word_and_qstring(&mut d, "Comment1", &p.here(), |d, x| d.set_comment1(x)));
    p.next();
    try!(word_and_qstring(&mut d, "Comment2", &p.here(), |d, x| d.set_comment1(x)));
    p.next();
    try!(word_and_qstring(&mut d, "Comment3", &p.here(), |d, x| d.set_comment1(x)));
    p.next();
    try!(word_and_qstring(&mut d, "Comment4", &p.here(), |d, x| d.set_comment1(x)));
    p.next();
    try!(assume_string("$EndDescr", &p.here()));
    Ok(d)
}

fn parse_component(p:&mut ParseState) -> ERes<Component> {
    let mut d = Component::new();
    Ok(d)
}

fn parse(s: &str) -> ERes<Schematic> {
    let mut sch = Schematic::new();
    let v:Vec<&str> = s.lines().collect();
    let p = &mut ParseState::new(v);
    assume_line!(p, "EESchema Schematic File Version 2");
    while !p.eof() {
        {
          let s = p.here();
          if !s.starts_with("LIBS:") {
              break
          }
            sch.add_library(&s[5..]);
        }
        p.next();
    }
    assume_line!(p, "EELAYER 25 0");
    assume_line!(p, "EELAYER END");
    while !p.eof() {
        {
            match p.here().split_whitespace().next() {
                Some("$Descr") => {
                    let d = try!(parse_description(p));
                    sch.set_description(&d)
                },
                Some("$Comp") => {
                    let d = try!(parse_component(p));
                    sch.append_component(d)
                },
                Some(x) => {
                    //println!("TODO other parts: {}", x);
                },
                None => unreachable!()
            }
        }
        p.next()
    }
    Ok(sch)
}

pub fn parse_str(s: &str) -> Schematic {
    parse(s).unwrap()
}

pub fn parse_file(name: &str) -> Schematic {
    let s = read_file(name).unwrap();
    parse(&s[..]).unwrap()
}

<|endoftext|>


<commit_before>use super::super::{in_coroutine};

use std::sync::mpsc;

use super::notify;
use super::broadcast;

/// Channel receiving end
///
/// Create with `channel()`
pub struct Receiver<T>{
    rx: Option<mpsc::Receiver<T>>,
    notify_rx: notify::Receiver,
}

impl<T> Receiver<T>
    where T: 'static
{
    /// Receive `T` sent using corresponding `Sender::send()`.
    ///
    /// Will block coroutine if no elements are available.
    pub fn recv(&self) -> Result<T, mpsc::RecvError> {
        if in_coroutine() {
            loop {
                self.notify_rx.reset();

                let recv = self.try_recv();

                match recv {
                    Err(mpsc::TryRecvError::Empty) =>
                        self.notify_rx.wait(),
                    Err(mpsc::TryRecvError::Disconnected) => return Err(mpsc::RecvError),
                    Ok(t) => {
                        return Ok(t)
                    },
                }
            }
        } else {
            let recv = self.rx.as_ref().unwrap().recv();

                match recv {
                    Err(e) => Err(e),
                    Ok(t) => {
                        return Ok(t)
                    },
                }
        }
    }

    /// Try reading data from the queue.
    ///
    /// This will not block.
    pub fn try_recv(&self) -> Result<T, mpsc::TryRecvError> {
        let recv = self.rx.as_ref().unwrap().try_recv();
        match recv {
            Err(e) => Err(e),
            Ok(t) => {
                return Ok(t)
            },
        }
    }
}

/// Channel sending end
///
/// Use this inside mioco coroutines or outside of mioco itself to send data
/// asynchronously to the receiving end.
///
/// Create with `channel()`
pub struct Sender<T> {
    tx: Option<mpsc::Sender<T>>,
    notif_tx: notify::Sender,
}

impl<T> Clone for Sender<T> {
    fn clone(&self) -> Self {
        Sender {
            tx: self.tx.clone(),
            notif_tx: self.notif_tx.clone(),
        }
    }
}

impl<T> Sender<T> {
    /// Deliver `T` to the other end of the channel.
    ///
    /// Channel behaves like a queue.
    ///
    /// This is non-blocking operation.
    pub fn send(&self, t: T) -> Result<(), mpsc::SendError<T>> {
        try!(self.tx.as_ref().unwrap().send(t));
        self.notif_tx.notify();
        Ok(())
    }
}

/// Channel receiving end
///
/// Create with `channel()`
pub struct SyncReceiver<T>{
    rx: Option<mpsc::Receiver<T>>,
    broadcast_tx: broadcast::Sender,
    broadcast_rx: broadcast::Receiver,
}

impl<T> SyncReceiver<T>
    where T: 'static
{
    /// Receive `T` sent using corresponding `Sender::send()`.
    ///
    /// Will block coroutine if no elements are available.
    pub fn recv(&self) -> Result<T, mpsc::RecvError> {
        if in_coroutine() {
            loop {
                self.broadcast_rx.reset();

                let recv = self.try_recv();

                match recv {
                    Err(mpsc::TryRecvError::Empty) => self.broadcast_rx.wait(),
                    Err(mpsc::TryRecvError::Disconnected) => return Err(mpsc::RecvError),
                    Ok(t) => {
                        self.broadcast_tx.notify();
                        return Ok(t)
                    },
                }
            }
        } else {
            let recv = self.rx.as_ref().unwrap().recv();

                match recv {
                    Err(e) => Err(e),
                    Ok(t) => {
                        return Ok(t)
                    },
                }
        }
    }

    /// Try reading data from the queue.
    ///
    /// This will not block.
    pub fn try_recv(&self) -> Result<T, mpsc::TryRecvError> {
        let recv = self.rx.as_ref().unwrap().try_recv();
        match recv {
            Err(e) => Err(e),
            Ok(t) => {
                return Ok(t)
            },
        }
    }
}

/// Channel sync sending end
///
/// Use this inside mioco coroutines or outside of mioco itself to send data
/// asynchronously to the receiving end.
///
/// Create with `sync_channel()`
pub struct SyncSender<T> {
    tx: Option<mpsc::SyncSender<T>>,
    broadcast_rx: broadcast::Receiver,
    broadcast_tx: broadcast::Sender,
}

impl<T> SyncSender<T> {
    pub fn send(&self, mut t: T) -> Result<(), mpsc::SendError<T>> {
        if in_coroutine() {
            loop {
                t = match self.try_send(t) {
                    Ok(t) => return Ok(t),
                    Err(mpsc::TrySendError::Full(t)) => {
                        self.broadcast_rx.wait();
                        t
                    },
                    Err(mpsc::TrySendError::Disconnected(v)) => return Err(mpsc::SendError(v))
                };
            }
        } else {
            // previous send is notified. so 'rx' will be
            // notified and there will be space for this
            // send at some point
            self.tx.as_ref().unwrap().send(t)?;
        }
        self.broadcast_tx.notify();
        Ok(())
    }

    /// Deliver `T` to the other end of the channel.
    ///
    /// Channel behaves like a queue.
    ///
    /// This is non-blocking operation.
    pub fn try_send(&self, t: T) -> Result<(), mpsc::TrySendError<T>> {
        self.tx.as_ref().unwrap().try_send(t)?;
        self.broadcast_tx.notify();
        Ok(())
    }
}

/// Create a channel
///
/// Channel can be used to deliver data via MPSC queue.
///
/// Channel is modeled after `std::sync::mpsc::channel()`, only
/// supporting mioco-aware sending and receiving.
///
/// When receiving end is outside of coroutine, channel will behave just
/// like `std::sync::mpsc::channel()`.
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {

    let (n_tx, n_rx) = notify::channel();
    let (tx, rx) = mpsc::channel();
    (Sender {
        tx: Some(tx),
        notif_tx: n_tx,
    },
        Receiver {
            rx: Some(rx),
            notify_rx: n_rx,
        })
}

impl<T> Drop for Sender<T> {
    fn drop(&mut self) {
        {
            self.tx.take();
        }
        self.notif_tx.notify()
    }
}

pub fn sync_channel<T>(size: usize) -> (SyncSender<T>, SyncReceiver<T>) {

    let (btx, brx) = broadcast::channel();
    let (tx, rx) = mpsc::sync_channel(size);
    (   SyncSender {
            tx: Some(tx),
            broadcast_tx: btx.clone(),
            broadcast_rx: brx.clone(),
        },
        SyncReceiver {
            rx: Some(rx),
            broadcast_tx: btx,
            broadcast_rx: brx,
        }
    )
}

impl<T> Drop for SyncSender<T> {
    fn drop(&mut self) {
        {
            self.tx.take();
        }
        self.broadcast_tx.notify()
    }
}
<commit_msg>add some comments<commit_after>use super::super::{in_coroutine};

use std::sync::mpsc;

use super::notify;
use super::broadcast;

/// Channel receiving end
///
/// Create with `channel()`
pub struct Receiver<T>{
    rx: Option<mpsc::Receiver<T>>,
    notify_rx: notify::Receiver,
}

impl<T> Receiver<T>
    where T: 'static
{
    /// Receive `T` sent using corresponding `Sender::send()`.
    ///
    /// Will block coroutine if no elements are available.
    pub fn recv(&self) -> Result<T, mpsc::RecvError> {
        if in_coroutine() {
            loop {
                self.notify_rx.reset();

                let recv = self.try_recv();

                match recv {
                    Err(mpsc::TryRecvError::Empty) =>
                        self.notify_rx.wait(),
                    Err(mpsc::TryRecvError::Disconnected) => return Err(mpsc::RecvError),
                    Ok(t) => {
                        return Ok(t)
                    },
                }
            }
        } else {
            let recv = self.rx.as_ref().unwrap().recv();

                match recv {
                    Err(e) => Err(e),
                    Ok(t) => {
                        return Ok(t)
                    },
                }
        }
    }

    /// Try reading data from the queue.
    ///
    /// This will not block.
    pub fn try_recv(&self) -> Result<T, mpsc::TryRecvError> {
        let recv = self.rx.as_ref().unwrap().try_recv();
        match recv {
            Err(e) => Err(e),
            Ok(t) => {
                return Ok(t)
            },
        }
    }
}

/// Channel sending end
///
/// Use this inside mioco coroutines or outside of mioco itself to send data
/// asynchronously to the receiving end.
///
/// Create with `channel()`
pub struct Sender<T> {
    tx: Option<mpsc::Sender<T>>,
    notif_tx: notify::Sender,
}

impl<T> Clone for Sender<T> {
    fn clone(&self) -> Self {
        Sender {
            tx: self.tx.clone(),
            notif_tx: self.notif_tx.clone(),
        }
    }
}

impl<T> Sender<T> {
    /// Deliver `T` to the other end of the channel.
    ///
    /// Channel behaves like a queue.
    ///
    /// This is non-blocking operation.
    pub fn send(&self, t: T) -> Result<(), mpsc::SendError<T>> {
        try!(self.tx.as_ref().unwrap().send(t));
        self.notif_tx.notify();
        Ok(())
    }
}

/// Channel receiving end
///
/// Create with `channel()`
pub struct SyncReceiver<T>{
    rx: Option<mpsc::Receiver<T>>,
    broadcast_tx: broadcast::Sender,
    broadcast_rx: broadcast::Receiver,
}

impl<T> SyncReceiver<T>
    where T: 'static
{
    /// Receive `T` sent using corresponding `Sender::send()`.
    ///
    /// Will block coroutine if no elements are available.
    pub fn recv(&self) -> Result<T, mpsc::RecvError> {
        if in_coroutine() {
            loop {
                self.broadcast_rx.reset();

                let recv = self.try_recv();

                match recv {
                    Err(mpsc::TryRecvError::Empty) => self.broadcast_rx.wait(),
                    Err(mpsc::TryRecvError::Disconnected) => return Err(mpsc::RecvError),
                    Ok(t) => {
                        // wake up sender fiber in case it context switched
                        // because of channel full error
                        self.broadcast_tx.notify();
                        return Ok(t)
                    },
                }
            }
        } else {
            let recv = self.rx.as_ref().unwrap().recv();

                match recv {
                    Err(e) => Err(e),
                    Ok(t) => return Ok(t),
                }
        }
    }

    /// Try reading data from the queue.
    ///
    /// This will not block.
    pub fn try_recv(&self) -> Result<T, mpsc::TryRecvError> {
        let recv = self.rx.as_ref().unwrap().try_recv();
        match recv {
            Err(e) => Err(e),
            Ok(t) => {
                return Ok(t)
            },
        }
    }
}

/// Channel sync sending end
///
/// Use this inside mioco coroutines or outside of mioco itself to send data
/// asynchronously to the receiving end.
///
/// Create with `sync_channel()`
pub struct SyncSender<T> {
    tx: Option<mpsc::SyncSender<T>>,
    broadcast_rx: broadcast::Receiver,
    broadcast_tx: broadcast::Sender,
}

impl<T> SyncSender<T> {
    pub fn send(&self, mut t: T) -> Result<(), mpsc::SendError<T>> {
        if in_coroutine() {
            loop {
                t = match self.try_send(t) {
                    Ok(t) => return Ok(t),
                    Err(mpsc::TrySendError::Full(t)) => {
                        self.broadcast_rx.wait();
                        t
                    },
                    Err(mpsc::TrySendError::Disconnected(v)) => return Err(mpsc::SendError(v))
                };
            }
        } else {
            // previous send's notify() will make sure 'rx' will be notified
            // and there will be space for this send at some point
            self.tx.as_ref().unwrap().send(t)?;
        }
        self.broadcast_tx.notify();
        Ok(())
    }

    /// Deliver `T` to the other end of the channel.
    ///
    /// Channel behaves like a queue.
    ///
    /// This is non-blocking operation.
    pub fn try_send(&self, t: T) -> Result<(), mpsc::TrySendError<T>> {
        self.tx.as_ref().unwrap().try_send(t)?;
        self.broadcast_tx.notify();
        Ok(())
    }
}

/// Create a channel
///
/// Channel can be used to deliver data via MPSC queue.
///
/// Channel is modeled after `std::sync::mpsc::channel()`, only
/// supporting mioco-aware sending and receiving.
///
/// When receiving end is outside of coroutine, channel will behave just
/// like `std::sync::mpsc::channel()`.
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {

    let (n_tx, n_rx) = notify::channel();
    let (tx, rx) = mpsc::channel();
    (Sender {
        tx: Some(tx),
        notif_tx: n_tx,
    },
        Receiver {
            rx: Some(rx),
            notify_rx: n_rx,
        })
}

impl<T> Drop for Sender<T> {
    fn drop(&mut self) {
        {
            self.tx.take();
        }
        self.notif_tx.notify()
    }
}

pub fn sync_channel<T>(size: usize) -> (SyncSender<T>, SyncReceiver<T>) {

    let (btx, brx) = broadcast::channel();
    let (tx, rx) = mpsc::sync_channel(size);
    (   SyncSender {
            tx: Some(tx),
            broadcast_tx: btx.clone(),
            broadcast_rx: brx.clone(),
        },
        SyncReceiver {
            rx: Some(rx),
            broadcast_tx: btx,
            broadcast_rx: brx,
        }
    )
}

impl<T> Drop for SyncSender<T> {
    fn drop(&mut self) {
        {
            self.tx.take();
        }
        self.broadcast_tx.notify()
    }
}
<|endoftext|>


<commit_before>use libc;
use std::os::unix::io::RawFd;
use {Errno, Result};
use std::ffi::CStr;

bitflags!(
    pub struct MemFdCreateFlag: libc::c_uint {
        const MFD_CLOEXEC       = 0x0001;
        const MFD_ALLOW_SEALING = 0x0002;
    }
);

pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result<RawFd> {
    let res = unsafe {
        libc::syscall(libc::SYS_memfd_create, name.as_ptr(), flags.bits())
    };

    Errno::result(res).map(|r| r as RawFd)
}
<commit_msg>Migrate memfd constants to libc<commit_after>use libc;
use std::os::unix::io::RawFd;
use {Errno, Result};
use std::ffi::CStr;

libc_bitflags!(
    pub struct MemFdCreateFlag: libc::c_uint {
        MFD_CLOEXEC;
        MFD_ALLOW_SEALING;
    }
);

pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result<RawFd> {
    let res = unsafe {
        libc::syscall(libc::SYS_memfd_create, name.as_ptr(), flags.bits())
    };

    Errno::result(res).map(|r| r as RawFd)
}
<|endoftext|>


<commit_before>// error-pattern: error reading Clippy's configuration file: No such file or directory

#![feature(plugin)]
#![plugin(clippy(conf_file="./tests/compile-fail/non_existant_conf.toml"))]

fn main() {}
<commit_msg>don't check for an exact error message<commit_after>// error-pattern: error reading Clippy's configuration file

#![feature(plugin)]
#![plugin(clippy(conf_file="./tests/compile-fail/non_existant_conf.toml"))]

fn main() {}
<|endoftext|>