<commit_before>use std::thread;
use std::cell::UnsafeCell;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver, RecvError};
use basetypes::*;
use chess_move::*;
use tt::*;
use position::Position;

pub enum Command {
    Search {
        search_id: usize,
        position: Position,
        depth: u8,
        lower_bound: Value,
        upper_bound: Value,
    },
    Stop,
    Exit,
}

pub enum Report {
    Progress {
        search_id: usize,
        searched_nodes: NodeCount,
        depth: u8,
    },
    Done {
        search_id: usize,
        searched_nodes: NodeCount,
        value: Option<Value>,
    },
}

pub fn run_deepening(tt: Arc<TranspositionTable>,
                     commands: Receiver<Command>,
                     reports: Sender<Report>) {
    let (slave_commands_tx, slave_commands_rx) = channel();
    let (slave_reports_tx, slave_reports_rx) = channel();
    let slave = thread::spawn(move || {
        run(tt, slave_commands_rx, slave_reports_tx);
    });
    let mut pending_command = None;
    loop {
        // If there is a pending command, we take it, otherwise we
        // block and wait to receive a new one.
        let command = match pending_command.take() {
            Some(cmd) => cmd,
            None => commands.recv().or::<RecvError>(Ok(Command::Exit)).unwrap(),
        };

        match command {
            Command::Search { search_id, position, depth, lower_bound, upper_bound } => {
                let mut searched_nodes_final = 0;
                let mut value_final = None;
                'depthloop: for n in 1..(depth + 1) {
                    slave_commands_tx.send(Command::Search {
                                         search_id: n as usize,
                                         position: position.clone(),
                                         depth: n,
                                         lower_bound: lower_bound,
                                         upper_bound: upper_bound,
                                     })
                                     .unwrap();
                    loop {
                        match slave_reports_rx.recv().unwrap() {
                            Report::Progress { searched_nodes, .. } => {
                                reports.send(Report::Progress {
                                           search_id: search_id,
                                           searched_nodes: searched_nodes_final + searched_nodes,
                                           depth: n,
                                       })
                                       .ok();
                                if pending_command.is_none() {
                                    pending_command = match commands.try_recv() {
                                        Ok(cmd) => {
                                            slave_commands_tx.send(Command::Stop).unwrap();
                                            Some(cmd)
                                        }
                                        _ => None,
                                    }
                                }
                            }
                            Report::Done { searched_nodes, value, .. } => {
                                searched_nodes_final += searched_nodes;
                                if n == depth {
                                    value_final = value;
                                }
                                if pending_command.is_some() {
                                    break 'depthloop;
                                }
                                break;
                            }
                        }
                    }
                }
                reports.send(Report::Done {
                           search_id: search_id,
                           searched_nodes: searched_nodes_final,
                           value: value_final,
                       })
                       .ok();
            }
            Command::Stop => {
                slave_commands_tx.send(Command::Stop).unwrap();
                continue;
            }
            Command::Exit => {
                slave_commands_tx.send(Command::Exit).unwrap();
                break;
            }
        }
    }
    slave.join().unwrap();
}

pub fn run(tt: Arc<TranspositionTable>, commands: Receiver<Command>, reports: Sender<Report>) {
    thread_local!(
        static MOVE_STACK: UnsafeCell<MoveStack> = UnsafeCell::new(MoveStack::new())
    );
    MOVE_STACK.with(|s| {
        let mut move_stack = unsafe { &mut *s.get() };
        let mut pending_command = None;
        loop {
            // If there is a pending command, we take it, otherwise we
            // block and wait to receive a new one.
            let command = match pending_command.take() {
                Some(cmd) => cmd,
                None => commands.recv().or::<RecvError>(Ok(Command::Exit)).unwrap(),
            };

            match command {
                Command::Search { search_id, position, depth, lower_bound, upper_bound } => {
                    let mut report = |n| {
                        reports.send(Report::Progress {
                                   search_id: search_id,
                                   searched_nodes: n,
                                   depth: depth,
                               })
                               .ok();
                        match commands.try_recv() {
                            Ok(x) => {
                                pending_command = Some(x);
                                Err(TerminatedSearch)
                            }
                            _ => Ok(()),
                        }
                    };
                    let mut search = Search::new(&tt, position, move_stack, &mut report);
                    let value = search.run(lower_bound, upper_bound, depth).ok();
                    reports.send(Report::Progress {
                               search_id: search_id,
                               searched_nodes: search.node_count(),
                               depth: depth,
                           })
                           .ok();
                    reports.send(Report::Done {
                               search_id: search_id,
                               searched_nodes: search.node_count(),
                               value: value,
                           })
                           .ok();
                    search.reset();
                }
                Command::Stop => continue,
                Command::Exit => break,
            }
        }
    })
}

// Represents a terminated search condition.
struct TerminatedSearch;

enum NodePhase {
    Pristine,
    TriedHashMove,
    GeneratedMoves,
}

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

const NODE_COUNT_REPORT_INTERVAL: NodeCount = 10000;

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) -> Result<(), TerminatedSearch>,
}

impl<'a> Search<'a> {
    fn new(tt: &'a TranspositionTable,
           position: Position,
           moves: &'a mut MoveStack,
           report_function: &'a mut FnMut(NodeCount) -> Result<(), TerminatedSearch>)
           -> Search<'a> {
        let moves_starting_ply = moves.ply();
        Search {
            tt: tt,
            position: position,
            moves: moves,
            moves_starting_ply: moves_starting_ply,
            state_stack: Vec::with_capacity(32),
            reported_nodes: 0,
            unreported_nodes: 0,
            report_function: report_function,
        }
    }

    // Helper function for `run()`. It implements the principal variation
    // search algorithm. When returning `Err(TerminatedSearch)`, this
    // function may leave un-restored move lists in `moves`.
    fn run(&mut self,
           mut alpha: Value, // lower bound
           beta: Value, // upper bound
           depth: u8)
           -> Result<Value, TerminatedSearch> {
        assert!(alpha < beta);

        let entry = self.node_begin();

        // 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) ||
               (value <= alpha && bound == BOUND_UPPER) || (bound == BOUND_EXACT) {
                self.node_end();
                return Ok(value);
            }
        }

        // Initial guests for the final result.
        let mut bound = BOUND_UPPER;
        let mut best_move = Move::invalid();

        if depth == 0 {
            // On leaf nodes, do quiescence search.
            let (value, nodes) = self.position
                                     .evaluate_quiescence(alpha, beta, Some(entry.eval_value()));
            try!(self.report_progress(nodes));

            // See how good this position is.
            if value >= beta {
                alpha = beta;
                bound = BOUND_LOWER;
            } else if value > alpha {
                alpha = value;
                bound = BOUND_EXACT;
            }

        } else {
            // On non-leaf nodes, 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 {
                alpha = self.position.evaluate_final();
                bound = BOUND_EXACT;
            }
        }

        self.store(alpha, bound, depth, best_move);
        self.node_end();
        Ok(alpha)
    }

    #[inline(always)]
    pub fn node_count(&self) -> NodeCount {
        self.reported_nodes + self.unreported_nodes
    }

    #[inline]
    fn node_begin(&mut self) -> EntryData {
        // 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,
        });
        entry
    }

    // Go back to the parent node.
    #[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();
    }

    #[inline]
    fn do_move(&mut self) -> Option<Move> {
        let state = self.state_stack.last_mut().unwrap();

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

            // We always try the hash move first.
            state.phase = NodePhase::TriedHashMove;
            if state.entry.move16() != 0 {
                if let Some(m) = self.position.try_move_digest(state.entry.move16()) {
                    if self.position.do_move(m) {
                        return Some(m);
                    }
                }
            }
        }

        if let NodePhase::TriedHashMove = state.phase {
            // 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.
            self.position.generate_moves(self.moves);
            if state.entry.move16() != 0 {
                self.moves.remove_move(state.entry.move16());
            }
            state.phase = NodePhase::GeneratedMoves;
        }

        // For the last, we spit the generated moves out.
        while let Some(m) = self.moves.remove_best_move() {
            if self.position.do_move(m) {
                return Some(m);
            }
        }
        None
    }

    #[inline]
    fn undo_move(&mut self) {
        self.position.undo_move();
    }

    // Store the updated info 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;
        let move16 = match best_move.digest() {
            0 => entry.move16(),
            x => x,
        };
        self.tt.store(self.position.hash(),
                      EntryData::new(value, bound, depth, move16, entry.eval_value()));
    }

    // From time to time, we report how many nodes had been searched
    // since the last report. 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 > NODE_COUNT_REPORT_INTERVAL {
            self.reported_nodes += self.unreported_nodes;
            self.unreported_nodes = 0;
            try!((*self.report_function)(self.reported_nodes));
        }
        Ok(())
    }

    #[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;
    }
}

#[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 = |_| Ok(());
        let mut search = Search::new(&tt, p, &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 docs<commit_after>use std::thread;
use std::cell::UnsafeCell;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver, RecvError};
use basetypes::*;
use chess_move::*;
use tt::*;
use position::Position;

pub enum Command {
    Search {
        search_id: usize,
        position: Position,
        depth: u8,
        lower_bound: Value,
        upper_bound: Value,
    },
    Stop,
    Exit,
}

pub enum Report {
    Progress {
        search_id: usize,
        searched_nodes: NodeCount,
        depth: u8,
    },
    Done {
        search_id: usize,
        searched_nodes: NodeCount,
        value: Option<Value>,
    },
}

pub fn run_deepening(tt: Arc<TranspositionTable>,
                     commands: Receiver<Command>,
                     reports: Sender<Report>) {
    let (slave_commands_tx, slave_commands_rx) = channel();
    let (slave_reports_tx, slave_reports_rx) = channel();
    let slave = thread::spawn(move || {
        run(tt, slave_commands_rx, slave_reports_tx);
    });
    let mut pending_command = None;
    loop {
        // If there is a pending command, we take it, otherwise we
        // block and wait to receive a new one.
        let command = match pending_command.take() {
            Some(cmd) => cmd,
            None => commands.recv().or::<RecvError>(Ok(Command::Exit)).unwrap(),
        };

        match command {
            Command::Search { search_id, position, depth, lower_bound, upper_bound } => {
                let mut searched_nodes_final = 0;
                let mut value_final = None;
                'depthloop: for n in 1..(depth + 1) {
                    slave_commands_tx.send(Command::Search {
                                         search_id: n as usize,
                                         position: position.clone(),
                                         depth: n,
                                         lower_bound: lower_bound,
                                         upper_bound: upper_bound,
                                     })
                                     .unwrap();
                    loop {
                        match slave_reports_rx.recv().unwrap() {
                            Report::Progress { searched_nodes, .. } => {
                                reports.send(Report::Progress {
                                           search_id: search_id,
                                           searched_nodes: searched_nodes_final + searched_nodes,
                                           depth: n,
                                       })
                                       .ok();
                                if pending_command.is_none() {
                                    pending_command = match commands.try_recv() {
                                        Ok(cmd) => {
                                            slave_commands_tx.send(Command::Stop).unwrap();
                                            Some(cmd)
                                        }
                                        _ => None,
                                    }
                                }
                            }
                            Report::Done { searched_nodes, value, .. } => {
                                searched_nodes_final += searched_nodes;
                                if n == depth {
                                    value_final = value;
                                }
                                if pending_command.is_some() {
                                    break 'depthloop;
                                }
                                break;
                            }
                        }
                    }
                }
                reports.send(Report::Done {
                           search_id: search_id,
                           searched_nodes: searched_nodes_final,
                           value: value_final,
                       })
                       .ok();
            }
            Command::Stop => {
                slave_commands_tx.send(Command::Stop).unwrap();
                continue;
            }
            Command::Exit => {
                slave_commands_tx.send(Command::Exit).unwrap();
                break;
            }
        }
    }
    slave.join().unwrap();
}

pub fn run(tt: Arc<TranspositionTable>, commands: Receiver<Command>, reports: Sender<Report>) {
    thread_local!(
        static MOVE_STACK: UnsafeCell<MoveStack> = UnsafeCell::new(MoveStack::new())
    );
    MOVE_STACK.with(|s| {
        let mut move_stack = unsafe { &mut *s.get() };
        let mut pending_command = None;
        loop {
            // If there is a pending command, we take it, otherwise we
            // block and wait to receive a new one.
            let command = match pending_command.take() {
                Some(cmd) => cmd,
                None => commands.recv().or::<RecvError>(Ok(Command::Exit)).unwrap(),
            };

            match command {
                Command::Search { search_id, position, depth, lower_bound, upper_bound } => {
                    let mut report = |n| {
                        reports.send(Report::Progress {
                                   search_id: search_id,
                                   searched_nodes: n,
                                   depth: depth,
                               })
                               .ok();
                        match commands.try_recv() {
                            Ok(x) => {
                                pending_command = Some(x);
                                Err(TerminatedSearch)
                            }
                            _ => Ok(()),
                        }
                    };
                    let mut search = Search::new(&tt, position, move_stack, &mut report);
                    let value = search.run(lower_bound, upper_bound, depth).ok();
                    reports.send(Report::Progress {
                               search_id: search_id,
                               searched_nodes: search.node_count(),
                               depth: depth,
                           })
                           .ok();
                    reports.send(Report::Done {
                               search_id: search_id,
                               searched_nodes: search.node_count(),
                               value: value,
                           })
                           .ok();
                    search.reset();
                }
                Command::Stop => continue,
                Command::Exit => break,
            }
        }
    })
}

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

enum NodePhase {
    Pristine,
    TriedHashMove,
    GeneratedMoves,
}

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

const NODE_COUNT_REPORT_INTERVAL: NodeCount = 10000;

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) -> Result<(), TerminatedSearch>,
}

impl<'a> Search<'a> {
    /// Creates a new instance.
    pub fn new(tt: &'a TranspositionTable,
               position: Position,
               moves: &'a mut MoveStack,
               report_function: &'a mut FnMut(NodeCount) -> Result<(), TerminatedSearch>)
               -> Search<'a> {
        let moves_starting_ply = moves.ply();
        Search {
            tt: tt,
            position: position,
            moves: moves,
            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 and returns a result.
    ///
    /// **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);

        let entry = self.node_begin();

        // 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) ||
               (value <= alpha && bound == BOUND_UPPER) || (bound == BOUND_EXACT) {
                self.node_end();
                return Ok(value);
            }
        }

        // Initial guests for the final result.
        let mut bound = BOUND_UPPER;
        let mut best_move = Move::invalid();

        if depth == 0 {
            // On leaf nodes, do quiescence search.
            let (value, nodes) = self.position
                                     .evaluate_quiescence(alpha, beta, Some(entry.eval_value()));
            try!(self.report_progress(nodes));

            // See how good this position is.
            if value >= beta {
                alpha = beta;
                bound = BOUND_LOWER;
            } else if value > alpha {
                alpha = value;
                bound = BOUND_EXACT;
            }

        } else {
            // On non-leaf nodes, 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 {
                alpha = self.position.evaluate_final();
                bound = BOUND_EXACT;
            }
        }

        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 is a TT entry telling
    // everything we know about the current position.
    #[inline]
    fn node_begin(&mut self) -> EntryData {
        // 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,
        });
        entry
    }

    // 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();
    }

    // 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 {
            // We save the move list at the last possible moment,
            // because most of the nodes are leafs.
            self.moves.save();

            // We always try the hash move first.
            state.phase = NodePhase::TriedHashMove;
            if state.entry.move16() != 0 {
                if let Some(m) = self.position.try_move_digest(state.entry.move16()) {
                    if self.position.do_move(m) {
                        return Some(m);
                    }
                }
            }
        }

        if let NodePhase::TriedHashMove = state.phase {
            // 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.
            self.position.generate_moves(self.moves);
            if state.entry.move16() != 0 {
                self.moves.remove_move(state.entry.move16());
            }
            state.phase = NodePhase::GeneratedMoves;
        }

        // For the last, we spit the generated moves out.
        while let Some(m) = self.moves.remove_best_move() {
            if self.position.do_move(m) {
                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;
        let move16 = match best_move.digest() {
            0 => entry.move16(),
            x => x,
        };
        self.tt.store(self.position.hash(),
                      EntryData::new(value, bound, depth, move16, 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 > NODE_COUNT_REPORT_INTERVAL {
            self.reported_nodes += self.unreported_nodes;
            self.unreported_nodes = 0;
            try!((*self.report_function)(self.reported_nodes));
        }
        Ok(())
    }
}

#[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 = |_| Ok(());
        let mut search = Search::new(&tt, p, &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>use super::point::Point;

#[derive(Debug)]
pub struct Triangle {
   pub a: Point,
   pub b: Point,
   pub c: Point
}

impl Triangle {
   pub fn new(a: Point, b: Point, c: Point) -> Self {
      Triangle {
         a: a,
         b: b,
         c: c
      }
   }
}
<commit_msg>Triangle orientation methods<commit_after>use std::mem;

use super::point::Point;

#[derive(Debug)]
pub struct Triangle {
   pub a: Point,
   pub b: Point,
   pub c: Point
}

impl Triangle {
   pub fn new(a: Point, b: Point, c: Point) -> Self {
      Triangle {
         a: a,
         b: b,
         c: c
      }
   }

   #[inline]
   pub fn clockwise(&self) -> bool {
      (self.b.x - self.a.x) * (self.c.y - self.a.y) < (self.c.x - self.a.x) * (self.b.y - self.a.y)
   }

   #[inline]
   pub fn change_orientation(&mut self) {
      mem::swap(&mut self.b, &mut self.c);
   }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::path::Path;

use common::ui::UI;
use hcore::crypto::SigKeyPair;
use hcore::env;

use {AUTH_TOKEN_ENVVAR, ORIGIN_ENVVAR};
use analytics;
use command;
use config;
use error::Result;

pub fn start(ui: &mut UI, cache_path: &Path, analytics_path: &Path) -> Result<()> {
    let mut generated_origin = false;

    ui.br()?;
    ui.title("Habitat CLI Setup")?;
    ui.para("Welcome to hab setup. Let's get started.")?;

    ui.heading("Set up a default origin")?;
    ui.para(
        "Every package in Habitat belongs to an origin, which indicates the person or \
               organization responsible for maintaining that package. Each origin also has \
               a key used to cryptographically sign packages in that origin.",
    )?;
    ui.para(
        "Selecting a default origin tells package building operations such as 'hab \
                  pkg build' what key should be used to sign the packages produced. If you \
                  do not set a default origin now, you will have to tell package building \
                  commands each time what origin to use.",
    )?;
    ui.para(
        "For more information on origins and how they are used in building packages, \
               please consult the docs at https://www.habitat.sh/docs/create-packages-build/",
    )?;
    if ask_default_origin(ui)? {
        ui.br()?;
        ui.para(
            "Enter the name of your origin. If you plan to publish your packages \
                      publicly, we recommend that you select one that is not already in use \
                      on the Habitat build service found at https://bldr.habitat.sh/.",
        )?;
        let origin = prompt_origin(ui)?;
        write_cli_config_origin(&origin)?;
        ui.br()?;
        if is_origin_in_cache(&origin, cache_path) {
            ui.para(&format!(
                "You already have an origin key for {} created and \
                                   installed. Great work!",
                &origin
            ))?;
        } else {
            ui.heading("Create origin key pair")?;
            ui.para(&format!(
                "It doesn't look like you have a signing key for the origin \
                                `{}'. Without it, you won't be able to build new packages \
                                successfully.",
                &origin
            ))?;
            ui.para(
                "You can either create a new signing key now, or, if you are building \
                       packages for an origin that already exists, ask the owner to give \
                       you the signing key.",
            )?;
            ui.para(
                "For more information on the use of origin keys, please consult \
                          the documentation at \
                          https://www.habitat.sh/docs/concepts-keys/#origin-keys",
            )?;
            if ask_create_origin(ui, &origin)? {
                create_origin(ui, &origin, cache_path)?;
                generated_origin = true;
            } else {
                ui.para(&format!(
                    "You might want to create an origin key later with: \
                                       `hab origin key generate {}'",
                    &origin
                ))?;
            }
        }
    } else {
        ui.para("Okay, maybe another time.")?;
    }
    ui.heading("GitHub Access Token")?;
    ui.para(
        "While you can build and run Habitat packages without sharing them on the public \
               depot, doing so allows you to collaborate with the Habitat community. In \
               addition, it is how you can perform continuous deployment with Habitat.",
    )?;
    ui.para(
        "The depot uses GitHub authentication by personal access token with the \
                  user:email and read:org scopes (https://help.github.\
                  com/articles/creating-an-access-token-for-command-line-use/).",
    )?;
    ui.para(
        "If you would like to share your packages on the depot, please enter your GitHub \
               access token. Otherwise, just enter No.",
    )?;
    ui.para(
        "For more information on sharing packages on the depot, please read the \
          documentation at https://www.habitat.sh/docs/share-packages-overview/",
    )?;
    if ask_default_auth_token(ui)? {
        ui.br()?;
        ui.para("Enter your GitHub access token.")?;
        let auth_token = prompt_auth_token(ui)?;
        write_cli_config_auth_token(&auth_token)?;
    } else {
        ui.para("Okay, maybe another time.")?;
    }
    ui.heading("Analytics")?;
    ui.para(
        "The `hab` command-line tool will optionally send anonymous usage data to \
               Habitat's Google Analytics account. This is a strictly opt-in activity and \
               no tracking will occur unless you respond affirmatively to the question \
               below.",
    )?;
    ui.para(
        "We collect this data to help improve Habitat's user experience. For example, we \
               would like to know the category of tasks users are performing, and which ones \
               they are having trouble with (e.g. mistyping command line arguments).",
    )?;
    ui.para(
        "To see what kinds of data are sent and how they are anonymized, please read more \
               about our analytics here: https://www.habitat.sh/docs/about-analytics/",
    )?;
    if ask_enable_analytics(ui, analytics_path)? {
        opt_in_analytics(ui, analytics_path, generated_origin)?;
    } else {
        opt_out_analytics(ui, analytics_path)?;
    }
    ui.heading("CLI Setup Complete")?;
    ui.para("That's all for now. Thanks for using Habitat!")?;
    Ok(())
}

fn ask_default_origin(ui: &mut UI) -> Result<bool> {
    Ok(ui.prompt_yes_no("Set up a default origin?", Some(true))?)
}

fn ask_create_origin(ui: &mut UI, origin: &str) -> Result<bool> {
    Ok(ui.prompt_yes_no(
        &format!("Create an origin key for `{}'?", origin),
        Some(true),
    )?)
}

fn write_cli_config_origin(origin: &str) -> Result<()> {
    let mut config = config::load()?;
    config.origin = Some(origin.to_string());
    config::save(&config)
}

fn write_cli_config_auth_token(auth_token: &str) -> Result<()> {
    let mut config = config::load()?;
    config.auth_token = Some(auth_token.to_string());
    config::save(&config)
}

fn is_origin_in_cache(origin: &str, cache_path: &Path) -> bool {
    match SigKeyPair::get_latest_pair_for(origin, cache_path, None) {
        Ok(pair) => {
            match pair.secret() {
                Ok(_) => true,
                _ => false,
            }
        }
        _ => false,
    }
}

fn create_origin(ui: &mut UI, origin: &str, cache_path: &Path) -> Result<()> {
    let result = command::origin::key::generate::start(ui, &origin, cache_path);
    ui.br()?;
    result
}

fn prompt_origin(ui: &mut UI) -> Result<String> {
    let config = config::load()?;
    let default = match config.origin {
        Some(o) => {
            ui.para(&format!(
                "You already have a default origin set up as `{}', but feel \
                                free to change it if you wish.",
                &o
            ))?;
            Some(o)
        }
        None => env::var(ORIGIN_ENVVAR).or(env::var("USER")).ok(),
    };
    Ok(ui.prompt_ask(
        "Default origin name",
        default.as_ref().map(|x| &**x),
    )?)
}

fn ask_default_auth_token(ui: &mut UI) -> Result<bool> {
    Ok(ui.prompt_yes_no(
        "Set up a default GitHub access token?",
        Some(true),
    )?)
}

fn prompt_auth_token(ui: &mut UI) -> Result<String> {
    let config = config::load()?;
    let default = match config.auth_token {
        Some(o) => {
            ui.para(
                "You already have a default auth token set up, but feel free to change it \
                       if you wish.",
            )?;
            Some(o)
        }
        None => env::var(AUTH_TOKEN_ENVVAR).ok(),
    };
    Ok(ui.prompt_ask(
        "GitHub access token",
        default.as_ref().map(|x| &**x),
    )?)
}

fn ask_enable_analytics(ui: &mut UI, analytics_path: &Path) -> Result<bool> {
    let default = match analytics::is_opted_in(analytics_path) {
        Some(val) => Some(val),
        None => Some(true),
    };
    Ok(ui.prompt_yes_no("Enable analytics?", default)?)
}

fn opt_in_analytics(ui: &mut UI, analytics_path: &Path, generated_origin: bool) -> Result<()> {
    let result = analytics::opt_in(ui, analytics_path, generated_origin);
    ui.br()?;
    result
}

fn opt_out_analytics(ui: &mut UI, analytics_path: &Path) -> Result<()> {
    let result = analytics::opt_out(ui, analytics_path);
    ui.br()?;
    result
}
<commit_msg>Validate origin before writing config file<commit_after>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::path::Path;

use common::ui::UI;
use hcore::crypto::SigKeyPair;
use hcore::env;
use hcore::origin::validate_origin;

use {AUTH_TOKEN_ENVVAR, ORIGIN_ENVVAR};
use analytics;
use command;
use config;
use error::Result;

pub fn start(ui: &mut UI, cache_path: &Path, analytics_path: &Path) -> Result<()> {
    let mut generated_origin = false;

    ui.br()?;
    ui.title("Habitat CLI Setup")?;
    ui.para("Welcome to hab setup. Let's get started.")?;

    ui.heading("Set up a default origin")?;
    ui.para(
        "Every package in Habitat belongs to an origin, which indicates the person or \
               organization responsible for maintaining that package. Each origin also has \
               a key used to cryptographically sign packages in that origin.",
    )?;
    ui.para(
        "Selecting a default origin tells package building operations such as 'hab \
                  pkg build' what key should be used to sign the packages produced. If you \
                  do not set a default origin now, you will have to tell package building \
                  commands each time what origin to use.",
    )?;
    ui.para(
        "For more information on origins and how they are used in building packages, \
               please consult the docs at https://www.habitat.sh/docs/create-packages-build/",
    )?;
    if ask_default_origin(ui)? {
        ui.br()?;
        ui.para(
            "Enter the name of your origin. If you plan to publish your packages \
                      publicly, we recommend that you select one that is not already in use \
                      on the Habitat build service found at https://bldr.habitat.sh/.",
        )?;
        let origin = prompt_origin(ui)?;
        validate_origin(&origin)?;
        write_cli_config_origin(&origin)?;
        ui.br()?;
        if is_origin_in_cache(&origin, cache_path) {
            ui.para(&format!(
                "You already have an origin key for {} created and \
                                   installed. Great work!",
                &origin
            ))?;
        } else {
            ui.heading("Create origin key pair")?;
            ui.para(&format!(
                "It doesn't look like you have a signing key for the origin \
                                `{}'. Without it, you won't be able to build new packages \
                                successfully.",
                &origin
            ))?;
            ui.para(
                "You can either create a new signing key now, or, if you are building \
                       packages for an origin that already exists, ask the owner to give \
                       you the signing key.",
            )?;
            ui.para(
                "For more information on the use of origin keys, please consult \
                          the documentation at \
                          https://www.habitat.sh/docs/concepts-keys/#origin-keys",
            )?;
            if ask_create_origin(ui, &origin)? {
                create_origin(ui, &origin, cache_path)?;
                generated_origin = true;
            } else {
                ui.para(&format!(
                    "You might want to create an origin key later with: \
                                       `hab origin key generate {}'",
                    &origin
                ))?;
            }
        }
    } else {
        ui.para("Okay, maybe another time.")?;
    }
    ui.heading("GitHub Access Token")?;
    ui.para(
        "While you can build and run Habitat packages without sharing them on the public \
               depot, doing so allows you to collaborate with the Habitat community. In \
               addition, it is how you can perform continuous deployment with Habitat.",
    )?;
    ui.para(
        "The depot uses GitHub authentication by personal access token with the \
                  user:email and read:org scopes (https://help.github.\
                  com/articles/creating-an-access-token-for-command-line-use/).",
    )?;
    ui.para(
        "If you would like to share your packages on the depot, please enter your GitHub \
               access token. Otherwise, just enter No.",
    )?;
    ui.para(
        "For more information on sharing packages on the depot, please read the \
          documentation at https://www.habitat.sh/docs/share-packages-overview/",
    )?;
    if ask_default_auth_token(ui)? {
        ui.br()?;
        ui.para("Enter your GitHub access token.")?;
        let auth_token = prompt_auth_token(ui)?;
        write_cli_config_auth_token(&auth_token)?;
    } else {
        ui.para("Okay, maybe another time.")?;
    }
    ui.heading("Analytics")?;
    ui.para(
        "The `hab` command-line tool will optionally send anonymous usage data to \
               Habitat's Google Analytics account. This is a strictly opt-in activity and \
               no tracking will occur unless you respond affirmatively to the question \
               below.",
    )?;
    ui.para(
        "We collect this data to help improve Habitat's user experience. For example, we \
               would like to know the category of tasks users are performing, and which ones \
               they are having trouble with (e.g. mistyping command line arguments).",
    )?;
    ui.para(
        "To see what kinds of data are sent and how they are anonymized, please read more \
               about our analytics here: https://www.habitat.sh/docs/about-analytics/",
    )?;
    if ask_enable_analytics(ui, analytics_path)? {
        opt_in_analytics(ui, analytics_path, generated_origin)?;
    } else {
        opt_out_analytics(ui, analytics_path)?;
    }
    ui.heading("CLI Setup Complete")?;
    ui.para("That's all for now. Thanks for using Habitat!")?;
    Ok(())
}

fn ask_default_origin(ui: &mut UI) -> Result<bool> {
    Ok(ui.prompt_yes_no("Set up a default origin?", Some(true))?)
}

fn ask_create_origin(ui: &mut UI, origin: &str) -> Result<bool> {
    Ok(ui.prompt_yes_no(
        &format!("Create an origin key for `{}'?", origin),
        Some(true),
    )?)
}

fn write_cli_config_origin(origin: &str) -> Result<()> {
    let mut config = config::load()?;
    config.origin = Some(origin.to_string());
    config::save(&config)
}

fn write_cli_config_auth_token(auth_token: &str) -> Result<()> {
    let mut config = config::load()?;
    config.auth_token = Some(auth_token.to_string());
    config::save(&config)
}

fn is_origin_in_cache(origin: &str, cache_path: &Path) -> bool {
    match SigKeyPair::get_latest_pair_for(origin, cache_path, None) {
        Ok(pair) => {
            match pair.secret() {
                Ok(_) => true,
                _ => false,
            }
        }
        _ => false,
    }
}

fn create_origin(ui: &mut UI, origin: &str, cache_path: &Path) -> Result<()> {
    let result = command::origin::key::generate::start(ui, &origin, cache_path);
    ui.br()?;
    result
}

fn prompt_origin(ui: &mut UI) -> Result<String> {
    let config = config::load()?;
    let default = match config.origin {
        Some(o) => {
            ui.para(&format!(
                "You already have a default origin set up as `{}', but feel \
                                free to change it if you wish.",
                &o
            ))?;
            Some(o)
        }
        None => env::var(ORIGIN_ENVVAR).or(env::var("USER")).ok(),
    };
    Ok(ui.prompt_ask(
        "Default origin name",
        default.as_ref().map(|x| &**x),
    )?)
}

fn ask_default_auth_token(ui: &mut UI) -> Result<bool> {
    Ok(ui.prompt_yes_no(
        "Set up a default GitHub access token?",
        Some(true),
    )?)
}

fn prompt_auth_token(ui: &mut UI) -> Result<String> {
    let config = config::load()?;
    let default = match config.auth_token {
        Some(o) => {
            ui.para(
                "You already have a default auth token set up, but feel free to change it \
                       if you wish.",
            )?;
            Some(o)
        }
        None => env::var(AUTH_TOKEN_ENVVAR).ok(),
    };
    Ok(ui.prompt_ask(
        "GitHub access token",
        default.as_ref().map(|x| &**x),
    )?)
}

fn ask_enable_analytics(ui: &mut UI, analytics_path: &Path) -> Result<bool> {
    let default = match analytics::is_opted_in(analytics_path) {
        Some(val) => Some(val),
        None => Some(true),
    };
    Ok(ui.prompt_yes_no("Enable analytics?", default)?)
}

fn opt_in_analytics(ui: &mut UI, analytics_path: &Path, generated_origin: bool) -> Result<()> {
    let result = analytics::opt_in(ui, analytics_path, generated_origin);
    ui.br()?;
    result
}

fn opt_out_analytics(ui: &mut UI, analytics_path: &Path) -> Result<()> {
    let result = analytics::opt_out(ui, analytics_path);
    ui.br()?;
    result
}
<|endoftext|>


<commit_before>use lexer::new;
use lexer::Lexer;
use lexer::StateFunction;
use lexer::Token;
use lexer::Category;

fn initial_state(lexer: &mut Lexer) -> Option<StateFunction> {
    if lexer.token_position >= lexer.char_count {
        lexer.tokenize(Category::Text);

        return None;
    }

    // TODO: Replace char_at with something UTF8 compatible.
    match lexer.data.char_at(lexer.token_position) {
        '{' => {
            lexer.tokenize(Category::Text);

            lexer.tokens.push(Token{ lexeme: lexer.data.char_at(lexer.token_position).to_string(), category: Category::Brace });
            lexer.token_start += 1;
            lexer.token_position += 1;
            Some(StateFunction(initial_state))
        },
        '[' => {
            lexer.tokenize(Category::Text);

            lexer.tokens.push(Token{ lexeme: lexer.data.char_at(lexer.token_position).to_string(), category: Category::Bracket });
            lexer.token_start += 1;
            lexer.token_position += 1;
            Some(StateFunction(initial_state))
        },
        ' ' | '\n' => {
            lexer.tokenize(Category::Text);

            lexer.token_position += 1;
            Some(StateFunction(whitespace))
        },
        '"' => {
            lexer.tokenize(Category::Text);

            lexer.token_position += 1;
            Some(StateFunction(inside_string))
        },
        ':' => {
            lexer.tokenize(Category::Text);

            lexer.tokens.push(Token{ lexeme: lexer.data.char_at(lexer.token_position).to_string(), category: Category::AssignmentOperator });
            lexer.token_start += 1;
            lexer.token_position += 1;
            Some(StateFunction(initial_state))
        },
        '}' => {
            lexer.tokenize(Category::Text);

            lexer.tokens.push(Token{ lexeme: lexer.data.char_at(lexer.token_position).to_string(), category: Category::Brace });
            None
        },
        ']' => {
            lexer.tokenize(Category::Text);

            lexer.tokens.push(Token{ lexeme: lexer.data.char_at(lexer.token_position).to_string(), category: Category::Bracket });
            lexer.token_start += 1;
            lexer.token_position += 1;
            Some(StateFunction(initial_state))
        },
        _ => {
            if lexer.token_position == lexer.token_start {
                let remaining_data = lexer.data.slice_from(lexer.token_position);
                if remaining_data.starts_with("true") {
                    lexer.token_position += 4;
                    lexer.tokens.push(Token{
                        lexeme: lexer.data.slice_chars(lexer.token_start,
                            lexer.token_position).to_string(),
                        category: Category::Boolean
                    });
                    lexer.token_start = lexer.token_position;
                } else if remaining_data.starts_with("false") {
                    lexer.token_position += 5;
                    lexer.tokens.push(Token{
                        lexeme: lexer.data.slice_chars(lexer.token_start,
                            lexer.token_position).to_string(),
                        category: Category::Boolean
                    });
                    lexer.token_start = lexer.token_position;
                } else if remaining_data.starts_with("null") {
                    lexer.token_position += 4;
                    lexer.tokens.push(Token{
                        lexeme: lexer.data.slice_chars(lexer.token_start,
                            lexer.token_position).to_string(),
                        category: Category::Keyword
                    });
                    lexer.token_start = lexer.token_position;
                } else {
                    lexer.token_position += 1;
                }
            } else {
                lexer.token_position += 1;
            }
            Some(StateFunction(initial_state))
        }
    }
}

fn inside_string(lexer: &mut Lexer) -> Option<StateFunction> {
    if lexer.token_position >= lexer.char_count {
        lexer.tokens.push(Token{ lexeme: lexer.data.slice_chars(lexer.token_start, lexer.token_position).to_string(), category: Category::String });
        return None;
    }
    match lexer.data.char_at(lexer.token_position) {
        '"' => {
            lexer.token_position += 1;
            lexer.tokens.push(Token{ lexeme: lexer.data.slice_chars(lexer.token_start, lexer.token_position).to_string(), category: Category::String });
            lexer.token_start = lexer.token_position;
            Some(StateFunction(initial_state))
        },
        '\\' => {
            lexer.token_position += 2;
            Some(StateFunction(inside_string))
        }
        _ => {
            lexer.token_position += 1;
            Some(StateFunction(inside_string))
        }
    }
}

fn whitespace(lexer: &mut Lexer) -> Option<StateFunction> {
    match lexer.data.char_at(lexer.token_position) {
        ' ' | '\n' => {
            lexer.token_position += 1;
            Some(StateFunction(whitespace))
        },
        _ => {
            lexer.tokens.push(Token{ lexeme: lexer.data.slice_chars(lexer.token_start, lexer.token_position).to_string(), category: Category::Whitespace });
            lexer.token_start = lexer.token_position;
            Some(StateFunction(initial_state))
        }
    }
}

fn lex(data: &str) -> Vec<Token> {
    let mut lexer = new(data);
    let mut state_function = StateFunction(initial_state);
    loop {
        let StateFunction(actual_function) = state_function;
        match actual_function(&mut lexer) {
            Some(f) => state_function = f,
            None => return lexer.tokens,
        }
    }
}

mod tests {
    use super::lex;
    use lexer::Token;
    use lexer::Category;
    use std::old_io::{File, Open, Read};

    #[test]
    fn it_works() {
        let data = File::open_mode(&Path::new("test_data/data.json"), Open, Read)
            .unwrap().read_to_string().unwrap();
        let tokens = lex(&data);
        let expected_tokens = vec![
            Token{ lexeme: "{".to_string(), category: Category::Brace },
            Token{ lexeme: "\n  ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "\"key\"".to_string(), category: Category::String },
            Token{ lexeme: ":".to_string(), category: Category::AssignmentOperator },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "\"4032\"".to_string(), category: Category::String },
            Token{ lexeme: ",".to_string(), category: Category::Text },
            Token{ lexeme: "\n  ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "'single'".to_string(), category: Category::Text },
            Token{ lexeme: ":".to_string(), category: Category::AssignmentOperator },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "'quotes\\'',".to_string(), category: Category::Text },
            Token{ lexeme: "\n  ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "\"literals\"".to_string(), category: Category::String },
            Token{ lexeme: ":".to_string(), category: Category::AssignmentOperator },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "[".to_string(), category: Category::Bracket },
            Token{ lexeme: "\n    ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "true".to_string(), category: Category::Boolean },
            Token{ lexeme: ",".to_string(), category: Category::Text },
            Token{ lexeme: "\n    ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "false".to_string(), category: Category::Boolean },
            Token{ lexeme: ",".to_string(), category: Category::Text },
            Token{ lexeme: "\n    ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "null".to_string(), category: Category::Keyword },
            Token{ lexeme: "\n  ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "]".to_string(), category: Category::Bracket },
            Token{ lexeme: "\n".to_string(), category: Category::Whitespace },
            Token{ lexeme: "}".to_string(), category: Category::Brace },
        ];

        for (index, token) in tokens.iter().enumerate() {
            assert_eq!(*token, expected_tokens[index]);
        }
    }

    #[test]
    fn it_can_handle_garbage() {
        let tokens = lex("} adwyx123&*_ ");
        let expected_tokens = vec![
            Token{ lexeme: "}".to_string(), category: Category::Brace },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "adwyx123&*_".to_string(), category: Category::Text },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
        ];

        for (index, token) in tokens.iter().enumerate() {
            assert_eq!(*token, expected_tokens[index]);
        }
    }

    #[test]
    fn it_can_handle_open_strings() {
        let tokens = lex("\"open!");
        let expected_tokens = vec![
            Token{ lexeme: "\"open!".to_string(), category: Category::String },
        ];

        for (index, token) in tokens.iter().enumerate() {
            assert_eq!(*token, expected_tokens[index]);
        }
    }
}
<commit_msg>Refactor JSON parse to use new lexer functions where possible.<commit_after>use lexer::new;
use lexer::Lexer;
use lexer::StateFunction;
use lexer::Token;
use lexer::Category;

fn initial_state(lexer: &mut Lexer) -> Option<StateFunction> {
    if lexer.has_more_data() {
        // TODO: Replace char_at with something UTF8 compatible.
        match lexer.data.char_at(lexer.token_position) {
            '{' => {
                lexer.tokenize_next(1, Category::Brace);
                Some(StateFunction(initial_state))
            },
            '[' => {
                lexer.tokenize_next(1, Category::Bracket);
                Some(StateFunction(initial_state))
            },
            ' ' | '\n' => {
                lexer.tokenize(Category::Text);
                lexer.advance();
                Some(StateFunction(whitespace))
            },
            '"' => {
                lexer.tokenize(Category::Text);
                lexer.advance();
                Some(StateFunction(inside_string))
            },
            ':' => {
                lexer.tokenize_next(1, Category::AssignmentOperator);
                Some(StateFunction(initial_state))
            },
            '}' => {
                lexer.tokenize_next(1, Category::Brace);
                None
            },
            ']' => {
                lexer.tokenize_next(1, Category::Bracket);
                Some(StateFunction(initial_state))
            },
            _ => {
                if lexer.token_position == lexer.token_start {
                    let remaining_data = lexer.data.slice_from(lexer.token_position);
                    if remaining_data.starts_with("true") {
                        lexer.token_position += 4;
                        lexer.tokens.push(Token{
                            lexeme: lexer.data.slice_chars(lexer.token_start,
                                lexer.token_position).to_string(),
                            category: Category::Boolean
                        });
                        lexer.token_start = lexer.token_position;
                    } else if remaining_data.starts_with("false") {
                        lexer.token_position += 5;
                        lexer.tokens.push(Token{
                            lexeme: lexer.data.slice_chars(lexer.token_start,
                                lexer.token_position).to_string(),
                            category: Category::Boolean
                        });
                        lexer.token_start = lexer.token_position;
                    } else if remaining_data.starts_with("null") {
                        lexer.token_position += 4;
                        lexer.tokens.push(Token{
                            lexeme: lexer.data.slice_chars(lexer.token_start,
                                lexer.token_position).to_string(),
                            category: Category::Keyword
                        });
                        lexer.token_start = lexer.token_position;
                    } else {
                        lexer.token_position += 1;
                    }
                } else {
                    lexer.token_position += 1;
                }
                Some(StateFunction(initial_state))
            }
        }
    } else {
        lexer.tokenize(Category::Text);
        None
    }

}

fn inside_string(lexer: &mut Lexer) -> Option<StateFunction> {
    if lexer.has_more_data() {
        match lexer.data.char_at(lexer.token_position) {
            '"' => {
                lexer.advance();
                lexer.tokenize(Category::String);
                Some(StateFunction(initial_state))
            },
            '\\' => {
                lexer.advance();
                lexer.advance();
                Some(StateFunction(inside_string))
            }
            _ => {
                lexer.advance();
                Some(StateFunction(inside_string))
            }
        }
    } else {
        lexer.tokenize(Category::String);
        None
    }
}

fn whitespace(lexer: &mut Lexer) -> Option<StateFunction> {
    match lexer.data.char_at(lexer.token_position) {
        ' ' | '\n' => {
            lexer.advance();
            Some(StateFunction(whitespace))
        },
        _ => {
            lexer.tokenize(Category::Whitespace);
            Some(StateFunction(initial_state))
        }
    }
}

fn lex(data: &str) -> Vec<Token> {
    let mut lexer = new(data);
    let mut state_function = StateFunction(initial_state);
    loop {
        let StateFunction(actual_function) = state_function;
        match actual_function(&mut lexer) {
            Some(f) => state_function = f,
            None => return lexer.tokens,
        }
    }
}

mod tests {
    use super::lex;
    use lexer::Token;
    use lexer::Category;
    use std::old_io::{File, Open, Read};

    #[test]
    fn it_works() {
        let data = File::open_mode(&Path::new("test_data/data.json"), Open, Read)
            .unwrap().read_to_string().unwrap();
        let tokens = lex(&data);
        let expected_tokens = vec![
            Token{ lexeme: "{".to_string(), category: Category::Brace },
            Token{ lexeme: "\n  ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "\"key\"".to_string(), category: Category::String },
            Token{ lexeme: ":".to_string(), category: Category::AssignmentOperator },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "\"4032\"".to_string(), category: Category::String },
            Token{ lexeme: ",".to_string(), category: Category::Text },
            Token{ lexeme: "\n  ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "'single'".to_string(), category: Category::Text },
            Token{ lexeme: ":".to_string(), category: Category::AssignmentOperator },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "'quotes\\'',".to_string(), category: Category::Text },
            Token{ lexeme: "\n  ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "\"literals\"".to_string(), category: Category::String },
            Token{ lexeme: ":".to_string(), category: Category::AssignmentOperator },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "[".to_string(), category: Category::Bracket },
            Token{ lexeme: "\n    ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "true".to_string(), category: Category::Boolean },
            Token{ lexeme: ",".to_string(), category: Category::Text },
            Token{ lexeme: "\n    ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "false".to_string(), category: Category::Boolean },
            Token{ lexeme: ",".to_string(), category: Category::Text },
            Token{ lexeme: "\n    ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "null".to_string(), category: Category::Keyword },
            Token{ lexeme: "\n  ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "]".to_string(), category: Category::Bracket },
            Token{ lexeme: "\n".to_string(), category: Category::Whitespace },
            Token{ lexeme: "}".to_string(), category: Category::Brace },
        ];

        for (index, token) in tokens.iter().enumerate() {
            assert_eq!(*token, expected_tokens[index]);
        }
    }

    #[test]
    fn it_can_handle_garbage() {
        let tokens = lex("} adwyx123&*_ ");
        let expected_tokens = vec![
            Token{ lexeme: "}".to_string(), category: Category::Brace },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "adwyx123&*_".to_string(), category: Category::Text },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
        ];

        for (index, token) in tokens.iter().enumerate() {
            assert_eq!(*token, expected_tokens[index]);
        }
    }

    #[test]
    fn it_can_handle_open_strings() {
        let tokens = lex("\"open!");
        let expected_tokens = vec![
            Token{ lexeme: "\"open!".to_string(), category: Category::String },
        ];

        for (index, token) in tokens.iter().enumerate() {
            assert_eq!(*token, expected_tokens[index]);
        }
    }
}
<|endoftext|>


<commit_before>use std::rt::io::mem::{MemReader, with_mem_writer};
use std::str;
use headers::{HeaderConvertible, HeaderValueByteIterator};

pub fn from_stream_with_str<T: HeaderConvertible>(s: &str) -> Option<T> {
    let mut bytes = s.as_bytes().into_owned();
    bytes.push_all(bytes!("\r\n/"));

    let mut reader = MemReader::new(bytes.into_owned());
    let mut iter = HeaderValueByteIterator::new(&mut reader);
    HeaderConvertible::from_stream(&mut iter)
}

pub fn to_stream_into_str<T: HeaderConvertible>(v: &T) -> ~str {
    let contents = do with_mem_writer |writer|
      { v.to_stream(writer); };
    str::from_utf8(contents)
}

// Verify that a value cannot be successfully interpreted as a header value of the specified type.
#[inline]
pub fn assert_invalid<T: HeaderConvertible>(string: &str) {
    assert_eq!(from_stream_with_str::<T>(string), None);
}

// Verify that all of the methods from the HeaderConvertible trait work correctly for the given
// valid header value and correct decoded value.
#[inline]
pub fn assert_conversion_correct<T: HeaderConvertible>(string: &'static str, value: T) {
    assert_eq!(from_stream_with_str(string), Some(value.clone()));
    let s = to_stream_into_str(&value);
    assert_eq!(s.as_slice(), string);
    let s = value.http_value();
    assert_eq!(s.as_slice(), string);
}

// Verify that from_stream interprets the given valid header value correctly.
#[inline]
pub fn assert_interpretation_correct<T: HeaderConvertible>(string: &'static str, value: T) {
    assert_eq!(from_stream_with_str(string), Some(value));
}
<commit_msg>Use the Decorator trait rather than workarounds<commit_after>use std::rt::io::Decorator;
use std::rt::io::mem::{MemReader, MemWriter};
use std::str;
use headers::{HeaderConvertible, HeaderValueByteIterator};

pub fn from_stream_with_str<T: HeaderConvertible>(s: &str) -> Option<T> {
    let bytes = s.as_bytes();
    let mut reader = MemReader::new(bytes.into_owned());
    reader.inner_mut_ref().push_all(bytes!("\r\n/"));
    let mut iter = HeaderValueByteIterator::new(&mut reader);
    HeaderConvertible::from_stream(&mut iter)
}

pub fn to_stream_into_str<T: HeaderConvertible>(v: &T) -> ~str {
    let mut writer = MemWriter::new();
    v.to_stream(&mut writer);
    str::from_utf8(writer.inner_ref().as_slice())
}

// Verify that a value cannot be successfully interpreted as a header value of the specified type.
#[inline]
pub fn assert_invalid<T: HeaderConvertible>(string: &str) {
    assert_eq!(from_stream_with_str::<T>(string), None);
}

// Verify that all of the methods from the HeaderConvertible trait work correctly for the given
// valid header value and correct decoded value.
#[inline]
pub fn assert_conversion_correct<T: HeaderConvertible>(string: &'static str, value: T) {
    assert_eq!(from_stream_with_str(string), Some(value.clone()));
    let s = to_stream_into_str(&value);
    assert_eq!(s.as_slice(), string);
    let s = value.http_value();
    assert_eq!(s.as_slice(), string);
}

// Verify that from_stream interprets the given valid header value correctly.
#[inline]
pub fn assert_interpretation_correct<T: HeaderConvertible>(string: &'static str, value: T) {
    assert_eq!(from_stream_with_str(string), Some(value));
}
<|endoftext|>


<commit_before>#[cfg(target_arch="x86")]
const B: [usize; 5]
    = [ 0x2, 0xC, 0xF0
      , 0xFF00
      , 0xFFFF0000];
#[cfg(target_arch="x86")]
const S: [usize; 5] = [ 1, 2, 4, 8, 16 ];

#[cfg(target_arch="x86_64")]
const B: [usize; 6]
    = [ 0x2, 0xC, 0xF0
      , 0xFF00, 0xFFFF0000
      , 0xFFFFFFFF00000000];

#[cfg(target_arch="x86_64")]
const S: [usize; 6] = [ 1, 2, 4, 8, 16, 32 ];

pub trait PowersOf2 {
    fn is_pow2(&self) -> bool;
    fn next_pow2(&self) -> Self;
    fn log2(&self) -> Self;
}

impl PowersOf2 for usize {
    fn is_pow2(&self) -> bool {
        *self != 0 && (self & (self - 1)) == 0
    }

    /// Returns the next power of 2
    fn next_pow2(&self) -> usize {
        let mut v = *self;
        if v == 0 {
            1
        } else {
            v -= 1;
            v = v | (v >> 1);
            v = v | (v >> 2);
            v = v | (v >> 4);
            v = v | (v >> 8);
            v = v | (v >> 16);
            v + 1
        }
    }

    #[cfg(not(any(target_arch="x86_64", target_arch="x86")))]
    fn log2(&self) -> usize {
        // This is the "obvious" log base 2 implementation. The lookup table
        // -based approach would be much faster, but we can't use it for
        // `usize` since we aren't sure what size a usize is without conditional
        // compilation.
        let mut res = 0;
        let mut num = *self >> 1;
        while num != 0 {
            res += 1;
            num >>= 1;
        }
        res
    }

    #[cfg(any(target_arch="x86_64", target_arch="x86"))]
    fn log2(&self) -> usize {
        let mut r: usize = 0;
        let mut v = *self;

        for i in (0..S.len()).rev() {
            if v & B[i] != 0 {
                v >>= S[i];
                r |=  S[i];
            }
        }
        r
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[cfg(feature = "bench")]
    use test::{self, Bencher};

    #[test]
    fn test_next_pow2() {
        assert_eq!(2usize.next_pow2(), 2);
        assert_eq!(0usize.next_pow2(), 1);
        assert_eq!(3usize.next_pow2(), 4);
        assert_eq!(5678usize.next_pow2(), 8192);
        assert_eq!(1,  0.next_pow2());
        assert_eq!(1,  1.next_pow2());
        assert_eq!(2,  2.next_pow2());
        assert_eq!(4,  3.next_pow2());
        assert_eq!(4,  4.next_pow2());
        assert_eq!(8,  5.next_pow2());
        assert_eq!(8,  8.next_pow2());
        assert_eq!(16, 9.next_pow2());
        assert_eq!(16, 16.next_pow2());
        assert_eq!(32, 17.next_pow2());
        assert_eq!(32, 32.next_pow2());
        assert_eq!(8388608, 8376263.next_pow2());
    }

    #[test]
    fn test_is_pow2() {
    assert_eq!(false, 0.is_pow2());
    assert_eq!(true,  1.is_pow2());
    assert_eq!(true,  2.is_pow2());
    assert_eq!(false, 3.is_pow2());
    assert_eq!(true,  4.is_pow2());
    assert_eq!(false, 255.is_pow2());
    assert_eq!(true,  256.is_pow2());
    assert_eq!(false, 257.is_pow2());
    assert_eq!(false, 4294967295.is_pow2());
    }

    #[test]
    fn test_log2() {
    assert_eq!(0, 0.log2());
    assert_eq!(0, 1.log2());
    assert_eq!(1, 2.log2());
    assert_eq!(5, 32.log2());
    assert_eq!(10, 1024.log2());
    }

    #[bench]
    fn our_next_pow2(b: &mut Bencher) {
        use collections::Vec;
        b.iter(|| {
            let n = test::black_box(100_000);

            (0..n).map(|x: usize| x.next_pow2())
                  .collect::<Vec<_>>() // force the map to return so it doesn't get optimised away
        })
    }

    #[bench]
    fn std_next_power_of_two(b: &mut Bencher) {
        use collections::Vec;
        b.iter(|| {
            let n = test::black_box(100_000);

            (0..n).map(|x: usize| x.next_power_of_two())
                  .collect::<Vec<_>>() // force the map to return so it doesn't get optimised away
        })
    }

    #[bench]
    fn our_is_pow2(b: &mut Bencher) {
        use collections::Vec;
        b.iter(|| {
            let n = test::black_box(100_000);

            (0..n).map(|ref x: usize| x.is_pow2())
                  .collect::<Vec<_>>() // force the map to return so it doesn't get optimised away
        })
    }

    #[bench]
    fn std_is_power_of_two(b: &mut Bencher) {
        use collections::Vec;
        b.iter(|| {
            let n = test::black_box(100_000);

            (0..n).map(|x: usize| x.next_power_of_two())
                  .collect::<Vec<_>>() // force the map to return so it doesn't get optimised away
        })
    }
}
<commit_msg>[alloc] fixed attempting to compile benches without bench flag<commit_after>#[cfg(target_arch="x86")]
const B: [usize; 5]
    = [ 0x2, 0xC, 0xF0
      , 0xFF00
      , 0xFFFF0000];
#[cfg(target_arch="x86")]
const S: [usize; 5] = [ 1, 2, 4, 8, 16 ];

#[cfg(target_arch="x86_64")]
const B: [usize; 6]
    = [ 0x2, 0xC, 0xF0
      , 0xFF00, 0xFFFF0000
      , 0xFFFFFFFF00000000];

#[cfg(target_arch="x86_64")]
const S: [usize; 6] = [ 1, 2, 4, 8, 16, 32 ];

pub trait PowersOf2 {
    fn is_pow2(&self) -> bool;
    fn next_pow2(&self) -> Self;
    fn log2(&self) -> Self;
}

impl PowersOf2 for usize {
    fn is_pow2(&self) -> bool {
        *self != 0 && (self & (self - 1)) == 0
    }

    /// Returns the next power of 2
    fn next_pow2(&self) -> usize {
        let mut v = *self;
        if v == 0 {
            1
        } else {
            v -= 1;
            v = v | (v >> 1);
            v = v | (v >> 2);
            v = v | (v >> 4);
            v = v | (v >> 8);
            v = v | (v >> 16);
            v + 1
        }
    }

    #[cfg(not(any(target_arch="x86_64", target_arch="x86")))]
    fn log2(&self) -> usize {
        // This is the "obvious" log base 2 implementation. The lookup table
        // -based approach would be much faster, but we can't use it for
        // `usize` since we aren't sure what size a usize is without conditional
        // compilation.
        let mut res = 0;
        let mut num = *self >> 1;
        while num != 0 {
            res += 1;
            num >>= 1;
        }
        res
    }

    #[cfg(any(target_arch="x86_64", target_arch="x86"))]
    fn log2(&self) -> usize {
        let mut r: usize = 0;
        let mut v = *self;

        for i in (0..S.len()).rev() {
            if v & B[i] != 0 {
                v >>= S[i];
                r |=  S[i];
            }
        }
        r
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[cfg(feature = "bench")]
    use test::{self, Bencher};

    #[test]
    fn test_next_pow2() {
        assert_eq!(2usize.next_pow2(), 2);
        assert_eq!(0usize.next_pow2(), 1);
        assert_eq!(3usize.next_pow2(), 4);
        assert_eq!(5678usize.next_pow2(), 8192);
        assert_eq!(1,  0.next_pow2());
        assert_eq!(1,  1.next_pow2());
        assert_eq!(2,  2.next_pow2());
        assert_eq!(4,  3.next_pow2());
        assert_eq!(4,  4.next_pow2());
        assert_eq!(8,  5.next_pow2());
        assert_eq!(8,  8.next_pow2());
        assert_eq!(16, 9.next_pow2());
        assert_eq!(16, 16.next_pow2());
        assert_eq!(32, 17.next_pow2());
        assert_eq!(32, 32.next_pow2());
        assert_eq!(8388608, 8376263.next_pow2());
    }

    #[test]
    fn test_is_pow2() {
    assert_eq!(false, 0.is_pow2());
    assert_eq!(true,  1.is_pow2());
    assert_eq!(true,  2.is_pow2());
    assert_eq!(false, 3.is_pow2());
    assert_eq!(true,  4.is_pow2());
    assert_eq!(false, 255.is_pow2());
    assert_eq!(true,  256.is_pow2());
    assert_eq!(false, 257.is_pow2());
    assert_eq!(false, 4294967295.is_pow2());
    }

    #[test]
    fn test_log2() {
    assert_eq!(0, 0.log2());
    assert_eq!(0, 1.log2());
    assert_eq!(1, 2.log2());
    assert_eq!(5, 32.log2());
    assert_eq!(10, 1024.log2());
    }

    #[cfg(feature = "bench")]
    #[bench]
    fn our_next_pow2(b: &mut Bencher) {
        use collections::Vec;
        b.iter(|| {
            let n = test::black_box(100_000);

            (0..n).map(|x: usize| x.next_pow2())
                  .collect::<Vec<_>>() // force the map to return so it doesn't get optimised away
        })
    }

    #[cfg(feature = "bench")]
    #[bench]
    fn std_next_power_of_two(b: &mut Bencher) {
        use collections::Vec;
        b.iter(|| {
            let n = test::black_box(100_000);

            (0..n).map(|x: usize| x.next_power_of_two())
                  .collect::<Vec<_>>() // force the map to return so it doesn't get optimised away
        })
    }

    #[cfg(feature = "bench")]
    #[bench]
    fn our_is_pow2(b: &mut Bencher) {
        use collections::Vec;
        b.iter(|| {
            let n = test::black_box(100_000);

            (0..n).map(|ref x: usize| x.is_pow2())
                  .collect::<Vec<_>>() // force the map to return so it doesn't get optimised away
        })
    }

    #[cfg(feature = "bench")]
    #[bench]
    fn std_is_power_of_two(b: &mut Bencher) {
        use collections::Vec;
        b.iter(|| {
            let n = test::black_box(100_000);

            (0..n).map(|x: usize| x.next_power_of_two())
                  .collect::<Vec<_>>() // force the map to return so it doesn't get optimised away
        })
    }
}
<|endoftext|>